Add article report function
authorJoshua Rüsweg <josh@bastelstu.be>
Tue, 28 Aug 2018 12:30:15 +0000 (14:30 +0200)
committerJoshua Rüsweg <josh@bastelstu.be>
Tue, 28 Aug 2018 12:30:15 +0000 (14:30 +0200)
See #2631

com.woltlab.wcf/objectType.xml
com.woltlab.wcf/templates/article.tpl
com.woltlab.wcf/templates/moderationArticle.tpl [new file with mode: 0644]
wcfsetup/install/files/lib/data/article/Article.class.php
wcfsetup/install/files/lib/system/moderation/queue/report/ArticleModerationQueueReportHandler.class.php [new file with mode: 0644]
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml

index e34a7a2816e1c01b2d205ac0366c843259e5603e..99b1d69fcd72c4f5775d4281040fe8746dfb55a9 100644 (file)
                        <classname>wcf\system\user\notification\object\type\ArticleCommentResponseUserNotificationObjectType</classname>
                        <category>com.woltlab.wcf.page</category>
                </type>
+               <type>
+                       <name>com.woltlab.wcf.article</name>
+                       <definitionname>com.woltlab.wcf.moderation.report</definitionname>
+                       <classname>wcf\system\moderation\queue\report\ArticleModerationQueueReportHandler</classname>
+               </type>
                <!-- /articles -->
                
                <type>
index 923599072adcfb33a77e8cf6359fd5ef80313dae..17da51536114e97cd2f50ada28a4b3c39b410720 100644 (file)
                                        <div class="col-xs-12 col-md-6">
                                                <ul class="articleLikeButtons buttonGroup">
                                                        <li class="jsOnly"><span class="button reactButton{if $articleLikeData[$article->articleID]|isset && $articleLikeData[$article->articleID]->reactionTypeID} active{/if}" title="{lang}wcf.reactions.react{/lang}">{if $articleLikeData[$article->articleID]|isset && $articleLikeData[$article->articleID]->reactionTypeID}{@$__wcf->getReactionHandler()->getReactionTypeByID($articleLikeData[$article->articleID]->reactionTypeID)->renderIcon()}{else}<img src="{$__wcf->getPath()}/images/reaction/reactionIcon.svg" class="reactionType" alt="">{/if}</span></li>
+                                                       <li class="jsReportArticle jsOnly" data-object-id="{@$articleContent->articleContentID}"><a href="#" title="{lang}wcf.moderation.report.reportContent{/lang}" class="button jsTooltip"><span class="icon icon16 fa-exclamation-triangle"></span> <span class="invisible">{lang}wcf.moderation.report.reportContent{/lang}</span></a></li>
                                                </ul>
                                        </div>
                                {/if}
        </script>
 {/if}
 
+{if $__wcf->session->getPermission('user.profile.canReportContent')}
+       <script data-relocate="true">
+               $(function() {
+                       WCF.Language.addObject({
+                               'wcf.moderation.report.reportContent': '{lang}wcf.moderation.report.reportContent{/lang}',
+                               'wcf.moderation.report.success': '{lang}wcf.moderation.report.success{/lang}'
+                       });
+                       new WCF.Moderation.Report.Content('com.woltlab.wcf.article', '.jsReportArticle');
+               });
+       </script>
+{/if}
+
 {include file='footer'}
diff --git a/com.woltlab.wcf/templates/moderationArticle.tpl b/com.woltlab.wcf/templates/moderationArticle.tpl
new file mode 100644 (file)
index 0000000..b385eef
--- /dev/null
@@ -0,0 +1,44 @@
+<article class="message messageReduced">
+       <section class="messageContent">
+               <header class="messageHeader">
+                       <div class="box32 messageHeaderWrapper">
+                               {if $article->getUserProfile()->userID}
+                                       <a href="{link controller='User' object=$article->getUserProfile()->getDecoratedObject()}{/link}">{@$article->getUserProfile()->getAvatar()->getImageTag(32)}</a>
+                               {else}
+                                       <span>{@$article->getUserProfile()->getAvatar()->getImageTag(32)}</span>
+                               {/if}
+                               
+                               <div class="messageHeaderBox">
+                                       <h2 class="messageTitle">
+                                               <a href="{@$article->getLink()}">{$article->getTitle()}</a>
+                                       </h2>
+                                       
+                                       <ul class="messageHeaderMetaData">
+                                               <li>
+                                                       {if $article->getUserProfile()->userID}
+                                                               <a href="{link controller='User' object=$article->getUserProfile()->getDecoratedObject()}{/link}" class="username">{$article->getUserProfile()}</a>
+                                                       {else}
+                                                               {$article->getUserProfile()->username}
+                                                       {/if}
+                                               </li>
+                                               <li><span class="messagePublicationTime">{@$article->time|time}</span></li>
+                                               
+                                               {event name='messageHeaderMetaData'}
+                                       </ul>
+                               </div>
+                       </div>
+                       
+                       {event name='messageHeader'}
+               </header>
+               
+               <div class="messageBody">
+                       {event name='beforeMessageText'}
+                       
+                       <div class="messageText">
+                               {@$article->getFormattedContent()}
+                       </div>
+                       
+                       {event name='afterMessageText'}
+               </div>
+       </section>
+</article>
index 64ba21bb81e482ef8d859eb7dbb325cd5a52f4d8..a9f3b4f047335099d95fd32bf52fa066cc143031 100644 (file)
@@ -4,6 +4,7 @@ use wcf\data\article\category\ArticleCategory;
 use wcf\data\article\content\ArticleContent;
 use wcf\data\DatabaseObject;
 use wcf\data\ILinkableObject;
+use wcf\data\IUserContent;
 use wcf\data\object\type\ObjectTypeCache;
 use wcf\system\article\discussion\CommentArticleDiscussionProvider;
 use wcf\system\article\discussion\IArticleDiscussionProvider;
@@ -34,7 +35,7 @@ use wcf\system\WCF;
  * @property-read      integer         $isDeleted              is 1 if the article is in trash bin, otherwise 0
  * @property-read      integer         $hasLabels              is `1` if labels are assigned to the article
  */
-class Article extends DatabaseObject implements ILinkableObject {
+class Article extends DatabaseObject implements ILinkableObject, IUserContent {
        /**
         * indicates that article is unpublished
         */
@@ -361,4 +362,28 @@ class Article extends DatabaseObject implements ILinkableObject {
                
                return $discussionProviders;
        }
+       
+       /**
+        * @inheritDoc
+        * @since       3.2
+        */
+       public function getTime() {
+               return $this->time;
+       }
+       
+       /**
+        * @inheritDoc
+        * @since       3.2
+        */
+       public function getUserID() {
+               return $this->userID;
+       }
+       
+       /**
+        * @inheritDoc
+        * @since       3.2
+        */
+       public function getUsername() {
+               return $this->username;
+       }
 }
diff --git a/wcfsetup/install/files/lib/system/moderation/queue/report/ArticleModerationQueueReportHandler.class.php b/wcfsetup/install/files/lib/system/moderation/queue/report/ArticleModerationQueueReportHandler.class.php
new file mode 100644 (file)
index 0000000..2613f67
--- /dev/null
@@ -0,0 +1,172 @@
+<?php
+namespace wcf\system\moderation\queue\report;
+use wcf\data\article\ArticleAction;
+use wcf\data\article\ViewableArticle;
+use wcf\data\moderation\queue\ModerationQueue;
+use wcf\data\moderation\queue\ViewableModerationQueue;
+use wcf\system\cache\runtime\ViewableArticleRuntimeCache;
+use wcf\system\moderation\queue\AbstractModerationQueueHandler;
+use wcf\system\moderation\queue\ModerationQueueManager;
+use wcf\system\WCF;
+
+/**
+ * An implementation of IModerationQueueReportHandler for articles.
+ *
+ * @author     Joshua Ruesweg
+ * @copyright  2001-2018 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Suite\System\Moderation\Queue\Report
+ * @since       3.2
+ */
+class ArticleModerationQueueReportHandler extends AbstractModerationQueueHandler implements IModerationQueueReportHandler {
+       /**
+        * @inheritDoc
+        */
+       protected $definitionName = 'com.woltlab.wcf.moderation.report';
+       
+       /**
+        * @inheritDoc
+        */
+       protected $objectType = 'com.woltlab.wcf.article';
+       
+       /**
+        * @inheritDoc
+        */
+       public function canReport($objectID) {
+               if (!$this->isValid($objectID)) {
+                       return false;
+               }
+               
+               if (!$this->getReportedObject($objectID)->canRead()) {
+                       return false;
+               }
+               
+               return true;
+       }
+       
+       /**
+        * @inheritDoc
+        */
+       public function getReportedContent(ViewableModerationQueue $queue) {
+               WCF::getTPL()->assign([
+                       'article' => $this->getArticle($queue->getAffectedObject()->articleID),
+               ]);
+               
+               return WCF::getTPL()->fetch('moderationArticle');
+       }
+       
+       /**
+        * @inheritDoc
+        * 
+        * @return      ViewableArticle|null
+        */
+       public function getReportedObject($objectID) {
+               if ($this->isValid($objectID)) {
+                       return $this->getArticle($objectID);
+               }
+               
+               return null;
+       }
+       
+       /**
+        * @param $articleID
+        * @return ViewableArticle|null
+        */
+       public function getArticle($articleID) {
+               return ViewableArticleRuntimeCache::getInstance()->getObject($articleID);
+       }
+       
+       /**
+        * @inheritDoc
+        */
+       public function assignQueues(array $queues) {
+               $assignments = $orphanedQueueIDs = [];
+               
+               // first cache all articles 
+               foreach ($queues as $queue) {
+                       ViewableArticleRuntimeCache::getInstance()->cacheObjectID($queue->objectID);
+               }
+               
+               // now process articles
+               foreach ($queues as $queue) {
+                       $article = ViewableArticleRuntimeCache::getInstance()->getObject($queue->objectID);
+                       
+                       if ($article === null) {
+                               $orphanedQueueIDs[] = $queue->queueID;
+                       }
+                       else {
+                               if ($article->canDelete()) {
+                                       $assignments[$queue->queueID] = true;
+                               }
+                               else {
+                                       $assignments[$queue->queueID] = false;
+                               }
+                       }
+               }
+               
+               ModerationQueueManager::getInstance()->removeOrphans($orphanedQueueIDs);
+               ModerationQueueManager::getInstance()->setAssignment($assignments);
+       }
+       
+       /**
+        * @inheritDoc
+        */
+       public function getContainerID($objectID) {
+               if ($this->isValid($objectID)) {
+                       return $this->getArticle($objectID)->getCategory()->categoryID;
+               }
+               
+               return 0;
+       }
+       
+       /**
+        * @inheritDoc
+        */
+       public function isValid($objectID) {
+               if ($this->getArticle($objectID) === null) {
+                       return false;
+               }
+               
+               return true;
+       }
+       
+       /**
+        * @inheritDoc
+        */
+       public function populate(array $queues) {
+               // first cache all articles 
+               foreach ($queues as $queue) {
+                       ViewableArticleRuntimeCache::getInstance()->cacheObjectID($queue->objectID);
+               }
+               
+               foreach ($queues as $object) {
+                       $article = ViewableArticleRuntimeCache::getInstance()->getObject($object->objectID);
+                       if ($article !== null) {
+                               $object->setAffectedObject($article->getDecoratedObject());
+                       }
+                       else {
+                               $object->setIsOrphaned();
+                       }
+               }
+       }
+       
+       /**
+        * @inheritDoc
+        */
+       public function canRemoveContent(ModerationQueue $queue) {
+               if ($this->isValid($queue->objectID)) {
+                       return $this->getArticle($queue->objectID)->canDelete();
+               }
+               
+               return false;
+       }
+       
+       /**
+        * @inheritDoc
+        */
+       public function removeContent(ModerationQueue $queue, $message) {
+               if ($this->isValid($queue->objectID)) {
+                       (new ArticleAction([$this->getArticle($queue->objectID)->getDecoratedObject()], 'trash'))->executeAction();
+               }
+       }
+}
\ No newline at end of file
index 967e4a7cd116e17e7df85158179af43e458f1386..1e78d63c051b741b675468df51bcd320ee507911 100644 (file)
@@ -3329,6 +3329,7 @@ E-Mail-Adresse: {@$emailAddress} {* this line ends with a space *}
                <item name="wcf.moderation.type.com.woltlab.wcf.comment.comment"><![CDATA[Kommentar]]></item>
                <item name="wcf.moderation.type.com.woltlab.wcf.comment.response"><![CDATA[Antwort auf Kommentar]]></item>
                <item name="wcf.moderation.type.com.woltlab.wcf.user"><![CDATA[Benutzerprofil]]></item>
+               <item name="wcf.moderation.type.com.woltlab.wcf.article"><![CDATA[Artikel]]></item>
                <item name="wcf.moderation.showAll"><![CDATA[Alle Einträge anzeigen]]></item>
                <item name="wcf.moderation.showDeletedContent"><![CDATA[Gelöschte Inhalte anzeigen]]></item>
                <item name="wcf.moderation.deletedContent.objectTypes"><![CDATA[Gelöschte Inhalte]]></item>
index 847298c6eb863db6c98f72819928a27ff8877d54..809ab2b974695d9224859ef1aae2809eb3aa416e 100644 (file)
@@ -3276,6 +3276,7 @@ Email: {@$emailAddress} {* this line ends with a space *}
                <item name="wcf.moderation.type.com.woltlab.wcf.comment.comment"><![CDATA[Comment]]></item>
                <item name="wcf.moderation.type.com.woltlab.wcf.comment.response"><![CDATA[Comment Reply]]></item>
                <item name="wcf.moderation.type.com.woltlab.wcf.user"><![CDATA[User Profile]]></item>
+               <item name="wcf.moderation.type.com.woltlab.wcf.article"><![CDATA[Article]]></item>
                <item name="wcf.moderation.showAll"><![CDATA[Display All Items]]></item>
                <item name="wcf.moderation.showDeletedContent"><![CDATA[Display Deleted Content]]></item>
                <item name="wcf.moderation.deletedContent.objectTypes"><![CDATA[Deleted Content]]></item>