Merged com.woltlab.wcf.moderation into WCF
authorMarcel Werk <burntime@woltlab.com>
Mon, 20 May 2013 22:00:59 +0000 (00:00 +0200)
committerMarcel Werk <burntime@woltlab.com>
Mon, 20 May 2013 22:00:59 +0000 (00:00 +0200)
39 files changed:
com.woltlab.wcf/coreObject.xml
com.woltlab.wcf/cronjob.xml
com.woltlab.wcf/objectType.xml
com.woltlab.wcf/objectTypeDefinition.xml
com.woltlab.wcf/template/moderationActivation.tpl [new file with mode: 0644]
com.woltlab.wcf/template/moderationList.tpl [new file with mode: 0644]
com.woltlab.wcf/template/moderationQueueList.tpl [new file with mode: 0644]
com.woltlab.wcf/template/moderationReport.tpl [new file with mode: 0644]
com.woltlab.wcf/template/moderationReportDialog.tpl [new file with mode: 0644]
com.woltlab.wcf/template/userPanel.tpl
com.woltlab.wcf/userGroupOption.xml
wcfsetup/install/files/js/WCF.Moderation.js [new file with mode: 0644]
wcfsetup/install/files/js/WCF.Moderation.min.js [new file with mode: 0644]
wcfsetup/install/files/lib/acp/form/UserEditForm.class.php
wcfsetup/install/files/lib/data/moderation/queue/ModerationQueue.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/moderation/queue/ModerationQueueAction.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/moderation/queue/ModerationQueueActivationAction.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/moderation/queue/ModerationQueueEditor.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/moderation/queue/ModerationQueueList.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/moderation/queue/ModerationQueueReportAction.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/moderation/queue/ViewableModerationQueue.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/moderation/queue/ViewableModerationQueueList.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/form/AbstractModerationForm.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/form/ModerationActivationForm.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/form/ModerationReportForm.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/page/ModerationListPage.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/cronjob/ModerationQueueCronjob.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/moderation/queue/AbstractModerationQueueHandler.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/moderation/queue/AbstractModerationQueueManager.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/moderation/queue/IModerationQueueHandler.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/moderation/queue/IModerationQueueManager.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/moderation/queue/ModerationQueueActivationManager.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/moderation/queue/ModerationQueueManager.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/moderation/queue/ModerationQueueReportManager.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/moderation/queue/activation/IModerationQueueActivationHandler.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/moderation/queue/report/IModerationQueueReportHandler.class.php [new file with mode: 0644]
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml
wcfsetup/setup/db/install.sql

index a6642cca0ee9c8439f9416526289e193c3087e00..cbf8994d9c25d3789d4315bcc0a22b1d84d21e44 100644 (file)
@@ -45,5 +45,9 @@
                <coreobject>
                        <objectname><![CDATA[wcf\system\user\object\watch\UserObjectWatchHandler]]></objectname>
                </coreobject>
+               
+               <coreobject>
+                       <objectname><![CDATA[wcf\system\moderation\queue\ModerationQueueManager]]></objectname>
+               </coreobject>
        </import>
 </data>
index 4ff071a68d8af471ca3f26f51a664dea65907ab2..bd1ef206e0972f2a103a4fc8d7efe18397c26002 100644 (file)
                        <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
index 6495cc84ce59206c4c0506ee6ff6f22c3b680b7b..2e628f4653f75ee50ec14eea7b5b37d1021d478e 100644 (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
index 1bddc5b386cfa4221554ba5b912ff2cd31b8a79d..57f677e7fdc177444ba87753e4bf64837b11eb25 100644 (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>
diff --git a/com.woltlab.wcf/template/moderationActivation.tpl b/com.woltlab.wcf/template/moderationActivation.tpl
new file mode 100644 (file)
index 0000000..14dbecc
--- /dev/null
@@ -0,0 +1,113 @@
+{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
diff --git a/com.woltlab.wcf/template/moderationList.tpl b/com.woltlab.wcf/template/moderationList.tpl
new file mode 100644 (file)
index 0000000..289cb52
--- /dev/null
@@ -0,0 +1,141 @@
+{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
diff --git a/com.woltlab.wcf/template/moderationQueueList.tpl b/com.woltlab.wcf/template/moderationQueueList.tpl
new file mode 100644 (file)
index 0000000..5ba8cb0
--- /dev/null
@@ -0,0 +1,13 @@
+{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
diff --git a/com.woltlab.wcf/template/moderationReport.tpl b/com.woltlab.wcf/template/moderationReport.tpl
new file mode 100644 (file)
index 0000000..72c8a0f
--- /dev/null
@@ -0,0 +1,121 @@
+{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
diff --git a/com.woltlab.wcf/template/moderationReportDialog.tpl b/com.woltlab.wcf/template/moderationReportDialog.tpl
new file mode 100644 (file)
index 0000000..e0d98db
--- /dev/null
@@ -0,0 +1,22 @@
+{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
index be0e1ea91391fbd4e559b788e96c15c087aa7082..597c19dadc6a00fcbf827468312bd4a4bdc32e72 100644 (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}
 
index 130e642ef56131892735f08678fc7ce26c8f8712..d18ab007d7e417c856881a95bedc41d021a31357 100644 (file)
@@ -466,6 +466,13 @@ jpeg
 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>
diff --git a/wcfsetup/install/files/js/WCF.Moderation.js b/wcfsetup/install/files/js/WCF.Moderation.js
new file mode 100644 (file)
index 0000000..44c6470
--- /dev/null
@@ -0,0 +1,383 @@
+/**
+ * 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'
+               };
+       }
+});
diff --git a/wcfsetup/install/files/js/WCF.Moderation.min.js b/wcfsetup/install/files/js/WCF.Moderation.min.js
new file mode 100644 (file)
index 0000000..5057dc6
--- /dev/null
@@ -0,0 +1 @@
+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
index 2f6b8ab2ff5504c78002c7b4bff02358f33fb4e8..5527238e214b8378b91933e25d6502b3129b45be 100755 (executable)
@@ -1,13 +1,8 @@
 <?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;
@@ -16,6 +11,8 @@ use wcf\data\user\UserProfileAction;
 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;
 
@@ -291,6 +288,15 @@ class UserEditForm extends UserAddForm {
                        $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
diff --git a/wcfsetup/install/files/lib/data/moderation/queue/ModerationQueue.class.php b/wcfsetup/install/files/lib/data/moderation/queue/ModerationQueue.class.php
new file mode 100644 (file)
index 0000000..3695010
--- /dev/null
@@ -0,0 +1,79 @@
+<?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']);
+       }
+}
diff --git a/wcfsetup/install/files/lib/data/moderation/queue/ModerationQueueAction.class.php b/wcfsetup/install/files/lib/data/moderation/queue/ModerationQueueAction.class.php
new file mode 100644 (file)
index 0000000..7dc76a6
--- /dev/null
@@ -0,0 +1,103 @@
+<?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()
+               );
+       }
+}
diff --git a/wcfsetup/install/files/lib/data/moderation/queue/ModerationQueueActivationAction.class.php b/wcfsetup/install/files/lib/data/moderation/queue/ModerationQueueActivationAction.class.php
new file mode 100644 (file)
index 0000000..6445cc6
--- /dev/null
@@ -0,0 +1,67 @@
+<?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();
+       }
+}
diff --git a/wcfsetup/install/files/lib/data/moderation/queue/ModerationQueueEditor.class.php b/wcfsetup/install/files/lib/data/moderation/queue/ModerationQueueEditor.class.php
new file mode 100644 (file)
index 0000000..dabc15e
--- /dev/null
@@ -0,0 +1,38 @@
+<?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));
+       }
+}
diff --git a/wcfsetup/install/files/lib/data/moderation/queue/ModerationQueueList.class.php b/wcfsetup/install/files/lib/data/moderation/queue/ModerationQueueList.class.php
new file mode 100644 (file)
index 0000000..d18bf6c
--- /dev/null
@@ -0,0 +1,20 @@
+<?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';
+}
diff --git a/wcfsetup/install/files/lib/data/moderation/queue/ModerationQueueReportAction.class.php b/wcfsetup/install/files/lib/data/moderation/queue/ModerationQueueReportAction.class.php
new file mode 100644 (file)
index 0000000..04fe279
--- /dev/null
@@ -0,0 +1,134 @@
+<?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
+               );
+       }
+}
diff --git a/wcfsetup/install/files/lib/data/moderation/queue/ViewableModerationQueue.class.php b/wcfsetup/install/files/lib/data/moderation/queue/ViewableModerationQueue.class.php
new file mode 100644 (file)
index 0000000..9c98939
--- /dev/null
@@ -0,0 +1,149 @@
+<?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));
+       }
+}
diff --git a/wcfsetup/install/files/lib/data/moderation/queue/ViewableModerationQueueList.class.php b/wcfsetup/install/files/lib/data/moderation/queue/ViewableModerationQueueList.class.php
new file mode 100644 (file)
index 0000000..db160ed
--- /dev/null
@@ -0,0 +1,121 @@
+<?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';
+       }
+}
diff --git a/wcfsetup/install/files/lib/form/AbstractModerationForm.class.php b/wcfsetup/install/files/lib/form/AbstractModerationForm.class.php
new file mode 100644 (file)
index 0000000..8e9912e
--- /dev/null
@@ -0,0 +1,169 @@
+<?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');
+       }
+}
diff --git a/wcfsetup/install/files/lib/form/ModerationActivationForm.class.php b/wcfsetup/install/files/lib/form/ModerationActivationForm.class.php
new file mode 100644 (file)
index 0000000..2b67b87
--- /dev/null
@@ -0,0 +1,27 @@
+<?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)
+               ));
+       }
+}
diff --git a/wcfsetup/install/files/lib/form/ModerationReportForm.class.php b/wcfsetup/install/files/lib/form/ModerationReportForm.class.php
new file mode 100644 (file)
index 0000000..e1583ef
--- /dev/null
@@ -0,0 +1,27 @@
+<?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)
+               ));
+       }
+}
diff --git a/wcfsetup/install/files/lib/page/ModerationListPage.class.php b/wcfsetup/install/files/lib/page/ModerationListPage.class.php
new file mode 100644 (file)
index 0000000..359fb55
--- /dev/null
@@ -0,0 +1,134 @@
+<?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
+               ));
+       }
+}
diff --git a/wcfsetup/install/files/lib/system/cronjob/ModerationQueueCronjob.class.php b/wcfsetup/install/files/lib/system/cronjob/ModerationQueueCronjob.class.php
new file mode 100644 (file)
index 0000000..3b30686
--- /dev/null
@@ -0,0 +1,53 @@
+<?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();
+               }
+       }
+}
diff --git a/wcfsetup/install/files/lib/system/moderation/queue/AbstractModerationQueueHandler.class.php b/wcfsetup/install/files/lib/system/moderation/queue/AbstractModerationQueueHandler.class.php
new file mode 100644 (file)
index 0000000..83d0ef8
--- /dev/null
@@ -0,0 +1,59 @@
+<?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();
+               }
+       }
+}
diff --git a/wcfsetup/install/files/lib/system/moderation/queue/AbstractModerationQueueManager.class.php b/wcfsetup/install/files/lib/system/moderation/queue/AbstractModerationQueueManager.class.php
new file mode 100644 (file)
index 0000000..289925b
--- /dev/null
@@ -0,0 +1,122 @@
+<?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();
+               }
+       }
+}
diff --git a/wcfsetup/install/files/lib/system/moderation/queue/IModerationQueueHandler.class.php b/wcfsetup/install/files/lib/system/moderation/queue/IModerationQueueHandler.class.php
new file mode 100644 (file)
index 0000000..d310c42
--- /dev/null
@@ -0,0 +1,62 @@
+<?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);
+}
diff --git a/wcfsetup/install/files/lib/system/moderation/queue/IModerationQueueManager.class.php b/wcfsetup/install/files/lib/system/moderation/queue/IModerationQueueManager.class.php
new file mode 100644 (file)
index 0000000..20ee9ae
--- /dev/null
@@ -0,0 +1,74 @@
+<?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 = '');
+}
diff --git a/wcfsetup/install/files/lib/system/moderation/queue/ModerationQueueActivationManager.class.php b/wcfsetup/install/files/lib/system/moderation/queue/ModerationQueueActivationManager.class.php
new file mode 100644 (file)
index 0000000..7145eec
--- /dev/null
@@ -0,0 +1,83 @@
+<?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);
+       }
+}
diff --git a/wcfsetup/install/files/lib/system/moderation/queue/ModerationQueueManager.class.php b/wcfsetup/install/files/lib/system/moderation/queue/ModerationQueueManager.class.php
new file mode 100644 (file)
index 0000000..2d7dae2
--- /dev/null
@@ -0,0 +1,366 @@
+<?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();
+       }
+}
diff --git a/wcfsetup/install/files/lib/system/moderation/queue/ModerationQueueReportManager.class.php b/wcfsetup/install/files/lib/system/moderation/queue/ModerationQueueReportManager.class.php
new file mode 100644 (file)
index 0000000..8d7025f
--- /dev/null
@@ -0,0 +1,108 @@
+<?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
+               );
+       }
+}
diff --git a/wcfsetup/install/files/lib/system/moderation/queue/activation/IModerationQueueActivationHandler.class.php b/wcfsetup/install/files/lib/system/moderation/queue/activation/IModerationQueueActivationHandler.class.php
new file mode 100644 (file)
index 0000000..ad5305e
--- /dev/null
@@ -0,0 +1,32 @@
+<?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);
+}
diff --git a/wcfsetup/install/files/lib/system/moderation/queue/report/IModerationQueueReportHandler.class.php b/wcfsetup/install/files/lib/system/moderation/queue/report/IModerationQueueReportHandler.class.php
new file mode 100644 (file)
index 0000000..2accf16
--- /dev/null
@@ -0,0 +1,40 @@
+<?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);
+}
index 50282f04f559c15f19cb52b9251b2dc7fa8869cd..04a51a543aa50737bd61e2251944098e2f96993a 100644 (file)
                <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">
@@ -1521,6 +1522,58 @@ Erlaubte Dateiendungen: {', '|implode:$attachmentHandler->getAllowedExtensions()
                <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>
index 4e8209eb8c811113f7eebfed3e4a19de40dbf011..1433ff768ba12814b5ae3cf9aac8b325002b9f06 100644 (file)
@@ -291,6 +291,7 @@ Examples for medium ID detection:
                <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">
@@ -1519,6 +1520,58 @@ Allowed extensions: {', '|implode:$attachmentHandler->getAllowedExtensions()}]]>
                <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>
index b3b452e8665ab23083914c0575ad3a79f2f1bddf..9283a40d733244a06af51be5c6aebd53943cb30f 100644 (file)
@@ -339,6 +339,37 @@ CREATE TABLE wcf1_language_server (
        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,
@@ -1279,6 +1310,13 @@ ALTER TABLE wcf1_user_profile_visitor ADD FOREIGN KEY (userID) REFERENCES wcf1_u
 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