Commit cb65c9652c15664d2966352995357c903d1ce8f5

Authored by Paul Barrett
2 parents 6b15ed67 2cba3736

Merge branch 'download_notification' 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 52 \ No newline at end of file
... ...
lib/foldermanagement/compressionArchiveUtil.inc.php
... ... @@ -311,6 +311,12 @@ class ZipFolder {
311 311  
312 312 KTUtil::download($sZipFile, $mimeType, $fileSize, $fileName);
313 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 320 return true;
315 321 }
316 322  
... ... @@ -398,6 +404,26 @@ class ZipFolder {
398 404  
399 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 436 private $bNotifications;
411 437 private $errors;
412 438 private $lockFile;
  439 + static private $notificationFile = 'download_queue_notification';
413 440  
414 441 /**
415 442 * Construct download queue object
... ... @@ -446,25 +473,25 @@ class DownloadQueue
446 473  
447 474 /**
448 475 * Remove an item from the download queue
  476 + * Will not remove zip object types, these must be independently removed
449 477 *
450 478 * @param string $code Identification string for the download item
451 479 * @return boolean | PEAR_Error
452 480 */
453 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 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 490 * @return Queue array | PEAR_Error
464 491 */
465 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 495 $rows = DBUtil::getResultArray($sql);
469 496  
470 497 if(PEAR::isError($rows)){
... ... @@ -502,12 +529,15 @@ class DownloadQueue
502 529 * @param string $error Optional. The error's generated during the archive
503 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 534 $fields = array();
508 535 $fields['status'] = $status;
509 536 $fields['errors'] = !empty($error) ? json_encode($error) : null;
510 537 $where = array('code' => $code);
  538 + if ($zip) {
  539 + $where['object_type'] = 'zip';
  540 + }
511 541 $res = DBUtil::whereUpdate('download_queue', $fields, $where);
512 542 return $res;
513 543 }
... ... @@ -617,6 +647,18 @@ class DownloadQueue
617 647 $this->errors = null;
618 648 $_SESSION['zipcompression'] = null;
619 649 }
  650 +
  651 + // check for any errors and if none found then create the entry for the zip file which will be used by the notification code
  652 + if (!PEAR::isError($res) && !PEAR::isError($result)/* && !PEAR::isError() // There was a third one here originally but I cannot remember what it was // */) {
  653 + // create the db entry
  654 + self::addItem($code, self::getFolderId($code), -1, 'zip');
  655 + // update the db entry with the appropriate status and message
  656 + $this->setItemStatus($code, 2, serialize(array($zip->getTmpPath(), $zip->getZipFileName())), true);
  657 + // Here was an attempt to allow the download notification to occur if the user left the page, which was using a session value (which didn't work properly) and then
  658 + // we were trying a file, which was untested and in process when the file corruption occurred. Will continue this once the rest of the code is committed & safe.
  659 + $config = KTConfig::getSingleton();
  660 + @touch($config->get('cache/cacheDirectory') . '/' . self::$notificationFile);
  661 + }
620 662  
621 663 // Remove lock file
622 664 @unlink($this->lockFile);
... ... @@ -757,7 +799,8 @@ class DownloadQueue
757 799 * @param Folder array $aFolderList
758 800 * @return unknown
759 801 */
760   - function getLinkingEntities($aFolderList){
  802 + function getLinkingEntities($aFolderList)
  803 + {
761 804 $aSearchFolders = array();
762 805 if(!empty($aFolderList)){
763 806 foreach($aFolderList as $oFolderItem){
... ... @@ -846,5 +889,142 @@ class DownloadQueue
846 889 {
847 890 return file_exists($this->lockFile);
848 891 }
  892 +
  893 + /**
  894 + * The code below has all been added for bulk download notifications
  895 + *
  896 + * The functions were declared as static because they are related to but not entirely part of the download queue process
  897 + * and I wanted to use them without having to instantiate the class
  898 + */
  899 +
  900 + /**
  901 + * Checks whether there are any bulk downloads which have passed the timeout limit
  902 + * Default limit is set to 48 hours but this can be changed in the calling code
  903 + *
  904 + * @param int $limit the number of hours after which a download should be considered timed out
  905 + */
  906 + static public function timeout($limit = 48)
  907 + {
  908 + DBUtil::runQuery('DELETE FROM download_queue WHERE DATE_ADD(date_added, INTERVAL ' . $limit . ' HOUR) < NOW()');
  909 + }
  910 +
  911 + /**
  912 + * Checks whether there is a bulk download available and waiting for the supplied user
  913 + *
  914 + * @param int $userID
  915 + */
  916 + static public function userDownloadAvailable($userID)
  917 + {
  918 + $result = DBUtil::getOneResult('SELECT code, errors FROM download_queue WHERE user_id = ' . $userID
  919 + . ' AND object_type = "zip" AND status = 2');
  920 + if (PEAR::isError($result)) {
  921 + return false;
  922 + }
  923 +
  924 + $code = $result['code'];
  925 +
  926 + $message = $result['errors'];
  927 + $message = json_decode($message, true);
  928 + $data = unserialize($message);
  929 +
  930 + // Create the archive session variables - I can't recall if this was needed, will have to find out by testing...
  931 + $_SESSION['zipcompression'][$code]['file'] = $data[0] . DIRECTORY_SEPARATOR . $data[1];
  932 + $_SESSION['zipcompression'][$code]['dir'] = $data[0];
  933 +
  934 + // Check that the archive file has been created
  935 + // 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?
  936 + // 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,
  937 + // some of which may no longer exist as physical files, and since the request only checks for one, it may miss am existing download.
  938 + // NOTE the above issue may only occur due to the way I have been testing, often breaking the process before it is finished,
  939 + // but conceivably this could actually happen in the real world also.
  940 + $zip = new ZipFolder('', $code);
  941 + if($zip->checkArchiveExists($code)) {
  942 + return $code;
  943 + }
  944 +
  945 + return false;
  946 + }
  947 +
  948 + /**
  949 + * Delete the download, including the database entry
  950 + *
  951 + * @param string $code
  952 + */
  953 + static public function deleteDownload($code)
  954 + {
  955 + // retrieve the data to allow deletion of the physical file
  956 + $result = DBUtil::getOneResult('SELECT errors FROM download_queue WHERE code = "' . $code . '"'
  957 + . ' AND object_type = "zip" AND status = 2');
  958 +
  959 + if (PEAR::isError($result)) {
  960 + return $result;
  961 + }
  962 +
  963 + $message = $result['errors'];
  964 + $message = json_decode($message, true);
  965 + $data = unserialize($message);
  966 +
  967 + // remove the database entry
  968 + DBUtil::whereDelete('download_queue', array('code' => $code));
  969 +
  970 + // remove the actual file/directory
  971 + KTUtil::deleteDirectory($data[0]);
  972 +
  973 + // remove the notification file if present
  974 + self::removeNotificationFile();
  975 + }
  976 +
  977 + /**
  978 + * Removes the notification file, if it exists, in a safe manner
  979 + *
  980 + * @param string $code
  981 + */
  982 + static public function removeNotificationFile() {
  983 + $config = KTConfig::getSingleton();
  984 + $file = DownloadQueue::getNotificationFileName();
  985 + if (!PEAR::isError($file)) {
  986 + $notificationFile = $config->get('cache/cacheDirectory') . '/' . $file;
  987 + }
  988 +
  989 + // ensure the file is actually a file and not a directory
  990 + if (is_file($notificationFile)) {
  991 + @unlink($notificationFile);
  992 + }
  993 + }
  994 +
  995 + /**
  996 + * Fetches a link to the download
  997 + *
  998 + * @param string $code
  999 + */
  1000 + static public function getDownloadLink($code)
  1001 + {
  1002 + return KTUtil::kt_url() . '/action.php?kt_path_info=ktcore.actions.bulk.export&action=downloadZipFile&fFolderId=' . self::getFolderId($code) . '&exportcode=' . $code;
  1003 + }
  1004 +
  1005 + /**
  1006 + * Fetches the folder id associated with the supplied code
  1007 + * Based on testing just before file corruption this may not actually be necessary, but we'll do it anyway
  1008 + *
  1009 + * @param string $code
  1010 + */
  1011 + static public function getFolderId($code)
  1012 + {
  1013 + $result = DBUtil::getOneResult('SELECT folder_id FROM download_queue WHERE code = "' . $code . '"');
  1014 +
  1015 + if (PEAR::isError($result)) {
  1016 + return -1;
  1017 + }
  1018 +
  1019 + return $result['folder_id'];
  1020 + }
  1021 +
  1022 + static public function getNotificationFileName() {
  1023 + if (!empty(self::$notificationFile)) {
  1024 + return self::$notificationFile;
  1025 + }
  1026 +
  1027 + return new PEAR_Error('Unable to get file name');
  1028 + }
849 1029 }
850 1030 ?>
... ...
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 113 \ No newline at end of file
... ...
lib/templating/kt3template.inc.php
... ... @@ -353,8 +353,9 @@ class KTPage {
353 353 function setSecondaryTitle($sSecondary) { $this->secondary_title = $sSecondary; }
354 354  
355 355 /* final render call. */
356   - function render() {
357   - global $default;
  356 + function render()
  357 + {
  358 + global $default;
358 359 $oConfig = KTConfig::getSingleton();
359 360  
360 361 if (empty($this->contents)) {
... ... @@ -366,70 +367,68 @@ class KTPage {
366 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 433 $oTemplating =& KTTemplating::getSingleton();
435 434 $oTemplate = $oTemplating->loadTemplate($this->template);
... ... @@ -442,13 +441,24 @@ class KTPage {
442 441 if ($oConfig->get("ui/automaticRefresh", false)) {
443 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 456 // unlike the rest of KT, we use echo here.
447 457 echo $oTemplate->render($aTemplateData);
448 458 }
449 459  
450 460  
451   - /** heler functions */
  461 + /** helper functions */
452 462 // returns an array ("url", "label")
453 463 function _actionhelper($aActionTuple) {
454 464 $aTuple = Array("label" => $aActionTuple["name"]);
... ...
login.php
... ... @@ -116,6 +116,9 @@ class LoginPageDispatcher extends KTDispatcher {
116 116 if (PEAR::isError($sessionID)) {
117 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 123 $redirect = strip_tags(KTUtil::arrayGet($_REQUEST, 'redirect'));
121 124  
... ...
plugins/ktcore/KTBulkActions.php
... ... @@ -1197,7 +1197,7 @@ class KTBrowseBulkExportAction extends KTBulkAction {
1197 1197 *
1198 1198 */
1199 1199 function perform_action($oEntity) {
1200   -// TODO find a way to do bulk email
  1200 + // TODO find a way to do bulk email
1201 1201 $exportCode = $_SESSION['exportcode'];
1202 1202 $this->oZip = ZipFolder::get($exportCode);
1203 1203  
... ...
plugins/ktcore/KTCorePlugin.php
... ... @@ -169,11 +169,13 @@ class KTCorePlugin extends KTPlugin {
169 169 $this->registerTrigger('add', 'postValidate', 'SavedSearchSubscriptionTrigger', 'ktcore.search2.savedsearch.subscription.add', KT_DIR . '/plugins/search2/Search2Triggers.php');
170 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 173 $this->registerTrigger('add', 'postValidate', 'KTAddDocumentTrigger', 'ktcore.triggers.tagcloud.add', KT_DIR.'/plugins/tagcloud/TagCloudTriggers.php');
174 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 179 // widgets
178 180 $this->registerWidget('KTCoreInfoWidget', 'ktcore.widgets.info', 'KTWidgets.php');
179 181 $this->registerWidget('KTCoreHiddenWidget', 'ktcore.widgets.hidden', '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 +?>
... ...
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 +}
... ...
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 17 \ No newline at end of file
... ...
templates/kt3/standard_page.smarty
... ... @@ -357,3 +357,8 @@
357 357 </div>
358 358 </body>
359 359 </html>
  360 +{if ($downloadNotification != '')}
  361 + <script type="text/javascript">
  362 + {$downloadNotification}
  363 + </script>
  364 +{/if}
... ...