<page><![CDATA[wcf\acp\page\UserListPage]]></page>
</pages>
</action>
+
+ <action name="revertContentChanges">
+ <actionclassname><![CDATA[wcf\system\clipboard\action\UserContentClipboardAction]]></actionclassname>
+ <showorder>9</showorder>
+ <pages>
+ <page><![CDATA[wcf\acp\page\UserListPage]]></page>
+ </pages>
+ </action>
</import>
</data>
</option>
<!-- /user.profileComment -->
+ <option name="admin.content.canBulkRevertContentChanges">
+ <categoryname>admin.content</categoryname>
+ <optiontype>boolean</optiontype>
+ <defaultvalue>0</defaultvalue>
+ <admindefaultvalue>1</admindefaultvalue>
+ <usersonly>1</usersonly>
+ </option>
+
<option name="admin.content.label.canManageLabel">
<categoryname>admin.content.label</categoryname>
<optiontype>boolean</optiontype>
--- /dev/null
+{include file='header' pageTitle='wcf.acp.user.revertChanges'}
+
+<header class="boxHeadline">
+ <h1>{lang}wcf.acp.user.revertChanges{/lang}</h1>
+</header>
+
+{include file='formError'}
+
+<div class="contentNavigation">
+ {hascontent}
+ <nav>
+ <ul>
+ {content}
+ {event name='contentNavigationButtons'}
+ {/content}
+ </ul>
+ </nav>
+ {/hascontent}
+</div>
+
+<form method="post" action="{link controller='UserContentRevertChanges'}{/link}">
+ <div class="container containerPadding marginTop">
+ <fieldset>
+ <legend>{lang}wcf.acp.user.revertChanges.markedUsers{/lang}</legend>
+
+ <div>
+ {implode from=$users item='user'}<a href="{link controller='UserEdit' id=$user->userID}{/link}">{$user}</a>{/implode}
+ </div>
+
+ {event name='markedUserFields'}
+ </fieldset>
+
+ <fieldset>
+ <legend>{lang}wcf.acp.user.revertChanges.timeframe{/lang}</legend>
+
+ <dl{if $errorField == 'timeframe'} class="formError"{/if}>
+ <dt><label for="timeframe">{lang}wcf.acp.user.revertChanges.timeframe{/lang}</label></dt>
+ <dd>
+ <input name="timeframe" type="number" min="0" value="{$timeframe}" />
+
+ {if $errorField == 'timeframe'}
+ <small class="innerError">
+ {if $errorType == 'empty'}{lang}wcf.global.form.error.empty{/lang}{/if}
+ </small>
+ {/if}
+ <small>{lang}wcf.acp.user.revertChanges.timeframe.description{/lang}</small>
+ <dd>
+ </dl>
+
+ {event name='mergeFields'}
+ </fieldset>
+
+ {event name='fieldsets'}
+ </div>
+
+ <div class="formSubmit">
+ <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s" />
+ {@SECURITY_TOKEN_INPUT_TAG}
+ </div>
+</form>
+
+{include file='footer'}
--- /dev/null
+<?php
+namespace wcf\acp\form;
+use wcf\data\object\type\ObjectTypeCache;
+use wcf\form\AbstractForm;
+use wcf\system\clipboard\ClipboardHandler;
+use wcf\system\edit\EditHistoryManager;
+use wcf\system\exception\IllegalLinkException;
+use wcf\system\exception\UserInputException;
+use wcf\system\WCF;
+
+/**
+ * Shows the user content revert changes form.
+ *
+ * @author Tim Duesterhus
+ * @copyright 2001-2014 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage acp.form
+ * @category Community Framework
+ */
+class UserContentRevertChangesForm extends AbstractForm {
+ /**
+ * @see \wcf\page\AbstractPage::$neededPermissions
+ */
+ public $neededPermissions = array('admin.content.canBulkRevertContentChanges');
+
+ /**
+ * @see \wcf\page\AbstractPage::$activeMenuItem
+ */
+ public $activeMenuItem = 'wcf.acp.menu.link.user.management';
+
+ /**
+ * ids of the relevant users
+ * @var array<integer>
+ */
+ public $userIDs = array();
+
+ /**
+ * relevant users
+ * @var array<\wcf\data\user\User>
+ */
+ public $users = array();
+
+ /**
+ * timeframe to consider
+ * @var integer
+ */
+ public $timeframe = 7;
+
+ /**
+ * id of the user clipboard item object type
+ * @var integer
+ */
+ protected $objectTypeID = null;
+
+ /**
+ * @see \wcf\page\IPage::readParameters()
+ */
+ public function readParameters() {
+ parent::readParameters();
+
+ // get object type id
+ $this->objectTypeID = ClipboardHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.user');
+ // get user
+ $this->users = ClipboardHandler::getInstance()->getMarkedItems($this->objectTypeID);
+ if (empty($this->users)) {
+ throw new IllegalLinkException();
+ }
+ $this->userIDs = array_keys($this->users);
+ }
+
+ /**
+ * @see \wcf\form\IForm::readFormParameters()
+ */
+ public function readFormParameters() {
+ parent::readFormParameters();
+
+ if (isset($_POST['timeframe'])) $this->timeframe = intval($_POST['timeframe']);
+ }
+
+ /**
+ * @see \wcf\form\IForm::validate()
+ */
+ public function validate() {
+ parent::validate();
+
+ if ($this->timeframe < 1) {
+ throw new UserInputException('timeframe');
+ }
+ }
+
+ /**
+ * @see \wcf\form\IForm::save()
+ */
+ public function save() {
+ parent::save();
+
+ EditHistoryManager::getInstance()->bulkRevert($this->userIDs, $this->timeframe * 86400);
+
+ // reset clipboard
+ ClipboardHandler::getInstance()->removeItems($this->objectTypeID);
+ $this->saved();
+
+ // show success message
+ WCF::getTPL()->assign('message', 'wcf.global.success');
+ WCF::getTPL()->display('success');
+ exit;
+ }
+
+ /**
+ * @see \wcf\page\IPage::assignVariables()
+ */
+ public function assignVariables() {
+ parent::assignVariables();
+
+ WCF::getTPL()->assign(array(
+ 'users' => $this->users,
+ 'userIDs' => $this->userIDs,
+ 'timeframe' => $this->timeframe
+ ));
+ }
+}
--- /dev/null
+<?php
+namespace wcf\data\user;
+use wcf\system\edit\EditHistoryManager;
+use wcf\system\WCF;
+
+/**
+ * Executes actions on user generated content.
+ *
+ * @author Tim Duesterhus
+ * @copyright 2001-2014 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage data.user
+ * @category Community Framework
+ */
+class UserContentAction extends UserAction {
+ /**
+ * Checks permissions to bulk revert.
+ */
+ public function validateBulkRevert() {
+ WCF::getSession()->checkPermissions('admin.content.canBulkRevertContentChanges');
+ }
+
+ /**
+ * Bulk reverts changes made to history saving objects.
+ */
+ public function bulkRevert() {
+ $this->readInteger('timeframe', true);
+ if (!$this->parameters['timeframe']) {
+ $this->parameters['timeframe'] = 86400 * 7;
+ }
+
+ EditHistoryManager::getInstance()->bulkRevert($this->objectIDs, $this->parameters['timeframe']);
+ }
+}
--- /dev/null
+<?php
+namespace wcf\system\clipboard\action;
+use wcf\data\clipboard\action\ClipboardAction;
+use wcf\system\request\LinkHandler;
+use wcf\system\WCF;
+
+/**
+ * Prepares clipboard editor items for edit history entries.
+ *
+ * @author Tim Duesterhus
+ * @copyright 2001-2014 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage system.clipboard.action
+ * @category Community Framework
+ */
+class UserContentClipboardAction extends AbstractClipboardAction {
+ /**
+ * @see \wcf\system\clipboard\action\AbstractClipboardAction::$supportedActions
+ */
+ protected $supportedActions = array('revertContentChanges');
+
+ /**
+ * @see \wcf\system\clipboard\action\IClipboardAction::execute()
+ */
+ public function execute(array $objects, ClipboardAction $action) {
+ $item = parent::execute($objects, $action);
+
+ if ($item === null) {
+ return null;
+ }
+
+ // handle actions
+ switch ($action->actionName) {
+ case 'revertContentChanges':
+ $item->setURL(LinkHandler::getInstance()->getLink('UserContentRevertChanges'));
+ break;
+ }
+
+ return $item;
+ }
+
+ /**
+ * @see \wcf\system\clipboard\action\IClipboardAction::getClassName()
+ */
+ public function getClassName() {
+ return 'wcf\data\user\UserContentAction';
+ }
+
+ /**
+ * @see \wcf\system\clipboard\action\IClipboardAction::getTypeName()
+ */
+ public function getTypeName() {
+ return 'com.woltlab.wcf.user';
+ }
+
+ /**
+ * Returns the ids of the users which can be enabled.
+ *
+ * @return array<integer>
+ */
+ protected function validateRevertChanges() {
+ // check permissions
+ if (!WCF::getSession()->getPermission('admin.content.canBulkRevertContentChanges')) {
+ return array();
+ }
+
+ $userIDs = array();
+ foreach ($this->objects as $user) {
+ $userIDs[] = $user->userID;
+ }
+
+ return $userIDs;
+ }
+}
<item name="wcf.acp.group.option.admin.template.canManageTemplate"><![CDATA[Kann Templates verwalten]]></item>
<item name="wcf.acp.group.option.admin.style.canManageStyle"><![CDATA[Kann Stile verwalten]]></item>
<item name="wcf.acp.group.option.category.admin.content"><![CDATA[Inhalte]]></item>
+ <item name="wcf.acp.group.option.admin.content.canBulkRevertContentChanges"><![CDATA[Kann Änderungen der letzten Tage zurücksetzen]]></item>
<item name="wcf.acp.group.option.category.admin.community"><![CDATA[Community]]></item>
<item name="wcf.acp.group.option.category.mod.general"><![CDATA[Allgemeine Rechte]]></item>
<item name="wcf.acp.group.option.category.admin.user.option"><![CDATA[Benutzerprofilfelder]]></item>
<item name="wcf.acp.user.merge.destination"><![CDATA[Ziel]]></item>
<item name="wcf.acp.user.merge.destination.description"><![CDATA[Die ausgewählten Benutzer werden in dieses Benutzerkonto zusammengefügt.]]></item>
<item name="wcf.acp.user.merge.markedUsers"><![CDATA[Folgende Benutzer zusammenfügen]]></item>
+ <item name="wcf.acp.user.revertChanges"><![CDATA[Änderungen an Inhalten zurücksetzen]]></item>
+ <item name="wcf.acp.user.revertChanges.timeframe"><![CDATA[Zeitraum]]></item>
+ <item name="wcf.acp.user.revertChanges.timeframe.description"><![CDATA[Zeitraum in dem Änderungen des Benutzers zurückgesetzt werden sollen. Inhalte werden auf die neuste Version, welche entweder älter als der angebene Zeitraum ist oder welche von einem anderen Nutzer stammt, zurückgesetzt. [Zeitraum in Tagen]]]></item>
+ <item name="wcf.acp.user.revertChanges.markedUsers"><![CDATA[Änderungen folgender Nutzer zurücksetzen]]></item>
<item name="wcf.acp.user.bulkProcessing"><![CDATA[Benutzer-Massenbearbeitung]]></item>
<item name="wcf.acp.user.bulkProcessing.action"><![CDATA[Aktion]]></item>
<item name="wcf.acp.user.bulkProcessing.conditions"><![CDATA[Bedingungen]]></item>
<item name="wcf.clipboard.item.com.woltlab.wcf.user.sendNewPassword.confirmMessage"><![CDATA[Wollen Sie wirklich {if $count == 1}einem{else}{#$count}{/if} Benutzer ein neues Kennwort zusenden?]]></item>
<item name="wcf.clipboard.label.com.woltlab.wcf.user.marked"><![CDATA[{if $count == 1}Ein{else}{#$count}{/if} Benutzer markiert]]></item>
<item name="wcf.clipboard.item.com.woltlab.wcf.user.merge"><![CDATA[Zusammenfügen]]></item>
+ <item name="wcf.clipboard.item.com.woltlab.wcf.user.revertContentChanges"><![CDATA[Änderungen an Inhalten zurücksetzen]]></item>
<item name="wcf.clipboard.item.com.woltlab.wcf.user.enable"><![CDATA[Aktivieren]]></item>
</category>
<item name="wcf.acp.group.option.admin.template.canManageTemplate"><![CDATA[Can manage templates]]></item>
<item name="wcf.acp.group.option.admin.style.canManageStyle"><![CDATA[Can manage styles]]></item>
<item name="wcf.acp.group.option.category.admin.content"><![CDATA[Content]]></item>
+ <item name="wcf.acp.group.option.admin.content.canBulkRevertContentChanges"><![CDATA[Can bulk revert content changes]]></item>
<item name="wcf.acp.group.option.category.admin.community"><![CDATA[Community]]></item>
<item name="wcf.acp.group.option.category.mod.general"><![CDATA[General]]></item>
<item name="wcf.acp.group.option.category.admin.user.option"><![CDATA[User Profile Fields]]></item>
<item name="wcf.acp.user.merge.destination"><![CDATA[Destination]]></item>
<item name="wcf.acp.user.merge.destination.description"><![CDATA[The selected users will be merged into this user account.]]></item>
<item name="wcf.acp.user.merge.markedUsers"><![CDATA[Merge the following users]]></item>
+ <item name="wcf.acp.user.revertChanges"><![CDATA[Revert Changes To Contents]]></item>
+ <item name="wcf.acp.user.revertChanges.timeframe"><![CDATA[Timeframe]]></item>
+ <item name="wcf.acp.user.revertChanges.timeframe.description"><![CDATA[Changes made in this timeframe will be reverted to the newest version that is either older than the given timeframe or made by an unrelated user [time in days]]]></item>
+ <item name="wcf.acp.user.revertChanges.markedUsers"><![CDATA[Revert changes by the following users]]></item>
<item name="wcf.acp.user.bulkProcessing"><![CDATA[Bulk Processing]]></item>
<item name="wcf.acp.user.bulkProcessing.action"><![CDATA[Actions]]></item>
<item name="wcf.acp.user.bulkProcessing.conditions"><![CDATA[Conditions]]></item>
<item name="wcf.clipboard.item.com.woltlab.wcf.user.sendNewPassword.confirmMessage"><![CDATA[Do you really want to send a new password to {#$count} user{if $count != 1}s{/if}?]]></item>
<item name="wcf.clipboard.label.com.woltlab.wcf.user.marked"><![CDATA[{#$count} User{if $count != 1}s{/if} marked]]></item>
<item name="wcf.clipboard.item.com.woltlab.wcf.user.merge"><![CDATA[Merge]]></item>
+ <item name="wcf.clipboard.item.com.woltlab.wcf.user.revertContentChanges"><![CDATA[Revert Changes To Contents]]></item>
<item name="wcf.clipboard.item.com.woltlab.wcf.user.enable"><![CDATA[Approve]]></item>
</category>