<coreobject>
<objectname><![CDATA[wcf\system\user\object\watch\UserObjectWatchHandler]]></objectname>
</coreobject>
+
+ <coreobject>
+ <objectname><![CDATA[wcf\system\moderation\queue\ModerationQueueManager]]></objectname>
+ </coreobject>
</import>
</data>
<canbeedited>1</canbeedited>
<canbedisabled>1</canbedisabled>
</cronjob>
+
+ <cronjob>
+ <classname>wcf\system\cronjob\ModerationQueueCronjob</classname>
+ <description>Moderation Queue Cleanup</description>
+ <startminute>0</startminute>
+ <starthour>1</starthour>
+ <startdom>*</startdom>
+ <startmonth>*</startmonth>
+ <startdow>*</startdow>
+ <active>1</active>
+ <canbeedited>1</canbeedited>
+ <canbedisabled>1</canbedisabled>
+ </cronjob>
</import>
</data>
\ No newline at end of file
<controller>wcf\form\SignatureEditForm</controller>
<languagevariable>wcf.user.usersOnline.location.SignatureEditForm</languagevariable>
</type>
+
+ <!-- moderation type -->
+ <type>
+ <name>com.woltlab.wcf.moderation.activation</name>
+ <definitionname>com.woltlab.wcf.moderation.type</definitionname>
+ <classname>wcf\system\moderation\queue\ModerationQueueActivationManager</classname>
+ </type>
+ <type>
+ <name>com.woltlab.wcf.moderation.report</name>
+ <definitionname>com.woltlab.wcf.moderation.type</definitionname>
+ <classname>wcf\system\moderation\queue\ModerationQueueReportManager</classname>
+ </type>
+ <!-- /moderation type -->
</import>
</data>
\ No newline at end of file
<name>com.woltlab.wcf.visitTracker.objectType</name>
<!-- <interfacename>wcf\system\visitTracker\IVisitTrackerObjectType</interfacename>-->
</definition>
+
+ <definition>
+ <name>com.woltlab.wcf.moderation.type</name>
+ <interfacename>wcf\system\moderation\queue\IModerationQueueManager</interfacename>
+ </definition>
+
+ <definition>
+ <name>com.woltlab.wcf.moderation.activation</name>
+ <interfacename>wcf\system\moderation\queue\activation\IModerationQueueActivationHandler</interfacename>
+ </definition>
+
+ <definition>
+ <name>com.woltlab.wcf.moderation.report</name>
+ <interfacename>wcf\system\moderation\queue\report\IModerationQueueReportHandler</interfacename>
+ </definition>
</import>
</data>
--- /dev/null
+{include file='documentHeader'}
+
+<head>
+ <title>{lang}wcf.moderation.activation{/lang} - {PAGE_TITLE|language}</title>
+
+ {include file='headInclude'}
+
+ <script type="text/javascript" src="{@$__wcf->getPath()}js/WCF.Moderation{if !ENABLE_DEBUG_MODE}.min{/if}.js"></script>
+ <script type="text/javascript">
+ //<![CDATA[
+ $(function() {
+ new WCF.Moderation.Activation.Management({@$queue->queueID}, '{link controller='ModerationList'}{/link}');
+
+ WCF.Language.addObject({
+ 'wcf.moderation.activation.enableContent.confirmMessage': '{lang}wcf.moderation.activation.enableContent.confirmMessage{/lang}',
+ 'wcf.moderation.activation.removeContent.confirmMessage': '{lang}wcf.moderation.activation.removeContent.confirmMessage{/lang}'
+ });
+ });
+ //]]>
+ </script>
+</head>
+
+<body id="tpl{$templateName|ucfirst}">
+
+{include file='header' sidebarOrientation='left'}
+
+<header class="boxHeadline">
+ <h1>{lang}wcf.moderation.activation{/lang}</h1>
+</header>
+
+{include file='userNotice'}
+
+<div class="contentNavigation">
+ <nav>
+ <ul>
+ <li><a href="{link controller='ModerationList'}{/link}" class="button"><span class="icon icon16 icon-list"></span> <span>{lang}wcf.moderation.moderation{/lang}</span></a></li>
+
+ {event name='contentNavigationButtonsTop'}
+ </ul>
+ </nav>
+</div>
+
+<form method="post" action="{link controller='ModerationActivation' id=$queue->queueID}{/link}" class="container containerPadding marginTop">
+ <fieldset>
+ <legend>{lang}wcf.moderation.activation.details{/lang}</legend>
+
+ <dl>
+ <dt>{lang}wcf.global.objectID{/lang}</dt>
+ <dd>{#$queue->queueID}</dd>
+ </dl>
+ {if $queue->lastChangeTime}
+ <dl>
+ <dt>{lang}wcf.moderation.lastChangeTime{/lang}</dt>
+ <dd>{@$queue->lastChangeTime|time}</dd>
+ </dl>
+ {/if}
+ <dl>
+ <dt>{lang}wcf.moderation.assignedUser{/lang}</dt>
+ <dd>
+ <ul>
+ {if $assignedUserID && ($assignedUserID != $__wcf->getUser()->userID)}
+ <li><label><input type="radio" name="assignedUserID" value="{@$assignedUserID}" checked="checked" /> {$queue->assignedUsername}</label></li>
+ {/if}
+ <li><label><input type="radio" name="assignedUserID" value="{@$__wcf->getUser()->userID}"{if $assignedUserID == $__wcf->getUser()->userID} checked="checked"{/if} /> {$__wcf->getUser()->username}</label></li>
+ <li><label><input type="radio" name="assignedUserID" value="0"{if !$assignedUserID} checked="checked"{/if} /> {lang}wcf.moderation.assignedUser.nobody{/lang}</label></li>
+ </ul>
+ </dd>
+ </dl>
+ {if $queue->assignedUser}
+ <dl>
+
+ <dd><a href="{link controller='User' id=$assignedUserID}{/link}" class="userLink" data-user-id="{@$assignedUserID}">{$queue->assignedUsername}</a></dd>
+ </dl>
+ {/if}
+ <dl>
+ <dt><label for="comment">{lang}wcf.moderation.comment{/lang}</label></dt>
+ <dd><textarea id="comment" name="comment" rows="4" cols="40">{$comment}</textarea></dd>
+ </dl>
+
+ {event name='detailsFields'}
+
+ <div class="formSubmit">
+ <input type="submit" value="{lang}wcf.global.button.submit{/lang}" />
+ </div>
+ </fieldset>
+
+ {event name='fieldsets'}
+</form>
+
+<header class="boxHeadline boxSubHeadline">
+ <h2>{lang}wcf.moderation.activation.content{/lang}</h2>
+</header>
+
+<div class="marginTop">
+ {@$disabledContent}
+</div>
+
+<div class="contentNavigation">
+ <nav>
+ <ul>
+ <li class="jsOnly"><button id="enableContent">{lang}wcf.moderation.activation.enableContent{/lang}</button></li>
+ <li class="jsOnly"><button id="removeContent">{lang}wcf.moderation.activation.removeContent{/lang}</button></li>
+ <li><a href="{link controller='ModerationList'}{/link}" class="button"><span class="icon icon16 icon-list"></span> <span>{lang}wcf.moderation.moderation{/lang}</span></a></li>
+
+ {event name='contentNavigationButtonsBottom'}
+ </ul>
+ </nav>
+</div>
+
+{include file='footer'}
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+{include file='documentHeader'}
+
+<head>
+ <title>{lang}wcf.moderation.moderation{/lang} {if $pageNo > 1}- {lang}wcf.page.pageNo{/lang} {/if}- {PAGE_TITLE|language}</title>
+
+ {include file='headInclude'}
+</head>
+
+<body id="tpl{$templateName|ucfirst}">
+
+{capture assign='sidebar'}
+ {* moderation type *}
+ <fieldset>
+ <legend>{lang}wcf.moderation.filterByType{/lang}</legend>
+
+ <nav>
+ <ul>
+ <li{if $definitionID == 0} class="active"{/if}><a href="{link controller='ModerationList'}definitionID=0&assignedUserID={@$assignedUserID}&status={@$status}&pageNo={@$pageNo}&sortField={@$sortField}&sortOrder={@$sortOrder}{/link}">{lang}wcf.moderation.type.all{/lang}</a></li>
+ {foreach from=$availableDefinitions key=__definitionID item=definitionName}
+ <li{if $definitionID == $__definitionID} class="active"{/if}><a href="{link controller='ModerationList'}definitionID={@$__definitionID}&assignedUserID={@$assignedUserID}&status={@$status}&pageNo={@$pageNo}&sortField={@$sortField}&sortOrder={@$sortOrder}{/link}">{lang}wcf.moderation.type.{$definitionName}{/lang}</a></li>
+ {/foreach}
+
+ {event name='sidebarModerationType'}
+ </ul>
+ </nav>
+ </fieldset>
+
+ {* assigned user *}
+ <fieldset>
+ <legend>{lang}wcf.moderation.filterByUser{/lang}</legend>
+
+ <nav>
+ <ul>
+ <li{if $assignedUserID == -1} class="active"{/if}><a href="{link controller='ModerationList'}definitionID={@$definitionID}&assignedUserID=-1&status={@$status}&pageNo={@$pageNo}&sortField={@$sortField}&sortOrder={@$sortOrder}{/link}">{lang}wcf.moderation.filterByUser.allEntries{/lang}</a></li>
+ <li{if $assignedUserID == 0} class="active"{/if}><a href="{link controller='ModerationList'}definitionID={@$definitionID}&assignedUserID=0&status={@$status}&pageNo={@$pageNo}&sortField={@$sortField}&sortOrder={@$sortOrder}{/link}">{lang}wcf.moderation.filterByUser.nobody{/lang}</a></li>
+ <li{if $assignedUserID == $__wcf->getUser()->userID} class="active"{/if}><a href="{link controller='ModerationList'}definitionID={@$definitionID}&assignedUserID={@$__wcf->getUser()->userID}&status={@$status}&pageNo={@$pageNo}&sortField={@$sortField}&sortOrder={@$sortOrder}{/link}">{lang}wcf.moderation.filterByUser.myself{/lang}</a></li>
+
+ {event name='sidebarAssignedUser'}
+ </ul>
+ </nav>
+ </fieldset>
+
+ {* status *}
+ <fieldset>
+ <legend>{lang}wcf.moderation.status{/lang}</legend>
+
+ <nav>
+ <ul>
+ <li{if $status == -1} class="active"{/if}><a href="{link controller='ModerationList'}definitionID={@$definitionID}&assignedUserID={@$assignedUserID}&status=-1&pageNo={@$pageNo}&sortField={@$sortField}&sortOrder={@$sortOrder}{/link}">{lang}wcf.moderation.status.all{/lang}</a></li>
+ <li{if $status == 2} class="active"{/if}><a href="{link controller='ModerationList'}definitionID={@$definitionID}&assignedUserID={@$assignedUserID}&status=2&pageNo={@$pageNo}&sortField={@$sortField}&sortOrder={@$sortOrder}{/link}">{lang}wcf.moderation.status.done{/lang}</a></li>
+
+ {event name='sidebarStatus'}
+ </ul>
+ </nav>
+ </fieldset>
+
+ {event name='sidebarBoxes'}
+{/capture}
+
+{include file='header' sidebarOrientation='left'}
+
+<header class="boxHeadline">
+ <h1>{lang}wcf.moderation.moderation{/lang}</h1>
+</header>
+
+{include file='userNotice'}
+
+<div class="contentNavigation">
+ {pages print=true assign=pagesLinks controller='ModerationList' link="id=$definitionID&pageNo=%d&sortField=$sortField&sortOrder=$sortOrder"}
+
+ {hascontent}
+ <nav>
+ <ul>
+ {content}
+ {event name='contentNavigationButtonsTop'}
+ {/content}
+ </ul>
+ </nav>
+ {/hascontent}
+</div>
+
+{if $objects|count}
+ <div class="marginTop tabularBox tabularBoxTitle messageGroupList">
+ <header>
+ <h2>{if $status == 2}{lang}wcf.moderation.doneItems{/lang}{else}{lang}wcf.moderation.outstandingItems{/lang}{/if} <span class="badge badgeInverse">{#$items}</span></h2>
+ </header>
+
+ <table class="table">
+ <thead>
+ <tr>
+ <th class="columnID{if $sortField == 'queueID'} active {@$sortOrder}{/if}"><a href="{link controller='ModerationList'}definitionID={@$definitionID}&assignedUserID={@$assignedUserID}&status={@$status}&pageNo={@$pageNo}&sortField=queueID&sortOrder={if $sortField == 'queueID' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.global.objectID{/lang}</a></th>
+ <th class="columnText columnTitle">{lang}wcf.moderation.title{/lang}</th>
+ <th class="columnText columnAssignedUserID{if $sortField == 'assignedUsername'} active {@$sortOrder}{/if}"><a href="{link controller='ModerationList'}definitionID={@$definitionID}&assignedUserID={@$assignedUserID}&status={@$status}&pageNo={@$pageNo}&sortField=assignedUsername&sortOrder={if $sortField == 'assignedUsername' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.moderation.assignedUser{/lang}</a></th>
+ <th class="columnDate columnLastChangeTime{if $sortField == 'lastChangeTime'} active {@$sortOrder}{/if}"><a href="{link controller='ModerationList'}definitionID={@$definitionID}&assignedUserID={@$assignedUserID}&status={@$status}&pageNo={@$pageNo}&sortField=lastChangeTime&sortOrder={if $sortField == 'lastChangeTime' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.moderation.lastChangeTime{/lang}</a></th>
+
+ {event name='columnHeads'}
+ </tr>
+ </thead>
+
+ <tbody>
+ {foreach from=$objects item=entry}
+ <tr>
+ <td class="columnID">{#$entry->queueID}</td>
+ <td class="columnText columnSubject">
+ <h3>
+ <span class="badge label">{lang}wcf.moderation.type.{@$definitionNames[$entry->objectTypeID]}{/lang}</span>
+ <a href="{$entry->getLink()}" class="messageGroupLink">{$entry->getTitle()}</a>
+ </h3>
+ <small>{if $entry->userID}<a href="{link controller='User' id=$entry->userID}{/link}" class="userLink" data-user-id="{@$entry->userID}">{$entry->username}</a>{else}{lang}wcf.user.guest{/lang}{/if} - {@$entry->time|time}</small>
+ </td>
+ <td class="columnText columnAssignedUserID">{if $entry->assignedUserID}<a href="{link controller='User' id=$entry->assignedUserID}{/link}" class="userLink" data-user-id="{@$entry->assignedUserID}">{$entry->assignedUsername}</a>{/if}</td>
+ <td class="columnDate columnLastChangeTime">{if $entry->lastChangeTime}{@$entry->lastChangeTime|time}{/if}</td>
+
+ {event name='columns'}
+ </tr>
+ {/foreach}
+ </tbody>
+ </table>
+ </div>
+
+ <div class="contentNavigation">
+ {@$pagesLinks}
+
+ {hascontent}
+ <nav>
+ <ul>
+ {content}
+ {event name='contentNavigationButtonsBottom'}
+ {/content}
+ </ul>
+ </nav>
+ {/hascontent}
+ </div>
+{else}
+ <p class="info">{lang}wcf.moderation.noItems{/lang}</p>
+{/if}
+
+{include file='footer'}
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+{foreach from=$queues item=queue}
+ <li>
+ <a href="{@$queue->getLink()}" class="box24">
+ <div class="framed">
+ {@$queue->getUserProfile()->getAvatar()->getImageTag(24)}
+ </div>
+ <div>
+ <h3>{$queue->getAffectedObject()->getTitle()}</h3>
+ <small>{$queue->getAffectedObject()->getUsername()} - {@$queue->getAffectedObject()->getTime()|time}</small>
+ </div>
+ </a>
+ </li>
+{/foreach}
\ No newline at end of file
--- /dev/null
+{include file='documentHeader'}
+
+<head>
+ <title>{lang}wcf.moderation.report{/lang} - {PAGE_TITLE|language}</title>
+
+ {include file='headInclude'}
+
+ <script type="text/javascript" src="{@$__wcf->getPath()}js/WCF.Moderation{if !ENABLE_DEBUG_MODE}.min{/if}.js"></script>
+ <script type="text/javascript">
+ //<![CDATA[
+ $(function() {
+ new WCF.Moderation.Report.Management({@$queue->queueID}, '{link controller='ModerationList'}{/link}');
+
+ WCF.Language.addObject({
+ 'wcf.moderation.report.removeContent.confirmMessage': '{lang}wcf.moderation.report.removeContent.confirmMessage{/lang}',
+ 'wcf.moderation.report.removeReport.confirmMessage': '{lang}wcf.moderation.report.removeReport.confirmMessage{/lang}'
+ });
+ });
+ //]]>
+ </script>
+</head>
+
+<body id="tpl{$templateName|ucfirst}">
+
+{include file='header' sidebarOrientation='left'}
+
+<header class="boxHeadline">
+ <h1>{lang}wcf.moderation.report{/lang}</h1>
+</header>
+
+{include file='userNotice'}
+
+<div class="contentNavigation">
+ <nav>
+ <ul>
+ <li><a href="{link controller='ModerationList'}{/link}" class="button"><span class="icon icon16 icon-list"></span> <span>{lang}wcf.moderation.moderation{/lang}</span></a></li>
+
+ {event name='contentNavigationButtonsTop'}
+ </ul>
+ </nav>
+</div>
+
+<form method="post" action="{link controller='ModerationReport' id=$queue->queueID}{/link}" class="container containerPadding marginTop">
+ <fieldset>
+ <legend>{lang}wcf.moderation.report.details{/lang}</legend>
+
+ <dl>
+ <dt>{lang}wcf.global.objectID{/lang}</dt>
+ <dd>{#$queue->queueID}</dd>
+ </dl>
+ <dl>
+ <dt>{lang}wcf.moderation.report.reportedBy{/lang}</dt>
+ <dd>{if $queue->userID}<a href="{link controller='User' id=$queue->userID}{/link}" class="userLink" data-user-id="{@$queue->userID}">{$queue->username}</a>{else}{lang}wcf.user.guest{/lang}{/if} ({@$queue->time|time})</dd>
+ </dl>
+ {if $queue->lastChangeTime}
+ <dl>
+ <dt>{lang}wcf.moderation.lastChangeTime{/lang}</dt>
+ <dd>{@$queue->lastChangeTime|time}</dd>
+ </dl>
+ {/if}
+ <dl>
+ <dt>{lang}wcf.moderation.assignedUser{/lang}</dt>
+ <dd>
+ <ul>
+ {if $assignedUserID && ($assignedUserID != $__wcf->getUser()->userID)}
+ <li><label><input type="radio" name="assignedUserID" value="{@$assignedUserID}" checked="checked" /> {$queue->assignedUsername}</label></li>
+ {/if}
+ <li><label><input type="radio" name="assignedUserID" value="{@$__wcf->getUser()->userID}"{if $assignedUserID == $__wcf->getUser()->userID} checked="checked"{/if} /> {$__wcf->getUser()->username}</label></li>
+ <li><label><input type="radio" name="assignedUserID" value="0"{if !$assignedUserID} checked="checked"{/if} /> {lang}wcf.moderation.assignedUser.nobody{/lang}</label></li>
+ </ul>
+ </dd>
+ </dl>
+ {if $queue->assignedUser}
+ <dl>
+
+ <dd><a href="{link controller='User' id=$assignedUserID}{/link}" class="userLink" data-user-id="{@$assignedUserID}">{$queue->assignedUsername}</a></dd>
+ </dl>
+ {/if}
+ <dl>
+ <dt>{lang}wcf.moderation.report.reason{/lang}</dt>
+ <dd>{@$queue->getFormattedMessage()}</dd>
+ </dl>
+ <dl>
+ <dt><label for="comment">{lang}wcf.moderation.comment{/lang}</label></dt>
+ <dd><textarea id="comment" name="comment" rows="4" cols="40">{$comment}</textarea></dd>
+ </dl>
+
+ {event name='detailsFields'}
+
+ <div class="formSubmit">
+ <input type="submit" value="{lang}wcf.global.button.submit{/lang}" />
+ </div>
+ </fieldset>
+
+ {event name='fieldsets'}
+</form>
+
+<header class="boxHeadline boxSubHeadline">
+ <h2>{lang}wcf.moderation.report.reportedContent{/lang}</h2>
+</header>
+
+<div class="marginTop">
+ {@$reportedContent}
+</div>
+
+<div class="contentNavigation">
+ <nav>
+ <ul>
+ <li class="jsOnly"><button id="removeContent">{lang}wcf.moderation.report.removeContent{/lang}</button></li>
+ <li class="jsOnly"><button id="removeReport">{lang}wcf.moderation.report.removeReport{/lang}</button></li>
+ <li><a href="{link controller='ModerationList'}{/link}" class="button"><span class="icon icon16 icon-list"></span> <span>{lang}wcf.moderation.moderation{/lang}</span></a></li>
+
+ {event name='contentNavigationButtonsBottom'}
+ </ul>
+ </nav>
+</div>
+
+{include file='footer'}
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+{if $alreadyReported}
+ <p class="info">{lang}wcf.moderation.report.alreadyReported{/lang}</p>
+{else}
+ <fieldset>
+ <legend><label for="reason">{lang}wcf.moderation.report.reason{/lang}</label></legend>
+
+ <dl class="wide">
+ <dd>
+ <textarea id="reason" required="required" cols="60" rows="10" class="jsReportMessage"></textarea>
+ <small>{lang}wcf.moderation.report.reason.description{/lang}</small>
+ </dd>
+ </dl>
+
+ {event name='reasonFields'}
+ </fieldset>
+
+ {event name='fieldsets'}
+
+ <div class="formSubmit">
+ <button class="jsSubmitReport buttonPrimary" accesskey="s">{lang}wcf.global.button.submit{/lang}</button>
+ </div>
+{/if}
\ No newline at end of file
{/if}
{if !$__hideUserMenu|isset}
+ {if $__wcf->user->userID && $__wcf->session->getPermission('mod.general.canUseModeration')}
+ <li id="outstandingModeration" data-count="{#$__wcf->getModerationQueueManager()->getOutstandingModerationCount()}">
+ <a href="{link controller='ModerationList'}{/link}">
+ <span class="icon icon16 icon-warning-sign"></span>
+ <span>{lang}wcf.moderation.moderation{/lang}</span>
+ {if $__wcf->getModerationQueueManager()->getOutstandingModerationCount()}<span class="badge badgeInverse">{#$__wcf->getModerationQueueManager()->getOutstandingModerationCount()}</span>{/if}
+ </a>
+ <script type="text/javascript" src="{@$__wcf->getPath()}js/WCF.Moderation{if !ENABLE_DEBUG_MODE}.min{/if}.js"></script>
+ <script type="text/javascript">
+ //<![CDATA[
+ $(function() {
+ WCF.Language.addObject({
+ 'wcf.moderation.noMoreItems': '{lang}wcf.moderation.noMoreItems{/lang}',
+ 'wcf.moderation.showAll': '{lang}wcf.moderation.showAll{/lang}'
+ });
+
+ new WCF.Moderation.UserPanel('{link controller='ModerationList'}{/link}');
+ });
+ //]]>
+ </script>
+ </li>
+ {/if}
+
{event name='menuItems'}
{/if}
png]]></defaultvalue>
</option>
<!-- /user.profile -->
+
+ <option name="mod.general.canUseModeration">
+ <categoryname>mod.general</categoryname>
+ <optiontype>boolean</optiontype>
+ <defaultvalue>0</defaultvalue>
+ <admindefaultvalue>1</admindefaultvalue>
+ </option>
</options>
</import>
</data>
--- /dev/null
+/**
+ * Namespace for moderation related classes.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2012 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ */
+WCF.Moderation = { };
+
+/**
+ * Moderation queue management.
+ *
+ * @param integer queueID
+ * @param string redirectURL
+ */
+WCF.Moderation.Management = Class.extend({
+ /**
+ * button selector
+ * @var string
+ */
+ _buttonSelector: '',
+
+ /**
+ * action class name
+ * @var string
+ */
+ _className: '',
+
+ /**
+ * language item pattern
+ * @var string
+ */
+ _languageItem: '',
+
+ /**
+ * action proxy
+ * @var WCF.Action.Proxy
+ */
+ _proxy: null,
+
+ /**
+ * queue id
+ * @var integer
+ */
+ _queueID: 0,
+
+ /**
+ * redirect URL
+ * @var string
+ */
+ _redirectURL: '',
+
+ /**
+ * Initializes the moderation report management.
+ *
+ * @param integer queueID
+ * @param string redirectURL
+ * @param string languageItem
+ */
+ init: function(queueID, redirectURL, languageItem) {
+ if (!this._buttonSelector) {
+ console.debug("[WCF.Moderation.Management] Missing button selector, aborting.");
+ return;
+ }
+ else if (!this._className) {
+ console.debug("[WCF.Moderation.Management] Missing class name, aborting.");
+ return;
+ }
+
+ this._queueID = queueID;
+ this._redirectURL = redirectURL;
+ this._languageItem = languageItem;
+
+ this._proxy = new WCF.Action.Proxy({
+ success: $.proxy(this._success, this)
+ });
+
+ $(this._buttonSelector).click($.proxy(this._click, this));
+ },
+
+ /**
+ * Handles clicks on the action buttons.
+ *
+ * @param object event
+ */
+ _click: function(event) {
+ var $actionName = $(event.currentTarget).wcfIdentify();
+
+ WCF.System.Confirmation.show(WCF.Language.get(this._languageItem.replace(/{actionName}/, $actionName)), $.proxy(function(action) {
+ if (action === 'confirm') {
+ this._proxy.setOption('data', {
+ actionName: $actionName,
+ className: this._className,
+ objectIDs: [ this._queueID ]
+ });
+ this._proxy.sendRequest();
+
+ $(this._buttonSelector).disable();
+ }
+ }, this));
+ },
+
+ /**
+ * Handles successful AJAX requests.
+ *
+ * @param object data
+ * @param string textStatus
+ * @param jQuery jqXHR
+ */
+ _success: function(data, textStatus, jqXHR) {
+ var $notification = new WCF.System.Notification(WCF.Language.get('wcf.global.success'));
+ var self = this;
+ $notification.show(function() {
+ window.location = self._redirectURL;
+ });
+ }
+});
+
+/**
+ * Namespace for activation related classes.
+ */
+WCF.Moderation.Activation = { };
+
+/**
+ * Manages disabled content within moderation.
+ *
+ * @see WCF.Moderation.Management
+ */
+WCF.Moderation.Activation.Management = WCF.Moderation.Management.extend({
+ /**
+ * @see WCF.Moderation.Management.init()
+ */
+ init: function(queueID, redirectURL) {
+ this._buttonSelector = '#enableContent, #removeContent';
+ this._className = 'wcf\\data\\moderation\\queue\\ModerationQueueActivationAction';
+
+ this._super(queueID, redirectURL, 'wcf.moderation.activation.{actionName}.confirmMessage');
+ }
+});
+
+/**
+ * Namespace for report related classes.
+ */
+WCF.Moderation.Report = { };
+
+/**
+ * Handles content report.
+ *
+ * @param string objectType
+ * @param string buttonSelector
+ */
+WCF.Moderation.Report.Content = Class.extend({
+ /**
+ * list of buttons
+ * @var object
+ */
+ _buttons: { },
+
+ /**
+ * button selector
+ * @var string
+ */
+ _buttonSelector: '',
+
+ /**
+ * dialog overlay
+ * @var jQuery
+ */
+ _dialog: null,
+
+ /**
+ * notification object
+ * @var WCF.System.Notification
+ */
+ _notification: null,
+
+ /**
+ * object id
+ * @var integer
+ */
+ _objectID: 0,
+
+ /**
+ * object type name
+ * @var string
+ */
+ _objectType: '',
+
+ /**
+ * action proxy
+ * @var WCF.Action.Proxy
+ */
+ _proxy: null,
+
+ /**
+ * Creates a new WCF.Moderation.Report object.
+ *
+ * @param string objectType
+ * @param string buttonSelector
+ */
+ init: function(objectType, buttonSelector) {
+ this._objectType = objectType;
+ this._buttonSelector = buttonSelector;
+
+ this._buttons = { };
+ this._notification = null;
+ this._objectID = 0;
+ this._proxy = new WCF.Action.Proxy({
+ success: $.proxy(this._success, this)
+ });
+
+ this._initButtons();
+
+ WCF.DOMNodeInsertedHandler.addCallback('WCF.Moderation.Report' + this._objectType.hashCode(), $.proxy(this._initButtons, this));
+ },
+
+ /**
+ * Initializes the report feature for all matching buttons.
+ */
+ _initButtons: function() {
+ var self = this;
+ $(this._buttonSelector).each(function(index, button) {
+ var $button = $(button);
+ var $buttonID = $button.wcfIdentify();
+
+ if (!self._buttons[$buttonID]) {
+ self._buttons[$buttonID] = $button;
+ $button.click($.proxy(self._click, self));
+ }
+ });
+ },
+
+ /**
+ * Handles clicks on a report button.
+ *
+ * @param object event
+ */
+ _click: function(event) {
+ this._objectID = $(event.currentTarget).data('objectID');
+
+ this._proxy.setOption('data', {
+ actionName: 'prepareReport',
+ className: 'wcf\\data\\moderation\\queue\\ModerationQueueReportAction',
+ parameters: {
+ objectID: this._objectID,
+ objectType: this._objectType
+ }
+ });
+ this._proxy.sendRequest();
+ },
+
+ /**
+ * Handles successful AJAX requests.
+ *
+ * @param object data
+ * @param string textStatus
+ * @param jQuery jqXHR
+ */
+ _success: function(data, textStatus, jqXHR) {
+ // object has been successfully reported
+ if (data.returnValues.reported) {
+ if (this._notification === null) {
+ this._notification = new WCF.System.Notification(WCF.Language.get('wcf.moderation.report.success'));
+ }
+
+ // show success and close dialog
+ this._dialog.wcfDialog('close');
+ this._notification.show();
+ }
+ else if (data.returnValues.template) {
+ // display template
+ this._showDialog(data.returnValues.template);
+
+ if (!data.returnValues.alreadyReported) {
+ // bind event listener for buttons
+ this._dialog.find('.jsSubmitReport').click($.proxy(this._submit, this));
+ }
+ }
+ },
+
+ /**
+ * Displays the dialog overlay.
+ *
+ * @param string template
+ */
+ _showDialog: function(template) {
+ if (this._dialog === null) {
+ this._dialog = $('#moderationReport');
+ if (!this._dialog.length) {
+ this._dialog = $('<div id="moderationReport" />').hide().appendTo(document.body);
+ }
+ }
+
+ this._dialog.html(template).wcfDialog({
+ title: WCF.Language.get('wcf.moderation.report.reportContent')
+ }).wcfDialog('render');
+ },
+
+ /**
+ * Submits a report unless the textarea is empty.
+ */
+ _submit: function() {
+ var $text = this._dialog.find('.jsReportMessage').val();
+ if ($text == '') {
+ this._dialog.find('fieldset > dl').addClass('formError');
+
+ if (!this._dialog.find('.innerError').length) {
+ this._dialog.find('.jsReportMessage').after($('<small class="innerError">' + WCF.Language.get('wcf.global.form.error.empty') + "</small>"));;
+ }
+
+ return;
+ }
+
+ this._proxy.setOption('data', {
+ actionName: 'report',
+ className: 'wcf\\data\\moderation\\queue\\ModerationQueueReportAction',
+ parameters: {
+ message: $text,
+ objectID: this._objectID,
+ objectType: this._objectType
+ }
+ });
+ this._proxy.sendRequest();
+ }
+});
+
+/**
+ * Manages reported content within moderation.
+ *
+ * @see WCF.Moderation.Management
+ */
+WCF.Moderation.Report.Management = WCF.Moderation.Management.extend({
+ /**
+ * @see WCF.Moderation.Management.init()
+ */
+ init: function(queueID, redirectURL) {
+ this._buttonSelector = '#removeContent, #removeReport';
+ this._className = 'wcf\\data\\moderation\\queue\\ModerationQueueReportAction';
+
+ this._super(queueID, redirectURL, 'wcf.moderation.report.{actionName}.confirmMessage');
+ }
+});
+
+/**
+ * Provides a dropdown for user panel.
+ *
+ * @see WCF.UserPanel
+ */
+WCF.Moderation.UserPanel = WCF.UserPanel.extend({
+ /**
+ * link to show all outstanding queues
+ * @var string
+ */
+ _showAllLink: '',
+
+ /**
+ * @see WCF.UserPanel.init()
+ */
+ init: function(showAllLink) {
+ this._noItems = 'wcf.moderation.noMoreItems';
+ this._showAllLink = showAllLink;
+
+ this._super('outstandingModeration');
+ },
+
+ /**
+ * @see WCF.UserPanel._addDefaultItems()
+ */
+ _addDefaultItems: function(dropdownMenu) {
+ this._addDivider(dropdownMenu);
+ $('<li><a href="' + this._showAllLink + '">' + WCF.Language.get('wcf.moderation.showAll') + '</a></li>').appendTo(dropdownMenu);
+ },
+
+ /**
+ * @see WCF.UserPanel._getParameters()
+ */
+ _getParameters: function() {
+ return {
+ actionName: 'getOutstandingQueues',
+ className: 'wcf\\data\\moderation\\queue\\ModerationQueueAction'
+ };
+ }
+});
--- /dev/null
+WCF.Moderation={};WCF.Moderation.Management=Class.extend({_buttonSelector:"",_className:"",_languageItem:"",_proxy:null,_queueID:0,_redirectURL:"",init:function(a,c,b){if(!this._buttonSelector){console.debug("[WCF.Moderation.Management] Missing button selector, aborting.");return}else{if(!this._className){console.debug("[WCF.Moderation.Management] Missing class name, aborting.");return}}this._queueID=a;this._redirectURL=c;this._languageItem=b;this._proxy=new WCF.Action.Proxy({success:$.proxy(this._success,this)});$(this._buttonSelector).click($.proxy(this._click,this))},_click:function(b){var a=$(b.currentTarget).wcfIdentify();WCF.System.Confirmation.show(WCF.Language.get(this._languageItem.replace(/{actionName}/,a)),$.proxy(function(c){if(c==="confirm"){this._proxy.setOption("data",{actionName:a,className:this._className,objectIDs:[this._queueID]});this._proxy.sendRequest();$(this._buttonSelector).disable()}},this))},_success:function(c,e,b){var d=new WCF.System.Notification(WCF.Language.get("wcf.global.success"));var a=this;d.show(function(){window.location=a._redirectURL})}});WCF.Moderation.Activation={};WCF.Moderation.Activation.Management=WCF.Moderation.Management.extend({init:function(a,b){this._buttonSelector="#enableContent, #removeContent";this._className="wcf\\data\\moderation\\queue\\ModerationQueueActivationAction";this._super(a,b,"wcf.moderation.activation.{actionName}.confirmMessage")}});WCF.Moderation.Report={};WCF.Moderation.Report.Content=Class.extend({_buttons:{},_buttonSelector:"",_dialog:null,_notification:null,_objectID:0,_objectType:"",_proxy:null,init:function(a,b){this._objectType=a;this._buttonSelector=b;this._buttons={};this._notification=null;this._objectID=0;this._proxy=new WCF.Action.Proxy({success:$.proxy(this._success,this)});this._initButtons();WCF.DOMNodeInsertedHandler.addCallback("WCF.Moderation.Report"+this._objectType.hashCode(),$.proxy(this._initButtons,this))},_initButtons:function(){var a=this;$(this._buttonSelector).each(function(c,d){var e=$(d);var b=e.wcfIdentify();if(!a._buttons[b]){a._buttons[b]=e;e.click($.proxy(a._click,a))}})},_click:function(a){this._objectID=$(a.currentTarget).data("objectID");this._proxy.setOption("data",{actionName:"prepareReport",className:"wcf\\data\\moderation\\queue\\ModerationQueueReportAction",parameters:{objectID:this._objectID,objectType:this._objectType}});this._proxy.sendRequest()},_success:function(b,c,a){if(b.returnValues.reported){if(this._notification===null){this._notification=new WCF.System.Notification(WCF.Language.get("wcf.moderation.report.success"))}this._dialog.wcfDialog("close");this._notification.show()}else{if(b.returnValues.template){this._showDialog(b.returnValues.template);if(!b.returnValues.alreadyReported){this._dialog.find(".jsSubmitReport").click($.proxy(this._submit,this))}}}},_showDialog:function(a){if(this._dialog===null){this._dialog=$("#moderationReport");if(!this._dialog.length){this._dialog=$('<div id="moderationReport" />').hide().appendTo(document.body)}}this._dialog.html(a).wcfDialog({title:WCF.Language.get("wcf.moderation.report.reportContent")}).wcfDialog("render")},_submit:function(){var a=this._dialog.find(".jsReportMessage").val();if(a==""){this._dialog.find("fieldset > dl").addClass("formError");if(!this._dialog.find(".innerError").length){this._dialog.find(".jsReportMessage").after($('<small class="innerError">'+WCF.Language.get("wcf.global.form.error.empty")+"</small>"))}return}this._proxy.setOption("data",{actionName:"report",className:"wcf\\data\\moderation\\queue\\ModerationQueueReportAction",parameters:{message:a,objectID:this._objectID,objectType:this._objectType}});this._proxy.sendRequest()}});WCF.Moderation.Report.Management=WCF.Moderation.Management.extend({init:function(a,b){this._buttonSelector="#removeContent, #removeReport";this._className="wcf\\data\\moderation\\queue\\ModerationQueueReportAction";this._super(a,b,"wcf.moderation.report.{actionName}.confirmMessage")}});WCF.Moderation.UserPanel=WCF.UserPanel.extend({_showAllLink:"",init:function(a){this._noItems="wcf.moderation.noMoreItems";this._showAllLink=a;this._super("outstandingModeration")},_addDefaultItems:function(a){this._addDivider(a);$('<li><a href="'+this._showAllLink+'">'+WCF.Language.get("wcf.moderation.showAll")+"</a></li>").appendTo(a)},_getParameters:function(){return{actionName:"getOutstandingQueues",className:"wcf\\data\\moderation\\queue\\ModerationQueueAction"}}});
\ No newline at end of file
<?php
namespace wcf\acp\form;
-use wcf\data\user\avatar\UserAvatarAction;
-
use wcf\data\user\avatar\Gravatar;
-
-use wcf\system\exception\UserInputException;
-
use wcf\data\user\avatar\UserAvatar;
-
+use wcf\data\user\avatar\UserAvatarAction;
use wcf\data\user\group\UserGroup;
use wcf\data\user\User;
use wcf\data\user\UserAction;
use wcf\form\AbstractForm;
use wcf\system\exception\IllegalLinkException;
use wcf\system\exception\PermissionDeniedException;
+use wcf\system\exception\UserInputException;
+use wcf\system\moderation\queue\ModerationQueueManager;
use wcf\system\WCF;
use wcf\util\StringUtil;
$action = new UserProfileAction(array($editor), 'updateUserOnlineMarking');
$action->executeAction();
}
+
+ // remove assignments
+ $sql = "DELETE FROM wcf".WCF_N."_moderation_queue_to_user
+ WHERE userID = ?";
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute(array($this->user->userID));
+
+ // reset moderation count
+ ModerationQueueManager::getInstance()->resetModerationCount($this->user->userID);
$this->saved();
// reset password
--- /dev/null
+<?php
+namespace wcf\data\moderation\queue;
+use wcf\data\DatabaseObject;
+use wcf\system\WCF;
+
+/**
+ * Represents a moderation queue entry.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2012 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.moderation
+ * @subpackage data.moderation.queue
+ * @category Community Framework
+ */
+class ModerationQueue extends DatabaseObject {
+ /**
+ * @see wcf\data\DatabaseObject::$databaseTableName
+ */
+ protected static $databaseTableName = 'moderation_queue';
+
+ /**
+ * @see wcf\data\DatabaseObject::$databaseIndexName
+ */
+ protected static $databaseTableIndexName = 'queueID';
+
+ // states of column 'status'
+ const STATUS_OUTSTANDING = 0;
+ const STATUS_PROCESSING = 1;
+ const STATUS_DONE = 2;
+
+ /**
+ * @see wcf\data\IStorableObject::__get()
+ */
+ public function __get($name) {
+ $value = parent::__get($name);
+
+ // treat additional data as data variables if it is an array
+ if ($value === null) {
+ if (is_array($this->data['additionalData']) && isset($this->data['additionalData'][$name])) {
+ $value = $this->data['additionalData'][$name];
+ }
+ }
+
+ return $value;
+ }
+
+ /**
+ * @see wcf\data\DatabaseObject::handleData()
+ */
+ protected function handleData($data) {
+ parent::handleData($data);
+
+ $this->data['additionalData'] = @unserialize($this->data['additionalData']);
+ if (!is_array($this->data['additionalData'])) {
+ $this->data['additionalData'] = array();
+ }
+ }
+
+ /**
+ * Returns true if current user can edit this moderation queue.
+ *
+ * @return boolean
+ */
+ public function canEdit() {
+ $sql = "SELECT isAffected
+ FROM wcf".WCF_N."_moderation_queue_to_user
+ WHERE queueID = ?
+ AND userID = ?";
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute(array(
+ $this->queueID,
+ WCF::getUser()->userID
+ ));
+ $row = $statement->fetchArray();
+
+ return ($row !== false && $row['isAffected']);
+ }
+}
--- /dev/null
+<?php
+namespace wcf\data\moderation\queue;
+use wcf\data\AbstractDatabaseObjectAction;
+use wcf\system\database\util\PreparedStatementConditionBuilder;
+use wcf\system\moderation\queue\ModerationQueueManager;
+use wcf\system\WCF;
+
+/**
+ * Executes moderation queue-related actions.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2013 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.moderation
+ * @subpackage data.moderation.queue
+ * @category Community Framework
+ */
+class ModerationQueueAction extends AbstractDatabaseObjectAction {
+ /**
+ * @see wcf\data\AbstractDatabaseObjectAction::$className
+ */
+ protected $className = 'wcf\data\moderation\queue\ModerationQueueEditor';
+
+ /**
+ * @see wcf\data\AbstractDatabaseObjectAction::create()
+ */
+ public function create() {
+ if (!isset($this->parameters['data']['lastChangeTime'])) {
+ $this->parameters['data']['lastChangeTime'] = TIME_NOW;
+ }
+
+ return parent::create();
+ }
+
+ /**
+ * @see wcf\data\AbstractDatabaseObjectAction::update()
+ */
+ public function update() {
+ if (!isset($this->parameters['data']['lastChangeTime'])) {
+ $this->parameters['data']['lastChangeTime'] = TIME_NOW;
+ }
+
+ parent::update();
+ }
+
+ /**
+ * Marks a list of objects as done.
+ */
+ public function markAsDone() {
+ if (empty($this->objects)) {
+ $this->readObjects();
+ }
+
+ $queueIDs = array();
+ foreach ($this->objects as $queue) {
+ $queueIDs[] = $queue->queueID;
+ }
+
+ $conditions = new PreparedStatementConditionBuilder();
+ $conditions->add("queueID IN (?)", array($queueIDs));
+
+ $sql = "UPDATE wcf".WCF_N."_moderation_queue
+ SET status = ".ModerationQueue::STATUS_DONE."
+ ".$conditions;
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute($conditions->getParameters());
+
+ // reset number of active moderation queue items
+ ModerationQueueManager::getInstance()->resetModerationCount();
+ }
+
+ /**
+ * Validates parameters to fetch a list of outstanding queues.
+ */
+ public function validateGetOutstandingQueues() {
+ WCF::getSession()->checkPermissions(array('mod.general.canUseModeration'));
+ }
+
+ /**
+ * Returns a list of outstanding queues.
+ *
+ * @return array<string>
+ */
+ public function getOutstandingQueues() {
+ $objectTypeIDs = ModerationQueueManager::getInstance()->getObjectTypeIDs(array_keys(ModerationQueueManager::getInstance()->getDefinitions()));
+
+ $queueList = new ViewableModerationQueueList();
+ $queueList->getConditionBuilder()->add("moderation_queue.objectTypeID IN (?)", array($objectTypeIDs));
+ $queueList->getConditionBuilder()->add("moderation_queue.status <> ?", array(ModerationQueue::STATUS_DONE));
+ $queueList->sqlLimit = 5;
+ $queueList->loadUserProfiles = true;
+ $queueList->readObjects();
+
+ WCF::getTPL()->assign(array(
+ 'queues' => $queueList
+ ));
+
+ return array(
+ 'template' => WCF::getTPL()->fetch('moderationQueueList'),
+ 'totalCount' => ModerationQueueManager::getInstance()->getOutstandingModerationCount()
+ );
+ }
+}
--- /dev/null
+<?php
+namespace wcf\data\moderation\queue;
+use wcf\system\exception\PermissionDeniedException;
+use wcf\system\exception\UserInputException;
+use wcf\system\moderation\queue\ModerationQueueActivationManager;
+use wcf\util\StringUtil;
+
+/**
+ * Executes actions for reports.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2013 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.moderation
+ * @subpackage data.moderation.queue
+ * @category Community Framework
+ */
+class ModerationQueueActivationAction extends ModerationQueueAction {
+ /**
+ * @see wcf\data\AbstractDatabaseObjectAction::$allowGuestAccess
+ */
+ protected $allowGuestAccess = array('enableContent', 'removeContent');
+
+ /**
+ * moderation queue editor object
+ * @var wcf\data\moderation\queue\ModerationQueueEditor
+ */
+ public $queue = null;
+
+ /**
+ * Validates parameters to enable content.
+ */
+ public function validateEnableContent() {
+ $this->queue = $this->getSingleObject();
+ if (!$this->queue->canEdit()) {
+ throw new PermissionDeniedException();
+ }
+ }
+
+ /**
+ * Enables content.
+ */
+ public function enableContent() {
+ // enable content
+ ModerationQueueActivationManager::getInstance()->enableContent($this->queue->getDecoratedObject());
+
+ $this->queue->markAsDone();
+ }
+
+ /**
+ * Validates parameters to delete reported content.
+ */
+ public function validateRemoveContent() {
+ $this->readString('message', true);
+ $this->validateEnableContent();
+ }
+
+ /**
+ * Deletes reported content.
+ */
+ public function removeContent() {
+ // mark content as deleted
+ ModerationQueueActivationManager::getInstance()->removeContent($this->queue->getDecoratedObject(), $this->parameters['message']);
+
+ $this->queue->markAsDone();
+ }
+}
--- /dev/null
+<?php
+namespace wcf\data\moderation\queue;
+use wcf\data\DatabaseObjectEditor;
+use wcf\system\moderation\queue\ModerationQueueManager;
+
+/**
+ * Extends the moderation queue object with functions to create, update and delete queue entries.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2012 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.moderation
+ * @subpackage data.moderation.queue
+ * @category Community Framework
+ */
+class ModerationQueueEditor extends DatabaseObjectEditor {
+ /**
+ * @see wcf\data\DatabaseObjectEditor::$baseClass
+ */
+ protected static $baseClass = 'wcf\data\moderation\queue\ModerationQueue';
+
+ /**
+ * Marks this entry as done.
+ */
+ public function markAsDone() {
+ $this->update(array('status' => ModerationQueue::STATUS_DONE));
+
+ // reset moderation count
+ ModerationQueueManager::getInstance()->resetModerationCount();
+ }
+
+ /**
+ * Marks this entry as in progress.
+ */
+ public function markAsInProgress() {
+ $this->update(array('status' => ModerationQueue::STATUS_PROCESSING));
+ }
+}
--- /dev/null
+<?php
+namespace wcf\data\moderation\queue;
+use wcf\data\DatabaseObjectList;
+
+/**
+ * Represents a list of moderation queue entries.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2012 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.moderation
+ * @subpackage data.moderation.queue
+ * @category Community Framework
+ */
+class ModerationQueueList extends DatabaseObjectList {
+ /**
+ * @see wcf\data\DatabaseObjectList::$className
+ */
+ public $className = 'wcf\data\moderation\queue\ModerationQueue';
+}
--- /dev/null
+<?php
+namespace wcf\data\moderation\queue;
+use wcf\system\exception\PermissionDeniedException;
+use wcf\system\exception\UserInputException;
+use wcf\system\moderation\queue\ModerationQueueReportManager;
+use wcf\system\WCF;
+use wcf\util\StringUtil;
+
+/**
+ * Executes actions for reports.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2012 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.moderation
+ * @subpackage data.moderation.queue
+ * @category Community Framework
+ */
+class ModerationQueueReportAction extends ModerationQueueAction {
+ /**
+ * @see wcf\data\AbstractDatabaseObjectAction::$allowGuestAccess
+ */
+ protected $allowGuestAccess = array('prepareReport', 'removeContent', 'removeReport', 'report');
+
+ /**
+ * moderation queue editor object
+ * @var wcf\data\moderation\queue\ModerationQueueEditor
+ */
+ public $queue = null;
+
+ /**
+ * Validates parameters to delete reported content.
+ */
+ public function validateRemoveContent() {
+ $this->validateRemoveReport();
+
+ $this->parameters['message'] = (isset($this->parameters['message']) ? StringUtil::trim($this->parameters['message']) : '');
+ }
+
+ /**
+ * Deletes reported content.
+ */
+ public function removeContent() {
+ // mark content as deleted
+ ModerationQueueReportManager::getInstance()->removeContent($this->queue->getDecoratedObject(), $this->parameters['message']);
+
+ $this->queue->markAsDone();
+ }
+
+ /**
+ * Validates parameters to mark this report as done.
+ */
+ public function validateRemoveReport() {
+ $this->queue = $this->getSingleObject();
+ if (!$this->queue->canEdit()) {
+ throw new PermissionDeniedException();
+ }
+ }
+
+ /**
+ * Removes this report by marking it as done without further processing.
+ */
+ public function removeReport() {
+ $this->queue->markAsDone();
+ }
+
+ /**
+ * Validates parameters to prepare a report.
+ */
+ public function validatePrepareReport() {
+ $this->readInteger('objectID');
+ $this->readString('objectType');
+
+ if (!ModerationQueueReportManager::getInstance()->isValid($this->parameters['objectType'])) {
+ throw new UserInputException('objectType');
+ }
+
+ // validate the combination of object type and object id
+ if (!ModerationQueueReportManager::getInstance()->isValid($this->parameters['objectType'], $this->parameters['objectID'])) {
+ throw new UserInputException('objectID');
+ }
+
+ // validate if user may read the content (prevent information disclosure by reporting random ids)
+ if (!ModerationQueueReportManager::getInstance()->canReport($this->parameters['objectType'], $this->parameters['objectID'])) {
+ throw new PermissionDeniedException();
+ }
+ }
+
+ /**
+ * Prepares a report.
+ */
+ public function prepareReport() {
+ // content was already reported
+ $alreadyReported = (ModerationQueueReportManager::getInstance()->isAlreadyReported($this->parameters['objectType'], $this->parameters['objectID'])) ? 1 : 0;
+
+ WCF::getTPL()->assign(array(
+ 'alreadyReported' => $alreadyReported,
+ 'object' => ModerationQueueReportManager::getInstance()->getReportedObject($this->parameters['objectType'], $this->parameters['objectID'])
+ ));
+
+ return array(
+ 'alreadyReported' => $alreadyReported,
+ 'template' => WCF::getTPL()->fetch('moderationReportDialog')
+ );
+ }
+
+ /**
+ * Validates parameters for reporting.
+ */
+ public function validateReport() {
+ $this->readString('message');
+
+ $this->validatePrepareReport();
+ }
+
+ /**
+ * Reports an item.
+ */
+ public function report() {
+ // if the specified content was already reported, e.g. a different user reported this
+ // item meanwhile, silently ignore it. Just display a success and the user is happy :)
+ if (!ModerationQueueReportManager::getInstance()->isAlreadyReported($this->parameters['objectType'], $this->parameters['objectID'])) {
+ ModerationQueueReportManager::getInstance()->addReport(
+ $this->parameters['objectType'],
+ $this->parameters['objectID'],
+ $this->parameters['message']
+ );
+ }
+
+ return array(
+ 'reported' => 1
+ );
+ }
+}
--- /dev/null
+<?php
+namespace wcf\data\moderation\queue;
+use wcf\data\user\UserProfile;
+use wcf\data\DatabaseObjectDecorator;
+use wcf\data\IUserContent;
+use wcf\system\moderation\queue\ModerationQueueManager;
+
+/**
+ * Represents a viewable moderation queue entry.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2013 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.moderation
+ * @subpackage data.moderation.queue
+ * @category Community Framework
+ */
+class ViewableModerationQueue extends DatabaseObjectDecorator {
+ /**
+ * @see wcf\data\DatabaseObject::$baseClass
+ */
+ protected static $baseClass = 'wcf\data\moderation\queue\ModerationQueue';
+
+ /**
+ * affected object
+ * @var wcf\data\IUserContent
+ */
+ protected $affectedObject = null;
+
+ /**
+ * true, if associated object was deleted
+ * @var boolean
+ */
+ protected $isOrphaned = false;
+
+ /**
+ * user profile object
+ * @var wcf\data\user\UserProfile
+ */
+ protected $userProfile = null;
+
+ /**
+ * Sets link for viewing/editing.
+ *
+ * @param wcf\data\IUserContent $object
+ */
+ public function setAffectedObject(IUserContent $object) {
+ $this->affectedObject = $object;
+ }
+
+ /**
+ * Returns the link for viewing/editing this object.
+ *
+ * @return string
+ */
+ public function getLink() {
+ return ModerationQueueManager::getInstance()->getLink($this->objectTypeID, $this->queueID);
+ }
+
+ /**
+ * Returns the title for this entry.
+ *
+ * @return string
+ */
+ public function getTitle() {
+ return ($this->affectedObject === null ? '' : $this->affectedObject->getTitle());
+ }
+
+ /**
+ * Returns affected object.
+ *
+ * @return wcf\data\IUserContent
+ */
+ public function getAffectedObject() {
+ return $this->affectedObject;
+ }
+
+ /**
+ * Sets associated user profile object.
+ *
+ * @param wcf\data\user\UserProfile $userProfile
+ */
+ public function setUserProfile(UserProfile $userProfile) {
+ if ($this->affectedObject !== null && ($userProfile->userID == $this->affectedObject->getUserID())) {
+ $this->userProfile = $userProfile;
+ }
+ }
+
+ /**
+ * Returns associated user profile object.
+ *
+ * @return wcf\data\user\UserProfile
+ */
+ public function getUserProfile() {
+ if ($this->affectedObject !== null && $this->userProfile === null) {
+ $this->userProfile = UserProfile::getUserProfile($this->affectedObject->getUserID());
+ }
+
+ return $this->userProfile;
+ }
+
+ /**
+ * Returns true if associated object was removed.
+ *
+ * @return boolean
+ */
+ public function isOrphaned() {
+ return $this->isOrphaned;
+ }
+
+ /**
+ * Marks associated objects as removed.
+ */
+ public function setIsOrphaned() {
+ $this->isOrphaned = true;
+ }
+
+ /**
+ * @see wcf\data\moderation\queue\ViewableModerationQueue::getTitle()
+ */
+ public function __toString() {
+ return $this->getTitle();
+ }
+
+ /**
+ * Returns a viewable moderation queue entry.
+ *
+ * @param integer $queueID
+ * @return wcf\data\moderation\queue\ViewableModerationQueue
+ */
+ public static function getViewableModerationQueue($queueID) {
+ $queueList = new ViewableModerationQueueList();
+ $queueList->getConditionBuilder()->add("moderation_queue.queueID = ?", array($queueID));
+ $queueList->sqlLimit = 1;
+ $queueList->readObjects();
+ $queues = $queueList->getObjects();
+
+ return (isset($queues[$queueID]) ? $queues[$queueID] : null);
+ }
+
+ /**
+ * Returns formatted message text.
+ *
+ * @return string
+ */
+ public function getFormattedMessage() {
+ return nl2br(htmlspecialchars($this->message));
+ }
+}
--- /dev/null
+<?php
+namespace wcf\data\moderation\queue;
+use wcf\data\user\UserProfile;
+use wcf\system\moderation\queue\ModerationQueueManager;
+use wcf\system\WCF;
+
+/**
+ * Represents a viewable list of moderation queue entries.
+ *
+ * WARNING: This database object list uses the moderation_queue_to_user table as primary
+ * table and uses a full join for moderation_queue, otherwise the LEFT JOIN
+ * would not work (MySQL is retarded).
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2013 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.moderation
+ * @subpackage data.moderation.queue
+ * @category Community Framework
+ */
+class ViewableModerationQueueList extends ModerationQueueList {
+ /**
+ * true, if objects should be populated with associated user profiles
+ * @var boolean
+ */
+ public $loadUserProfiles = false;
+
+ /**
+ * @see wcf\data\DatabaseObjectList::$useQualifiedShorthand
+ */
+ public $useQualifiedShorthand = false;
+
+ /**
+ * @see wcf\data\DatabaseObjectList::__construct()
+ */
+ public function __construct() {
+ parent::__construct();
+
+ $this->sqlSelects = "moderation_queue.*, assigned_user.username AS assignedUsername, user_table.username";
+ $this->sqlConditionJoins = ", wcf".WCF_N."_moderation_queue moderation_queue";
+ $this->sqlJoins = ", wcf".WCF_N."_moderation_queue moderation_queue";
+ $this->sqlJoins .= " LEFT JOIN wcf".WCF_N."_user assigned_user ON (assigned_user.userID = moderation_queue.assignedUserID)";
+ $this->sqlJoins .= " LEFT JOIN wcf".WCF_N."_user user_table ON (user_table.userID = moderation_queue.userID)";
+ $this->getConditionBuilder()->add("moderation_queue_to_user.queueID = moderation_queue.queueID");
+ $this->getConditionBuilder()->add("moderation_queue_to_user.userID = ?", array(WCF::getUser()->userID));
+ $this->getConditionBuilder()->add("moderation_queue_to_user.isAffected = ?", array(1));
+ }
+
+ /**
+ * @see wcf\data\DatabaseObjectList::readObjects()
+ */
+ public function readObjects() {
+ parent::readObjects();
+
+ if (!empty($this->objects)) {
+ $objects = array();
+ foreach ($this->objects as &$object) {
+ $object = new ViewableModerationQueue($object);
+
+ if (!isset($objects[$object->objectTypeID])) {
+ $objects[$object->objectTypeID] = array();
+ }
+
+ $objects[$object->objectTypeID][] = $object;
+ }
+ unset($object);
+
+ foreach ($objects as $objectTypeID => $queueItems) {
+ ModerationQueueManager::getInstance()->populate($objectTypeID, $queueItems);
+ }
+
+ // check for non-existant items
+ $queueIDs = array();
+ foreach ($this->objects as $index => $object) {
+ if ($object->isOrphaned()) {
+ $queueIDs[] = $object->queueID;
+ unset($this->objects[$index]);
+ }
+ }
+
+ // remove orphaned queues
+ if (!empty($queueIDs)) {
+ $this->indexToObject = array_keys($this->objects);
+
+ ModerationQueueManager::getInstance()->removeOrphans($queueIDs);
+ }
+
+ if ($this->loadUserProfiles) {
+ $userIDs = array();
+ foreach ($this->objects as $object) {
+ $userIDs[] = $object->getAffectedObject()->getUserID();
+ }
+
+ $userProfiles = UserProfile::getUserProfiles($userIDs);
+ foreach ($this->objects as $object) {
+ if (isset($userProfiles[$object->getAffectedObject()->getUserID()])) {
+ $object->setUserProfile($userProfiles[$object->getAffectedObject()->getUserID()]);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the name of the database table.
+ *
+ * @return string
+ */
+ public function getDatabaseTableName() {
+ return parent::getDatabaseTableName() . '_to_user';
+ }
+
+ /**
+ * Returns the name of the database table alias.
+ *
+ * @return string
+ */
+ public function getDatabaseTableAlias() {
+ return parent::getDatabaseTableAlias() . '_to_user';
+ }
+}
--- /dev/null
+<?php
+namespace wcf\form;
+use wcf\data\moderation\queue\ModerationQueue;
+use wcf\data\moderation\queue\ModerationQueueAction;
+use wcf\data\moderation\queue\ViewableModerationQueue;
+use wcf\system\breadcrumb\Breadcrumb;
+use wcf\system\event\EventHandler;
+use wcf\system\exception\IllegalLinkException;
+use wcf\system\exception\PermissionDeniedException;
+use wcf\system\request\LinkHandler;
+use wcf\system\WCF;
+use wcf\util\StringUtil;
+
+/**
+ * Provides an abstract form for moderation queue processing.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2013 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.moderation
+ * @subpackage form
+ * @category Community Framework
+ */
+abstract class AbstractModerationForm extends AbstractForm {
+ /**
+ * assigned user id
+ * @var integer
+ */
+ public $assignedUserID = 0;
+
+ /**
+ * comment
+ * @var string
+ */
+ public $comment = '';
+
+ /**
+ * data used for moderation queue update
+ * @var array
+ */
+ public $data = array();
+
+ /**
+ * @see wcf\page\AbstractPage::$loginRequired
+ */
+ public $loginRequired = true;
+
+ /**
+ * moderation queue object
+ * @var wcf\data\moderation\queue\ViewableModerationQueue
+ */
+ public $queue = null;
+
+ /**
+ * queue id
+ * @var integer
+ */
+ public $queueID = 0;
+
+ /**
+ * @see wcf\page\IPage::readParameters()
+ */
+ public function readParameters() {
+ parent::readParameters();
+
+ if (isset($_REQUEST['id'])) $this->queueID = intval($_REQUEST['id']);
+ $this->queue = ViewableModerationQueue::getViewableModerationQueue($this->queueID);
+ if (!$this->queue === null) {
+ throw new IllegalLinkException();
+ }
+
+ if (!$this->queue->canEdit()) {
+ throw new PermissionDeniedException();
+ }
+ }
+
+ /**
+ * @see wcf\form\IForm::readFormParameters()
+ */
+ public function readFormParameters() {
+ parent::readFormParameters();
+
+ if (isset($_POST['comment'])) $this->comment = StringUtil::trim($_POST['comment']);
+
+ // verify assigned user id
+ if (isset($_POST['assignedUserID'])) {
+ $this->assignedUserID = intval($_POST['assignedUserID']);
+ if ($this->assignedUserID) {
+ if ($this->assignedUserID != WCF::getUser()->userID && $this->assignedUserID != $this->queue->assignedUserID) {
+ // user id is either faked or changed during viewing, use database value instead
+ $this->assignedUserID = $this->queue->assignedUserID;
+ }
+ }
+ }
+ }
+
+ /**
+ * @see wcf\page\IPage::readData()
+ */
+ public function readData() {
+ parent::readData();
+
+ if (empty($_POST)) {
+ $this->assignedUserID = $this->queue->assignedUserID;
+ $this->comment = $this->queue->comment;
+ }
+
+ WCF::getBreadcrumbs()->add(new Breadcrumb(
+ WCF::getLanguage()->get('wcf.moderation.moderation'),
+ LinkHandler::getInstance()->getLink('ModerationList')
+ ));
+ }
+
+ /**
+ * @see wcf\page\IPage::assignVariables()
+ */
+ public function assignVariables() {
+ parent::assignVariables();
+
+ WCF::getTPL()->assign(array(
+ 'assignedUserID' => $this->assignedUserID,
+ 'comment' => $this->comment,
+ 'queue' => $this->queue
+ ));
+ }
+
+ /**
+ * @see wcf\form\IForm::save()
+ */
+ public function save() {
+ parent::save();
+
+ $this->data = array(
+ 'assignedUserID' => ($this->assignedUserID ?: null),
+ 'comment' => $this->comment
+ );
+ if ($this->assignedUserID) {
+ // queue item is being processed
+ if ($this->assignedUserID != $this->queue->assignedUserID) {
+ $this->data['status'] = ModerationQueue::STATUS_PROCESSING;
+ }
+ }
+ else {
+ // queue is no longer processed, mark as outstanding
+ if ($this->queue->assignedUserID) {
+ $this->data['status'] = ModerationQueue::STATUS_OUTSTANDING;
+ }
+ }
+
+ $this->prepareSave();
+ $this->objectAction = new ModerationQueueAction(array($this->queue->getDecoratedObject()), 'update', array('data' => $this->data));
+ $this->objectAction->executeAction();
+
+ // call saved event
+ $this->saved();
+
+ // reload queue to update assignment
+ if ($this->assignedUserID != $this->queue->assignedUserID) {
+ $this->queue = ViewableModerationQueue::getViewableModerationQueue($this->queue->queueID);
+ }
+ }
+
+ /**
+ * Prepares update of moderation queue item.
+ */
+ protected function prepareSave() {
+ EventHandler::getInstance()->fireAction($this, 'prepareSave');
+ }
+}
--- /dev/null
+<?php
+namespace wcf\form;
+use wcf\system\moderation\queue\ModerationQueueActivationManager;
+use wcf\system\WCF;
+
+/**
+ * Shows the moderation activation form.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2012 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.moderation
+ * @subpackage form
+ * @category Community Framework
+ */
+class ModerationActivationForm extends AbstractModerationForm {
+ /**
+ * @see wcf\page\IPage::assignVariables()
+ */
+ public function assignVariables() {
+ parent::assignVariables();
+
+ WCF::getTPL()->assign(array(
+ 'disabledContent' => ModerationQueueActivationManager::getInstance()->getDisabledContent($this->queue)
+ ));
+ }
+}
--- /dev/null
+<?php
+namespace wcf\form;
+use wcf\system\moderation\queue\ModerationQueueReportManager;
+use wcf\system\WCF;
+
+/**
+ * Shows the moderation report form.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2012 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.moderation
+ * @subpackage form
+ * @category Community Framework
+ */
+class ModerationReportForm extends AbstractModerationForm {
+ /**
+ * @see wcf\page\IPage::assignVariables()
+ */
+ public function assignVariables() {
+ parent::assignVariables();
+
+ WCF::getTPL()->assign(array(
+ 'reportedContent' => ModerationQueueReportManager::getInstance()->getReportedContent($this->queue)
+ ));
+ }
+}
--- /dev/null
+<?php
+namespace wcf\page;
+use wcf\data\moderation\queue\ModerationQueue;
+use wcf\system\exception\IllegalLinkException;
+use wcf\system\moderation\queue\ModerationQueueManager;
+use wcf\system\WCF;
+
+/**
+ * List of moderation queue entries.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2012 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.moderation
+ * @subpackage page
+ * @category Community Framework
+ */
+class ModerationListPage extends SortablePage {
+ /**
+ * assigned user id
+ * @var integer
+ */
+ public $assignedUserID = -1;
+
+ /**
+ * list of available definitions
+ * @var array<string>
+ */
+ public $availableDefinitions = array();
+
+ /**
+ * @see wcf\page\SortablePage::$defaultSortField
+ */
+ public $defaultSortField = 'lastChangeTime';
+
+ /**
+ * @see wcf\page\SortablePage::$defaultSortField
+ */
+ public $defaultSortOrder = 'DESC';
+
+ /**
+ * definiton id for filtering
+ * @var integer
+ */
+ public $definitionID = 0;
+
+ /**
+ * @see wcf\page\AbstractPage::$loginRequired
+ */
+ public $loginRequired = true;
+
+ /**
+ * @see wcf\page\AbstractPage::$neededPermissions
+ */
+ public $neededPermissions = array('mod.general.canUseModeration');
+
+ /**
+ * @see wcf\page\MultipleLinkPage::$objectListClassName
+ */
+ public $objectListClassName = 'wcf\data\moderation\queue\ViewableModerationQueueList';
+
+ /**
+ * status bit
+ * @var integer
+ */
+ public $status = -1;
+
+ /**
+ * @see wcf\page\SortablePage::$validSortFields
+ */
+ public $validSortFields = array('assignedUsername', 'lastChangeTime', 'queueID', 'time', 'username');
+
+ /**
+ * @see wcf\page\IPage::readParameters()
+ */
+ public function readParameters() {
+ parent::readParameters();
+
+ if (isset($_REQUEST['assignedUserID'])) $this->assignedUserID = intval($_REQUEST['assignedUserID']);
+ if (isset($_REQUEST['status'])) $this->status = intval($_REQUEST['status']);
+
+ $this->availableDefinitions = ModerationQueueManager::getInstance()->getDefinitions();
+ if (isset($_REQUEST['definitionID'])) {
+ $this->definitionID = intval($_REQUEST['definitionID']);
+ if ($this->definitionID && !isset($this->availableDefinitions[$this->definitionID])) {
+ throw new IllegalLinkException();
+ }
+ }
+ }
+
+ /**
+ * @see wcf\page\MultipleLinkPage::initObjectList()
+ */
+ protected function initObjectList() {
+ parent::initObjectList();
+
+ // filter by object type id
+ $objectTypeIDs = ModerationQueueManager::getInstance()->getObjectTypeIDs( ($this->definitionID ? array($this->definitionID) : array_keys($this->availableDefinitions)) );
+ if (empty($objectTypeIDs)) {
+ // no object type ids given? screw that, display nothing
+ $this->objectList->getConditionBuilder()->add("0 = 1");
+ return;
+ }
+
+ $this->objectList->getConditionBuilder()->add("moderation_queue.objectTypeID IN (?)", array($objectTypeIDs));
+
+ // filter by assigned user id
+ if ($this->assignedUserID == 0) $this->objectList->getConditionBuilder()->add("moderation_queue.assignedUserID IS NULL");
+ else if ($this->assignedUserID > 0) $this->objectList->getConditionBuilder()->add("moderation_queue.assignedUserID = ?", array($this->assignedUserID));
+
+ // filter by status
+ if ($this->status == ModerationQueue::STATUS_DONE) {
+ $this->objectList->getConditionBuilder()->add("moderation_queue.status = ?", array(ModerationQueue::STATUS_DONE));
+ }
+ else {
+ $this->objectList->getConditionBuilder()->add("moderation_queue.status IN (?)", array(array(ModerationQueue::STATUS_OUTSTANDING, ModerationQueue::STATUS_PROCESSING)));
+ }
+ }
+
+ /**
+ * @see wcf\page\IPage::assignVariables()
+ */
+ public function assignVariables() {
+ parent::assignVariables();
+
+ WCF::getTPL()->assign(array(
+ 'assignedUserID' => $this->assignedUserID,
+ 'availableDefinitions' => $this->availableDefinitions,
+ 'definitionID' => $this->definitionID,
+ 'definitionNames' => ModerationQueueManager::getInstance()->getDefinitionNamesByObjectTypeIDs(),
+ 'status' => $this->status
+ ));
+ }
+}
--- /dev/null
+<?php
+namespace wcf\system\cronjob;
+use wcf\data\cronjob\Cronjob;
+use wcf\data\moderation\queue\ModerationQueue;
+use wcf\system\database\util\PreparedStatementConditionBuilder;
+use wcf\system\moderation\queue\ModerationQueueManager;
+use wcf\system\WCF;
+
+/**
+ * Removes moderation queue entries if they're done and older than 30 days.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2012 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.moderation
+ * @subpackage system.cronjob
+ * @category Community Framework
+ */
+class ModerationQueueCronjob extends AbstractCronjob {
+ /**
+ * @see wcf\system\cronjob\ICronjob::execute()
+ */
+ public function execute(Cronjob $cronjob) {
+ parent::execute($cronjob);
+
+ $sql = "SELECT queueID
+ FROM wcf".WCF_N."_moderation_queue
+ WHERE status = ?
+ AND lastChangeTime < ?";
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute(array(
+ ModerationQueue::STATUS_DONE,
+ (TIME_NOW - (86400 * 30))
+ ));
+ $queueIDs = array();
+ while ($row = $statement->fetchArray()) {
+ $queueIDs[] = $row['queueID'];
+ }
+
+ if (!empty($queueIDs)) {
+ $conditions = new PreparedStatementConditionBuilder();
+ $conditions->add("queueID IN (?)", array($queueIDs));
+
+ $sql = "DELETE FROM wcf".WCF_N."_moderation_queue
+ ".$conditions;
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute($conditions->getParameters());
+
+ // reset moderation count for all users
+ ModerationQueueManager::getInstance()->resetModerationCount();
+ }
+ }
+}
--- /dev/null
+<?php
+namespace wcf\system\moderation\queue;
+use wcf\data\moderation\queue\ModerationQueueAction;
+use wcf\system\database\util\PreparedStatementConditionBuilder;
+use wcf\system\exception\SystemException;
+use wcf\system\WCF;
+
+/**
+ * Default implementation for moderation queue handlers.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2013 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.moderation
+ * @subpackage system.moderation.queue
+ * @category Community Framework
+ */
+abstract class AbstractModerationQueueHandler implements IModerationQueueHandler {
+ /**
+ * definition name
+ * @var string
+ */
+ protected $definitionName = '';
+
+ /**
+ * object type
+ * @var string
+ */
+ protected $objectType = '';
+
+ /**
+ * @see wcf\system\moderation\queue\IModerationQueueHandler::removeQueues()
+ */
+ public function removeQueues(array $objectIDs) {
+ $objectTypeID = ModerationQueueManager::getInstance()->getObjectTypeID($this->definitionName, $this->objectType);
+ if ($objectTypeID === null) {
+ throw new SystemException("Object type '".$this->objectType."' is not valid for definition '".$this->definitionName."'");
+ }
+
+ $conditions = new PreparedStatementConditionBuilder();
+ $conditions->add("objectTypeID = ?", array($objectTypeID));
+ $conditions->add("objectID IN (?)", array($objectIDs));
+
+ $sql = "SELECT queueID
+ FROM wcf".WCF_N."_moderation_queue
+ ".$conditions;
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute($conditions->getParameters());
+ $queueIDs = array();
+ while ($row = $statement->fetchArray()) {
+ $queueIDs[] = $row['queueID'];
+ }
+
+ if (!empty($queueIDs)) {
+ $queueAction = new ModerationQueueAction($queueIDs, 'delete');
+ $queueAction->executeAction();
+ }
+ }
+}
--- /dev/null
+<?php
+namespace wcf\system\moderation\queue;
+use wcf\data\moderation\queue\ModerationQueue;
+use wcf\data\moderation\queue\ModerationQueueAction;
+use wcf\data\moderation\queue\ModerationQueueList;
+use wcf\system\SingletonFactory;
+use wcf\system\WCF;
+
+/**
+ * Default implementation for moderation queue managers.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2012 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.moderation
+ * @subpackage system.moderation.queue
+ * @category Community Framework
+ */
+abstract class AbstractModerationQueueManager extends SingletonFactory implements IModerationQueueManager {
+ /**
+ * definition name
+ * @var string
+ */
+ protected $definitionName = '';
+
+ /**
+ * @see wcf\system\moderation\queue\IModerationQueueManager::assignQueues()
+ */
+ public function assignQueues($objectTypeID, array $queues) {
+ ModerationQueueManager::getInstance()->getProcessor($this->definitionName, null, $objectTypeID)->assignQueues($queues);
+ }
+
+ /**
+ * @see wcf\system\moderation\queue\IModerationQueueManager::isValid()
+ */
+ public function isValid($objectType, $objectID = null) {
+ return ModerationQueueManager::getInstance()->isValid($this->definitionName, $objectType);
+ }
+
+ /**
+ * @see wcf\system\moderation\queue\IModerationQueueManager::getObjectTypeID()
+ */
+ public function getObjectTypeID($objectType) {
+ return ModerationQueueManager::getInstance()->getObjectTypeID($this->definitionName, $objectType);
+ }
+
+ /**
+ * @see wcf\system\moderation\queue\IModerationQueueManager::getProcessor()
+ */
+ public function getProcessor($objectType, $objectTypeID = null) {
+ return ModerationQueueManager::getInstance()->getProcessor($this->definitionName, $objectType, $objectTypeID);
+ }
+
+ /**
+ * @see wcf\system\moderation\queue\IModerationQueueManager::populate()
+ */
+ public function populate($objectTypeID, array $objects) {
+ ModerationQueueManager::getInstance()->getProcessor($this->definitionName, null, $objectTypeID)->populate($objects);
+ }
+
+ /**
+ * @see wcf\system\moderation\queue\IModerationQueueManager::removeContent()
+ */
+ public function removeContent(ModerationQueue $queue, $message = '') {
+ $this->getProcessor(null, $queue->objectTypeID)->removeContent($queue, $message);
+ }
+
+ /**
+ * Adds an entry to moderation queue.
+ *
+ * @param integer $objectTypeID
+ * @param integer $objectID
+ * @param integer $containerID
+ * @param array $additionalData
+ */
+ protected function addEntry($objectTypeID, $objectID, $containerID = 0, array $additionalData = array()) {
+ $sql = "SELECT COUNT(*) AS count
+ FROM wcf".WCF_N."_moderation_queue
+ WHERE objectTypeID = ?
+ AND objectID = ?";
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute(array(
+ $objectTypeID,
+ $objectID
+ ));
+ $row = $statement->fetchArray();
+
+ if ($row['count'] == 0) {
+ $objectAction = new ModerationQueueAction(array(), 'create', array(
+ 'data' => array(
+ 'objectTypeID' => $objectTypeID,
+ 'objectID' => $objectID,
+ 'containerID' => $containerID,
+ 'userID' => (WCF::getUser()->userID ?: null),
+ 'time' => TIME_NOW,
+ 'additionalData' => serialize($additionalData)
+ )
+ ));
+ $objectAction->executeAction();
+
+ ModerationQueueManager::getInstance()->resetModerationCount();
+ }
+ }
+
+ /**
+ * Marks a list of moderation queue entries as done.
+ *
+ * @param integer $objectTypeID
+ * @param array<integer> $objectIDs
+ */
+ protected function removeEntries($objectTypeID, array $objectIDs) {
+ $queueList = new ModerationQueueList();
+ $queueList->getConditionBuilder()->add("moderation_queue.objectTypeID = ?", array($objectTypeID));
+ $queueList->getConditionBuilder()->add("moderation_queue.objectID IN (?)", array($objectIDs));
+ $queueList->readObjects();
+
+ if (count($queueList)) {
+ $objectAction = new ModerationQueueAction($queueList->getObjects(), 'markAsDone');
+ $objectAction->executeAction();
+ }
+ }
+}
--- /dev/null
+<?php
+namespace wcf\system\moderation\queue;
+use wcf\data\moderation\queue\ModerationQueue;
+
+/**
+ * Default interface for moderation queue handlers.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2013 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.moderation
+ * @subpackage system.moderation.queue
+ * @category Community Framework
+ */
+interface IModerationQueueHandler {
+ /**
+ * Creates queue assignments for matching object ids.
+ *
+ * @param array<wcf\data\moderation\queue\ModerationQueue> $queues
+ */
+ public function assignQueues(array $queues);
+
+ /**
+ * Returns the container id for current object id, may return 0.
+ *
+ * @param integer $objectID
+ * @return integer
+ */
+ public function getContainerID($objectID);
+
+ /**
+ * Returns true if given object id is valid.
+ *
+ * @param integer $objectID
+ * @return boolean
+ */
+ public function isValid($objectID);
+
+ /**
+ * Populates object properties for viewing.
+ *
+ * @param array<wcf\data\moderation\queue\ViewableModerationQueue> $queues
+ */
+ public function populate(array $queues);
+
+ /**
+ * Removes affected content. It is up to the processing class to either
+ * soft-delete the content or remove it permanently.
+ *
+ * @param wcf\data\moderation\queue\ModerationQueue $queue
+ * @param string $message
+ */
+ public function removeContent(ModerationQueue $queue, $message);
+
+ /**
+ * Removes queses from database, should only be called if the referenced
+ * object is permanently deleted.
+ *
+ * @param array<integer> $objectIDs
+ */
+ public function removeQueues(array $objectIDs);
+}
--- /dev/null
+<?php
+namespace wcf\system\moderation\queue;
+use wcf\data\moderation\queue\ModerationQueue;
+
+/**
+ * Default interface for moderation queue managers.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2012 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.moderation
+ * @subpackage system.moderation.queue
+ * @category Community Framework
+ */
+interface IModerationQueueManager {
+ /**
+ * Creates queue assignments for matching object type ids.
+ *
+ * @param integer $objectTypeID
+ * @param array<wcf\data\moderation\queue\ModerationQueue> $queues
+ */
+ public function assignQueues($objectTypeID, array $queues);
+
+ /**
+ * Returns true if given object type is valid, optionally checking object id.
+ *
+ * @param string $objectType
+ * @param integer $objectID
+ * @return boolean
+ */
+ public function isValid($objectType, $objectID = null);
+
+ /**
+ * Returns link for viewing/editing objects for this moderation type.
+ *
+ * @param integer $queueID
+ * @return string
+ */
+ public function getLink($queueID);
+
+ /**
+ * Returns object type id for given object type.
+ *
+ * @param string $objectType
+ * @return integer
+ */
+ public function getObjectTypeID($objectType);
+
+ /**
+ * Returns object type processor by object type.
+ *
+ * @param string $objectType
+ * @param integer $objectTypeID
+ * @return object
+ */
+ public function getProcessor($objectType, $objectTypeID = null);
+
+ /**
+ * Populates object properties for viewing.
+ *
+ * @param integer $objectTypeID
+ * @param array<wcf\data\moderation\queue\ViewableModerationQueue> $objects
+ */
+ public function populate($objectTypeID, array $objects);
+
+ /**
+ * Removes affected content. It is up to the processing object to use a
+ * soft-delete or remove the content permanently.
+ *
+ * @param wcf\data\moderation\queue\ModerationQueue $queue
+ * @param string $message
+ */
+ public function removeContent(ModerationQueue $queue, $message = '');
+}
--- /dev/null
+<?php
+namespace wcf\system\moderation\queue;
+use wcf\data\moderation\queue\ModerationQueue;
+use wcf\data\moderation\queue\ViewableModerationQueue;
+use wcf\system\exception\SystemException;
+use wcf\system\request\LinkHandler;
+
+/**
+ * Moderation queue implementation for moderated content.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2012 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.moderation
+ * @subpackage system.moderation.queue
+ * @category Community Framework
+ */
+class ModerationQueueActivationManager extends AbstractModerationQueueManager {
+ /**
+ * @see wcf\system\moderation\queue\AbstractModerationQueueManager::$definitionName
+ */
+ protected $definitionName = 'com.woltlab.wcf.moderation.activation';
+
+ /**
+ * Enables affected content.
+ *
+ * @param wcf\data\moderation\queue\ModerationQueue $queue
+ */
+ public function enableContent(ModerationQueue $queue) {
+ $this->getProcessor(null, $queue->objectTypeID)->enableContent($queue);
+ }
+
+ /**
+ * Returns outstanding content.
+ *
+ * @param wcf\data\moderation\queue\ViewableModerationQueue $queue
+ * @return string
+ */
+ public function getDisabledContent(ViewableModerationQueue $queue) {
+ return $this->getProcessor(null, $queue->objectTypeID)->getDisabledContent($queue);
+ }
+
+ /**
+ * @see wcf\system\moderation\queue\IModerationQueueManager::getLink()
+ */
+ public function getLink($queueID) {
+ return LinkHandler::getInstance()->getLink('ModerationActivation', array('id' => $queueID));
+ }
+
+ /**
+ * Adds an entry for moderated content.
+ *
+ * @param string $objectType
+ * @param integer $objectID
+ * @param array $additionalData
+ */
+ public function addModeratedContent($objectType, $objectID, array $additionalData = array()) {
+ if (!$this->isValid($objectType)) {
+ throw new SystemException("Object type '".$objectType."' is not valid for definition 'com.woltlab.wcf.moderation.activation'");
+ }
+
+ $this->addEntry(
+ $this->getObjectTypeID($objectType),
+ $objectID,
+ $this->getProcessor($objectType)->getContainerID($objectID),
+ $additionalData
+ );
+ }
+
+ /**
+ * Marks entries from moderation queue as done.
+ *
+ * @param string $objectType
+ * @param array<integer> $objectIDs
+ */
+ public function removeModeratedContent($objectType, array $objectIDs) {
+ if (!$this->isValid($objectType)) {
+ throw new SystemException("Object type '".$objectType."' is not valid for definition 'com.woltlab.wcf.moderation.activation'");
+ }
+
+ $this->removeEntries($this->getObjectTypeID($objectType), $objectIDs);
+ }
+}
--- /dev/null
+<?php
+namespace wcf\system\moderation\queue;
+use wcf\data\moderation\queue\ModerationQueue;
+use wcf\data\moderation\queue\ModerationQueueAction;
+use wcf\data\moderation\queue\ModerationQueueList;
+use wcf\data\object\type\ObjectTypeCache;
+use wcf\system\exception\SystemException;
+use wcf\system\user\storage\UserStorageHandler;
+use wcf\system\SingletonFactory;
+use wcf\system\WCF;
+
+/**
+ * Provides methods to manage moderated content and reports.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2013 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.moderation
+ * @subpackage system.moderation.queue
+ * @category Community Framework
+ */
+class ModerationQueueManager extends SingletonFactory {
+ /**
+ * list of definition names by definition id
+ * @var array<string>
+ */
+ protected $definitions = array();
+
+ /**
+ * list of moderation types
+ * @var array<wcf\data\object\type\ObjectType>
+ */
+ protected $moderationTypes = array();
+
+ /**
+ * list of object type names categorized by type
+ * @var array<array>
+ */
+ protected $objectTypeNames = array();
+
+ /**
+ * list of object types
+ * @var array<wcf\data\object\type\ObjectType>
+ */
+ protected $objectTypes = array();
+
+ /**
+ * @see wcf\system\SingletonFactory::init()
+ */
+ protected function init() {
+ $moderationTypes = ObjectTypeCache::getInstance()->getObjectTypes('com.woltlab.wcf.moderation.type');
+ if (empty($moderationTypes)) {
+ throw new SystemException("There are no registered moderation types");
+ }
+
+ foreach ($moderationTypes as $moderationType) {
+ $this->moderationTypes[$moderationType->objectType] = $moderationType;
+
+ $definition = ObjectTypeCache::getInstance()->getDefinitionByName($moderationType->objectType);
+ if ($definition === null) {
+ throw new SystemException("Could not find corresponding definition for moderation type '".$moderationType->objectType."'");
+ }
+
+ $this->definitions[$definition->definitionID] = $definition->definitionName;
+ $this->objectTypeNames[$definition->definitionName] = array();
+
+ $objectTypes = ObjectTypeCache::getInstance()->getObjectTypes($definition->definitionName);
+ foreach ($objectTypes as $objectType) {
+ $this->objectTypeNames[$definition->definitionName][$objectType->objectType] = $objectType->objectTypeID;
+ $this->objectTypes[$objectType->objectTypeID] = $objectType;
+ }
+ }
+ }
+
+ /**
+ * Returns true if the given combination of definition and object type is valid.
+ *
+ * @param string $definitionName
+ * @param string $objectType
+ * @return boolean
+ */
+ public function isValid($definitionName, $objectType) {
+ if (!isset($this->objectTypeNames[$definitionName])) {
+ return false;
+ }
+ else if (!isset($this->objectTypeNames[$definitionName][$objectType])) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns the object type processor.
+ *
+ * @param string $definitionName
+ * @param string $objectType
+ * @param integer $objectTypeID
+ * @return object
+ */
+ public function getProcessor($definitionName, $objectType, $objectTypeID = null) {
+ if ($objectType !== null) {
+ $objectTypeID = $this->getObjectTypeID($definitionName, $objectType);
+ }
+
+ if ($objectTypeID !== null && isset($this->objectTypes[$objectTypeID])) {
+ return $this->objectTypes[$objectTypeID]->getProcessor();
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns link for viewing/editing an object type.
+ *
+ * @param integer $objectTypeID
+ * @param integer $queueID
+ * @return string
+ */
+ public function getLink($objectTypeID, $queueID) {
+ foreach ($this->objectTypeNames as $definitionName => $objectTypeIDs) {
+ if (in_array($objectTypeID, $objectTypeIDs)) {
+ return $this->moderationTypes[$definitionName]->getProcessor()->getLink($queueID);
+ }
+ }
+
+ return '';
+ }
+
+ /**
+ * Returns object type id.
+ *
+ * @param string $definitionName
+ * @param string $objectType
+ * @return integer
+ */
+ public function getObjectTypeID($definitionName, $objectType) {
+ if ($this->isValid($definitionName, $objectType)) {
+ return $this->objectTypeNames[$definitionName][$objectType];
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a list of moderation types.
+ *
+ * @return array<string>
+ */
+ public function getModerationTypes() {
+ return array_keys($this->objectTypeNames);
+ }
+
+ /**
+ * Returns a list of available definitions.
+ *
+ * @return array<string>
+ */
+ public function getDefinitions() {
+ return $this->definitions;
+ }
+
+ /**
+ * Returns a list of object type ids for given definiton ids.
+ *
+ * @param array<integer> $definitionIDs
+ * @return array<integer>
+ */
+ public function getObjectTypeIDs(array $definitionIDs) {
+ $objectTypeIDs = array();
+ foreach ($definitionIDs as $definitionID) {
+ if (isset($this->definitions[$definitionID])) {
+ foreach ($this->objectTypeNames[$this->definitions[$definitionID]] as $objectTypeID) {
+ $objectTypeIDs[] = $objectTypeID;
+ }
+ }
+ }
+
+ return $objectTypeIDs;
+ }
+
+ /**
+ * Populates object properties for viewing.
+ *
+ * @param integer $objectTypeID
+ * @param array<wcf\data\moderation\queue\ViewableModerationQueue> $objects
+ */
+ public function populate($objectTypeID, array $objects) {
+ $moderationType = '';
+ foreach ($this->objectTypeNames as $definitionName => $data) {
+ if (in_array($objectTypeID, $data)) {
+ $moderationType = $definitionName;
+ break;
+ }
+ }
+
+ if (empty($moderationType)) {
+ throw new SystemException("Unable to resolve object type id '".$objectTypeID."'");
+ }
+
+ // forward call to processor
+ $this->moderationTypes[$moderationType]->getProcessor()->populate($objectTypeID, $objects);
+ }
+
+ /**
+ * Returns the count of outstanding moderation queue items.
+ *
+ * @return integer
+ */
+ public function getOutstandingModerationCount() {
+ // load storage data
+ UserStorageHandler::getInstance()->loadStorage(array(WCF::getUser()->userID));
+
+ // get count
+ $data = UserStorageHandler::getInstance()->getStorage(array(WCF::getUser()->userID), 'outstandingModerationCount');
+ $count = $data[WCF::getUser()->userID];
+
+ // cache does not exist or is outdated
+ if ($count === null) {
+ // force update of non-tracked queues for this user
+ $queueList = new ModerationQueueList();
+ $queueList->sqlJoins = "LEFT JOIN wcf".WCF_N."_moderation_queue_to_user moderation_queue_to_user ON (moderation_queue_to_user.queueID = moderation_queue.queueID AND moderation_queue_to_user.userID = ".WCF::getUser()->userID.")";
+ $queueList->getConditionBuilder()->add("moderation_queue_to_user.queueID IS NULL");
+ $queueList->readObjects();
+
+ if (count($queueList)) {
+ $queues = array();
+ foreach ($queueList as $queue) {
+ if (!isset($queues[$queue->objectTypeID])) {
+ $queues[$queue->objectTypeID] = array();
+ }
+
+ $queues[$queue->objectTypeID][$queue->queueID] = $queue;
+ }
+
+ foreach ($this->objectTypeNames as $definitionName => $objectTypeIDs) {
+ foreach ($objectTypeIDs as $objectTypeID) {
+ if (isset($queues[$objectTypeID])) {
+ $this->moderationTypes[$definitionName]->getProcessor()->assignQueues($objectTypeID, $queues[$objectTypeID]);
+ }
+ }
+ }
+ }
+
+ // count outstanding and assigned queues
+ $sql = "SELECT COUNT(*) AS count
+ FROM wcf".WCF_N."_moderation_queue_to_user moderation_queue_to_user
+ LEFT JOIN wcf".WCF_N."_moderation_queue moderation_queue
+ ON (moderation_queue.queueID = moderation_queue_to_user.queueID)
+ WHERE moderation_queue_to_user.userID = ?
+ AND moderation_queue.status <> ?";
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute(array(
+ WCF::getUser()->userID,
+ ModerationQueue::STATUS_DONE
+ ));
+ $row = $statement->fetchArray();
+ $count = $row['count'];
+
+ // update storage data
+ UserStorageHandler::getInstance()->update(WCF::getUser()->userID, 'outstandingModerationCount', $count);
+ }
+
+ return $count;
+ }
+
+ /**
+ * Saves moderation queue assignments.
+ *
+ * @param array<boolean> $assignments
+ */
+ public function setAssignment(array $assignments) {
+ $sql = "INSERT INTO wcf".WCF_N."_moderation_queue_to_user
+ (queueID, userID, isAffected)
+ VALUES (?, ?, ?)";
+ $statement = WCF::getDB()->prepareStatement($sql);
+
+ WCF::getDB()->beginTransaction();
+ foreach ($assignments as $queueID => $isAffected) {
+ $statement->execute(array(
+ $queueID,
+ WCF::getUser()->userID,
+ ($isAffected ? 1 : 0)
+ ));
+ }
+ WCF::getDB()->commitTransaction();
+ }
+
+ /**
+ * Removes a list of orphaned queue ids.
+ *
+ * @param array<integer> $queueIDs
+ */
+ public function removeOrphans(array $queueIDs) {
+ $queueAction = new ModerationQueueAction($queueIDs, 'markAsDone');
+ $queueAction->executeAction();
+
+ $this->resetModerationCount();
+ }
+
+ /**
+ * Resets moderation count for all users or optionally only for one user.
+ *
+ * @param integer $userID
+ */
+ public function resetModerationCount($userID = null) {
+ if ($userID === null) {
+ UserStorageHandler::getInstance()->resetAll('outstandingModerationCount');
+ }
+ else {
+ UserStorageHandler::getInstance()->reset(array($userID), 'outstandingModerationCount');
+ }
+ }
+
+ /**
+ * Returns a list of object type ids and their parent definition name.
+ *
+ * @return array<string>
+ */
+ public function getDefinitionNamesByObjectTypeIDs() {
+ $definitionNames = array();
+ foreach ($this->objectTypeNames as $definitionName => $objectTypes) {
+ foreach ($objectTypes as $objectTypeID) {
+ $definitionNames[$objectTypeID] = $definitionName;
+ }
+ }
+
+ return $definitionNames;
+ }
+
+ /**
+ * Returns a list of definition names associated with the specified object type.
+ *
+ * @param string $objectType
+ * @return array<string>
+ */
+ public function getDefinitionNamesByObjectType($objectType) {
+ $definitionNames = array();
+ foreach ($this->objectTypeNames as $definitionName => $objectTypes) {
+ if (isset($objectTypes[$objectType])) {
+ $definitionNames[] = $definitionName;
+ }
+ }
+
+ return $definitionNames;
+ }
+
+ /**
+ * Removes moderation queues, should only be called if related objects are permanently deleted.
+ *
+ * @param string $objectType
+ * @param array<integer> $objectIDs
+ */
+ public function removeQueues($objectType, array $objectIDs) {
+ $definitionNames = $this->getDefinitionNamesByObjectType($objectType);
+ if (empty($definitionNames)) {
+ throw new SystemException("Object type '".$objectType."' is invalid");
+ }
+
+ foreach ($definitionNames as $definitionName) {
+ $this->getProcessor($definitionName, $objectType)->removeQueues($objectIDs);
+ }
+
+ $this->resetModerationCount();
+ }
+}
--- /dev/null
+<?php
+namespace wcf\system\moderation\queue;
+use wcf\data\moderation\queue\ViewableModerationQueue;
+use wcf\system\exception\SystemException;
+use wcf\system\request\LinkHandler;
+use wcf\system\WCF;
+
+/**
+ * Moderation queue implementation for reports.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2012 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.moderation
+ * @subpackage system.moderation.queue
+ * @category Community Framework
+ */
+class ModerationQueueReportManager extends AbstractModerationQueueManager {
+ /**
+ * @see wcf\system\moderation\queue\AbstractModerationQueueManager::$definitionName
+ */
+ protected $definitionName = 'com.woltlab.wcf.moderation.report';
+
+ /**
+ * Returns true if given item was already reported.
+ *
+ * @param string $objectType
+ * @param integer $objectID
+ * @return boolean
+ */
+ public function isAlreadyReported($objectType, $objectID) {
+ $objectTypeID = $this->getObjectTypeID($objectType);
+
+ $sql = "SELECT COUNT(*) AS count
+ FROM wcf".WCF_N."_moderation_queue
+ WHERE objectTypeID = ?
+ AND objectID = ?";
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute(array(
+ $objectTypeID,
+ $objectID
+ ));
+ $row = $statement->fetchArray();
+
+ return ($row['count'] == 0 ? false : true);
+ }
+
+ /**
+ * Returns true if current user can report given content.
+ *
+ * @param string $objectType
+ * @param integer $objectID
+ * @return boolean
+ */
+ public function canReport($objectType, $objectID) {
+ return $this->getProcessor($objectType)->canReport($objectID);
+ }
+
+ /**
+ * @see wcf\system\moderation\queue\IModerationQueueManager::getLink()
+ */
+ public function getLink($queueID) {
+ return LinkHandler::getInstance()->getLink('ModerationReport', array('id' => $queueID));
+ }
+
+ /**
+ * Returns rendered template for reported content.
+ *
+ * @param wcf\data\moderation\queue\ViewableModerationQueue $queue
+ * @return string
+ */
+ public function getReportedContent(ViewableModerationQueue $queue) {
+ return $this->getProcessor(null, $queue->objectTypeID)->getReportedContent($queue);
+ }
+
+ /**
+ * Returns the reported object.
+ *
+ * @param string $objectType
+ * @param integer $objectID
+ * @return wcf\data\IUserContent
+ */
+ public function getReportedObject($objectType, $objectID) {
+ return $this->getProcessor($objectType)->getReportedObject($objectID);
+ }
+
+ /**
+ * Adds a report for specified content.
+ *
+ * @param string $objectType
+ * @param integer $objectID
+ * @param string $message
+ * @param array $additionalData
+ */
+ public function addReport($objectType, $objectID, $message, array $additionalData = array()) {
+ if (!$this->isValid($objectType)) {
+ throw new SystemException("Object type '".$objectType."' is not valid for definition 'com.woltlab.wcf.moderation.report'");
+ }
+
+ $additionalData['message'] = $message;
+ $this->addEntry(
+ $this->getObjectTypeID($objectType),
+ $objectID,
+ $this->getProcessor($objectType)->getContainerID($objectID),
+ $additionalData
+ );
+ }
+}
--- /dev/null
+<?php
+namespace wcf\system\moderation\queue\activation;
+use wcf\data\moderation\queue\ModerationQueue;
+use wcf\data\moderation\queue\ViewableModerationQueue;
+use wcf\system\moderation\queue\IModerationQueueHandler;
+
+/**
+ * Default interface for moderation queue activation handlers.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2012 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.moderation
+ * @subpackage system.moderation.queue.activiation
+ * @category Community Framework
+ */
+interface IModerationQueueActivationHandler extends IModerationQueueHandler {
+ /**
+ * Enables affected content.
+ *
+ * @param wcf\data\moderation\queue\ModerationQueue $queue
+ */
+ public function enableContent(ModerationQueue $queue);
+
+ /**
+ * Returns rendered template for disabled content.
+ *
+ * @param wcf\data\moderation\queue\ViewableModerationQueue $queue
+ * @return string
+ */
+ public function getDisabledContent(ViewableModerationQueue $queue);
+}
--- /dev/null
+<?php
+namespace wcf\system\moderation\queue\report;
+use wcf\data\moderation\queue\ViewableModerationQueue;
+use wcf\system\moderation\queue\IModerationQueueHandler;
+
+/**
+ * Default interface for moderation queue report handlers.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2012 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.moderation
+ * @subpackage system.moderation.queue.report
+ * @category Community Framework
+ */
+interface IModerationQueueReportHandler extends IModerationQueueHandler {
+ /**
+ * Returns true if current user can report given content.
+ *
+ * @param integer $objectID
+ * @return boolean
+ */
+ public function canReport($objectID);
+
+ /**
+ * Returns rendered template for reported content.
+ *
+ * @param wcf\data\moderation\queue\ViewableModerationQueue $queue
+ * @return string
+ */
+ public function getReportedContent(ViewableModerationQueue $queue);
+
+ /**
+ * Returns reported object.
+ *
+ * @param integer $objectID
+ * @return wcf\data\IUserContent
+ */
+ public function getReportedObject($objectID);
+}
<item name="wcf.acp.group.option.user.profile.renamePeriod"><![CDATA[Umbenennung]]></item>
<item name="wcf.acp.group.option.user.profile.renamePeriod.description"><![CDATA[Zeitraum nach dem Mitglieder dieser Benutzergruppe ihren Benutzernamen ändern können. [Zeit in Tagen]]]></item>
<item name="wcf.acp.group.option.user.profile.cannotBeIgnored"><![CDATA[Kann nicht ignoriert werden]]></item>
+ <item name="wcf.acp.group.option.mod.general.canUseModeration"><![CDATA[Kann Moderation benutzen]]></item>
</category>
<category name="wcf.acp.index">
<item name="wcf.message.error.editorAlreadyInUse"><![CDATA[Der Editor ist bereits aktiv, beenden Sie die Bearbeitung bevor Sie fortfahren.]]></item>
<item name="wcf.message.error.tooLong"><![CDATA[Ihre Nachricht ist zu lang. Es stehen maximal {#$maxTextLength} Zeichen zur Verfügung.]]></item>
</category>
+
+ <category name="wcf.moderation">
+ <item name="wcf.moderation.assignedUser"><![CDATA[Zugewiesener Benutzer]]></item>
+ <item name="wcf.moderation.assignedUser.nobody"><![CDATA[Niemand]]></item>
+ <item name="wcf.moderation.comment"><![CDATA[Kommentar (intern)]]></item>
+ <item name="wcf.moderation.filterByType"><![CDATA[Typ]]></item>
+ <item name="wcf.moderation.filterByUser"><![CDATA[Zugewiesener Benutzer]]></item>
+ <item name="wcf.moderation.filterByUser.allEntries"><![CDATA[Alle Einträge]]></item>
+ <item name="wcf.moderation.filterByUser.myself"><![CDATA[Ich ({$__wcf->getUser()->username})]]></item>
+ <item name="wcf.moderation.filterByUser.nobody"><![CDATA[Niemand]]></item>
+ <item name="wcf.moderation.outstandingItems"><![CDATA[Ausstehende Elemente]]></item>
+ <item name="wcf.moderation.doneItems"><![CDATA[Erledigte Elemente]]></item>
+ <item name="wcf.moderation.lastChangeTime"><![CDATA[Letzte Änderung]]></item>
+ <item name="wcf.moderation.moderation"><![CDATA[Moderation]]></item>
+ <item name="wcf.moderation.noItems"><![CDATA[Keine Einträge entsprechen den gewählten Kriterien]]></item>
+ <item name="wcf.moderation.noMoreItems"><![CDATA[Keine weiteren Einträge]]></item>
+ <item name="wcf.moderation.status"><![CDATA[Status]]></item>
+ <item name="wcf.moderation.status.all"><![CDATA[Alle Einträge]]></item>
+ <item name="wcf.moderation.status.done"><![CDATA[Erledigt]]></item>
+ <item name="wcf.moderation.time"><![CDATA[Datum]]></item>
+ <item name="wcf.moderation.title"><![CDATA[Titel]]></item>
+ <item name="wcf.moderation.type"><![CDATA[Typ]]></item>
+ <item name="wcf.moderation.type.all"><![CDATA[Alle Einträge]]></item>
+ <item name="wcf.moderation.type.com.woltlab.wcf.moderation.activation"><![CDATA[Freischaltung]]></item>
+ <item name="wcf.moderation.type.com.woltlab.wcf.moderation.report"><![CDATA[Meldung]]></item>
+ <item name="wcf.moderation.showAll"><![CDATA[Alle Einträge anzeigen]]></item>
+ </category>
+
+ <category name="wcf.moderation.activation">
+ <item name="wcf.moderation.activation"><![CDATA[Freischaltung]]></item>
+ <item name="wcf.moderation.activation.content"><![CDATA[Freizuschaltender Inhalt]]></item>
+ <item name="wcf.moderation.activation.enableContent"><![CDATA[Inhalt freischalten]]></item>
+ <item name="wcf.moderation.activation.enableContent.confirmMessage"><![CDATA[Wollen Sie diesen Inhalt wirklich freischalten?]]></item>
+ <item name="wcf.moderation.activation.removeContent"><![CDATA[Inhalt löschen]]></item>
+ <item name="wcf.moderation.activation.removeContent.confirmMessage"><![CDATA[Wollen Sie diesen Inhalt wirklich löschen?]]></item>
+ </category>
+
+ <category name="wcf.moderation.report">
+ <item name="wcf.moderation.report"><![CDATA[Meldung bearbeiten]]></item>
+ <item name="wcf.moderation.report.alreadyReported"><![CDATA[Dieser Inhalt wurde bereits gemeldet.]]></item>
+ <item name="wcf.moderation.report.details"><![CDATA[Meldung]]></item>
+ <item name="wcf.moderation.report.reason"><![CDATA[Grund der Meldung]]></item>
+ <item name="wcf.moderation.report.reason.description"><![CDATA[Diese Funktion ist ausschließlich zu verwenden bei: Spam, Werbung und anderen problematischen (rassistischen, gewaltverherrlichenden, agressiven, beleidigenden oder sexistischen) Inhalten.]]></item>
+ <item name="wcf.moderation.report.removeContent"><![CDATA[Gemeldeten Inhalt löschen]]></item>
+ <item name="wcf.moderation.report.removeContent.confirmMessage"><![CDATA[Wollen Sie den gemeldeten Inhalt wirklich löschen?]]></item>
+ <item name="wcf.moderation.report.removeReport"><![CDATA[Meldung löschen]]></item>
+ <item name="wcf.moderation.report.removeReport.confirmMessage"><![CDATA[Wollen Sie diese Meldung wirklich löschen?]]></item>
+ <item name="wcf.moderation.report.reportContent"><![CDATA[Inhalt melden]]></item>
+ <item name="wcf.moderation.report.reportedBy"><![CDATA[Gemeldet von]]></item>
+ <item name="wcf.moderation.report.reportedContent"><![CDATA[Gemeldeter Inhalt]]></item>
+ <item name="wcf.moderation.report.success"><![CDATA[Der Inhalt wurde den Moderatoren gemeldet.]]></item>
+ </category>
<category name="wcf.page">
<item name="wcf.page.pageNo"><![CDATA[Seite {#$pageNo}]]></item>
<item name="wcf.acp.group.option.user.profile.renamePeriod"><![CDATA[Rename]]></item>
<item name="wcf.acp.group.option.user.profile.renamePeriod.description"><![CDATA[Minimum period until members may rename themselves. [time in days]]]></item>
<item name="wcf.acp.group.option.user.profile.cannotBeIgnored"><![CDATA[Can not be ignored]]></item>
+ <item name="wcf.acp.group.option.mod.general.canUseModeration"><![CDATA[Can access moderation]]></item>
</category>
<category name="wcf.acp.index">
<item name="wcf.message.error.tooLong"><![CDATA[Message is too long, must be below {#$maxTextLength} characters.]]></item>
</category>
+ <category name="wcf.moderation">
+ <item name="wcf.moderation.assignedUser"><![CDATA[Assigned User]]></item>
+ <item name="wcf.moderation.assignedUser.nobody"><![CDATA[Nobody]]></item>
+ <item name="wcf.moderation.comment"><![CDATA[Comment (internal)]]></item>
+ <item name="wcf.moderation.filterByType"><![CDATA[Type]]></item>
+ <item name="wcf.moderation.filterByUser"><![CDATA[Assigned User]]></item>
+ <item name="wcf.moderation.filterByUser.allEntries"><![CDATA[All Items]]></item>
+ <item name="wcf.moderation.filterByUser.myself"><![CDATA[Myself ({$__wcf->getUser()->username})]]></item>
+ <item name="wcf.moderation.filterByUser.nobody"><![CDATA[Nobody]]></item>
+ <item name="wcf.moderation.outstandingItems"><![CDATA[Outstanding Items]]></item>
+ <item name="wcf.moderation.doneItems"><![CDATA[Done Items]]></item>
+ <item name="wcf.moderation.lastChangeTime"><![CDATA[Last Change]]></item>
+ <item name="wcf.moderation.moderation"><![CDATA[Moderation]]></item>
+ <item name="wcf.moderation.noItems"><![CDATA[No items matched your criteria.]]></item>
+ <item name="wcf.moderation.noMoreItems"><![CDATA[No more items]]></item>
+ <item name="wcf.moderation.status"><![CDATA[Status]]></item>
+ <item name="wcf.moderation.status.all"><![CDATA[All Items]]></item>
+ <item name="wcf.moderation.status.done"><![CDATA[Done]]></item>
+ <item name="wcf.moderation.time"><![CDATA[Time]]></item>
+ <item name="wcf.moderation.title"><![CDATA[Title]]></item>
+ <item name="wcf.moderation.type"><![CDATA[Type]]></item>
+ <item name="wcf.moderation.type.all"><![CDATA[All Items]]></item>
+ <item name="wcf.moderation.type.com.woltlab.wcf.moderation.activation"><![CDATA[Approval]]></item>
+ <item name="wcf.moderation.type.com.woltlab.wcf.moderation.report"><![CDATA[Report]]></item>
+ <item name="wcf.moderation.showAll"><![CDATA[Show All Items]]></item>
+ </category>
+
+ <category name="wcf.moderation.activation">
+ <item name="wcf.moderation.activation"><![CDATA[Approval]]></item>
+ <item name="wcf.moderation.activation.content"><![CDATA[Content Awaiting Approval]]></item>
+ <item name="wcf.moderation.activation.enableContent"><![CDATA[Approve]]></item>
+ <item name="wcf.moderation.activation.enableContent.confirmMessage"><![CDATA[Do you really want to approve this content?]]></item>
+ <item name="wcf.moderation.activation.removeContent"><![CDATA[Delete Content]]></item>
+ <item name="wcf.moderation.activation.removeContent.confirmMessage"><![CDATA[Do you really want to delete this content?]]></item>
+ </category>
+
+ <category name="wcf.moderation.report">
+ <item name="wcf.moderation.report"><![CDATA[Edit Report]]></item>
+ <item name="wcf.moderation.report.alreadyReported"><![CDATA[This content has already been reported.]]></item>
+ <item name="wcf.moderation.report.details"><![CDATA[Report]]></item>
+ <item name="wcf.moderation.report.reason"><![CDATA[Reason]]></item>
+ <item name="wcf.moderation.report.reason.description"><![CDATA[This function is reserved for: Spam, Advertisement and other questionable (rassism, glorification of violence, offending or sexist) content]]></item>
+ <item name="wcf.moderation.report.removeContent"><![CDATA[Delete Reported Content]]></item>
+ <item name="wcf.moderation.report.removeContent.confirmMessage"><![CDATA[Do you really want to delete the reported content?]]></item>
+ <item name="wcf.moderation.report.removeReport"><![CDATA[Delete Report]]></item>
+ <item name="wcf.moderation.report.removeReport.confirmMessage"><![CDATA[Do you really want to delete this report?]]></item>
+ <item name="wcf.moderation.report.reportContent"><![CDATA[Report Content]]></item>
+ <item name="wcf.moderation.report.reportedBy"><![CDATA[Reported By]]></item>
+ <item name="wcf.moderation.report.reportedContent"><![CDATA[Reported Content]]></item>
+ <item name="wcf.moderation.report.success"><![CDATA[Content has been reported.]]></item>
+ </category>
+
<category name="wcf.page">
<item name="wcf.page.pageNo"><![CDATA[Page {#$pageNo}]]></item>
<item name="wcf.page.offline"><![CDATA[Page is currently in maintenance mode{if OFFLINE_MESSAGE != ''}:{else}.{/if}]]></item>
isDisabled TINYINT(1) NOT NULL DEFAULT 0
);
+DROP TABLE IF EXISTS wcf1_moderation_queue;
+CREATE TABLE wcf1_moderation_queue (
+ queueID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ objectTypeID INT(10) NOT NULL,
+ objectID INT(10) NOT NULL,
+ containerID INT(10) NOT NULL DEFAULT 0,
+ userID INT(10) NULL,
+ time INT(10) NOT NULL DEFAULT 0,
+
+ -- internal
+ assignedUserID INT(10) NULL,
+ status TINYINT(1) NOT NULL DEFAULT 0,
+ comment TEXT,
+ lastChangeTime INT(10) NOT NULL DEFAULT 0,
+
+ -- additional data, e.g. message if reporting content
+ additionalData TEXT,
+
+ UNIQUE KEY affectedObject (objectTypeID, objectID)
+);
+
+DROP TABLE IF EXISTS wcf1_moderation_queue_to_user;
+CREATE TABLE wcf1_moderation_queue_to_user (
+ queueID INT(10) NOT NULL,
+ userID INT(10) NOT NULL,
+ isAffected TINYINT(1) NOT NULL DEFAULT 0,
+
+ UNIQUE KEY queue (queueID, userID),
+ KEY affected (queueID, userID, isAffected)
+);
+
DROP TABLE IF EXISTS wcf1_modification_log;
CREATE TABLE wcf1_modification_log (
logID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
ALTER TABLE wcf1_user_object_watch ADD FOREIGN KEY (userID) REFERENCES wcf1_user (userID) ON DELETE CASCADE;
ALTER TABLE wcf1_user_object_watch ADD FOREIGN KEY (objectTypeID) REFERENCES wcf1_object_type (objectTypeID) ON DELETE CASCADE;
+ALTER TABLE wcf1_moderation_queue ADD FOREIGN KEY (objectTypeID) REFERENCES wcf1_object_type (objectTypeID) ON DELETE CASCADE;
+ALTER TABLE wcf1_moderation_queue ADD FOREIGN KEY (userID) REFERENCES wcf1_user (userID) ON DELETE SET NULL;
+ALTER TABLE wcf1_moderation_queue ADD FOREIGN KEY (assignedUserID) REFERENCES wcf1_user (userID) ON DELETE SET NULL;
+
+ALTER TABLE wcf1_moderation_queue_to_user ADD FOREIGN KEY (queueID) REFERENCES wcf1_moderation_queue (queueID) ON DELETE CASCADE;
+ALTER TABLE wcf1_moderation_queue_to_user ADD FOREIGN KEY (userID) REFERENCES wcf1_user (userID) ON DELETE CASCADE;
+
/* default inserts */
-- default user groups