Removing participants and displaying inline log entries
authorAlexander Ebert <ebert@woltlab.com>
Wed, 6 Mar 2013 19:17:10 +0000 (20:17 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Wed, 6 Mar 2013 19:17:10 +0000 (20:17 +0100)
files/js/WCF.Conversation.js
files/lib/data/conversation/ConversationAction.class.php
files/lib/data/conversation/ConversationEditor.class.php
files/lib/data/modification/log/ConversationLogModificationLogList.class.php
files/lib/page/ConversationPage.class.php
files/lib/system/log/modification/ConversationModificationLogHandler.class.php
language/de.xml
templates/conversation.tpl
templates/conversationMessageList.tpl
templates/conversationMessageListLog.tpl [new file with mode: 0644]

index 6402e6e437f97e0a794f0a481e93e2be8cbd6d52..051c152bfecc1ab8d2ffa36bd13f18387f4db9d7 100644 (file)
@@ -2,7 +2,7 @@
  * Namespace for conversations.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2011 WoltLab GmbH
+ * @copyright  2001-2013 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  */
 WCF.Conversation = { };
@@ -790,6 +790,50 @@ WCF.Conversation.AddParticipants = Class.extend({
        }
 });
 
+/**
+ * Provides methods to remove participants from conversations.
+ * 
+ * @see        WCF.Action.Delete
+ */
+WCF.Conversation.RemoveParticipant = WCF.Action.Delete.extend({
+       /**
+        * conversation id
+        * @var integer
+        */
+       _conversationID: 0,
+       
+       /**
+        * @see WCF.Action.Delete.init()
+        */
+       init: function(conversationID) {
+               this._conversationID = conversationID;
+               this._super('wcf\\data\\conversation\\ConversationAction', '.jsParticipant');
+       },
+       
+       /**
+        * @see WCF.Action.Delete._sendRequest()
+        */
+       _sendRequest: function(object) {
+               this.proxy.setOption('data', {
+                       actionName: 'removeParticipant',
+                       className: this._className,
+                       objectIDs: [ this._conversationID ],
+                       parameters: {
+                               userID: $(object).data('objectID')
+                       }
+               });
+               
+               this.proxy.sendRequest();
+       },
+       
+       /**
+        * @see WCF.Action.Delete._success()
+        */
+       _success: function(data, textStatus, jqXHR) {
+               this.triggerEffect([ data.returnValues.userID ]);
+       }
+});
+
 /**
  * Namespace for label-related classes.
  */
index 70a9d8ad7d3da2498e302af2542ab14029003e2a..d7e47a663f497666d729b97e4a272e98b745797c 100644 (file)
@@ -584,6 +584,44 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                );
        }
        
+       /**
+        * Validates parameters to remove a participant from a conversation.
+        */
+       public function validateRemoveParticipant() {
+               $this->readInteger('userID');
+               
+               // validate conversation
+               $this->conversation = $this->getSingleObject();
+               if (!$this->conversation->conversationID) {
+                       throw new UserInputException('objectIDs');
+               }
+               
+               // check ownership
+               if ($this->conversation->userID != WCF::getUser()->userID) {
+                       throw new PermissionDeniedException();
+               }
+               
+               // validate participants
+               if ($this->parameters['userID'] == WCF::getUser()->userID || !Conversation::isParticipant(array($this->conversation->conversationID)) || !Conversation::isParticipant(array($this->conversation->conversationID), $this->parameters['userID'])) {
+                       throw new PermissionDeniedException();
+               }
+               
+       }
+       
+       /**
+        * Removes a participant from a conversation.
+        */
+       public function removeParticipant() {
+               $this->conversation->removeParticipant($this->parameters['userID']);
+               $this->conversation->updateParticipantSummary();
+               
+               ConversationModificationLogHandler::getInstance()->removeParticipant($this->conversation->getDecoratedObject(), $this->parameters['userID']);
+               
+               return array(
+                       'userID' => $this->parameters['userID']
+               );
+       }
+       
        /**
         * Adds conversation modification data.
         * 
index 89c8e70fb487b1f4bbe2856f7fbc82ff6b1efca9..dcfead6501bd2f033a50b1b82cf831e16c8dfecd 100644 (file)
@@ -99,6 +99,22 @@ class ConversationEditor extends DatabaseObjectEditor {
                ));
        }
        
+       /**
+        * Removes a participant from this conversation.
+        * 
+        * @param       integer         $userID
+        */
+       public function removeParticipant($userID) {
+               $sql = "DELETE FROM     wcf".WCF_N."_conversation_to_user
+                       WHERE           conversationID = ?
+                                       AND participantID = ?";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute(array(
+                       $this->conversationID,
+                       $userID
+               ));
+       }
+       
        /**
         * Updates the participant summary of the given conversations.
         * 
index 76445568dc975522c7f56d40f62b9336f2f4113f..6233658f307ede3f3e048303f18bb17ca7336336 100644 (file)
@@ -97,4 +97,27 @@ class ConversationLogModificationLogList extends ModificationLogList {
                }
                unset($object);
        }
+       
+       /**
+        * Returns all log entries created before given point of time. Applicable entries
+        * will be returned and removed from collection.
+        * 
+        * @param       integer         $time
+        * @return      array<wcf\data\modification\log\ViewableConversationModificationLog>
+        */
+       public function getEntriesUntil($time) {
+               $entries = array();
+               foreach ($this->objects as $index => $entry) {
+                       if ($entry->time < $time) {
+                               $entries[] = $entry;
+                               unset($this->objects[$index]);
+                       }
+               }
+               
+               if (!empty($entries)) {
+                       $this->indexToObject = array_keys($this->objects);
+               }
+               
+               return $entries;
+       }
 }
index 7d2b4983a277020aa3b1963fe50ec145e8b3a93e..27b865d1af1da80462dd13791c927c06a39a65ba 100644 (file)
@@ -1,5 +1,7 @@
 <?php
 namespace wcf\page;
+use wcf\data\modification\log\ConversationLogModificationLogList;
+
 use wcf\data\conversation\label\ConversationLabel;
 use wcf\data\conversation\message\ConversationMessage;
 use wcf\data\conversation\Conversation;
@@ -67,8 +69,8 @@ class ConversationPage extends MultipleLinkPage {
        public $conversationID = 0;
        
        /**
-        * conversation object
-        * @var wcf\data\conversation\Conversation
+        * viewable conversation object
+        * @var wcf\data\conversation\ViewableConversation
         */
        public $conversation = null;
        
@@ -90,6 +92,12 @@ class ConversationPage extends MultipleLinkPage {
         */
        public $message = null;
        
+       /**
+        * modification log list object
+        * @var wcf\data\wcf\data\modification\log\ConversationLogModificationLogList
+        */
+       public $modificationLogList = null;
+       
        /**
         * sidebar factory object
         * @var wcf\system\message\sidebar\MessageSidebarFactory
@@ -186,6 +194,26 @@ class ConversationPage extends MultipleLinkPage {
                                'canViewPreview' => true                
                        ));
                }
+               
+               // get timeframe for modifications
+               $this->objectList->rewind();
+               $startTime = $this->objectList->current()->time;
+               
+               $count = count($this->objectList);
+               if ($count == 1) {
+                       $endTime = $startTime;
+               }
+               else {
+                       $this->objectList->seek($count - 1);
+                       $endTime = $this->objectList->current()->time;
+               }
+               $this->objectList->rewind();
+               
+               // load modification log entries
+               $this->modificationLogList = new ConversationLogModificationLogList();
+               $this->modificationLogList->setConversation($this->conversation->getDecoratedObject());
+               $this->modificationLogList->getConditionBuilder()->add("modification_log.time BETWEEN ? AND ?", array($startTime, $endTime));
+               $this->modificationLogList->readObjects();
        }
        
        /**
@@ -199,6 +227,7 @@ class ConversationPage extends MultipleLinkPage {
                WCF::getTPL()->assign(array(
                        'attachmentList' => $this->objectList->getAttachmentList(),
                        'labelList' => $this->labelList,
+                       'modificationLogList' => $this->modificationLogList,
                        'sidebarFactory' => $this->sidebarFactory,
                        'sortOrder' => $this->sortOrder,
                        'conversation' => $this->conversation,
index f55580b3e99685cb8074cd3ad5658fcd6f202491..7109722dfafe1c4c9e7498b2d4cfb201b272d0a1 100644 (file)
@@ -1,13 +1,14 @@
 <?php
 namespace wcf\system\log\modification;
 use wcf\data\conversation\Conversation;
+use wcf\data\user\User;
 use wcf\data\user\UserList;
 
 /**
  * Handles conversation modification logs.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2012 WoltLab GmbH
+ * @copyright  2001-2013 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    com.woltlab.wcf.conversation
  * @subpackage system.log.modification
@@ -55,6 +56,20 @@ class ConversationModificationLogHandler extends ModificationLogHandler {
                $this->add($conversation, 'open');
        }
        
+       /**
+        * Adds a log entry for a removed participant.
+        * 
+        * @param       wcf\data\conversation\Conversation      $conversation
+        * @param       integer                                 $userID
+        */
+       public function removeParticipant(Conversation $conversation, $userID) {
+               $user = new User($userID);
+               $this->add($conversation, 'removeParticipant', array(
+                       'userID' => $userID,
+                       'username' => $user->username
+               ));
+       }
+       
        /**
         * Adds a conversation modification log entry.
         * 
index 722e46973831711d6c3c88bd474fd8d26bc46a9f..7ce472af1243b91dc74147fde6a96f1439fbaec5 100644 (file)
@@ -51,6 +51,8 @@
                <item name="wcf.conversation.participants"><![CDATA[Teilnehmer]]></item>
                <item name="wcf.conversation.participants.description"><![CDATA[Mehrere Teilnehmer können mit Komma getrennt angegeben werden.]]></item>
                <item name="wcf.conversation.participants.error.mailboxIsFull"><![CDATA[{$errorData[username]} hat das zulässige Limit für Konversationen bereits erreicht und kann an keinen neuen Konversation teilnehmen.]]></item>
+               <item name="wcf.conversation.participants.removeParticipant"><![CDATA[Teilnehmer entfernen]]></item>
+               <item name="wcf.conversation.participants.removeParticipant.confirmMessage"><![CDATA[Möchten Sie „{$participant->username}“ wirklich aus dieser Konversation entfernen?]]></item>
                <item name="wcf.conversation.quota"><![CDATA[Speicherplatz]]></item>
                <item name="wcf.conversation.quota.description"><![CDATA[{#$conversationCount/$maxConversationCount*100}% belegt ({#$conversationCount} von {#$maxConversationCount})]]></item>
                <item name="wcf.conversation.replies"><![CDATA[Antworten]]></item>
@@ -96,7 +98,8 @@
                <item name="wcf.conversation.log.time"><![CDATA[Datum]]></item>
                <item name="wcf.conversation.log.conversation.open"><![CDATA[Konversation geöffnet]]></item>
                <item name="wcf.conversation.log.conversation.close"><![CDATA[Konversation geschlossen]]></item>
-               <item name="wcf.conversation.log.conversation.addParticipants"><![CDATA[Neue Teilnehmer wurden hinzugefügt: {implode from=$additionalData[participants] item=participant}<a href="{link controller='User' id=$participant[userID] title=$participant[username]}{/link}">{$participant[username]}</a>{/implode}]]></item>
+               <item name="wcf.conversation.log.conversation.addParticipants"><![CDATA[Neue Teilnehmer wurden hinzugefügt: {implode from=$additionalData[participants] item=participant}<a href="{link controller='User' id=$participant[userID] title=$participant[username]}{/link}" class="userLink" data-user-id="{@$participant[userID]}">{$participant[username]}</a>{/implode}]]></item>
+               <item name="wcf.conversation.log.conversation.removeParticipant"><![CDATA[Ein Teilnehmer wurde entfernt: <a href="{link controller='User' id=$additionalData[userID] title=$additionalData[username]}{/link}" class="userLink" data-user-id="{@$additionalData[userID]}">{$additionalData[username]}</a>]]></item>
        </category>
        
        <category name="wcf.search">
index dbb7216c58d1bae80c0cb8a72aeca2e2ffec9416..1c829a5d9c1af29949eb89597e7006eafd438dbe 100644 (file)
@@ -35,6 +35,7 @@
                        {if !$conversation->isClosed}new WCF.Conversation.QuickReply($quoteManager);{/if}
                        
                        new WCF.Moderation.Report.Content('com.woltlab.wcf.conversation.message', '.jsReportConversationMessage');
+                       new WCF.Conversation.RemoveParticipant({@$conversation->conversationID});
                });
                //]]>
        </script>
                        
                        <ul class="containerBoxList tripleColumned conversationParticipantList">
                                {foreach from=$participants item=participant}
-                                       <li>
+                                       <li class="jsParticipant">
                                                <div class="box24">
                                                        <a href="{link controller='User' object=$participant}{/link}" class="framed">{@$participant->getAvatar()->getImageTag(24)}</a>
                                                        <hgroup>
-                                                               <h1><a href="{link controller='User' object=$participant}{/link}" class="userLink{if $participant->hideConversation == 2} conversationLeft{/if}" data-user-id="{@$participant->userID}">{$participant->username}</a>
-                                                               {if $participant->isInvisible}<small>({lang}wcf.conversation.invisible{/lang})</small>{/if}
+                                                               <h1>
+                                                                       <a href="{link controller='User' object=$participant}{/link}" class="userLink{if $participant->hideConversation == 2} conversationLeft{/if}" data-user-id="{@$participant->userID}">{$participant->username}</a>
+                                                                       {if $participant->isInvisible}<small>({lang}wcf.conversation.invisible{/lang})</small>{/if}
+                                                                       {if ($conversation->userID == $__wcf->getUser()->userID) && ($participant->userID != $__wcf->getUser()->userID)}
+                                                                               <a class="jsDeleteButton jsTooltip" title="{lang}wcf.conversation.participants.removeParticipant{/lang}" data-confirm-message="{lang}wcf.conversation.participants.removeParticipant.confirmMessage{/lang}" data-object-id="{@$participant->userID}"><span class="icon icon16 icon-remove"></span></a>
+                                                                       {/if}
                                                                </h1>
                                                                <h2><dl class="plain inlineDataList">
                                                                        <dt>{lang}wcf.conversation.lastVisitTime{/lang}</dt>
index 67fd9d764acefea6e8444c83ca082b916ee06c3c..40a48df29b7d67954b8323202cf4edc5db84e5f7 100644 (file)
@@ -1,4 +1,7 @@
 {foreach from=$objects item=message}
+       {assign var=__modificationLogTime value=$message->time}
+       {include file='conversationMessageListLog'}
+       
        {if !$conversation|isset && $container|isset}{assign var=conversation value=$container}{/if}
        {assign var='objectID' value=$message->messageID}
        {assign var='userProfile' value=$message->getUserProfile()}
@@ -54,3 +57,6 @@
                </article>
        </li>
 {/foreach}
+
+{assign var=__modificationLogTime value=TIME_NOW}
+{include file='conversationMessageListLog'}
diff --git a/templates/conversationMessageListLog.tpl b/templates/conversationMessageListLog.tpl
new file mode 100644 (file)
index 0000000..f42b0ee
--- /dev/null
@@ -0,0 +1,23 @@
+{if $modificationLogList|isset}
+       {assign var=__modificationLogEntries value=$modificationLogList->getEntriesUntil($__modificationLogTime)}
+       {foreach from=$__modificationLogEntries item=modificationLogEntry}
+               <li class="marginTop jsModificationLogEntry">
+                       <article class="message messageCollapsed">
+                               <div class="messageHeader">
+                                       <div class="box24">
+                                               <span class="icon icon16 icon-tasks"></span>
+                                               
+                                               <hgroup>
+                                                       <h1>{@$modificationLogEntry}</h1>
+                                                       <h2>
+                                                               <a href="{link controller='User' id=$modificationLogEntry->userID title=$modificationLogEntry->username}{/link}" class="userLink" data-user-id="{@$modificationLogEntry->userID}">{$modificationLogEntry->username}</a>
+                                                               -
+                                                               {@$modificationLogEntry->time|time}
+                                                       </h2>
+                                               </hgroup>
+                                       </div>
+                               </div>
+                       </article>
+               </li>
+       {/foreach}
+{/if}
\ No newline at end of file