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 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,17 @@ class DownloadQueue
617 647 $this->errors = null;
618 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 662 // Remove lock file
622 663 @unlink($this->lockFile);
... ... @@ -757,7 +798,8 @@ class DownloadQueue
757 798 * @param Folder array $aFolderList
758 799 * @return unknown
759 800 */
760   - function getLinkingEntities($aFolderList){
  801 + function getLinkingEntities($aFolderList)
  802 + {
761 803 $aSearchFolders = array();
762 804 if(!empty($aFolderList)){
763 805 foreach($aFolderList as $oFolderItem){
... ... @@ -846,5 +888,142 @@ class DownloadQueue
846 888 {
847 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 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');
... ... @@ -198,6 +200,7 @@ class KTCorePlugin extends KTPlugin {
198 200 $this->registerWidget('KTCoreLayerWidget', 'ktcore.widgets.layer', 'KTWidgets.php');
199 201 $this->registerWidget('KTCoreConditionalSelectionWidget', 'ktcore.widgets.conditionalselection', 'KTWidgets.php');
200 202 $this->registerWidget('KTCoreImageWidget', 'ktcore.widgets.image', 'KTWidgets.php');
  203 + $this->registerWidget('KTCoreImageSelectWidget', 'ktcore.widgets.imageselect', 'KTWidgets.php');
201 204 $this->registerWidget('KTCoreImageCropWidget', 'ktcore.widgets.imagecrop', 'KTWidgets.php');
202 205  
203 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 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 84 'encoding' => 'multipart/form-data',
85 85 'context' => &$this,
86 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 90 $oWF =& KTWidgetFactory::getSingleton();
... ... @@ -99,7 +99,7 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
99 99 'name' => 'file',
100 100 'id' => 'file',
101 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 105 $aVocab['crop'] = 'Crop - Cut out a selection';
... ... @@ -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 200 * Returns the crop logo form
146 201 *
147 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 366  
312 367 //Changing to logo.jpg (Need to preserve extention as GD requires the exact image type to work)
313 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 370 $logoFile = $logoDir.DIRECTORY_SEPARATOR.$logoFileName;
316 371  
317 372 // deleting old tmp file
... ... @@ -329,6 +384,8 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
329 384  
330 385 $resizeMethod = $_REQUEST['data']['resize_method'];
331 386  
  387 + $relDir = 'var'.DIRECTORY_SEPARATOR.'branding'.DIRECTORY_SEPARATOR.'logo'.DIRECTORY_SEPARATOR;
  388 +
332 389 switch ($resizeMethod) {
333 390 case 'crop':
334 391 $cropLogoForm = $this->getCropLogoForm($logoFileName);
... ... @@ -336,9 +393,24 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
336 393  
337 394 case 'scale':
338 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 414 return $form->render();
343 415  
344 416 default:
... ... @@ -354,7 +426,7 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
354 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 430 global $default;
359 431  
360 432 //Requires the GD library if not exit gracefully
... ... @@ -399,7 +471,11 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
399 471  
400 472 $image_x = $width;
401 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 481 * create the new image, and scale the original into it.
... ... @@ -426,7 +502,6 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
426 502 return false;
427 503 }
428 504  
429   -
430 505 } else {
431 506 //Handle Error
432 507 $default->log->error("Couldn't obtain a valid GD resource");
... ... @@ -446,9 +521,13 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
446 521 function do_crop(){
447 522 global $default;
448 523  
449   - $logoFileName = $_REQUEST['data']['logo_file_name'];
  524 + $logoFileName = $_REQUEST['data']['logo_file_name'];
450 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 531 $x1 = $_REQUEST['data']['crop_x1'];
453 532 $y1 = $_REQUEST['data']['crop_y1'];
454 533  
... ... @@ -458,7 +537,7 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
458 537 $type = $this->getMime($logoFileName);
459 538  
460 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 542 //If dimensions don't conform then will scale it further
464 543 $width = $x2 - $x1;
... ... @@ -466,7 +545,7 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
466 545  
467 546 if (($width > $this->maxLogoWidth) || ($height > $this->maxLogoHeight)) {
468 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 551 // ImageMagick Crop
... ... @@ -485,7 +564,7 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
485 564 $result = KTUtil::pexec($cmd);
486 565 */
487 566  
488   - $applyLogoForm = $this->getApplyLogoForm($logoFileName);
  567 + $applyLogoForm = $this->getApplyLogoForm($destFileName);
489 568 return $applyLogoForm->render();
490 569  
491 570 }
... ... @@ -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 699 * Action responsible for applying the logo
... ... @@ -628,10 +722,12 @@ class ManageBrandDispatcher extends KTAdminDispatcher {
628 722 $brandDir = $default->varDirectory.DIRECTORY_SEPARATOR.'branding'.DIRECTORY_SEPARATOR.'logo'.DIRECTORY_SEPARATOR;
629 723 $handle = opendir($brandDir);
630 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 726 if (!@unlink($brandDir.$file)) {
633 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 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 648 `code` char(16) NOT NULL,
649 649 `folder_id` int(11) NOT NULL,
650 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 652 `user_id` int(11) NOT NULL,
653 653 `date_added` timestamp NOT NULL default CURRENT_TIMESTAMP,
654 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 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 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}
... ...
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>
... ...