diff --git a/download_notification.php b/download_notification.php new file mode 100644 index 0000000..9281b8f --- /dev/null +++ b/download_notification.php @@ -0,0 +1,51 @@ +getNotificationForm($head); +} + +exit; +?> \ No newline at end of file diff --git a/lib/foldermanagement/compressionArchiveUtil.inc.php b/lib/foldermanagement/compressionArchiveUtil.inc.php index fcec614..46361d6 100644 --- a/lib/foldermanagement/compressionArchiveUtil.inc.php +++ b/lib/foldermanagement/compressionArchiveUtil.inc.php @@ -311,6 +311,12 @@ class ZipFolder { KTUtil::download($sZipFile, $mimeType, $fileSize, $fileName); KTUtil::deleteDirectory($sTmpPath); + // remove notification file if it exists + DownloadQueue::removeNotificationFile(); + + // remove zip file database entry and any stragglers + DBUtil::whereDelete('download_queue', array('code' => $exportCode)); + return true; } @@ -398,6 +404,26 @@ class ZipFolder { return false; } + + /** + * Returns the zip file name with extension + * + * @return string + */ + public function getZipFileName() + { + return $this->sZipFileName . '.' . $this->extension; + } + + /** + * Returns the path to the zip file + * + * @return string + */ + public function getTmpPath() + { + return $this->sTmpPath; + } } /** @@ -410,6 +436,7 @@ class DownloadQueue private $bNotifications; private $errors; private $lockFile; + static private $notificationFile = 'download_queue_notification'; /** * Construct download queue object @@ -446,25 +473,25 @@ class DownloadQueue /** * Remove an item from the download queue + * Will not remove zip object types, these must be independently removed * * @param string $code Identification string for the download item * @return boolean | PEAR_Error */ public function removeItem($code) { - $where = array('code' => $code); - $res = DBUtil::whereDelete('download_queue', $where); + $res = DBUtil::runQuery('DELETE FROM download_queue WHERE code = "' . $code . '" AND object_type != "zip"'); return $res; } /** - * Get all download items in the queue + * Get all download items (other than zip object type) in the queue * * @return Queue array | PEAR_Error */ public function getQueue() { - $sql = 'SELECT * FROM download_queue d WHERE status = 0 ORDER BY date_added, code'; + $sql = 'SELECT * FROM download_queue d WHERE status = 0 AND object_type != "zip" ORDER BY date_added, code'; $rows = DBUtil::getResultArray($sql); if(PEAR::isError($rows)){ @@ -502,12 +529,15 @@ class DownloadQueue * @param string $error Optional. The error's generated during the archive * @return boolean */ - public function setItemStatus($code, $status = 1, $error = null) + public function setItemStatus($code, $status = 1, $error = null, $zip = false) { $fields = array(); $fields['status'] = $status; $fields['errors'] = !empty($error) ? json_encode($error) : null; $where = array('code' => $code); + if ($zip) { + $where['object_type'] = 'zip'; + } $res = DBUtil::whereUpdate('download_queue', $fields, $where); return $res; } @@ -617,6 +647,18 @@ class DownloadQueue $this->errors = null; $_SESSION['zipcompression'] = null; } + + // check for any errors and if none found then create the entry for the zip file which will be used by the notification code + if (!PEAR::isError($res) && !PEAR::isError($result)/* && !PEAR::isError() // There was a third one here originally but I cannot remember what it was // */) { + // create the db entry + self::addItem($code, self::getFolderId($code), -1, 'zip'); + // update the db entry with the appropriate status and message + $this->setItemStatus($code, 2, serialize(array($zip->getTmpPath(), $zip->getZipFileName())), true); + // 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 + // 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. + $config = KTConfig::getSingleton(); + @touch($config->get('cache/cacheDirectory') . '/' . self::$notificationFile); + } // Remove lock file @unlink($this->lockFile); @@ -757,7 +799,8 @@ class DownloadQueue * @param Folder array $aFolderList * @return unknown */ - function getLinkingEntities($aFolderList){ + function getLinkingEntities($aFolderList) + { $aSearchFolders = array(); if(!empty($aFolderList)){ foreach($aFolderList as $oFolderItem){ @@ -846,5 +889,142 @@ class DownloadQueue { return file_exists($this->lockFile); } + + /** + * The code below has all been added for bulk download notifications + * + * The functions were declared as static because they are related to but not entirely part of the download queue process + * and I wanted to use them without having to instantiate the class + */ + + /** + * Checks whether there are any bulk downloads which have passed the timeout limit + * Default limit is set to 48 hours but this can be changed in the calling code + * + * @param int $limit the number of hours after which a download should be considered timed out + */ + static public function timeout($limit = 48) + { + DBUtil::runQuery('DELETE FROM download_queue WHERE DATE_ADD(date_added, INTERVAL ' . $limit . ' HOUR) < NOW()'); + } + + /** + * Checks whether there is a bulk download available and waiting for the supplied user + * + * @param int $userID + */ + static public function userDownloadAvailable($userID) + { + $result = DBUtil::getOneResult('SELECT code, errors FROM download_queue WHERE user_id = ' . $userID + . ' AND object_type = "zip" AND status = 2'); + if (PEAR::isError($result)) { + return false; + } + + $code = $result['code']; + + $message = $result['errors']; + $message = json_decode($message, true); + $data = unserialize($message); + + // Create the archive session variables - I can't recall if this was needed, will have to find out by testing... + $_SESSION['zipcompression'][$code]['file'] = $data[0] . DIRECTORY_SEPARATOR . $data[1]; + $_SESSION['zipcompression'][$code]['dir'] = $data[0]; + + // Check that the archive file has been created + // 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? + // 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, + // some of which may no longer exist as physical files, and since the request only checks for one, it may miss am existing download. + // NOTE the above issue may only occur due to the way I have been testing, often breaking the process before it is finished, + // but conceivably this could actually happen in the real world also. + $zip = new ZipFolder('', $code); + if($zip->checkArchiveExists($code)) { + return $code; + } + + return false; + } + + /** + * Delete the download, including the database entry + * + * @param string $code + */ + static public function deleteDownload($code) + { + // retrieve the data to allow deletion of the physical file + $result = DBUtil::getOneResult('SELECT errors FROM download_queue WHERE code = "' . $code . '"' + . ' AND object_type = "zip" AND status = 2'); + + if (PEAR::isError($result)) { + return $result; + } + + $message = $result['errors']; + $message = json_decode($message, true); + $data = unserialize($message); + + // remove the database entry + DBUtil::whereDelete('download_queue', array('code' => $code)); + + // remove the actual file/directory + KTUtil::deleteDirectory($data[0]); + + // remove the notification file if present + self::removeNotificationFile(); + } + + /** + * Removes the notification file, if it exists, in a safe manner + * + * @param string $code + */ + static public function removeNotificationFile() { + $config = KTConfig::getSingleton(); + $file = DownloadQueue::getNotificationFileName(); + if (!PEAR::isError($file)) { + $notificationFile = $config->get('cache/cacheDirectory') . '/' . $file; + } + + // ensure the file is actually a file and not a directory + if (is_file($notificationFile)) { + @unlink($notificationFile); + } + } + + /** + * Fetches a link to the download + * + * @param string $code + */ + static public function getDownloadLink($code) + { + return KTUtil::kt_url() . '/action.php?kt_path_info=ktcore.actions.bulk.export&action=downloadZipFile&fFolderId=' . self::getFolderId($code) . '&exportcode=' . $code; + } + + /** + * Fetches the folder id associated with the supplied code + * Based on testing just before file corruption this may not actually be necessary, but we'll do it anyway + * + * @param string $code + */ + static public function getFolderId($code) + { + $result = DBUtil::getOneResult('SELECT folder_id FROM download_queue WHERE code = "' . $code . '"'); + + if (PEAR::isError($result)) { + return -1; + } + + return $result['folder_id']; + } + + static public function getNotificationFileName() { + if (!empty(self::$notificationFile)) { + return self::$notificationFile; + } + + return new PEAR_Error('Unable to get file name'); + } } ?> diff --git a/lib/foldermanagement/downloadNotification.inc.php b/lib/foldermanagement/downloadNotification.inc.php new file mode 100644 index 0000000..c614a4b --- /dev/null +++ b/lib/foldermanagement/downloadNotification.inc.php @@ -0,0 +1,112 @@ +code = $code; + } + + /** + * Returns the form displaying the download link (and option to cancel the download?) + * + * @author KnowledgeTree Team + * @access public + * @param string $head The heading for the form + * @param string $request_type Determines the actions for the buttons + * @return html + */ + public function getNotificationForm($head) + { + global $default; + + // check for the download link + + $link = DownloadQueue::getDownloadLink($this->code); + $text = 'Download Now'; + + $cancelAction = 'deleteDownload()'; + $closeAction = 'deferDownload()'; + + $oTemplating =& KTTemplating::getSingleton(); + $oTemplate = $oTemplating->loadTemplate('kt3/notifications/notification.BulkDownload'); + $aTemplateData = array( + 'head' => $head, + 'downloadLink' => $link, + 'downloadText' => $text, + 'exportCode' => $this->code, + 'cancelAction' => $cancelAction, + 'closeAction' => $closeAction + ); + + return $oTemplate->render($aTemplateData); + } + + /** + * Returns the error from the attempted signature + * + * @author KnowledgeTree Team + * @access public + * @return string + */ + public function getError() + { + return '
'.$this->error.'
'; + } + + /** + * Displays a button for closing the panel + * + * @author KnowledgeTree Team + * @access public + * @param string $request_type Determines the action taken on close - close = redirect action | null = close panel action + * @param string $request Optional. Used within the close action. + * @return string + */ + public function getCloseButton($request_type, $request = null) + { + switch ($request_type){ + case 'close': + $cancelAction = "window.location.href = '{$request}'"; + break; + + default: + $cancelAction = "panel_close()"; + } + + return '
+ '._kt('Close').' +
'; + } +} + +?> \ No newline at end of file diff --git a/lib/templating/kt3template.inc.php b/lib/templating/kt3template.inc.php index d8978cb..49f57f6 100644 --- a/lib/templating/kt3template.inc.php +++ b/lib/templating/kt3template.inc.php @@ -353,8 +353,9 @@ class KTPage { function setSecondaryTitle($sSecondary) { $this->secondary_title = $sSecondary; } /* final render call. */ - function render() { - global $default; + function render() + { + global $default; $oConfig = KTConfig::getSingleton(); if (empty($this->contents)) { @@ -366,70 +367,68 @@ class KTPage { $this->contents = ""; } - if (!is_string($this->contents)) { - $this->contents = $this->contents->render(); - } - - // if we have no portlets, make the ui a tad nicer. - if (empty($this->portlets)) { - $this->show_portlets = false; - } - - if (empty($this->title)) { - if (!empty($this->breadcrumbDetails)) { - $this->title = $this->breadcrumbDetails; - } else if (!empty($this->breadcrumbs)) { - $this->title = array_slice($this->breadcrumbs, -1); - $this->title = $this->title[0]['label']; - } else if (!empty($this->breadcrumbSection)) { - $this->title = $this->breadcrumbSection['label']; - } else { - $this->title = $this->componentLabel; - } - } - - $this->userMenu = array(); - $sBaseUrl = KTUtil::kt_url(); + if (!is_string($this->contents)) { + $this->contents = $this->contents->render(); + } - if (!(PEAR::isError($this->user) || is_null($this->user) || $this->user->isAnonymous())) { - if ($oConfig->get("user_prefs/restrictPreferences", false) && !Permission::userIsSystemAdministrator($this->user->getId())) { - $this->userMenu['logout'] = array('label' => _kt('Logout'), 'url' => $sBaseUrl.'/presentation/logout.php'); - } else { + // if we have no portlets, make the ui a tad nicer. + if (empty($this->portlets)) { + $this->show_portlets = false; + } - if($default->enableESignatures){ - $sUrl = KTPluginUtil::getPluginPath('electronic.signatures.plugin', true); - $heading = _kt('You are attempting to modify Preferences'); - $this->userMenu['preferences']['url'] = '#'; - $this->userMenu['preferences']['onclick'] = "javascript: showSignatureForm('{$sUrl}', '{$heading}', 'dms.administration.accessing_preferences', 'system', '{$sBaseUrl}/preferences.php', 'redirect');"; - }else{ - $this->userMenu['preferences']['url'] = $sBaseUrl.'/preferences.php'; + if (empty($this->title)) { + if (!empty($this->breadcrumbDetails)) { + $this->title = $this->breadcrumbDetails; + } else if (!empty($this->breadcrumbs)) { + $this->title = array_slice($this->breadcrumbs, -1); + $this->title = $this->title[0]['label']; + } else if (!empty($this->breadcrumbSection)) { + $this->title = $this->breadcrumbSection['label']; + } else { + $this->title = $this->componentLabel; } + } -// $this->userMenu['preferences'] = array('label' => _kt('Preferences'), 'url' => $sBaseUrl.'/preferences.php'); - $this->userMenu['preferences']['label'] = _kt('Preferences'); - $this->userMenu['aboutkt'] = array('label' => _kt('About'), 'url' => $sBaseUrl.'/about.php'); - $this->userMenu['logout'] = array('label' => _kt('Logout'), 'url' => $sBaseUrl.'/presentation/logout.php'); - } - } else { - $this->userMenu['login'] = array('label' => _kt('Login'), 'url' => $sBaseUrl.'/login.php'); - } - - // FIXME we need a more complete solution to navigation restriction - if (!is_null($this->menu['administration']) && !is_null($this->user)) { - if (!Permission::userIsSystemAdministrator($this->user->getId())) { - unset($this->menu['administration']); - } - } + $this->userMenu = array(); + $sBaseUrl = KTUtil::kt_url(); + + if (!(PEAR::isError($this->user) || is_null($this->user) || $this->user->isAnonymous())) { + if ($oConfig->get("user_prefs/restrictPreferences", false) && !Permission::userIsSystemAdministrator($this->user->getId())) { + $this->userMenu['logout'] = array('label' => _kt('Logout'), 'url' => $sBaseUrl.'/presentation/logout.php'); + } else { + if($default->enableESignatures) { + $sUrl = KTPluginUtil::getPluginPath('electronic.signatures.plugin', true); + $heading = _kt('You are attempting to modify Preferences'); + $this->userMenu['preferences']['url'] = '#'; + $this->userMenu['preferences']['onclick'] = "javascript: showSignatureForm('{$sUrl}', '{$heading}', 'dms.administration.accessing_preferences', 'system', '{$sBaseUrl}/preferences.php', 'redirect');"; + } else { + $this->userMenu['preferences']['url'] = $sBaseUrl.'/preferences.php'; + } + + // $this->userMenu['preferences'] = array('label' => _kt('Preferences'), 'url' => $sBaseUrl.'/preferences.php'); + $this->userMenu['preferences']['label'] = _kt('Preferences'); + $this->userMenu['aboutkt'] = array('label' => _kt('About'), 'url' => $sBaseUrl.'/about.php'); + $this->userMenu['logout'] = array('label' => _kt('Logout'), 'url' => $sBaseUrl.'/presentation/logout.php'); + } + } else { + $this->userMenu['login'] = array('label' => _kt('Login'), 'url' => $sBaseUrl.'/login.php'); + } - $sContentType = 'Content-type: ' . $this->contentType; - if(!empty($this->charset)) { - $sContentType .= '; charset=' . $this->charset; - }; + // FIXME we need a more complete solution to navigation restriction + if (!is_null($this->menu['administration']) && !is_null($this->user)) { + if (!Permission::userIsSystemAdministrator($this->user->getId())) { + unset($this->menu['administration']); + } + } + $sContentType = 'Content-type: ' . $this->contentType; + if(!empty($this->charset)) { + $sContentType .= '; charset=' . $this->charset; + }; - header($sContentType); + header($sContentType); - $savedSearches = SearchHelper::getSavedSearches($_SESSION['userID']); + $savedSearches = SearchHelper::getSavedSearches($_SESSION['userID']); $oTemplating =& KTTemplating::getSingleton(); $oTemplate = $oTemplating->loadTemplate($this->template); @@ -442,13 +441,24 @@ class KTPage { if ($oConfig->get("ui/automaticRefresh", false)) { $aTemplateData['refreshTimeout'] = (int)$oConfig->get("session/sessionTimeout") + 3; } + + // Trigger for pending downloads + $aTemplateData['downloadNotification'] = null; + require_once(KT_LIB_DIR . '/triggers/triggerregistry.inc.php'); + $oKTTriggerRegistry = KTTriggerRegistry::getSingleton(); + $aTriggers = $oKTTriggerRegistry->getTriggers('ktcore', 'pageLoad'); + foreach ($aTriggers as $aTrigger) { + $sTrigger = $aTrigger[0]; + $oTrigger = new $sTrigger; + $aTemplateData['downloadNotification'] = $oTrigger->invoke(); + } // unlike the rest of KT, we use echo here. echo $oTemplate->render($aTemplateData); } - /** heler functions */ + /** helper functions */ // returns an array ("url", "label") function _actionhelper($aActionTuple) { $aTuple = Array("label" => $aActionTuple["name"]); diff --git a/login.php b/login.php index f26c827..24cedf1 100644 --- a/login.php +++ b/login.php @@ -116,6 +116,9 @@ class LoginPageDispatcher extends KTDispatcher { if (PEAR::isError($sessionID)) { return $sessionID; } + + // add a flag to check for bulk downloads after login is succesful; this will be cleared in the code which checks + $_SESSION['checkBulkDownload'] = true; $redirect = strip_tags(KTUtil::arrayGet($_REQUEST, 'redirect')); diff --git a/plugins/ktcore/KTBulkActions.php b/plugins/ktcore/KTBulkActions.php index b54b664..a022d00 100644 --- a/plugins/ktcore/KTBulkActions.php +++ b/plugins/ktcore/KTBulkActions.php @@ -1197,7 +1197,7 @@ class KTBrowseBulkExportAction extends KTBulkAction { * */ function perform_action($oEntity) { -// TODO find a way to do bulk email + // TODO find a way to do bulk email $exportCode = $_SESSION['exportcode']; $this->oZip = ZipFolder::get($exportCode); diff --git a/plugins/ktcore/KTCorePlugin.php b/plugins/ktcore/KTCorePlugin.php index 7b3ca7d..acedab0 100755 --- a/plugins/ktcore/KTCorePlugin.php +++ b/plugins/ktcore/KTCorePlugin.php @@ -169,11 +169,13 @@ class KTCorePlugin extends KTPlugin { $this->registerTrigger('add', 'postValidate', 'SavedSearchSubscriptionTrigger', 'ktcore.search2.savedsearch.subscription.add', KT_DIR . '/plugins/search2/Search2Triggers.php'); $this->registerTrigger('discussion', 'postValidate', 'SavedSearchSubscriptionTrigger', 'ktcore.search2.savedsearch.subscription.discussion', KT_DIR . '/plugins/search2/Search2Triggers.php'); - //Tag Cloud Triggers + // Tag Cloud Triggers $this->registerTrigger('add', 'postValidate', 'KTAddDocumentTrigger', 'ktcore.triggers.tagcloud.add', KT_DIR.'/plugins/tagcloud/TagCloudTriggers.php'); $this->registerTrigger('edit', 'postValidate', 'KTEditDocumentTrigger', 'ktcore.triggers.tagcloud.edit', KT_DIR.'/plugins/tagcloud/TagCloudTriggers.php'); - + // Bulk Download Trigger + $this->registerTrigger('ktcore', 'pageLoad', 'BulkDownloadTrigger', 'ktcore.triggers.pageload', 'KTDownloadTriggers.inc.php'); + // widgets $this->registerWidget('KTCoreInfoWidget', 'ktcore.widgets.info', 'KTWidgets.php'); $this->registerWidget('KTCoreHiddenWidget', 'ktcore.widgets.hidden', 'KTWidgets.php'); diff --git a/plugins/ktcore/KTDownloadTriggers.inc.php b/plugins/ktcore/KTDownloadTriggers.inc.php new file mode 100644 index 0000000..565589e --- /dev/null +++ b/plugins/ktcore/KTDownloadTriggers.inc.php @@ -0,0 +1,91 @@ +. + * + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, + * California 94120-7775, or email info@knowledgetree.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU General Public License version 3. + * + * In accordance with Section 7(b) of the GNU General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * KnowledgeTree" logo and retain the original copyright notice. If the display of the + * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices + * must display the words "Powered by KnowledgeTree" and retain the original + * copyright notice. + * Contributor( s): ______________________________________ + * + */ + +class BulkDownloadTrigger { + + var $sNamespace = 'ktcore.triggers.download'; + var $sFriendlyName; + var $sDescription; + + function __construct() + { + $this->sFriendlyName = _kt('Bulk Download Notification'); + $this->sDescription = _kt('Notifies the newly logged in user of any waiting bulk downloads.'); + } + + public function invoke() + { + // TODO get this working with triggers instead of this? + // check for timed out downloads - now we may be looking at enough code to justify a trigger instead of all being here...? + DownloadQueue::timeout(); + + // determine whether there is a waiting bulk download + global $main; + // first check whether there is in fact a download waiting for this user + $config = KTConfig::getSingleton(); + $file = DownloadQueue::getNotificationFileName(); + if (!PEAR::isError($file)) { + $notificationFile = $config->get('cache/cacheDirectory') . '/' . $file; + } + if ((isset($_SESSION['checkBulkDownload']) && ($_SESSION['checkBulkDownload'])) || (file_exists($notificationFile))) { + unset($_SESSION['checkBulkDownload']); + DownloadQueue::removeNotificationFile(); + + require_once(KT_LIB_DIR . DIRECTORY_SEPARATOR . 'foldermanagement' . DIRECTORY_SEPARATOR . 'compressionArchiveUtil.inc.php'); + + $userID = $_SESSION['userID']; + $code = DownloadQueue::userDownloadAvailable($userID); + if ($code) { + $sBaseUrl = KTUtil::kt_url(); + $sUrl = $sBaseUrl . '/'; + $heading = _kt('You have a download waiting'); + $main->requireJSResource('resources/js/download_notification.js'); + $notification = "showDownloadNotification('{$sUrl}', '{$heading}', 'dms.users.bulk_download_notification', " + . "'{$code}', 'close');"; + } + + return $notification; + } + + return null; + } + +} + +?> diff --git a/resources/js/download_notification.js b/resources/js/download_notification.js new file mode 100644 index 0000000..ef02a84 --- /dev/null +++ b/resources/js/download_notification.js @@ -0,0 +1,128 @@ +var win; +var head; +var sUrl; +var type; +var request; +var request_type; +var request_details; + +/* +* Create the download notification dialog +*/ +var showDownloadNotification = function(sUrl, head, action, code, request_type, details){ + createNotification(); + + this.sUrl = sUrl + 'download_notification.php'; + + if(details === undefined) details = ''; + if(request_type === undefined) request_type = 'submit'; + if(type === undefined) type = 'system'; + + this.head = head; + this.code = code; + this.request = request; + this.request_type = request_type; + this.request_details = new Array(); + this.request_details[0] = action; + this.request_details[1] = details; + + // create the window + this.win = new Ext.Window({ + applyTo : 'download_notification', + layout : 'fit', + width : 370, + height : 150, + resizable : false, + closable : false, + closeAction :'destroy', + y : 150, + shadow: false, + modal: true + }); + this.win.show(); + + var info = document.getElementById('download_link'); + + Ext.Ajax.request({ + url: this.sUrl, + success: function(response) { + info.innerHTML = response.responseText; + document.getElementById('download_link').focus(); + }, + failure: function(response) { + alert('Error. Couldn\'t locate download.'); + }, + params: { + action: 'fetch', + head: head, + code: this.code, + request_type: this.request_type, + request: this.request + } + }); +} + +/* +* Create the html required to display the download link +*/ +var createNotification = function() { + + if(document.getElementById('download-panel')){ + p = document.getElementById('download-panel'); + }else { + p = document.getElementById('pageBody').appendChild(document.createElement('div')); + p.id = 'download-panel'; + } + + inner = '
Download Notification
'; + inner = inner + '
'; + p.innerHTML = inner; +} + +/* +* Close the popup +*/ +var panel_close = function() { + this.win.destroy(); +} + +/** + * Defer the download to next login + */ +var deferDownload = function() { + if (confirm("This will defer the download until your next login")) { + panel_close(); + } +} + +/** + * Delete the download and close the window + */ +var deleteDownload = function() { + if (confirm("Cancelling will delete the download.\nYou will not be able to start the download at a later time.\n\nAre you sure?")) { + var info = document.getElementById('exportcode'); + + Ext.Ajax.request({ + url: this.sUrl, + success: function(response) { + if(response.responseText == 'success'){ + if(this.request_type == 'close'){ + // follow the close action + this.win.destroy(); + return; + } + } + info.innerHTML = response.responseText; + }, + failure: function(response) { + alert('Error. Couldn\'t delete download.'); + }, + params: { + action: 'delete', + code: this.code + } + }); + + panel_close(); + } +} diff --git a/templates/kt3/notifications/notification.BulkDownload.smarty b/templates/kt3/notifications/notification.BulkDownload.smarty new file mode 100644 index 0000000..bab68fa --- /dev/null +++ b/templates/kt3/notifications/notification.BulkDownload.smarty @@ -0,0 +1,16 @@ +

{$head}

+

 

+
+ {$downloadText} +
+

 

+

 

+
+ {i18n}Cancel{/i18n} +   + {i18n}Close{/i18n} +
+ + \ No newline at end of file diff --git a/templates/kt3/standard_page.smarty b/templates/kt3/standard_page.smarty index c1be49c..b89b395 100644 --- a/templates/kt3/standard_page.smarty +++ b/templates/kt3/standard_page.smarty @@ -357,3 +357,8 @@ +{if ($downloadNotification != '')} + +{/if}