Added template/JS for workers / bulk copy action methods
authorAlexander Ebert <ebert@woltlab.com>
Sat, 31 May 2014 23:46:21 +0000 (01:46 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Sat, 31 May 2014 23:46:21 +0000 (01:46 +0200)
com.woltlab.wcf/templates/worker.tpl [new file with mode: 0644]
wcfsetup/install/files/js/WCF.js
wcfsetup/install/files/lib/data/attachment/AttachmentAction.class.php
wcfsetup/install/files/lib/data/like/LikeAction.class.php
wcfsetup/install/files/lib/data/poll/PollAction.class.php
wcfsetup/install/files/style/icon.less

diff --git a/com.woltlab.wcf/templates/worker.tpl b/com.woltlab.wcf/templates/worker.tpl
new file mode 100644 (file)
index 0000000..08e0ca1
--- /dev/null
@@ -0,0 +1,10 @@
+<div id="workerContainer">
+       <header class="box48 boxHeadline">
+               <span class="icon icon48 fa-spinner"></span>
+               
+               <div>
+                       <h1>{lang}wcf.global.worker.executing{/lang}</h1>
+                       <small><progress value="0" max="100">0%</progress> <span>0%</span></small>
+               </div>
+       </header>
+</div>
index 071c39441c8de2f03939d80eaac7dc0c2d52b4d0..5209f95e42b78cbbaa0e96e48cf30880a573535d 100755 (executable)
@@ -7218,6 +7218,156 @@ WCF.System.KeepAlive = Class.extend({
        }
 });
 
+/**
+ * Worker support for frontend based upon DatabaseObjectActions.
+ * 
+ * @param      string          className
+ * @param      string          title
+ * @param      object          parameters
+ * @param      object          callback
+ */
+WCF.System.Worker = Class.extend({
+       /**
+        * worker aborted
+        * @var boolean
+        */
+       _aborted: false,
+       
+       /**
+        * DBOAction method name
+        * @var string
+        */
+       _actionName: '',
+       
+       /**
+        * callback invoked after worker completed
+        * @var object
+        */
+       _callback: null,
+       
+       /**
+        * DBOAction class name
+        * @var string
+        */
+       _className: '',
+       
+       /**
+        * dialog object
+        * @var jQuery
+        */
+       _dialog: null,
+       
+       /**
+        * action proxy
+        * @var WCF.Action.Proxy
+        */
+       _proxy: null,
+       
+       /**
+        * dialog title
+        * @var string
+        */
+       _title: '',
+       
+       /**
+        * Initializes a new worker instance.
+        * 
+        * @param       string          actionName
+        * @param       string          className
+        * @param       string          title
+        * @param       object          parameters
+        * @param       object          callback
+        * @param       object          confirmMessage
+        */
+       init: function(actionName, className, title, parameters, callback) {
+               this._aborted = false;
+               this._actionName = actionName;
+               this._callback = callback || null;
+               this._className = className;
+               this._dialog = null;
+               this._proxy = new WCF.Action.Proxy({
+                       autoSend: true,
+                       data: {
+                               actionName: this._actionName,
+                               className: this._className,
+                               parameters: parameters || { }
+                       },
+                       showLoadingOverlay: false,
+                       success: $.proxy(this._success, this)
+               });
+               this._title = title;
+       },
+       
+       /**
+        * Handles response from server.
+        * 
+        * @param       object          data
+        */
+       _success: function(data) {
+               // init binding
+               if (this._dialog === null) {
+                       this._dialog = $('<div />').hide().appendTo(document.body);
+                       this._dialog.wcfDialog({
+                               closeConfirmMessage: WCF.Language.get('wcf.worker.abort.confirmMessage'),
+                               closeViaModal: false,
+                               onClose: $.proxy(function() {
+                                       this._aborted = true;
+                                       this._proxy.abortPrevious();
+                                       
+                                       window.location.reload();
+                               }, this),
+                               title: this._title
+                       });
+               }
+               
+               if (this._aborted) {
+                       return;
+               }
+               
+               if (data.returnValues.template) {
+                       this._dialog.html(data.returnValues.template);
+               }
+               
+               // update progress
+               this._dialog.find('progress').attr('value', data.returnValues.progress).text(data.returnValues.progress + '%').next('span').text(data.returnValues.progress + '%');
+               
+               // worker is still busy with its business, carry on
+               if (data.returnValues.progress < 100) {
+                       // send request for next loop
+                       var $parameters = data.returnValues.parameters || { };
+                       $parameters.loopCount = data.returnValues.loopCount;
+                       
+                       this._proxy.setOption('data', {
+                               actionName: this._actionName,
+                               className: this._className,
+                               parameters: $parameters
+                       });
+                       this._proxy.sendRequest();
+               }
+               else if (this._callback !== null) {
+                       this._callback(this, data);
+               }
+               else {
+                       // exchange icon
+                       this._dialog.find('.fa-spinner').removeClass('fa-spinner').addClass('fa-check green');
+                       this._dialog.find('.boxHeadline h1').text(WCF.Language.get('wcf.global.worker.completed'));
+                       
+                       // display continue button
+                       var $formSubmit = $('<div class="formSubmit" />').appendTo(this._dialog);
+                       $('<button class="buttonPrimary">' + WCF.Language.get('wcf.global.button.next') + '</button>').appendTo($formSubmit).focus().click(function() {
+                               if (data.returnValues.redirectURL) {
+                                       window.location = data.returnValues.redirectURL;
+                               }
+                               else {
+                                       window.location.reload();
+                               }
+                       });
+                       
+                       this._dialog.wcfDialog('render');
+               }
+       }
+});
+
 /**
  * Default implementation for inline editors.
  * 
index 18fb529b03d5c43e95f301bed928f54909a6ca09..893aac97bf4b6e1c775de7c892369ca4c0a353bb 100644 (file)
@@ -397,4 +397,61 @@ class AttachmentAction extends AbstractDatabaseObjectAction {
                }
                WCF::getDB()->commitTransaction();
        }
+       
+       /**
+        * Copies attachments from one object id to another.
+        */
+       public function copy() {
+               $sourceObjectType = ObjectTypeCache::getInstance()->getObjectTypeByName('com.woltlab.wcf.attachment.objectType', $this->parameters['sourceObjectType']);
+               $targetObjectType = ObjectTypeCache::getInstance()->getObjectTypeByName('com.woltlab.wcf.attachment.objectType', $this->parameters['targetObjectType']);
+               
+               $attachmentList = new AttachmentList();
+               $attachmentList->getConditionBuilder()->add("attachment.objectTypeID = ?", array($sourceObjectType->objectTypeID));
+               $attachmentList->getConditionBuilder()->add("attachment.objectID = ?", array($this->parameters['sourceObjectID']));
+               $attachmentList->readObjects();
+               
+               $newAttachmentIDs = array();
+               foreach ($attachmentList as $attachment) {
+                       $newAttachment = AttachmentEditor::create(array(
+                               'objectTypeID' => $targetObjectType->objectTypeID,
+                               'objectID' => $this->parameters['targetObjectID'],
+                               'userID' => $attachment->userID,
+                               'filename' => $attachment->filename,
+                               'filesize' => $attachment->filesize,
+                               'fileType' => $attachment->fileType,
+                               'fileHash' => $attachment->fileHash,
+                               'isImage' => $attachment->isImage,
+                               'width' => $attachment->width,
+                               'height' => $attachment->height,
+                               'tinyThumbnailType' => $attachment->tinyThumbnailType,
+                               'tinyThumbnailSize' => $attachment->tinyThumbnailSize,
+                               'tinyThumbnailWidth' => $attachment->tinyThumbnailWidth,
+                               'tinyThumbnailHeight' => $attachment->tinyThumbnailHeight,
+                               'thumbnailType' => $attachment->thumbnailType,
+                               'thumbnailSize' => $attachment->thumbnailSize,
+                               'thumbnailWidth' => $attachment->thumbnailWidth,
+                               'thumbnailHeight' => $attachment->thumbnailHeight,
+                               'downloads' => $attachment->downloads,
+                               'lastDownloadTime' => $attachment->lastDownloadTime,
+                               'uploadTime' => $attachment->uploadTime,
+                               'showOrder' => $attachment->showOrder
+                       ));
+                       
+                       // copy attachment
+                       @copy($attachment->getLocation(), $newAttachment->getLocation());
+                       
+                       if ($attachment->tinyThumbnailSize) {
+                               @copy($attachment->getTinyThumbnailLocation(), $newAttachment->getTinyThumbnailLocation());
+                       }
+                       if ($attachment->thumbnailSize) {
+                               @copy($attachment->getThumbnailLocation(), $newAttachment->getThumbnailLocation());
+                       }
+                       
+                       $newAttachmentIDs[$attachment->attachmentID] = $newAttachment->attachmentID;
+               }
+               
+               return array(
+                       'attachmentIDs' => $newAttachmentIDs
+               );
+       }
 }
index 16119d8d045431adf6fed2919554cf9597b2abbf..b1272d0b4928b7470ff62f30ce9fd881790368da 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 namespace wcf\data\like;
+use wcf\data\object\type\ObjectTypeCache;
 use wcf\data\AbstractDatabaseObjectAction;
 use wcf\data\IGroupedUserListAction;
 use wcf\system\exception\PermissionDeniedException;
@@ -8,6 +9,11 @@ use wcf\system\like\LikeHandler;
 use wcf\system\user\activity\event\UserActivityEventHandler;
 use wcf\system\user\GroupedUserList;
 use wcf\system\WCF;
+use wcf\data\like\object\LikeObjectEditor;
+use wcf\data\user\UserEditor;
+use wcf\data\user\User;
+use wcf\system\user\activity\point\UserActivityPointHandler;
+
 
 /**
  * Executes like-related actions.
@@ -314,4 +320,84 @@ class LikeAction extends AbstractDatabaseObjectAction implements IGroupedUserLis
                        'template' => WCF::getTPL()->fetch('userProfileLikeItem')
                );
        }
+       
+       /**
+        * Copies a poll from one object id to another.
+        */
+       public function copy() {
+               $sourceObjectType = ObjectTypeCache::getInstance()->getObjectTypeByName('com.woltlab.wcf.like.likeableObject', $this->parameters['sourceObjectType']);
+               $targetObjectType = ObjectTypeCache::getInstance()->getObjectTypeByName('com.woltlab.wcf.like.likeableObject', $this->parameters['targetObjectType']);
+               
+               //
+               // step 1) get data
+               //
+               
+               // get like object
+               $sql = "SELECT  *
+                       FROM    wcf".WCF_N."_like_object
+                       WHERE   objectTypeID = ?
+                               AND objectID = ?";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute(array(
+                       $sourceObjectType->objectTypeID,
+                       $this->parameters['sourceObjectID']
+               ));
+               $row = $statement->fetchArray();
+               
+               // no (dis-)likes at all
+               if ($row === false) {
+                       return;
+               }
+               
+               unset($row['likeObjectID']);
+               $row['objectTypeID'] = $targetObjectType->objectTypeID;
+               $row['objectID'] = $this->parameters['targetObjectID'];
+               $newLikeObject = LikeObjectEditor::create($row);
+               
+               //
+               // step 2) copy
+               //
+               
+               $sql = "INSERT INTO     wcf".WCF_N."_like
+                                       (objectID, objectTypeID, objectUserID, userID, time, likeValue)
+                       SELECT          ".$this->parameters['targetObjectID'].", ".$targetObjectType->objectTypeID.", objectUserID, userID, time, likeValue
+                       FROM            wcf".WCF_N."_like
+                       WHERE           objectTypeID = ?
+                                       AND objectID = ?";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute(array(
+                       $sourceObjectType->objectTypeID,
+                       $this->parameters['sourceObjectID']
+               ));
+               
+               //
+               // step 3) update owner
+               //
+               
+               if ($newLikeObject->objectUserID) {
+                       $sql = "SELECT  COUNT(*) AS count
+                               FROM    wcf".WCF_N."_like
+                               WHERE   objectTypeID = ?
+                                       AND objectID = ?
+                                       AND likeValue = ?";
+                       $statement = WCF::getDB()->prepareStatement($sql);
+                       $statement->execute(array(
+                               $targetObjectType->objectTypeID,
+                               $this->parameters['targetObjectID'],
+                               Like::LIKE
+                       ));
+                       $row = $statement->fetchArray();
+                       
+                       if ($row['count']) {
+                               // update received likes
+                               $userEditor = new UserEditor(new User($newLikeObject->objectUserID));
+                               $userEditor->updateCounters(array(
+                                       'likesReceived' => $row['count']
+                               ));
+                               
+                               // add activity points
+                               UserActivityPointHandler::getInstance()->fireEvents('com.woltlab.wcf.like.activityPointEvent.receivedLikes', array($newLikeObject->objectUserID => $row['count']));
+                       }
+               }
+       }
 }
index fea5cfcf50c457de2d2aaf41960d709f7bb8eb31..1813af808e13525332543a69b00fccc819157f3a 100644 (file)
@@ -1,5 +1,7 @@
 <?php
 namespace wcf\data\poll;
+use wcf\data\object\type\ObjectTypeCache;
+use wcf\data\poll\option\PollOptionEditor;
 use wcf\data\poll\option\PollOptionList;
 use wcf\data\AbstractDatabaseObjectAction;
 use wcf\data\IGroupedUserListAction;
@@ -8,6 +10,7 @@ use wcf\system\exception\UserInputException;
 use wcf\system\user\GroupedUserList;
 use wcf\system\WCF;
 
+
 /**
  * Executes poll-related actions.
  * 
@@ -303,4 +306,81 @@ class PollAction extends AbstractDatabaseObjectAction implements IGroupedUserLis
                        'template' => WCF::getTPL()->fetch('groupedUserList')
                );
        }
+       
+       /**
+        * Copies a poll from one object id to another.
+        */
+       public function copy() {
+               $sourceObjectType = ObjectTypeCache::getInstance()->getObjectTypeByName('com.woltlab.wcf.poll', $this->parameters['sourceObjectType']);
+               $targetObjectType = ObjectTypeCache::getInstance()->getObjectTypeByName('com.woltlab.wcf.poll', $this->parameters['targetObjectType']);
+               
+               //
+               // step 1) get data
+               //
+               
+               // get poll
+               $sql = "SELECT  *
+                       FROM    wcf".WCF_N."_poll
+                       WHERE   objectTypeID = ?
+                               AND objectID = ?";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute(array(
+                       $sourceObjectType->objectTypeID,
+                       $this->parameters['sourceObjectID']
+               ));
+               $row = $statement->fetchArray();
+               
+               if ($row === false) {
+                       return array(
+                               'pollID' => null
+                       );
+               }
+               
+               // get options
+               $pollOptionList = new PollOptionList();
+               $pollOptionList->getConditionBuilder()->add("poll_option.pollID = ?", array($row['pollID']));
+               $pollOptionList->readObjects();
+               
+               //
+               // step 2) copy
+               //
+               
+               // cretae poll
+               $pollData = $row;
+               $pollData['objectTypeID'] = $targetObjectType->objectTypeID;
+               $pollData['objectID'] = $this->parameters['targetObjectID'];
+               unset($pollData['pollID']);
+               
+               $newPoll = PollEditor::create($pollData);
+               
+               // create options
+               $newOptionIDs = array();
+               foreach ($pollOptionList as $pollOption) {
+                       $newOption = PollOptionEditor::create(array(
+                               'pollID' => $newPoll->pollID,
+                               'optionValue' => $pollOption->optionValue,
+                               'votes' => $pollOption->votes,
+                               'showOrder' => $pollOption->showOrder
+                       ));
+                       
+                       $newOptionIDs[$pollOption->optionID] = $newOption->optionID;
+               }
+               
+               // copy votes
+               WCF::getDB()->beginTransaction();
+               foreach ($newOptionIDs as $oldOptionID => $newOptionID) {
+                       $sql = "INSERT INTO     wcf".WCF_N."_poll_option_vote
+                                               (pollID, optionID, userID)
+                               SELECT          ".$newPoll->pollID.", ".$newOptionID.", userID
+                               FROM            wcf".WCF_N."_poll_option_vote
+                               WHERE           optionID = ?";
+                       $statement = WCF::getDB()->prepareStatement($sql);
+                       $statement->execute(array($oldOptionID));
+               }
+               WCF::getDB()->commitTransaction();
+               
+               return array(
+                       'pollID' => $newPoll->pollID
+               );
+       }
 }
index 0271cbc01072942969c465d28d8d4c9820f1b268..e175ea9292747f6297eb2364ba3bc9266cd0bfbf 100644 (file)
@@ -107,7 +107,8 @@ a > span.fa:not(.pointer) {
 }
 
 // spinner animation
-.icon-spinner {
+.icon-spinner,
+.fa-spinner {
        height: auto;
        
        -moz-animation: spin 2s infinite linear;