From: Alexander Ebert Date: Sat, 31 May 2014 23:46:21 +0000 (+0200) Subject: Added template/JS for workers / bulk copy action methods X-Git-Tag: 2.1.0_Alpha_1~771 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=e53269d674321d74210ff3f908f12be7a0aa0027;p=GitHub%2FWoltLab%2FWCF.git Added template/JS for workers / bulk copy action methods --- diff --git a/com.woltlab.wcf/templates/worker.tpl b/com.woltlab.wcf/templates/worker.tpl new file mode 100644 index 0000000000..08e0ca1a31 --- /dev/null +++ b/com.woltlab.wcf/templates/worker.tpl @@ -0,0 +1,10 @@ +
+
+ + +
+

{lang}wcf.global.worker.executing{/lang}

+ 0% 0% +
+
+
diff --git a/wcfsetup/install/files/js/WCF.js b/wcfsetup/install/files/js/WCF.js index 071c39441c..5209f95e42 100755 --- a/wcfsetup/install/files/js/WCF.js +++ b/wcfsetup/install/files/js/WCF.js @@ -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 = $('
').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 = $('
').appendTo(this._dialog); + $('').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. * diff --git a/wcfsetup/install/files/lib/data/attachment/AttachmentAction.class.php b/wcfsetup/install/files/lib/data/attachment/AttachmentAction.class.php index 18fb529b03..893aac97bf 100644 --- a/wcfsetup/install/files/lib/data/attachment/AttachmentAction.class.php +++ b/wcfsetup/install/files/lib/data/attachment/AttachmentAction.class.php @@ -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 + ); + } } diff --git a/wcfsetup/install/files/lib/data/like/LikeAction.class.php b/wcfsetup/install/files/lib/data/like/LikeAction.class.php index 16119d8d04..b1272d0b49 100644 --- a/wcfsetup/install/files/lib/data/like/LikeAction.class.php +++ b/wcfsetup/install/files/lib/data/like/LikeAction.class.php @@ -1,5 +1,6 @@ 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'])); + } + } + } } diff --git a/wcfsetup/install/files/lib/data/poll/PollAction.class.php b/wcfsetup/install/files/lib/data/poll/PollAction.class.php index fea5cfcf50..1813af808e 100644 --- a/wcfsetup/install/files/lib/data/poll/PollAction.class.php +++ b/wcfsetup/install/files/lib/data/poll/PollAction.class.php @@ -1,5 +1,7 @@ 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 + ); + } } diff --git a/wcfsetup/install/files/style/icon.less b/wcfsetup/install/files/style/icon.less index 0271cbc010..e175ea9292 100644 --- a/wcfsetup/install/files/style/icon.less +++ b/wcfsetup/install/files/style/icon.less @@ -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;