Commit 208791a19a4a5fbef14dd9aa149e98049e16bad3

Authored by Jarrett Jordaan
2 parents dd9d7b61 fd5af8dc

Merge branch 'edge' of git@github.com:ktgit/knowledgetree into edge

download_notification.php 0 → 100644
  1 +<?php
  2 +/*
  3 + * Electronic Signatures ajax functionality
  4 + *
  5 + * The contents of this file are subject to the KnowledgeTree
  6 + * Commercial Editions On-Premise License ("License");
  7 + * You may not use this file except in compliance with the License.
  8 + * You may obtain a copy of the License at
  9 + * http://www.knowledgetree.com/about/legal/
  10 + * The terms of this license may change from time to time and the latest
  11 + * license will be published from time to time at the above Internet address.
  12 + *
  13 + * This edition of the KnowledgeTree software
  14 + * is NOT licensed to you under Open Source terms.
  15 + * You may not redistribute this source code.
  16 + * For more information please see the License above.
  17 + *
  18 + * (c) 2008, 2009 KnowledgeTree Inc.
  19 + * All Rights Reserved.
  20 + *
  21 + * @copyright 2008-2009, KnowledgeTree Inc.
  22 + * @license GNU General Public License version 3
  23 + * @author KnowledgeTree Team
  24 + * @package Electronic Signatures
  25 + * @version Version 0.9
  26 + */
  27 +
  28 +//$full_dir = dirname(__FILE__);
  29 +
  30 +//$pos = strpos($full_dir, 'plugins');
  31 +//$dir = substr($full_dir, 0, $pos);
  32 +
  33 +require_once('config/dmsDefaults.php');
  34 +require_once(KT_LIB_DIR . '/foldermanagement/compressionArchiveUtil.inc.php');
  35 +require_once(KT_LIB_DIR . '/foldermanagement/downloadNotification.inc.php');
  36 +
  37 +$action = $_POST['action'];
  38 +$code = $_POST['code'];
  39 +if ($action == 'delete') {
  40 + DownloadQueue::deleteDownload($code);
  41 +}
  42 +else {
  43 + $head = $_POST['head'];
  44 +
  45 + // display the download notification
  46 + $notification = new KTDownloadNotification($code);
  47 + echo $notification->getNotificationForm($head);
  48 +}
  49 +
  50 +exit;
  51 +?>
0 \ No newline at end of file 52 \ No newline at end of file
lib/foldermanagement/compressionArchiveUtil.inc.php
@@ -311,6 +311,12 @@ class ZipFolder { @@ -311,6 +311,12 @@ class ZipFolder {
311 311
312 KTUtil::download($sZipFile, $mimeType, $fileSize, $fileName); 312 KTUtil::download($sZipFile, $mimeType, $fileSize, $fileName);
313 KTUtil::deleteDirectory($sTmpPath); 313 KTUtil::deleteDirectory($sTmpPath);
  314 + // remove notification file if it exists
  315 + DownloadQueue::removeNotificationFile();
  316 +
  317 + // remove zip file database entry and any stragglers
  318 + DBUtil::whereDelete('download_queue', array('code' => $exportCode));
  319 +
314 return true; 320 return true;
315 } 321 }
316 322
@@ -398,6 +404,26 @@ class ZipFolder { @@ -398,6 +404,26 @@ class ZipFolder {
398 404
399 return false; 405 return false;
400 } 406 }
  407 +
  408 + /**
  409 + * Returns the zip file name with extension
  410 + *
  411 + * @return string
  412 + */
  413 + public function getZipFileName()
  414 + {
  415 + return $this->sZipFileName . '.' . $this->extension;
  416 + }
  417 +
  418 + /**
  419 + * Returns the path to the zip file
  420 + *
  421 + * @return string
  422 + */
  423 + public function getTmpPath()
  424 + {
  425 + return $this->sTmpPath;
  426 + }
401 } 427 }
402 428
403 /** 429 /**
@@ -410,6 +436,7 @@ class DownloadQueue @@ -410,6 +436,7 @@ class DownloadQueue
410 private $bNotifications; 436 private $bNotifications;
411 private $errors; 437 private $errors;
412 private $lockFile; 438 private $lockFile;
  439 + static private $notificationFile = 'download_queue_notification';
413 440
414 /** 441 /**
415 * Construct download queue object 442 * Construct download queue object
@@ -446,25 +473,25 @@ class DownloadQueue @@ -446,25 +473,25 @@ class DownloadQueue
446 473
447 /** 474 /**
448 * Remove an item from the download queue 475 * Remove an item from the download queue
  476 + * Will not remove zip object types, these must be independently removed
449 * 477 *
450 * @param string $code Identification string for the download item 478 * @param string $code Identification string for the download item
451 * @return boolean | PEAR_Error 479 * @return boolean | PEAR_Error
452 */ 480 */
453 public function removeItem($code) 481 public function removeItem($code)
454 { 482 {
455 - $where = array('code' => $code);  
456 - $res = DBUtil::whereDelete('download_queue', $where); 483 + $res = DBUtil::runQuery('DELETE FROM download_queue WHERE code = "' . $code . '" AND object_type != "zip"');
457 return $res; 484 return $res;
458 } 485 }
459 486
460 /** 487 /**
461 - * Get all download items in the queue 488 + * Get all download items (other than zip object type) in the queue
462 * 489 *
463 * @return Queue array | PEAR_Error 490 * @return Queue array | PEAR_Error
464 */ 491 */
465 public function getQueue() 492 public function getQueue()
466 { 493 {
467 - $sql = 'SELECT * FROM download_queue d WHERE status = 0 ORDER BY date_added, code'; 494 + $sql = 'SELECT * FROM download_queue d WHERE status = 0 AND object_type != "zip" ORDER BY date_added, code';
468 $rows = DBUtil::getResultArray($sql); 495 $rows = DBUtil::getResultArray($sql);
469 496
470 if(PEAR::isError($rows)){ 497 if(PEAR::isError($rows)){
@@ -502,12 +529,15 @@ class DownloadQueue @@ -502,12 +529,15 @@ class DownloadQueue
502 * @param string $error Optional. The error's generated during the archive 529 * @param string $error Optional. The error's generated during the archive
503 * @return boolean 530 * @return boolean
504 */ 531 */
505 - public function setItemStatus($code, $status = 1, $error = null) 532 + public function setItemStatus($code, $status = 1, $error = null, $zip = false)
506 { 533 {
507 $fields = array(); 534 $fields = array();
508 $fields['status'] = $status; 535 $fields['status'] = $status;
509 $fields['errors'] = !empty($error) ? json_encode($error) : null; 536 $fields['errors'] = !empty($error) ? json_encode($error) : null;
510 $where = array('code' => $code); 537 $where = array('code' => $code);
  538 + if ($zip) {
  539 + $where['object_type'] = 'zip';
  540 + }
511 $res = DBUtil::whereUpdate('download_queue', $fields, $where); 541 $res = DBUtil::whereUpdate('download_queue', $fields, $where);
512 return $res; 542 return $res;
513 } 543 }
@@ -617,6 +647,17 @@ class DownloadQueue @@ -617,6 +647,17 @@ class DownloadQueue
617 $this->errors = null; 647 $this->errors = null;
618 $_SESSION['zipcompression'] = null; 648 $_SESSION['zipcompression'] = null;
619 } 649 }
  650 +
  651 + if (count($queue) && !PEAR::isError($res) && !PEAR::isError($result)) {
  652 + // create the db entry
  653 + self::addItem($code, self::getFolderId($code), -1, 'zip');
  654 + // update the db entry with the appropriate status and message
  655 + $this->setItemStatus($code, 2, serialize(array($zip->getTmpPath(), $zip->getZipFileName())), true);
  656 + // write a file which will be checked if the user has not been logged out and back in
  657 + // (in which case the required session value will not be set and this file acts as a trigger instead)
  658 + $config = KTConfig::getSingleton();
  659 + @touch($config->get('cache/cacheDirectory') . '/' . self::$notificationFile);
  660 + }
620 661
621 // Remove lock file 662 // Remove lock file
622 @unlink($this->lockFile); 663 @unlink($this->lockFile);
@@ -757,7 +798,8 @@ class DownloadQueue @@ -757,7 +798,8 @@ class DownloadQueue
757 * @param Folder array $aFolderList 798 * @param Folder array $aFolderList
758 * @return unknown 799 * @return unknown
759 */ 800 */
760 - function getLinkingEntities($aFolderList){ 801 + function getLinkingEntities($aFolderList)
  802 + {
761 $aSearchFolders = array(); 803 $aSearchFolders = array();
762 if(!empty($aFolderList)){ 804 if(!empty($aFolderList)){
763 foreach($aFolderList as $oFolderItem){ 805 foreach($aFolderList as $oFolderItem){
@@ -846,5 +888,142 @@ class DownloadQueue @@ -846,5 +888,142 @@ class DownloadQueue
846 { 888 {
847 return file_exists($this->lockFile); 889 return file_exists($this->lockFile);
848 } 890 }
  891 +
  892 + /**
  893 + * The code below has all been added for bulk download notifications
  894 + *
  895 + * The functions were declared as static because they are related to but not entirely part of the download queue process
  896 + * and I wanted to use them without having to instantiate the class
  897 + */
  898 +
  899 + /**
  900 + * Checks whether there are any bulk downloads which have passed the timeout limit
  901 + * Default limit is set to 48 hours but this can be changed in the calling code
  902 + *
  903 + * @param int $limit the number of hours after which a download should be considered timed out
  904 + */
  905 + static public function timeout($limit = 48)
  906 + {
  907 + DBUtil::runQuery('DELETE FROM download_queue WHERE DATE_ADD(date_added, INTERVAL ' . $limit . ' HOUR) < NOW()');
  908 + }
  909 +
  910 + /**
  911 + * Checks whether there is a bulk download available and waiting for the supplied user
  912 + *
  913 + * @param int $userID
  914 + */
  915 + static public function userDownloadAvailable($userID)
  916 + {
  917 + $result = DBUtil::getOneResult('SELECT code, errors FROM download_queue WHERE user_id = ' . $userID
  918 + . ' AND object_type = "zip" AND status = 2');
  919 + if (PEAR::isError($result)) {
  920 + return false;
  921 + }
  922 +
  923 + $code = $result['code'];
  924 +
  925 + $message = $result['errors'];
  926 + $message = json_decode($message, true);
  927 + $data = unserialize($message);
  928 +
  929 + // Create the archive session variables - I can't recall if this was needed, will have to find out by testing...
  930 + $_SESSION['zipcompression'][$code]['file'] = $data[0] . DIRECTORY_SEPARATOR . $data[1];
  931 + $_SESSION['zipcompression'][$code]['dir'] = $data[0];
  932 +
  933 + // Check that the archive file has been created
  934 + // NOTE If it does not exist, consider deleting the db entry and looping back to check again, only returning when no more results are found in the db?
  935 + // The reason for this is that it is sometimes possible to end up with multiple zips listed in the db as waiting for the same user,
  936 + // some of which may no longer exist as physical files, and since the request only checks for one, it may miss am existing download.
  937 + // NOTE the above issue may only occur due to the way I have been testing, often breaking the process before it is finished,
  938 + // but conceivably this could actually happen in the real world also.
  939 + $zip = new ZipFolder('', $code);
  940 + if($zip->checkArchiveExists($code)) {
  941 + return $code;
  942 + }
  943 +
  944 + return false;
  945 + }
  946 +
  947 + /**
  948 + * Delete the download, including the database entry
  949 + *
  950 + * @param string $code
  951 + */
  952 + static public function deleteDownload($code)
  953 + {
  954 + // retrieve the data to allow deletion of the physical file
  955 + $result = DBUtil::getOneResult('SELECT errors FROM download_queue WHERE code = "' . $code . '"'
  956 + . ' AND object_type = "zip" AND status = 2');
  957 +
  958 + if (PEAR::isError($result)) {
  959 + return $result;
  960 + }
  961 +
  962 + $message = $result['errors'];
  963 + $message = json_decode($message, true);
  964 + $data = unserialize($message);
  965 +
  966 + // remove the database entry
  967 + DBUtil::whereDelete('download_queue', array('code' => $code));
  968 +
  969 + // remove the actual file/directory
  970 + KTUtil::deleteDirectory($data[0]);
  971 +
  972 + // remove the notification file if present
  973 + self::removeNotificationFile();
  974 + }
  975 +
  976 + /**
  977 + * Removes the notification file, if it exists, in a safe manner
  978 + *
  979 + * @param string $code
  980 + */
  981 + static public function removeNotificationFile() {
  982 + $config = KTConfig::getSingleton();
  983 + $file = DownloadQueue::getNotificationFileName();
  984 + if (!PEAR::isError($file)) {
  985 + $notificationFile = $config->get('cache/cacheDirectory') . '/' . $file;
  986 + }
  987 +
  988 + // ensure the file is actually a file and not a directory
  989 + if (is_file($notificationFile)) {
  990 + @unlink($notificationFile);
  991 + }
  992 + }
  993 +
  994 + /**
  995 + * Fetches a link to the download
  996 + *
  997 + * @param string $code
  998 + */
  999 + static public function getDownloadLink($code)
  1000 + {
  1001 + return KTUtil::kt_url() . '/action.php?kt_path_info=ktcore.actions.bulk.export&action=downloadZipFile&fFolderId=' . self::getFolderId($code) . '&exportcode=' . $code;
  1002 + }
  1003 +
  1004 + /**
  1005 + * Fetches the folder id associated with the supplied code
  1006 + * Based on testing just before file corruption this may not actually be necessary, but we'll do it anyway
  1007 + *
  1008 + * @param string $code
  1009 + */
  1010 + static public function getFolderId($code)
  1011 + {
  1012 + $result = DBUtil::getOneResult('SELECT folder_id FROM download_queue WHERE code = "' . $code . '"');
  1013 +
  1014 + if (PEAR::isError($result)) {
  1015 + return -1;
  1016 + }
  1017 +
  1018 + return $result['folder_id'];
  1019 + }
  1020 +
  1021 + static public function getNotificationFileName() {
  1022 + if (!empty(self::$notificationFile)) {
  1023 + return self::$notificationFile;
  1024 + }
  1025 +
  1026 + return new PEAR_Error('Unable to get file name');
  1027 + }
849 } 1028 }
850 ?> 1029 ?>
lib/foldermanagement/downloadNotification.inc.php 0 → 100644
  1 +<?php
  2 +
  3 +/**
  4 + * Class handles the bulk download notification
  5 + *
  6 + * @author KnowledgeTree Team
  7 + * @package Bulk Downloads
  8 + */
  9 +class KTDownloadNotification
  10 +{
  11 + /**
  12 + * The error returned
  13 + *
  14 + * @access public
  15 + * @var $error
  16 + */
  17 + public $error;
  18 +
  19 + /**
  20 + * The user for which the download notification is being generated
  21 + *
  22 + * @access private
  23 + * @var $code
  24 + */
  25 + private $code;
  26 +
  27 + /**
  28 + * Constructor function for the class
  29 + *
  30 + * @author KnowledgeTree Team
  31 + * @access public
  32 + * @return KTElectronicSignatures
  33 + */
  34 + public function KTDownloadNotification($code)
  35 + {
  36 + $this->code = $code;
  37 + }
  38 +
  39 + /**
  40 + * Returns the form displaying the download link (and option to cancel the download?)
  41 + *
  42 + * @author KnowledgeTree Team
  43 + * @access public
  44 + * @param string $head The heading for the form
  45 + * @param string $request_type Determines the actions for the buttons
  46 + * @return html
  47 + */
  48 + public function getNotificationForm($head)
  49 + {
  50 + global $default;
  51 +
  52 + // check for the download link
  53 +
  54 + $link = DownloadQueue::getDownloadLink($this->code);
  55 + $text = 'Download Now';
  56 +
  57 + $cancelAction = 'deleteDownload()';
  58 + $closeAction = 'deferDownload()';
  59 +
  60 + $oTemplating =& KTTemplating::getSingleton();
  61 + $oTemplate = $oTemplating->loadTemplate('kt3/notifications/notification.BulkDownload');
  62 + $aTemplateData = array(
  63 + 'head' => $head,
  64 + 'downloadLink' => $link,
  65 + 'downloadText' => $text,
  66 + 'exportCode' => $this->code,
  67 + 'cancelAction' => $cancelAction,
  68 + 'closeAction' => $closeAction
  69 + );
  70 +
  71 + return $oTemplate->render($aTemplateData);
  72 + }
  73 +
  74 + /**
  75 + * Returns the error from the attempted signature
  76 + *
  77 + * @author KnowledgeTree Team
  78 + * @access public
  79 + * @return string
  80 + */
  81 + public function getError()
  82 + {
  83 + return '<div class="error">'.$this->error.'</div>';
  84 + }
  85 +
  86 + /**
  87 + * Displays a button for closing the panel
  88 + *
  89 + * @author KnowledgeTree Team
  90 + * @access public
  91 + * @param string $request_type Determines the action taken on close - close = redirect action | null = close panel action
  92 + * @param string $request Optional. Used within the close action.
  93 + * @return string
  94 + */
  95 + public function getCloseButton($request_type, $request = null)
  96 + {
  97 + switch ($request_type){
  98 + case 'close':
  99 + $cancelAction = "window.location.href = '{$request}'";
  100 + break;
  101 +
  102 + default:
  103 + $cancelAction = "panel_close()";
  104 + }
  105 +
  106 + return '<div class="form_actions" style="margin-top: 30px;">
  107 + <a href="#" onclick="javascript: '.$cancelAction.'">'._kt('Close').'</a>
  108 + </div>';
  109 + }
  110 +}
  111 +
  112 +?>
0 \ No newline at end of file 113 \ No newline at end of file
lib/templating/kt3template.inc.php
@@ -353,8 +353,9 @@ class KTPage { @@ -353,8 +353,9 @@ class KTPage {
353 function setSecondaryTitle($sSecondary) { $this->secondary_title = $sSecondary; } 353 function setSecondaryTitle($sSecondary) { $this->secondary_title = $sSecondary; }
354 354
355 /* final render call. */ 355 /* final render call. */
356 - function render() {  
357 - global $default; 356 + function render()
  357 + {
  358 + global $default;
358 $oConfig = KTConfig::getSingleton(); 359 $oConfig = KTConfig::getSingleton();
359 360
360 if (empty($this->contents)) { 361 if (empty($this->contents)) {
@@ -366,70 +367,68 @@ class KTPage { @@ -366,70 +367,68 @@ class KTPage {
366 $this->contents = ""; 367 $this->contents = "";
367 } 368 }
368 369
369 - if (!is_string($this->contents)) {  
370 - $this->contents = $this->contents->render();  
371 - }  
372 -  
373 - // if we have no portlets, make the ui a tad nicer.  
374 - if (empty($this->portlets)) {  
375 - $this->show_portlets = false;  
376 - }  
377 -  
378 - if (empty($this->title)) {  
379 - if (!empty($this->breadcrumbDetails)) {  
380 - $this->title = $this->breadcrumbDetails;  
381 - } else if (!empty($this->breadcrumbs)) {  
382 - $this->title = array_slice($this->breadcrumbs, -1);  
383 - $this->title = $this->title[0]['label'];  
384 - } else if (!empty($this->breadcrumbSection)) {  
385 - $this->title = $this->breadcrumbSection['label'];  
386 - } else {  
387 - $this->title = $this->componentLabel;  
388 - }  
389 - }  
390 -  
391 - $this->userMenu = array();  
392 - $sBaseUrl = KTUtil::kt_url(); 370 + if (!is_string($this->contents)) {
  371 + $this->contents = $this->contents->render();
  372 + }
393 373
394 - if (!(PEAR::isError($this->user) || is_null($this->user) || $this->user->isAnonymous())) {  
395 - if ($oConfig->get("user_prefs/restrictPreferences", false) && !Permission::userIsSystemAdministrator($this->user->getId())) {  
396 - $this->userMenu['logout'] = array('label' => _kt('Logout'), 'url' => $sBaseUrl.'/presentation/logout.php');  
397 - } else { 374 + // if we have no portlets, make the ui a tad nicer.
  375 + if (empty($this->portlets)) {
  376 + $this->show_portlets = false;
  377 + }
398 378
399 - if($default->enableESignatures){  
400 - $sUrl = KTPluginUtil::getPluginPath('electronic.signatures.plugin', true);  
401 - $heading = _kt('You are attempting to modify Preferences');  
402 - $this->userMenu['preferences']['url'] = '#';  
403 - $this->userMenu['preferences']['onclick'] = "javascript: showSignatureForm('{$sUrl}', '{$heading}', 'dms.administration.accessing_preferences', 'system', '{$sBaseUrl}/preferences.php', 'redirect');";  
404 - }else{  
405 - $this->userMenu['preferences']['url'] = $sBaseUrl.'/preferences.php'; 379 + if (empty($this->title)) {
  380 + if (!empty($this->breadcrumbDetails)) {
  381 + $this->title = $this->breadcrumbDetails;
  382 + } else if (!empty($this->breadcrumbs)) {
  383 + $this->title = array_slice($this->breadcrumbs, -1);
  384 + $this->title = $this->title[0]['label'];
  385 + } else if (!empty($this->breadcrumbSection)) {
  386 + $this->title = $this->breadcrumbSection['label'];
  387 + } else {
  388 + $this->title = $this->componentLabel;
406 } 389 }
  390 + }
407 391
408 -// $this->userMenu['preferences'] = array('label' => _kt('Preferences'), 'url' => $sBaseUrl.'/preferences.php');  
409 - $this->userMenu['preferences']['label'] = _kt('Preferences');  
410 - $this->userMenu['aboutkt'] = array('label' => _kt('About'), 'url' => $sBaseUrl.'/about.php');  
411 - $this->userMenu['logout'] = array('label' => _kt('Logout'), 'url' => $sBaseUrl.'/presentation/logout.php');  
412 - }  
413 - } else {  
414 - $this->userMenu['login'] = array('label' => _kt('Login'), 'url' => $sBaseUrl.'/login.php');  
415 - }  
416 -  
417 - // FIXME we need a more complete solution to navigation restriction  
418 - if (!is_null($this->menu['administration']) && !is_null($this->user)) {  
419 - if (!Permission::userIsSystemAdministrator($this->user->getId())) {  
420 - unset($this->menu['administration']);  
421 - }  
422 - } 392 + $this->userMenu = array();
  393 + $sBaseUrl = KTUtil::kt_url();
  394 +
  395 + if (!(PEAR::isError($this->user) || is_null($this->user) || $this->user->isAnonymous())) {
  396 + if ($oConfig->get("user_prefs/restrictPreferences", false) && !Permission::userIsSystemAdministrator($this->user->getId())) {
  397 + $this->userMenu['logout'] = array('label' => _kt('Logout'), 'url' => $sBaseUrl.'/presentation/logout.php');
  398 + } else {
  399 + if($default->enableESignatures) {
  400 + $sUrl = KTPluginUtil::getPluginPath('electronic.signatures.plugin', true);
  401 + $heading = _kt('You are attempting to modify Preferences');
  402 + $this->userMenu['preferences']['url'] = '#';
  403 + $this->userMenu['preferences']['onclick'] = "javascript: showSignatureForm('{$sUrl}', '{$heading}', 'dms.administration.accessing_preferences', 'system', '{$sBaseUrl}/preferences.php', 'redirect');";
  404 + } else {
  405 + $this->userMenu['preferences']['url'] = $sBaseUrl.'/preferences.php';
  406 + }
  407 +
  408 + // $this->userMenu['preferences'] = array('label' => _kt('Preferences'), 'url' => $sBaseUrl.'/preferences.php');
  409 + $this->userMenu['preferences']['label'] = _kt('Preferences');
  410 + $this->userMenu['aboutkt'] = array('label' => _kt('About'), 'url' => $sBaseUrl.'/about.php');
  411 + $this->userMenu['logout'] = array('label' => _kt('Logout'), 'url' => $sBaseUrl.'/presentation/logout.php');
  412 + }
  413 + } else {
  414 + $this->userMenu['login'] = array('label' => _kt('Login'), 'url' => $sBaseUrl.'/login.php');
  415 + }
423 416
424 - $sContentType = 'Content-type: ' . $this->contentType;  
425 - if(!empty($this->charset)) {  
426 - $sContentType .= '; charset=' . $this->charset;  
427 - }; 417 + // FIXME we need a more complete solution to navigation restriction
  418 + if (!is_null($this->menu['administration']) && !is_null($this->user)) {
  419 + if (!Permission::userIsSystemAdministrator($this->user->getId())) {
  420 + unset($this->menu['administration']);
  421 + }
  422 + }
428 423
  424 + $sContentType = 'Content-type: ' . $this->contentType;
  425 + if(!empty($this->charset)) {
  426 + $sContentType .= '; charset=' . $this->charset;
  427 + };
429 428
430 - header($sContentType); 429 + header($sContentType);
431 430
432 - $savedSearches = SearchHelper::getSavedSearches($_SESSION['userID']); 431 + $savedSearches = SearchHelper::getSavedSearches($_SESSION['userID']);
433 432
434 $oTemplating =& KTTemplating::getSingleton(); 433 $oTemplating =& KTTemplating::getSingleton();
435 $oTemplate = $oTemplating->loadTemplate($this->template); 434 $oTemplate = $oTemplating->loadTemplate($this->template);
@@ -442,13 +441,24 @@ class KTPage { @@ -442,13 +441,24 @@ class KTPage {
442 if ($oConfig->get("ui/automaticRefresh", false)) { 441 if ($oConfig->get("ui/automaticRefresh", false)) {
443 $aTemplateData['refreshTimeout'] = (int)$oConfig->get("session/sessionTimeout") + 3; 442 $aTemplateData['refreshTimeout'] = (int)$oConfig->get("session/sessionTimeout") + 3;
444 } 443 }
  444 +
  445 + // Trigger for pending downloads
  446 + $aTemplateData['downloadNotification'] = null;
  447 + require_once(KT_LIB_DIR . '/triggers/triggerregistry.inc.php');
  448 + $oKTTriggerRegistry = KTTriggerRegistry::getSingleton();
  449 + $aTriggers = $oKTTriggerRegistry->getTriggers('ktcore', 'pageLoad');
  450 + foreach ($aTriggers as $aTrigger) {
  451 + $sTrigger = $aTrigger[0];
  452 + $oTrigger = new $sTrigger;
  453 + $aTemplateData['downloadNotification'] = $oTrigger->invoke();
  454 + }
445 455
446 // unlike the rest of KT, we use echo here. 456 // unlike the rest of KT, we use echo here.
447 echo $oTemplate->render($aTemplateData); 457 echo $oTemplate->render($aTemplateData);
448 } 458 }
449 459
450 460
451 - /** heler functions */ 461 + /** helper functions */
452 // returns an array ("url", "label") 462 // returns an array ("url", "label")
453 function _actionhelper($aActionTuple) { 463 function _actionhelper($aActionTuple) {
454 $aTuple = Array("label" => $aActionTuple["name"]); 464 $aTuple = Array("label" => $aActionTuple["name"]);
login.php
@@ -116,6 +116,9 @@ class LoginPageDispatcher extends KTDispatcher { @@ -116,6 +116,9 @@ class LoginPageDispatcher extends KTDispatcher {
116 if (PEAR::isError($sessionID)) { 116 if (PEAR::isError($sessionID)) {
117 return $sessionID; 117 return $sessionID;
118 } 118 }
  119 +
  120 + // add a flag to check for bulk downloads after login is succesful; this will be cleared in the code which checks
  121 + $_SESSION['checkBulkDownload'] = true;
119 122
120 $redirect = strip_tags(KTUtil::arrayGet($_REQUEST, 'redirect')); 123 $redirect = strip_tags(KTUtil::arrayGet($_REQUEST, 'redirect'));
121 124
plugins/ktcore/KTBulkActions.php
@@ -1197,7 +1197,7 @@ class KTBrowseBulkExportAction extends KTBulkAction { @@ -1197,7 +1197,7 @@ class KTBrowseBulkExportAction extends KTBulkAction {
1197 * 1197 *
1198 */ 1198 */
1199 function perform_action($oEntity) { 1199 function perform_action($oEntity) {
1200 -// TODO find a way to do bulk email 1200 + // TODO find a way to do bulk email
1201 $exportCode = $_SESSION['exportcode']; 1201 $exportCode = $_SESSION['exportcode'];
1202 $this->oZip = ZipFolder::get($exportCode); 1202 $this->oZip = ZipFolder::get($exportCode);
1203 1203
plugins/ktcore/KTCorePlugin.php
@@ -169,11 +169,13 @@ class KTCorePlugin extends KTPlugin { @@ -169,11 +169,13 @@ class KTCorePlugin extends KTPlugin {
169 $this->registerTrigger('add', 'postValidate', 'SavedSearchSubscriptionTrigger', 'ktcore.search2.savedsearch.subscription.add', KT_DIR . '/plugins/search2/Search2Triggers.php'); 169 $this->registerTrigger('add', 'postValidate', 'SavedSearchSubscriptionTrigger', 'ktcore.search2.savedsearch.subscription.add', KT_DIR . '/plugins/search2/Search2Triggers.php');
170 $this->registerTrigger('discussion', 'postValidate', 'SavedSearchSubscriptionTrigger', 'ktcore.search2.savedsearch.subscription.discussion', KT_DIR . '/plugins/search2/Search2Triggers.php'); 170 $this->registerTrigger('discussion', 'postValidate', 'SavedSearchSubscriptionTrigger', 'ktcore.search2.savedsearch.subscription.discussion', KT_DIR . '/plugins/search2/Search2Triggers.php');
171 171
172 - //Tag Cloud Triggers 172 + // Tag Cloud Triggers
173 $this->registerTrigger('add', 'postValidate', 'KTAddDocumentTrigger', 'ktcore.triggers.tagcloud.add', KT_DIR.'/plugins/tagcloud/TagCloudTriggers.php'); 173 $this->registerTrigger('add', 'postValidate', 'KTAddDocumentTrigger', 'ktcore.triggers.tagcloud.add', KT_DIR.'/plugins/tagcloud/TagCloudTriggers.php');
174 $this->registerTrigger('edit', 'postValidate', 'KTEditDocumentTrigger', 'ktcore.triggers.tagcloud.edit', KT_DIR.'/plugins/tagcloud/TagCloudTriggers.php'); 174 $this->registerTrigger('edit', 'postValidate', 'KTEditDocumentTrigger', 'ktcore.triggers.tagcloud.edit', KT_DIR.'/plugins/tagcloud/TagCloudTriggers.php');
175 175
176 - 176 + // Bulk Download Trigger
  177 + $this->registerTrigger('ktcore', 'pageLoad', 'BulkDownloadTrigger', 'ktcore.triggers.pageload', 'KTDownloadTriggers.inc.php');
  178 +
177 // widgets 179 // widgets
178 $this->registerWidget('KTCoreInfoWidget', 'ktcore.widgets.info', 'KTWidgets.php'); 180 $this->registerWidget('KTCoreInfoWidget', 'ktcore.widgets.info', 'KTWidgets.php');
179 $this->registerWidget('KTCoreHiddenWidget', 'ktcore.widgets.hidden', 'KTWidgets.php'); 181 $this->registerWidget('KTCoreHiddenWidget', 'ktcore.widgets.hidden', 'KTWidgets.php');
@@ -198,6 +200,7 @@ class KTCorePlugin extends KTPlugin { @@ -198,6 +200,7 @@ class KTCorePlugin extends KTPlugin {
198 $this->registerWidget('KTCoreLayerWidget', 'ktcore.widgets.layer', 'KTWidgets.php'); 200 $this->registerWidget('KTCoreLayerWidget', 'ktcore.widgets.layer', 'KTWidgets.php');
199 $this->registerWidget('KTCoreConditionalSelectionWidget', 'ktcore.widgets.conditionalselection', 'KTWidgets.php'); 201 $this->registerWidget('KTCoreConditionalSelectionWidget', 'ktcore.widgets.conditionalselection', 'KTWidgets.php');
200 $this->registerWidget('KTCoreImageWidget', 'ktcore.widgets.image', 'KTWidgets.php'); 202 $this->registerWidget('KTCoreImageWidget', 'ktcore.widgets.image', 'KTWidgets.php');
  203 + $this->registerWidget('KTCoreImageSelectWidget', 'ktcore.widgets.imageselect', 'KTWidgets.php');
201 $this->registerWidget('KTCoreImageCropWidget', 'ktcore.widgets.imagecrop', 'KTWidgets.php'); 204 $this->registerWidget('KTCoreImageCropWidget', 'ktcore.widgets.imagecrop', 'KTWidgets.php');
202 205
203 $this->registerPage('collection', 'KTCoreCollectionPage', 'KTWidgets.php'); 206 $this->registerPage('collection', 'KTCoreCollectionPage', 'KTWidgets.php');
plugins/ktcore/KTDownloadTriggers.inc.php 0 → 100644
  1 +<?php
  2 +
  3 +/**
  4 + * $Id$
  5 + *
  6 + * KnowledgeTree Community Edition
  7 + * Document Management Made Simple
  8 + * Copyright (C) 2008, 2009 KnowledgeTree Inc.
  9 + *
  10 + *
  11 + * This program is free software; you can redistribute it and/or modify it under
  12 + * the terms of the GNU General Public License version 3 as published by the
  13 + * Free Software Foundation.
  14 + *
  15 + * This program is distributed in the hope that it will be useful, but WITHOUT
  16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  18 + * details.
  19 + *
  20 + * You should have received a copy of the GNU General Public License
  21 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  22 + *
  23 + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco,
  24 + * California 94120-7775, or email info@knowledgetree.com.
  25 + *
  26 + * The interactive user interfaces in modified source and object code versions
  27 + * of this program must display Appropriate Legal Notices, as required under
  28 + * Section 5 of the GNU General Public License version 3.
  29 + *
  30 + * In accordance with Section 7(b) of the GNU General Public License version 3,
  31 + * these Appropriate Legal Notices must retain the display of the "Powered by
  32 + * KnowledgeTree" logo and retain the original copyright notice. If the display of the
  33 + * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
  34 + * must display the words "Powered by KnowledgeTree" and retain the original
  35 + * copyright notice.
  36 + * Contributor( s): ______________________________________
  37 + *
  38 + */
  39 +
  40 +class BulkDownloadTrigger {
  41 +
  42 + var $sNamespace = 'ktcore.triggers.download';
  43 + var $sFriendlyName;
  44 + var $sDescription;
  45 +
  46 + function __construct()
  47 + {
  48 + $this->sFriendlyName = _kt('Bulk Download Notification');
  49 + $this->sDescription = _kt('Notifies the newly logged in user of any waiting bulk downloads.');
  50 + }
  51 +
  52 + public function invoke()
  53 + {
  54 + // TODO get this working with triggers instead of this?
  55 + // check for timed out downloads - now we may be looking at enough code to justify a trigger instead of all being here...?
  56 + DownloadQueue::timeout();
  57 +
  58 + // determine whether there is a waiting bulk download
  59 + global $main;
  60 + // first check whether there is in fact a download waiting for this user
  61 + $config = KTConfig::getSingleton();
  62 + $file = DownloadQueue::getNotificationFileName();
  63 + if (!PEAR::isError($file)) {
  64 + $notificationFile = $config->get('cache/cacheDirectory') . '/' . $file;
  65 + }
  66 + if ((isset($_SESSION['checkBulkDownload']) && ($_SESSION['checkBulkDownload'])) || (file_exists($notificationFile))) {
  67 + unset($_SESSION['checkBulkDownload']);
  68 + DownloadQueue::removeNotificationFile();
  69 +
  70 + require_once(KT_LIB_DIR . DIRECTORY_SEPARATOR . 'foldermanagement' . DIRECTORY_SEPARATOR . 'compressionArchiveUtil.inc.php');
  71 +
  72 + $userID = $_SESSION['userID'];
  73 + $code = DownloadQueue::userDownloadAvailable($userID);
  74 + if ($code) {
  75 + $sBaseUrl = KTUtil::kt_url();
  76 + $sUrl = $sBaseUrl . '/';
  77 + $heading = _kt('You have a download waiting');
  78 + $main->requireJSResource('resources/js/download_notification.js');
  79 + $notification = "showDownloadNotification('{$sUrl}', '{$heading}', 'dms.users.bulk_download_notification', "
  80 + . "'{$code}', 'close');";
  81 + }
  82 +
  83 + return $notification;
  84 + }
  85 +
  86 + return null;
  87 + }
  88 +
  89 +}
  90 +
  91 +?>
plugins/ktcore/KTWidgets.php
@@ -1140,6 +1140,56 @@ class KTCoreImageWidget extends KTWidget { @@ -1140,6 +1140,56 @@ class KTCoreImageWidget extends KTWidget {
1140 return $oTemplate->render($aTemplateData); 1140 return $oTemplate->render($aTemplateData);
1141 } 1141 }
1142 1142
  1143 +}
  1144 +
  1145 +class KTCoreImageSelectWidget extends KTWidget {
  1146 + var $sNamespace = 'ktcore.widgets.imageselect';
  1147 + var $sTemplate = 'ktcore/forms/widgets/imageselect';
  1148 +
  1149 + function configure($aOptions) {
  1150 + $res = parent::configure($aOptions);
  1151 + if (PEAR::isError($res)) {
  1152 + return $res;
  1153 + }
  1154 +
  1155 + }
  1156 +
  1157 + function render() {
  1158 + $oTemplating =& KTTemplating::getSingleton();
  1159 + $oTemplate = $oTemplating->loadTemplate('ktcore/forms/widgets/base');
  1160 +
  1161 + $this->aJavascript[] = 'thirdpartyjs/jquery/jquery-1.3.2.js';
  1162 +
  1163 + if (!empty($this->aJavascript)) {
  1164 + // grab our inner page.
  1165 + $oPage =& $GLOBALS['main'];
  1166 + $oPage->requireJSResources($this->aJavascript);
  1167 + }
  1168 +
  1169 + $this->aCSS[] = 'resources/css/kt_imageselect.css';
  1170 +
  1171 + if (!empty($this->aCSS)) {
  1172 + // grab our inner page.
  1173 + $oPage =& $GLOBALS['main'];
  1174 + $oPage->requireCSSResources($this->aCSS);
  1175 + }
  1176 +
  1177 + $widget_content = $this->getWidget();
  1178 +
  1179 + $aTemplateData = array(
  1180 + "context" => $this,
  1181 + "label" => $this->sLabel,
  1182 + "description" => $this->sDescription,
  1183 + "name" => $this->sName,
  1184 + "has_value" => ($this->value !== null),
  1185 + "value" => $this->value,
  1186 + "has_errors" => $bHasErrors,
  1187 + "errors" => $this->aErrors,
  1188 + "options" => $this->aOptions,
  1189 + "widget" => $widget_content,
  1190 + );
  1191 + return $oTemplate->render($aTemplateData);
  1192 + }
1143 1193
1144 } 1194 }
1145 1195
plugins/ktcore/admin/manageBranding.php
@@ -84,7 +84,7 @@ class ManageBrandDispatcher extends KTAdminDispatcher { @@ -84,7 +84,7 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
84 'encoding' => 'multipart/form-data', 84 'encoding' => 'multipart/form-data',
85 'context' => &$this, 85 'context' => &$this,
86 'extraargs' => $this->meldPersistQuery("","",true), 86 'extraargs' => $this->meldPersistQuery("","",true),
87 - 'description' => _kt('The logo upload facility allows you to upload a logo to brand your knowledgetree site.') 87 + 'description' => _kt('You can upload a logo to brand your KnowledgeTree site.')
88 )); 88 ));
89 89
90 $oWF =& KTWidgetFactory::getSingleton(); 90 $oWF =& KTWidgetFactory::getSingleton();
@@ -99,7 +99,7 @@ class ManageBrandDispatcher extends KTAdminDispatcher { @@ -99,7 +99,7 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
99 'name' => 'file', 99 'name' => 'file',
100 'id' => 'file', 100 'id' => 'file',
101 'value' => '', 101 'value' => '',
102 - '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"'), 102 + 'description' => _kt("The logo's dimensions should be 313px width by 50px height. If your logo doesn't fit these dimensions, you can choose to crop or scale it."),
103 )); 103 ));
104 104
105 $aVocab['crop'] = 'Crop - Cut out a selection'; 105 $aVocab['crop'] = 'Crop - Cut out a selection';
@@ -142,6 +142,61 @@ class ManageBrandDispatcher extends KTAdminDispatcher { @@ -142,6 +142,61 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
142 142
143 143
144 /** 144 /**
  145 + * Returns the scale logo form
  146 + *
  147 + * This form will display a preview of all the possible sclaled combinations.
  148 + * This includes:
  149 + *
  150 + * Stretched, Top Left Cropped, Proportional Stretch, Proportional Top Left Cropped
  151 + *
  152 + * @return KTForm
  153 + *
  154 + */
  155 +
  156 + function getScaleLogoForm($logoItems = array()) {
  157 + $this->oPage->setBreadcrumbDetails(_kt("Scale Logo"));
  158 +
  159 + $oForm = new KTForm;
  160 + $oForm->setOptions(array(
  161 + 'identifier' => 'ktcore.folder.branding',
  162 + 'label' => _kt('Choose Logo'),
  163 + 'submit_label' => _kt('Select'),
  164 + 'action' => 'selectLogo',
  165 + 'fail_action' => 'main',
  166 + 'encoding' => 'multipart/form-data',
  167 + 'context' => &$this,
  168 + 'extraargs' => $this->meldPersistQuery("","",true),
  169 + 'description' => _kt('Choose a logo by clicking on one of the images')
  170 + ));
  171 +
  172 + $oWF =& KTWidgetFactory::getSingleton();
  173 +
  174 + $widgets = array();
  175 + $validators = array();
  176 +
  177 + $logoFileName = 'var'.DIRECTORY_SEPARATOR.'branding'.DIRECTORY_SEPARATOR.'logo'.DIRECTORY_SEPARATOR.$logoFileName;
  178 +
  179 + // Adding the image select widget (User will select the best image)
  180 + $widgets[] = $oWF->get('ktcore.widgets.imageselect', array(
  181 + 'label' => _kt('Logo Preview'),
  182 + 'name' => $logoFileName,
  183 + 'value' => $logoItems,
  184 + ));
  185 +
  186 + // Adding the Hidden FileName Input String
  187 + $widgets[] = $oWF->get('ktcore.widgets.hidden', array(
  188 + 'name' => 'kt_imageselect',
  189 + 'value' => $logoItems[0],
  190 + ));
  191 +
  192 + $oForm->setWidgets($widgets);
  193 + $oForm->setValidators($validators);
  194 +
  195 + return $oForm;
  196 + }
  197 +
  198 +
  199 + /**
145 * Returns the crop logo form 200 * Returns the crop logo form
146 * 201 *
147 * This form will assist the user in selecting an area of the image to use as the logo 202 * This form will assist the user in selecting an area of the image to use as the logo
@@ -311,7 +366,7 @@ class ManageBrandDispatcher extends KTAdminDispatcher { @@ -311,7 +366,7 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
311 366
312 //Changing to logo.jpg (Need to preserve extention as GD requires the exact image type to work) 367 //Changing to logo.jpg (Need to preserve extention as GD requires the exact image type to work)
313 $ext = end(explode('.', $logoFileName)); 368 $ext = end(explode('.', $logoFileName));
314 - $logoFileName = 'logo_tmp.'.$ext; 369 + $logoFileName = 'logo_tmp_'.md5(Date('ymd-hms')).'.'.$ext; //Fighting the browser cache here
315 $logoFile = $logoDir.DIRECTORY_SEPARATOR.$logoFileName; 370 $logoFile = $logoDir.DIRECTORY_SEPARATOR.$logoFileName;
316 371
317 // deleting old tmp file 372 // deleting old tmp file
@@ -329,6 +384,8 @@ class ManageBrandDispatcher extends KTAdminDispatcher { @@ -329,6 +384,8 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
329 384
330 $resizeMethod = $_REQUEST['data']['resize_method']; 385 $resizeMethod = $_REQUEST['data']['resize_method'];
331 386
  387 + $relDir = 'var'.DIRECTORY_SEPARATOR.'branding'.DIRECTORY_SEPARATOR.'logo'.DIRECTORY_SEPARATOR;
  388 +
332 switch ($resizeMethod) { 389 switch ($resizeMethod) {
333 case 'crop': 390 case 'crop':
334 $cropLogoForm = $this->getCropLogoForm($logoFileName); 391 $cropLogoForm = $this->getCropLogoForm($logoFileName);
@@ -336,9 +393,24 @@ class ManageBrandDispatcher extends KTAdminDispatcher { @@ -336,9 +393,24 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
336 393
337 case 'scale': 394 case 'scale':
338 $type = $_FILES['_kt_attempt_unique_file']['type']; 395 $type = $_FILES['_kt_attempt_unique_file']['type'];
339 - $res = $this->scaleImage($logoFile, $logoFile, $this->maxLogoWidth, $this->maxLogoHeight, $type);  
340 396
341 - $form = $this->getApplyLogoForm($logoFileName); 397 + $logoFileNameStretched = 'logo_tmp_stretched_'.md5(Date('ymd-hms')).'.'.$ext; //Fighting the browser cache here
  398 + $logoFileStretched = $logoDir.DIRECTORY_SEPARATOR.$logoFileNameStretched;
  399 +
  400 + $logoFileNameCropped = 'logo_tmp_cropped_'.md5(Date('ymd-hms')).'.'.$ext; //Fighting the browser cache here
  401 + $logoFileCropped = $logoDir.DIRECTORY_SEPARATOR.$logoFileNameCropped;
  402 +
  403 + //Creating stretched image
  404 + $res = $this->scaleImage($logoFile, $logoFileStretched, $this->maxLogoWidth, $this->maxLogoHeight, $type, false, false);
  405 +
  406 + //Creating top-left cropped image
  407 + $res = $this->scaleImage($logoFile, $logoFileCropped, $this->maxLogoWidth, $this->maxLogoHeight, $type, false, true);
  408 + $res = $this->cropImage($logoFileCropped, $logoFileCropped, 0, 0, $this->maxLogoWidth, $this->maxLogoHeight, $type);
  409 +
  410 + $logoItem[] = $relDir.$logoFileNameStretched;
  411 + $logoItem[] = $relDir.$logoFileNameCropped;
  412 +
  413 + $form = $this->getScaleLogoForm($logoItem);
342 return $form->render(); 414 return $form->render();
343 415
344 default: 416 default:
@@ -354,7 +426,7 @@ class ManageBrandDispatcher extends KTAdminDispatcher { @@ -354,7 +426,7 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
354 * - Supported images are jpeg, png and gif 426 * - Supported images are jpeg, png and gif
355 * 427 *
356 */ 428 */
357 - public function scaleImage( $origFile, $destFile, $width, $height, $type = 'image/jpeg', $scaleUp = true) { 429 + public function scaleImage( $origFile, $destFile, $width, $height, $type = 'image/jpeg', $scaleUp = false, $keepProportion = true) {
358 global $default; 430 global $default;
359 431
360 //Requires the GD library if not exit gracefully 432 //Requires the GD library if not exit gracefully
@@ -399,7 +471,11 @@ class ManageBrandDispatcher extends KTAdminDispatcher { @@ -399,7 +471,11 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
399 471
400 $image_x = $width; 472 $image_x = $width;
401 $image_y = $height; 473 $image_y = $height;
402 - //$image_y = round(($orig_y * $image_x) / $orig_x); //Preserve proportion 474 +
  475 + //Constraining proportion
  476 + if ($keepProportion) {
  477 + $image_y = round(($orig_y * $image_x) / $orig_x); //Preserve proportion
  478 + }
403 479
404 /* 480 /*
405 * create the new image, and scale the original into it. 481 * create the new image, and scale the original into it.
@@ -426,7 +502,6 @@ class ManageBrandDispatcher extends KTAdminDispatcher { @@ -426,7 +502,6 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
426 return false; 502 return false;
427 } 503 }
428 504
429 -  
430 } else { 505 } else {
431 //Handle Error 506 //Handle Error
432 $default->log->error("Couldn't obtain a valid GD resource"); 507 $default->log->error("Couldn't obtain a valid GD resource");
@@ -446,9 +521,13 @@ class ManageBrandDispatcher extends KTAdminDispatcher { @@ -446,9 +521,13 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
446 function do_crop(){ 521 function do_crop(){
447 global $default; 522 global $default;
448 523
449 - $logoFileName = $_REQUEST['data']['logo_file_name']; 524 + $logoFileName = $_REQUEST['data']['logo_file_name'];
450 $logoFile = 'var'.DIRECTORY_SEPARATOR.'branding'.DIRECTORY_SEPARATOR.'logo'.DIRECTORY_SEPARATOR.$logoFileName; 525 $logoFile = 'var'.DIRECTORY_SEPARATOR.'branding'.DIRECTORY_SEPARATOR.'logo'.DIRECTORY_SEPARATOR.$logoFileName;
451 - 526 +
  527 + $ext = end(explode('.', $logoFileName));
  528 + $destFileName = 'logo_tmp_'.md5(Date('ymd-hms')).'.'.$ext;
  529 + $destFile = 'var'.DIRECTORY_SEPARATOR.'branding'.DIRECTORY_SEPARATOR.'logo'.DIRECTORY_SEPARATOR.$destFileName;
  530 +
452 $x1 = $_REQUEST['data']['crop_x1']; 531 $x1 = $_REQUEST['data']['crop_x1'];
453 $y1 = $_REQUEST['data']['crop_y1']; 532 $y1 = $_REQUEST['data']['crop_y1'];
454 533
@@ -458,7 +537,7 @@ class ManageBrandDispatcher extends KTAdminDispatcher { @@ -458,7 +537,7 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
458 $type = $this->getMime($logoFileName); 537 $type = $this->getMime($logoFileName);
459 538
460 //GD Crop 539 //GD Crop
461 - $res = $this->cropImage($logoFile, $logoFile, $x1, $y1, $x2, $y2, $type); 540 + $res = $this->cropImage($logoFile, $destFile, $x1, $y1, $x2, $y2, $type);
462 541
463 //If dimensions don't conform then will scale it further 542 //If dimensions don't conform then will scale it further
464 $width = $x2 - $x1; 543 $width = $x2 - $x1;
@@ -466,7 +545,7 @@ class ManageBrandDispatcher extends KTAdminDispatcher { @@ -466,7 +545,7 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
466 545
467 if (($width > $this->maxLogoWidth) || ($height > $this->maxLogoHeight)) { 546 if (($width > $this->maxLogoWidth) || ($height > $this->maxLogoHeight)) {
468 $default->log->info('SCALING IMAGE AFTER CROP'); 547 $default->log->info('SCALING IMAGE AFTER CROP');
469 - $res = $this->scaleImage($logoFile, $logoFile, $this->maxLogoWidth, $this->maxLogoHeight, $type); 548 + $res = $this->scaleImage($destFile, $destFile, $this->maxLogoWidth, $this->maxLogoHeight, $type, false, false);
470 } 549 }
471 550
472 // ImageMagick Crop 551 // ImageMagick Crop
@@ -485,7 +564,7 @@ class ManageBrandDispatcher extends KTAdminDispatcher { @@ -485,7 +564,7 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
485 $result = KTUtil::pexec($cmd); 564 $result = KTUtil::pexec($cmd);
486 */ 565 */
487 566
488 - $applyLogoForm = $this->getApplyLogoForm($logoFileName); 567 + $applyLogoForm = $this->getApplyLogoForm($destFileName);
489 return $applyLogoForm->render(); 568 return $applyLogoForm->render();
490 569
491 } 570 }
@@ -600,6 +679,21 @@ class ManageBrandDispatcher extends KTAdminDispatcher { @@ -600,6 +679,21 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
600 } 679 }
601 680
602 681
  682 + /*
  683 + * Action responsible for selecting the logo after it has been scaled.
  684 + *
  685 + */
  686 + function do_selectLogo(){
  687 + global $default;
  688 +
  689 + $tmpLogoFileName = end(explode(DIRECTORY_SEPARATOR, $_REQUEST['kt_imageselect']));
  690 +
  691 + $form = $this->getApplyLogoForm($tmpLogoFileName);
  692 + return $form->render();
  693 +
  694 + }
  695 +
  696 +
603 697
604 /* 698 /*
605 * Action responsible for applying the logo 699 * Action responsible for applying the logo
@@ -628,10 +722,12 @@ class ManageBrandDispatcher extends KTAdminDispatcher { @@ -628,10 +722,12 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
628 $brandDir = $default->varDirectory.DIRECTORY_SEPARATOR.'branding'.DIRECTORY_SEPARATOR.'logo'.DIRECTORY_SEPARATOR; 722 $brandDir = $default->varDirectory.DIRECTORY_SEPARATOR.'branding'.DIRECTORY_SEPARATOR.'logo'.DIRECTORY_SEPARATOR;
629 $handle = opendir($brandDir); 723 $handle = opendir($brandDir);
630 while (false !== ($file = readdir($handle))) { 724 while (false !== ($file = readdir($handle))) {
631 - if (!is_dir($file) && $file != 'logo_tmp.jpg' && $file != $logoFileName) { 725 + if (!is_dir($file) && $file != $tmpLogoFileName && $file != $logoFileName) {
632 if (!@unlink($brandDir.$file)) { 726 if (!@unlink($brandDir.$file)) {
633 $default->log->error("Couldn't delete '".$brandDir.$file."'"); 727 $default->log->error("Couldn't delete '".$brandDir.$file."'");
634 - } 728 + } else {
  729 + $default->log->error("Cleaning Brand Logo Dir: Deleted '".$brandDir.$file."'");
  730 + }
635 } 731 }
636 } 732 }
637 } 733 }
@@ -665,128 +761,6 @@ class ManageBrandDispatcher extends KTAdminDispatcher { @@ -665,128 +761,6 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
665 $this->successRedirectTo('', _kt("Logo succesfully applied.")); 761 $this->successRedirectTo('', _kt("Logo succesfully applied."));
666 } 762 }
667 763
668 -  
669 - /*  
670 -  
671 - Old Manage Views Code!  
672 - Crap, must delete  
673 -  
674 - */  
675 - function do_editView() {  
676 - $oTemplating =& KTTemplating::getSingleton();  
677 - $oTemplate = $oTemplating->loadTemplate('ktcore/misc/columns/edit_view');  
678 -  
679 - $oColumnRegistry =& KTColumnRegistry::getSingleton();  
680 - $aColumns = $oColumnRegistry->getColumnsForView($_REQUEST['viewNS']);  
681 - //var_dump($aColumns); exit(0);  
682 - $aAllColumns = $oColumnRegistry->getColumns();  
683 -  
684 - $view_name = $oColumnRegistry->getViewName(($_REQUEST['viewNS']));  
685 - $this->oPage->setTitle($view_name);  
686 - $this->oPage->setBreadcrumbDetails($view_name);  
687 -  
688 - $aOptions = array();  
689 - $vocab = array();  
690 - foreach ($aAllColumns as $aInfo) {  
691 - $vocab[$aInfo['namespace']] = $aInfo['name'];  
692 - }  
693 - $aOptions['vocab'] = $vocab;  
694 - $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);  
695 -  
696 - $aTemplateData = array(  
697 - 'context' => $this,  
698 - 'current_columns' => $aColumns,  
699 - 'all_columns' => $aAllColumns,  
700 - 'view' => $_REQUEST['viewNS'],  
701 - 'add_field' => $add_field,  
702 - );  
703 - return $oTemplate->render($aTemplateData);  
704 - }  
705 -  
706 - function do_deleteEntry() {  
707 - $entry_id = KTUtil::arrayGet($_REQUEST, 'entry_id');  
708 - $view = KTUtil::arrayGet($_REQUEST, 'viewNS');  
709 -  
710 - // none of these conditions can be reached "normally".  
711 -  
712 - $oEntry = KTColumnEntry::get($entry_id);  
713 - if (PEAR::isError($oEntry)) {  
714 - $this->errorRedirectToMain(_kt("Unable to locate the entry"));  
715 - }  
716 -  
717 - if ($oEntry->getRequired()) {  
718 - $this->errorRedirectToMain(_kt("That column is required"));  
719 - }  
720 -  
721 - if ($oEntry->getViewNamespace() != $view) {  
722 - $this->errorRedirectToMain(_kt("That column is not for the specified view"));  
723 - }  
724 -  
725 - $res = $oEntry->delete();  
726 -  
727 - if (PEAR::isError($res)) {  
728 - $this->errorRedirectToMain(sprintf(_kt("Failed to remove that column: %s"), $res->getMessage()));  
729 - }  
730 -  
731 - $this->successRedirectTo("editView", _kt("Deleted Entry"), sprintf("viewNS=%s", $view));  
732 - }  
733 -  
734 - function do_addEntry() {  
735 - $column_ns = KTUtil::arrayGet($_REQUEST, 'column_ns');  
736 - $view = KTUtil::arrayGet($_REQUEST, 'viewNS');  
737 -  
738 - $this->startTransaction();  
739 -  
740 - $position = KTColumnEntry::getNextEntryPosition($view);  
741 - $oEntry = KTColumnEntry::createFromArray(array(  
742 - 'ColumnNamespace' => $column_ns,  
743 - 'ViewNamespace' => $view,  
744 - 'Position' => $position, // start it at the bottom  
745 - 'config' => array(), // stub, for now.  
746 - 'Required' => 0  
747 - ));  
748 -  
749 - $this->successRedirectTo("editView", _kt("Added Entry"), sprintf("viewNS=%s", $view));  
750 - }  
751 -  
752 - function do_orderUp(){  
753 - $entryId = $_REQUEST['entry_id'];  
754 - $view = $_REQUEST['viewNS'];  
755 -  
756 - $oEntry = KTColumnEntry::get($entryId);  
757 - if (PEAR::isError($oEntry)) {  
758 - $this->errorRedirectTo('editView', _kt('Unable to locate the column entry'), "viewNS={$view}");  
759 - exit();  
760 - }  
761 -  
762 - $res = $oEntry->movePosition($view, $entryId, 'up');  
763 - if (PEAR::isError($res)) {  
764 - $this->errorRedirectTo('editView', $res->getMessage(), "viewNS={$view}");  
765 - exit();  
766 - }  
767 -  
768 - $this->redirectTo('editView', "viewNS={$view}");  
769 - }  
770 -  
771 - function do_orderDown(){  
772 - $entryId = $_REQUEST['entry_id'];  
773 - $view = $_REQUEST['viewNS'];  
774 -  
775 - $oEntry = KTColumnEntry::get($entryId);  
776 - if (PEAR::isError($oEntry)) {  
777 - $this->errorRedirectTo('editView', _kt('Unable to locate the column entry'), "viewNS={$view}");  
778 - exit();  
779 - }  
780 -  
781 - $res = $oEntry->movePosition($view, $entryId, 'down');  
782 - if (PEAR::isError($res)) {  
783 - $this->errorRedirectTo('editView', $res->getMessage(), "viewNS={$view}");  
784 - exit();  
785 - }  
786 -  
787 - $this->redirectTo("editView", "viewNS={$view}");  
788 - }  
789 -  
790 } 764 }
791 765
792 ?> 766 ?>
resources/css/kt_imageselect.css 0 → 100644
  1 +#kt_image_select_container img {
  2 + cursor: pointer;
  3 + text-decoration: none;
  4 + border: 10px solid white;
  5 +}
  6 +
  7 +#kt_image_select_container img:hover {
  8 + text-decoration: none;
  9 + border: 10px solid white;
  10 +}
  11 +
resources/js/download_notification.js 0 → 100644
  1 +var win;
  2 +var head;
  3 +var sUrl;
  4 +var type;
  5 +var request;
  6 +var request_type;
  7 +var request_details;
  8 +
  9 +/*
  10 +* Create the download notification dialog
  11 +*/
  12 +var showDownloadNotification = function(sUrl, head, action, code, request_type, details){
  13 + createNotification();
  14 +
  15 + this.sUrl = sUrl + 'download_notification.php';
  16 +
  17 + if(details === undefined) details = '';
  18 + if(request_type === undefined) request_type = 'submit';
  19 + if(type === undefined) type = 'system';
  20 +
  21 + this.head = head;
  22 + this.code = code;
  23 + this.request = request;
  24 + this.request_type = request_type;
  25 + this.request_details = new Array();
  26 + this.request_details[0] = action;
  27 + this.request_details[1] = details;
  28 +
  29 + // create the window
  30 + this.win = new Ext.Window({
  31 + applyTo : 'download_notification',
  32 + layout : 'fit',
  33 + width : 370,
  34 + height : 150,
  35 + resizable : false,
  36 + closable : false,
  37 + closeAction :'destroy',
  38 + y : 150,
  39 + shadow: false,
  40 + modal: true
  41 + });
  42 + this.win.show();
  43 +
  44 + var info = document.getElementById('download_link');
  45 +
  46 + Ext.Ajax.request({
  47 + url: this.sUrl,
  48 + success: function(response) {
  49 + info.innerHTML = response.responseText;
  50 + document.getElementById('download_link').focus();
  51 + },
  52 + failure: function(response) {
  53 + alert('Error. Couldn\'t locate download.');
  54 + },
  55 + params: {
  56 + action: 'fetch',
  57 + head: head,
  58 + code: this.code,
  59 + request_type: this.request_type,
  60 + request: this.request
  61 + }
  62 + });
  63 +}
  64 +
  65 +/*
  66 +* Create the html required to display the download link
  67 +*/
  68 +var createNotification = function() {
  69 +
  70 + if(document.getElementById('download-panel')){
  71 + p = document.getElementById('download-panel');
  72 + }else {
  73 + p = document.getElementById('pageBody').appendChild(document.createElement('div'));
  74 + p.id = 'download-panel';
  75 + }
  76 +
  77 + inner = '<div id="download_notification" class="x-hidden"><div class="x-window-header">Download Notification</div><div class="x-window-body">';
  78 + inner = inner + '<div id="popup_content"><div id="download_link">Loading...</div></div></div></div>';
  79 + p.innerHTML = inner;
  80 +}
  81 +
  82 +/*
  83 +* Close the popup
  84 +*/
  85 +var panel_close = function() {
  86 + this.win.destroy();
  87 +}
  88 +
  89 +/**
  90 + * Defer the download to next login
  91 + */
  92 +var deferDownload = function() {
  93 + if (confirm("This will defer the download until your next login")) {
  94 + panel_close();
  95 + }
  96 +}
  97 +
  98 +/**
  99 + * Delete the download and close the window
  100 + */
  101 +var deleteDownload = function() {
  102 + if (confirm("Cancelling will delete the download.\nYou will not be able to start the download at a later time.\n\nAre you sure?")) {
  103 + var info = document.getElementById('exportcode');
  104 +
  105 + Ext.Ajax.request({
  106 + url: this.sUrl,
  107 + success: function(response) {
  108 + if(response.responseText == 'success'){
  109 + if(this.request_type == 'close'){
  110 + // follow the close action
  111 + this.win.destroy();
  112 + return;
  113 + }
  114 + }
  115 + info.innerHTML = response.responseText;
  116 + },
  117 + failure: function(response) {
  118 + alert('Error. Couldn\'t delete download.');
  119 + },
  120 + params: {
  121 + action: 'delete',
  122 + code: this.code
  123 + }
  124 + });
  125 +
  126 + panel_close();
  127 + }
  128 +}
sql/mysql/install/structure.sql
@@ -648,7 +648,7 @@ CREATE TABLE `download_queue` ( @@ -648,7 +648,7 @@ CREATE TABLE `download_queue` (
648 `code` char(16) NOT NULL, 648 `code` char(16) NOT NULL,
649 `folder_id` int(11) NOT NULL, 649 `folder_id` int(11) NOT NULL,
650 `object_id` int(11) NOT NULL, 650 `object_id` int(11) NOT NULL,
651 - `object_type` enum('document', 'folder') NOT NULL default 'folder', 651 + `object_type` enum('document', 'folder', 'zip') NOT NULL default 'folder',
652 `user_id` int(11) NOT NULL, 652 `user_id` int(11) NOT NULL,
653 `date_added` timestamp NOT NULL default CURRENT_TIMESTAMP, 653 `date_added` timestamp NOT NULL default CURRENT_TIMESTAMP,
654 `status` tinyint(4) NOT NULL default 0, 654 `status` tinyint(4) NOT NULL default 0,
sql/mysql/upgrade/3.7.0.3/download_queue_zip.sql 0 → 100644
  1 +ALTER TABLE download_queue MODIFY object_type ENUM ('document', 'folder', 'zip') NOT NULL DEFAULT 'folder';
0 \ No newline at end of file 2 \ No newline at end of file
templates/kt3/notifications/notification.BulkDownload.smarty 0 → 100644
  1 +<h2><span class="warning" />{$head}</h2>
  2 +<p>&nbsp;</p>
  3 +<div id="download_form">
  4 + <a href="{$downloadLink}" onclick="win.destroy();">{$downloadText}</a>
  5 +</div>
  6 +<p>&nbsp;</p>
  7 +<p>&nbsp;</p>
  8 +<div class="form_actions">
  9 + <a href="#" onclick="javascript: {$cancelAction}">{i18n}Cancel{/i18n}</a>
  10 + &nbsp;
  11 + <a href="#" onclick="javascript: {$closeAction}">{i18n}Close{/i18n}</a>
  12 +</div>
  13 +<div id="process_msg" style="visibility: hidden;">
  14 + {i18n}Starting download, please wait{/i18n}...
  15 +</div>
  16 +<input type="hidden" name="exportcode" id="exportcode" value="{$exportCode}" />
0 \ No newline at end of file 17 \ No newline at end of file
templates/kt3/standard_page.smarty
@@ -357,3 +357,8 @@ @@ -357,3 +357,8 @@
357 </div> 357 </div>
358 </body> 358 </body>
359 </html> 359 </html>
  360 +{if ($downloadNotification != '')}
  361 + <script type="text/javascript">
  362 + {$downloadNotification}
  363 + </script>
  364 +{/if}
templates/ktcore/forms/widgets/imageselect.smarty 0 → 100755
  1 +<fieldset {if $has_name}title="{$name}"{/if}>
  2 + <field>
  3 + <div id="kt_image_select_container">
  4 +
  5 + {foreach key=id item=src from=$value}
  6 +
  7 + <img class="kt_image_select" id="kt_image_select_{$id}" src="{$src}" border="0"/>
  8 +
  9 + <script type="text/javascript">
  10 + var toggle_{$id} = 1;
  11 + var selected = '';
  12 +
  13 + var multiselect = false;
  14 +
  15 + var hover = '#f9f9f9';
  16 + var click = '#f2943a'; //Orange
  17 + var background_color = 'white'; //also set in css
  18 +
  19 + jQuery('#kt_image_select_{$id}').click(function(){ldelim}
  20 + jQuery('#kt_image_select').val('{$src}');
  21 +
  22 + //Resetting background:
  23 + jQuery("img[id*='kt_image_select_']").css('border', '10px solid ' + background_color);
  24 + jQuery('#kt_image_select_{$id}').css('border', '10px solid ' + click);
  25 +
  26 + {rdelim})
  27 + </script>
  28 +
  29 + {/foreach}
  30 +
  31 + </div>
  32 +
  33 + <input type="hidden" name="kt_imageselect" value="" id="kt_image_select"/>
  34 + </field>
  35 +</fieldset>