Merge branch '3.1' into 5.2
authorMatthias Schmidt <gravatronics@live.com>
Mon, 26 Apr 2021 14:37:39 +0000 (16:37 +0200)
committerMatthias Schmidt <gravatronics@live.com>
Mon, 26 Apr 2021 14:37:39 +0000 (16:37 +0200)
107 files changed:
.github/javascript-syntax.json [new file with mode: 0644]
.github/php-syntax.json [new file with mode: 0644]
.github/workflows/codestyle.yml [new file with mode: 0644]
.github/workflows/javascript.yml [new file with mode: 0644]
.github/workflows/php.yml [new file with mode: 0644]
.phpcs.xml [new file with mode: 0644]
.travis.yml [deleted file]
acptemplates/__userGroupAddCanBeAddedAsConversationParticipant.tpl [new file with mode: 0644]
clipboardAction.xml
constants.php
coreObject.xml
eventListener.xml
files/acp/install_com.woltlab.wcf.conversation.php
files/acp/update_com.woltlab.wcf.conversation_3.1_addColumn.php [deleted file]
files/acp/update_com.woltlab.wcf.conversation_5.2.php [new file with mode: 0644]
files/js/WCF.Conversation.js
files/js/WoltLabSuite.Core.Conversation.min.js
files/js/WoltLabSuite.Core.Conversation.tiny.min.js
files/js/WoltLabSuite/Core/Conversation/Ui/Participant/Add.js
files/js/WoltLabSuite/Core/Conversation/Ui/Subject/Editor.js
files/lib/data/conversation/Conversation.class.php
files/lib/data/conversation/ConversationAction.class.php
files/lib/data/conversation/ConversationEditor.class.php
files/lib/data/conversation/ConversationList.class.php
files/lib/data/conversation/ConversationParticipantList.class.php
files/lib/data/conversation/FeedConversation.class.php
files/lib/data/conversation/FeedConversationList.class.php
files/lib/data/conversation/UserConversationList.class.php
files/lib/data/conversation/ViewableConversation.class.php
files/lib/data/conversation/label/ConversationLabel.class.php
files/lib/data/conversation/label/ConversationLabelAction.class.php
files/lib/data/conversation/label/ConversationLabelEditor.class.php
files/lib/data/conversation/label/ConversationLabelList.class.php
files/lib/data/conversation/message/ConversationMessage.class.php
files/lib/data/conversation/message/ConversationMessageAction.class.php
files/lib/data/conversation/message/ConversationMessageEditor.class.php
files/lib/data/conversation/message/ConversationMessageList.class.php
files/lib/data/conversation/message/SearchResultConversationMessage.class.php
files/lib/data/conversation/message/SearchResultConversationMessageList.class.php
files/lib/data/conversation/message/SimplifiedViewableConversationMessageList.class.php
files/lib/data/conversation/message/ViewableConversationMessage.class.php
files/lib/data/conversation/message/ViewableConversationMessageList.class.php
files/lib/data/modification/log/ConversationLogModificationLogList.class.php
files/lib/data/modification/log/ViewableConversationModificationLog.class.php
files/lib/form/ConversationAddForm.class.php
files/lib/form/ConversationDraftEditForm.class.php
files/lib/page/ConversationFeedPage.class.php
files/lib/page/ConversationListPage.class.php
files/lib/page/ConversationPage.class.php
files/lib/system/attachment/ConversationMessageAttachmentObjectType.class.php
files/lib/system/cache/runtime/ConversationRuntimeCache.class.php
files/lib/system/cache/runtime/UserConversationRuntimeCache.class.php
files/lib/system/clipboard/action/ConversationClipboardAction.class.php
files/lib/system/conversation/ConversationHandler.class.php
files/lib/system/event/listener/ConversationPruneIpAddressesCronjobListener.class.php [new file with mode: 0644]
files/lib/system/event/listener/ConversationUserActionRenameListener.class.php
files/lib/system/event/listener/ConversationUserMergeListener.class.php
files/lib/system/event/listener/UserGroupAddCanBeAddedAsConversationParticipantListener.class.php [new file with mode: 0644]
files/lib/system/importer/ConversationAttachmentImporter.class.php
files/lib/system/importer/ConversationImporter.class.php
files/lib/system/importer/ConversationLabelImporter.class.php
files/lib/system/importer/ConversationMessageImporter.class.php
files/lib/system/importer/ConversationUserImporter.class.php
files/lib/system/log/modification/ConversationModificationLogHandler.class.php
files/lib/system/message/quote/ConversationMessageQuoteHandler.class.php
files/lib/system/moderation/queue/report/ConversationMessageModerationQueueReportHandler.class.php
files/lib/system/page/handler/ConversationListPageHandler.class.php
files/lib/system/page/handler/DefaultConversationRelatedPageHandler.class.php
files/lib/system/page/handler/TConversationOnlineLocationPageHandler.class.php
files/lib/system/search/ConversationMessageSearch.class.php
files/lib/system/stat/ConversationMessageStatDailyHandler.class.php
files/lib/system/stat/ConversationStatDailyHandler.class.php
files/lib/system/user/content/provider/ConversationMessageUserContentProvider.class.php [new file with mode: 0644]
files/lib/system/user/content/provider/ConversationUserContentProvider.class.php [new file with mode: 0644]
files/lib/system/user/notification/event/ConversationMessageUserNotificationEvent.class.php
files/lib/system/user/notification/event/ConversationUserNotificationEvent.class.php
files/lib/system/user/notification/event/TTestableConversationRelatedUserNotificationEvent.class.php
files/lib/system/user/notification/object/ConversationMessageUserNotificationObject.class.php
files/lib/system/user/notification/object/ConversationUserNotificationObject.class.php
files/lib/system/user/notification/object/type/ConversationMessageNotificationObjectType.class.php
files/lib/system/user/notification/object/type/ConversationNotificationObjectType.class.php
files/lib/system/worker/ConversationMessageRebuildDataWorker.class.php
files/lib/system/worker/ConversationRebuildDataWorker.class.php
install.sql
language/de.xml
language/en.xml
objectType.xml
option.xml
package.xml
page.xml
templateListener.xml
templates/__userPanelConversationDropdown.tpl
templates/__userStartConversation.tpl [deleted file]
templates/conversation.tpl
templates/conversationAdd.tpl
templates/conversationAddParticipants.tpl
templates/conversationLabelManagement.tpl
templates/conversationLeave.tpl
templates/conversationList.tpl
templates/conversationMessageListLog.tpl
templates/conversationMessagePreview.tpl
templates/conversationQuickReply.tpl
templates/moderationConversationMessage.tpl
update_3.1.sql [deleted file]
userGroupOption.xml
userNotificationEvent.xml
userOption.xml

diff --git a/.github/javascript-syntax.json b/.github/javascript-syntax.json
new file mode 100644 (file)
index 0000000..151a7c6
--- /dev/null
@@ -0,0 +1,15 @@
+{
+  "problemMatcher": [
+    {
+      "owner": "node -c",
+      "pattern": [
+        {
+          "regexp": "^(./\\S+):(\\d+) - (.*)$",
+          "file": 1,
+          "line": 2,
+          "message": 3
+        }
+      ]
+    }
+  ]
+}
diff --git a/.github/php-syntax.json b/.github/php-syntax.json
new file mode 100644 (file)
index 0000000..c9c5738
--- /dev/null
@@ -0,0 +1,15 @@
+{
+  "problemMatcher": [
+    {
+      "owner": "php -l",
+      "pattern": [
+        {
+          "regexp": "^\\s*(PHP\\s+)?([a-zA-Z\\s]+):\\s+(.*)\\s+in\\s+(\\S+)\\s+on\\s+line\\s+(\\d+)$",
+          "file": 4,
+          "line": 5,
+          "message": 3
+        }
+      ]
+    }
+  ]
+}
diff --git a/.github/workflows/codestyle.yml b/.github/workflows/codestyle.yml
new file mode 100644 (file)
index 0000000..485c149
--- /dev/null
@@ -0,0 +1,18 @@
+name: Code Style
+
+on:
+  push:
+    branches:
+    - "5.2"
+    - "5.3"
+    - master
+  pull_request:
+
+jobs:
+  php:
+    name: PHP CodeSniffer
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v2
+    - run: git clone --branch=5.2 --depth=1 --quiet git://github.com/WoltLab/WCF.git WCF
+    - uses: chekalsky/phpcs-action@e269c2f264f400adcda7c6b24c8550302350d495
diff --git a/.github/workflows/javascript.yml b/.github/workflows/javascript.yml
new file mode 100644 (file)
index 0000000..c2ef1b5
--- /dev/null
@@ -0,0 +1,31 @@
+name: JavaScript
+
+on:
+  push:
+    branches:
+    - "5.2"
+    - "5.3"
+    - master
+  pull_request:
+
+jobs:
+  syntax:
+    name: "Check Syntax"
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+    steps:
+    - name: Set up node.js
+      uses: actions/setup-node@v1
+      with:
+        node-version: "12"
+    - uses: actions/checkout@v2
+    - run: echo "::add-matcher::.github/javascript-syntax.json"
+    - name: Remove files to be ignored
+      run: |
+        true
+    - run: |
+        ! find . -type f -name '*.js' -exec node -c '{}' \; 2>&1 \
+          |awk 'BEGIN {m=0} /(.js):[0-9]+$/ {m=1; printf "%s - ",$0} m==1 && /^SyntaxError/ { m=0; print }' \
+          |sed "s@$(pwd)@.@" \
+          |grep '^'
diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml
new file mode 100644 (file)
index 0000000..6a06b52
--- /dev/null
@@ -0,0 +1,36 @@
+name: PHP
+
+on:
+  push:
+    branches:
+    - "5.2"
+    - "5.3"
+    - master
+  pull_request:
+
+jobs:
+  syntax:
+    name: "Check Syntax (${{ matrix.php }})"
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        php:
+        - '7.0'
+        - '7.1'
+        - '7.2'
+        - '7.3'
+        - '7.4'
+        - '8.0'
+    steps:
+    - name: Set up PHP
+      uses: shivammathur/setup-php@v2
+      with:
+        php-version: ${{ matrix.php }}
+    - uses: actions/checkout@v2
+    - run: echo "::add-matcher::.github/php-syntax.json"
+    - name: Remove files to be ignored
+      run: |
+        true
+    - run: |
+        ! find . -type f -name '*.php' -exec php -l '{}' \; 2>&1 |grep -v '^No syntax errors detected'
diff --git a/.phpcs.xml b/.phpcs.xml
new file mode 100644 (file)
index 0000000..57a48ad
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<ruleset>
+       <file>files/</file>
+       <arg name="extensions" value="php" />
+       <arg value="p"/>
+       <arg name="basepath" value="."/>
+
+       <rule ref="./WCF/CodeSniff/WCF/ruleset.xml"/>
+</ruleset>
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644 (file)
index 1f467ee..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-language: php
-sudo: false
-dist: trusty
-php:
-  - 7.1
-  - 5.5
-before_install:
-  - export PATH="$PATH:$(composer global config bin-dir --absolute)"
-  - composer global require "squizlabs/php_codesniffer=3.*"
-  - phpenv rehash
-before_script:
-  - git clone --branch=master --depth=1 --quiet git://github.com/WoltLab/WCF.git WCF
-script:
-  - find files -type f -name '*.php' |xargs -I file php -l file
-  - phpcs -p --extensions=php --standard="`pwd`/WCF/CodeSniff/WCF" files
diff --git a/acptemplates/__userGroupAddCanBeAddedAsConversationParticipant.tpl b/acptemplates/__userGroupAddCanBeAddedAsConversationParticipant.tpl
new file mode 100644 (file)
index 0000000..21abf0f
--- /dev/null
@@ -0,0 +1,8 @@
+{if MODULE_CONVERSATION && ($action == 'add' || $group->groupType > 3)}
+       <dl>
+               <dt></dt>
+               <dd>
+                       <label><input type="checkbox" id="canBeAddedAsConversationParticipant" name="canBeAddedAsConversationParticipant" value="1"{if $canBeAddedAsConversationParticipant} checked{/if}> {lang}wcf.acp.group.canBeAddedAsConversationParticipant{/lang}</label>
+               </dd>
+       </dl>
+{/if}
index 4ef07f3f9343d03fc295fb47ad62b5a191d17e33..7653b899718b57ccf26edf31e61f41fc08cb5094 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/vortex/clipboardAction.xsd">
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/2019/clipboardAction.xsd">
        <import>
                <!-- conversation -->
                <action name="assignLabel">
@@ -51,6 +51,5 @@
                                <page>wcf\page\ConversationListPage</page>
                        </pages>
                </action>
-               <!-- /conversation -->
        </import>
 </data>
index e2eb8a4ff0f78a3d22652a339f0119ec15bb1cc6..487355fe33180957b1bf43b745610b075196536b 100644 (file)
@@ -3,7 +3,7 @@
  * Defines constants for autocompletion in IDEs. This file is not meant to be actively used anywhere!
  *
  * @author     Matthias Schmidt
- * @copyright  2001-2017 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core
  */
index 8e661ce515d6b3a33ab35902993b24340d6c6622..42fdba3053f4966da639287d801dd5026b49ddd7 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/vortex/coreObject.xsd">
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/2019/coreObject.xsd">
        <import>
                <coreobject>
                        <objectname>wcf\system\conversation\ConversationHandler</objectname>
index 9d9ec72873d244da6a8e5bc253a63bb80c27672e..6be706bc52ac0115c48f3eddae1015f3ea6be553 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/vortex/eventListener.xsd">
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/2019/eventListener.xsd">
        <import>
                <eventlistener name="userMerge">
                        <eventclassname>wcf\acp\form\UserMergeForm</eventclassname>
@@ -7,12 +7,10 @@
                        <listenerclassname>wcf\system\event\listener\ConversationUserMergeListener</listenerclassname>
                        <environment>admin</environment>
                </eventlistener>
-               
                <eventlistener name="userRenameUser">
                        <eventclassname>wcf\data\user\UserAction</eventclassname>
                        <eventname>rename</eventname>
                        <listenerclassname>wcf\system\event\listener\ConversationUserActionRenameListener</listenerclassname>
-                       <environment>user</environment>
                </eventlistener>
                <eventlistener name="userRenameAdmin">
                        <eventclassname>wcf\data\user\UserAction</eventclassname>
                        <listenerclassname>wcf\system\event\listener\ConversationUserActionRenameListener</listenerclassname>
                        <environment>admin</environment>
                </eventlistener>
-       </import>
-       
-       <delete>
-               <eventlistener>
-                       <eventclassname>wcf\acp\form\UserMergeForm</eventclassname>
-                       <eventname>save</eventname>
-                       <listenerclassname>wcf\system\event\listener\ConversationUserMergeListener</listenerclassname>
+               <eventlistener name="pruneIpAddresses">
+                       <eventclassname>wcf\system\cronjob\PruneIpAddressesCronjob</eventclassname>
+                       <eventname>execute</eventname>
+                       <listenerclassname>wcf\system\event\listener\ConversationPruneIpAddressesCronjobListener</listenerclassname>
+                       <environment>user</environment>
+               </eventlistener>
+               <eventlistener name="pruneIpAddressesAdmin">
+                       <eventclassname>wcf\system\cronjob\PruneIpAddressesCronjob</eventclassname>
+                       <eventname>execute</eventname>
+                       <listenerclassname>wcf\system\event\listener\ConversationPruneIpAddressesCronjobListener</listenerclassname>
                        <environment>admin</environment>
                </eventlistener>
-               
-               <eventlistener>
-                       <eventclassname>wcf\data\user\UserAction</eventclassname>
-                       <eventname>rename</eventname>
-                       <listenerclassname>wcf\system\event\listener\ConversationUserActionRenameListener</listenerclassname>
-                       <environment>user</environment>
+               <eventlistener name="userGroupAddCanBeAddedAsConversationParticipant">
+                       <eventclassname>wcf\acp\form\UserGroupAddForm</eventclassname>
+                       <eventname>assignVariables,readFormParameters,save</eventname>
+                       <listenerclassname>wcf\system\event\listener\UserGroupAddCanBeAddedAsConversationParticipantListener</listenerclassname>
+                       <environment>admin</environment>
+                       <inherit>1</inherit>
                </eventlistener>
-               <eventlistener>
-                       <eventclassname>wcf\data\user\UserAction</eventclassname>
-                       <eventname>rename</eventname>
-                       <listenerclassname>wcf\system\event\listener\ConversationUserActionRenameListener</listenerclassname>
+               <eventlistener name="userGroupEditCanBeAddedAsConversationParticipant">
+                       <eventclassname>wcf\acp\form\UserGroupEditForm</eventclassname>
+                       <eventname>readData</eventname>
+                       <listenerclassname>wcf\system\event\listener\UserGroupAddCanBeAddedAsConversationParticipantListener</listenerclassname>
                        <environment>admin</environment>
                </eventlistener>
-       </delete>
+       </import>
 </data>
index 07d45ccbe4df74e56d604edb9442efce4318c81b..a56bfc3f17bbef9cb0f202d1701cd23fc8378738 100644 (file)
@@ -4,7 +4,7 @@ use wcf\system\WCF;
 
 /**
  * @author     Matthias Schmidt
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  */
 // set default mod permissions
diff --git a/files/acp/update_com.woltlab.wcf.conversation_3.1_addColumn.php b/files/acp/update_com.woltlab.wcf.conversation_3.1_addColumn.php
deleted file mode 100644 (file)
index 740680f..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-use wcf\system\package\SplitNodeException;
-use wcf\system\WCF;
-use wcf\util\StringUtil;
-
-/**
- * Adds database columns, each row in the data section
- * below is executed in a separate request.
- * 
- * @author     Alexander Ebert
- * @copyright  2001-2018 WoltLab GmbH
- * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    WoltLabSuite\Core\Conversation
- */
-$data = <<<DATA
-ALTER TABLE wcf1_conversation_to_user ADD COLUMN joinedAt INT(10) NOT NULL DEFAULT 0, ADD COLUMN leftAt INT(10) NOT NULL DEFAULT 0, ADD COLUMN lastMessageID INT(10) NULL;
-DATA;
-
-$lines = explode("\n", StringUtil::trim($data));
-
-$rebuildData = WCF::getSession()->getVar('__wcfConversationUpdateAddColumns');
-if ($rebuildData === null) {
-       $rebuildData = [
-               'i' => 0,
-               'max' => count($lines)
-       ];
-}
-
-// MySQL adds a column by creating a new table in the
-// background and copying over all the data afterwards.
-// 
-// Using a single `ALTER TABLE` to add multiple columns
-// results in the same runtime, because copying the table
-// is what actually takes ages.
-$statement = WCF::getDB()->prepareStatement(str_replace('wcf1_', 'wcf'.WCF_N.'_', $lines[$rebuildData['i']]));
-$statement->execute();
-
-$rebuildData['i']++;
-
-if ($rebuildData['i'] === $rebuildData['max']) {
-       WCF::getSession()->unregister('__wcfConversationUpdateAddColumns');
-}
-else {
-       WCF::getSession()->register('__wcfConversationUpdateAddColumns', $rebuildData);
-       
-       // call this script again
-       throw new SplitNodeException();
-}
diff --git a/files/acp/update_com.woltlab.wcf.conversation_5.2.php b/files/acp/update_com.woltlab.wcf.conversation_5.2.php
new file mode 100644 (file)
index 0000000..ee50c43
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+use wcf\system\database\table\column\DefaultFalseBooleanDatabaseTableColumn;
+use wcf\system\database\table\column\DefaultTrueBooleanDatabaseTableColumn;
+use wcf\system\database\table\DatabaseTable;
+use wcf\system\database\table\DatabaseTableChangeProcessor;
+use wcf\system\package\plugin\ScriptPackageInstallationPlugin;
+use wcf\system\WCF;
+
+/**
+ * @author      Alexander Ebert
+ * @copyright   2001-2019 WoltLab GmbH
+ * @license     GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ */
+
+$tables = [
+       DatabaseTable::create('wcf1_conversation_to_user')
+               ->columns([
+                       DefaultTrueBooleanDatabaseTableColumn::create('leftByOwnChoice')
+               ]),
+       
+       DatabaseTable::create('wcf1_user_group')
+               ->columns([
+                       DefaultFalseBooleanDatabaseTableColumn::create('canBeAddedAsConversationParticipant'),
+               ]),
+];
+
+(new DatabaseTableChangeProcessor(
+       /** @var ScriptPackageInstallationPlugin $this */
+       $this->installation->getPackage(),
+       $tables,
+       WCF::getDB()->getEditor())
+)->process();
index 083750475d00d602a9a3c652219e36db554df26a..f1b1dddda8d90d3986816b43734f54551e9e4009 100644 (file)
@@ -2,7 +2,7 @@
  * Namespace for conversations.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  */
 WCF.Conversation = { };
index d0529b8f5b4241ef269bb79d88acd8c1a20e5c94..39c25e8fa6945aab8b241337909d1947f4030ed9 100644 (file)
@@ -1 +1 @@
-define("WoltLabSuite/Core/Conversation/Ui/Participant/Add",["Ajax","Language","Ui/Dialog","Ui/Notification","WoltLabSuite/Core/Ui/ItemList/User"],function(t,e,n,i,a){"use strict";function s(t){this.init(t)}return s.prototype={init:function(e){this._conversationId=e,t.api(this,{actionName:"getAddParticipantsForm"})},_ajaxSetup:function(){return{data:{className:"wcf\\data\\conversation\\ConversationAction",objectIDs:[this._conversationId]}}},_ajaxSuccess:function(t){switch(t.actionName){case"addParticipants":this._handleResponse(t);break;case"getAddParticipantsForm":this._render(t)}},_handleResponse:function(t){if(t.returnValues.errorMessage){var e=elCreate("small");e.className="innerError",e.textContent=t.returnValues.errorMessage;var a=elById("participantsInput").closest(".inputItemList");a.parentNode.insertBefore(e,a.nextSibling);var s=e.nextElementSibling;return void(s&&s.classList.contains("innerError")&&elRemove(s))}t.returnValues.count&&i.show(t.returnValues.successMessage,window.location.reload.bind(window.location)),n.close(this)},_render:function(t){n.open(this,t.returnValues.template);var e=elById("addParticipants");e.disabled=!0,a.init("participantsInput",{callbackChange:function(t,n){e.disabled=0===n.length},excludedSearchValues:t.returnValues.excludedSearchValues,maxItems:t.returnValues.maxItems}),e.addEventListener("click",this._submit.bind(this))},_submit:function(){for(var e=a.getValues("participantsInput"),i=[],s=0,o=e.length;s<o;s++)i.push(e[s].value);var r={participants:i},c=elBySel('input[name="messageVisibility"]:checked, input[name="messageVisibility"][type="hidden"]',n.getDialog(this).content);c&&(r.visibility=c.value),t.api(this,{actionName:"addParticipants",parameters:r})},_dialogSetup:function(){return{id:"conversationAddParticipants",options:{title:e.get("wcf.conversation.edit.addParticipants")},source:null}}},s}),define("WoltLabSuite/Core/Conversation/Ui/Subject/Editor",["Ajax","EventKey","Language","Ui/Dialog","Ui/Notification"],function(t,e,n,i,a){"use strict";var s=0,o=null;return{beginEdit:function(t){s=t,i.open(this)},_saveEdit:function(e){e.preventDefault();var i=o.nextElementSibling;i&&i.classList.contains("innerError")&&elRemove(i);var a=o.value.trim();""===a?(i=elCreate("small"),i.className="innerError",i.textContent=n.get("wcf.global.form.error.empty"),o.parentNode.insertBefore(i,o.nextElementSibling)):t.api(this,{parameters:{subject:a},objectIDs:[s]})},_getCurrentValue:function(){var t="";return elBySelAll('.jsConversationSubject[data-conversation-id="'+s+'"], .conversationLink[data-conversation-id="'+s+'"]',void 0,function(e){t=e.textContent}),t},_ajaxSuccess:function(t){i.close(this),elBySelAll('.jsConversationSubject[data-conversation-id="'+s+'"], .conversationLink[data-conversation-id="'+s+'"]',void 0,function(e){e.textContent=t.returnValues.subject}),a.show()},_dialogSetup:function(){return{id:"dialogConversationSubjectEditor",options:{onSetup:function(t){o=elById("jsConversationSubject"),o.addEventListener("keyup",function(t){e.Enter(t)&&this._saveEdit(t)}.bind(this)),elBySel(".jsButtonSave",t).addEventListener(WCF_CLICK_EVENT,this._saveEdit.bind(this))}.bind(this),onShow:function(){o.value=this._getCurrentValue()}.bind(this),title:n.get("wcf.conversation.edit.subject")},source:'<dl><dt><label for="jsConversationSubject">'+n.get("wcf.global.subject")+'</label></dt><dd><input type="text" id="jsConversationSubject" class="long" maxlength="255"></dd></dl><div class="formSubmit"><button class="buttonPrimary jsButtonSave">'+n.get("wcf.global.button.save")+"</button></div>"}},_ajaxSetup:function(){return{data:{actionName:"editSubject",className:"wcf\\data\\conversation\\ConversationAction"}}}}});
\ No newline at end of file
+define("WoltLabSuite/Core/Conversation/Ui/Participant/Add",["Ajax","Language","Ui/Dialog","Ui/Notification","WoltLabSuite/Core/Ui/ItemList/User"],function(t,e,n,i,a){"use strict";function s(t){this.init(t)}return s.prototype={init:function(e){this._conversationId=e,t.api(this,{actionName:"getAddParticipantsForm"})},_ajaxSetup:function(){return{data:{className:"wcf\\data\\conversation\\ConversationAction",objectIDs:[this._conversationId]}}},_ajaxSuccess:function(t){switch(t.actionName){case"addParticipants":this._handleResponse(t);break;case"getAddParticipantsForm":this._render(t)}},_handleResponse:function(t){if(t.returnValues.errorMessage){var e=elCreate("small");e.className="innerError",e.textContent=t.returnValues.errorMessage;var a=elById("participantsInput").closest(".inputItemList");a.parentNode.insertBefore(e,a.nextSibling);var s=e.nextElementSibling;return void(s&&s.classList.contains("innerError")&&elRemove(s))}t.returnValues.count&&i.show(t.returnValues.successMessage,window.location.reload.bind(window.location)),n.close(this)},_render:function(t){n.open(this,t.returnValues.template);var e=elById("addParticipants");e.disabled=!0,a.init("participantsInput",{callbackChange:function(t,n){e.disabled=0===n.length},excludedSearchValues:t.returnValues.excludedSearchValues,maxItems:t.returnValues.maxItems,includeUserGroups:t.returnValues.canAddGroupParticipants&&t.returnValues.restrictUserGroupIDs.length>0,restrictUserGroupIDs:t.returnValues.restrictUserGroupIDs,csvPerType:!0}),e.addEventListener("click",this._submit.bind(this))},_submit:function(){for(var e=a.getValues("participantsInput"),i=[],s=[],r=0,o=e.length;r<o;r++)"group"===e[r].type?s.push(e[r].objectId):i.push(e[r].value);var c={participants:i,participantsGroupIDs:s},u=elBySel('input[name="messageVisibility"]:checked, input[name="messageVisibility"][type="hidden"]',n.getDialog(this).content);u&&(c.visibility=u.value),t.api(this,{actionName:"addParticipants",parameters:c})},_dialogSetup:function(){return{id:"conversationAddParticipants",options:{title:e.get("wcf.conversation.edit.addParticipants")},source:null}}},s}),define("WoltLabSuite/Core/Conversation/Ui/Subject/Editor",["Ajax","EventKey","Language","Ui/Dialog","Ui/Notification"],function(t,e,n,i,a){"use strict";var s=0,r=null;return{beginEdit:function(t){s=t,i.open(this)},_saveEdit:function(e){e.preventDefault();var i=r.nextElementSibling;i&&i.classList.contains("innerError")&&elRemove(i);var a=r.value.trim();""===a?(i=elCreate("small"),i.className="innerError",i.textContent=n.get("wcf.global.form.error.empty"),r.parentNode.insertBefore(i,r.nextElementSibling)):t.api(this,{parameters:{subject:a},objectIDs:[s]})},_getCurrentValue:function(){var t="";return elBySelAll('.jsConversationSubject[data-conversation-id="'+s+'"], .conversationLink[data-conversation-id="'+s+'"]',void 0,function(e){t=e.textContent}),t},_ajaxSuccess:function(t){i.close(this),elBySelAll('.jsConversationSubject[data-conversation-id="'+s+'"], .conversationLink[data-conversation-id="'+s+'"]',void 0,function(e){e.textContent=t.returnValues.subject}),a.show()},_dialogSetup:function(){return{id:"dialogConversationSubjectEditor",options:{onSetup:function(t){r=elById("jsConversationSubject"),r.addEventListener("keyup",function(t){e.Enter(t)&&this._saveEdit(t)}.bind(this)),elBySel(".jsButtonSave",t).addEventListener(WCF_CLICK_EVENT,this._saveEdit.bind(this))}.bind(this),onShow:function(){r.value=this._getCurrentValue()}.bind(this),title:n.get("wcf.conversation.edit.subject")},source:'<dl><dt><label for="jsConversationSubject">'+n.get("wcf.global.subject")+'</label></dt><dd><input type="text" id="jsConversationSubject" class="long" maxlength="255"></dd></dl><div class="formSubmit"><button class="buttonPrimary jsButtonSave">'+n.get("wcf.global.button.save")+"</button></div>"}},_ajaxSetup:function(){return{data:{actionName:"editSubject",className:"wcf\\data\\conversation\\ConversationAction"}}}}});
\ No newline at end of file
index d0529b8f5b4241ef269bb79d88acd8c1a20e5c94..39c25e8fa6945aab8b241337909d1947f4030ed9 100644 (file)
@@ -1 +1 @@
-define("WoltLabSuite/Core/Conversation/Ui/Participant/Add",["Ajax","Language","Ui/Dialog","Ui/Notification","WoltLabSuite/Core/Ui/ItemList/User"],function(t,e,n,i,a){"use strict";function s(t){this.init(t)}return s.prototype={init:function(e){this._conversationId=e,t.api(this,{actionName:"getAddParticipantsForm"})},_ajaxSetup:function(){return{data:{className:"wcf\\data\\conversation\\ConversationAction",objectIDs:[this._conversationId]}}},_ajaxSuccess:function(t){switch(t.actionName){case"addParticipants":this._handleResponse(t);break;case"getAddParticipantsForm":this._render(t)}},_handleResponse:function(t){if(t.returnValues.errorMessage){var e=elCreate("small");e.className="innerError",e.textContent=t.returnValues.errorMessage;var a=elById("participantsInput").closest(".inputItemList");a.parentNode.insertBefore(e,a.nextSibling);var s=e.nextElementSibling;return void(s&&s.classList.contains("innerError")&&elRemove(s))}t.returnValues.count&&i.show(t.returnValues.successMessage,window.location.reload.bind(window.location)),n.close(this)},_render:function(t){n.open(this,t.returnValues.template);var e=elById("addParticipants");e.disabled=!0,a.init("participantsInput",{callbackChange:function(t,n){e.disabled=0===n.length},excludedSearchValues:t.returnValues.excludedSearchValues,maxItems:t.returnValues.maxItems}),e.addEventListener("click",this._submit.bind(this))},_submit:function(){for(var e=a.getValues("participantsInput"),i=[],s=0,o=e.length;s<o;s++)i.push(e[s].value);var r={participants:i},c=elBySel('input[name="messageVisibility"]:checked, input[name="messageVisibility"][type="hidden"]',n.getDialog(this).content);c&&(r.visibility=c.value),t.api(this,{actionName:"addParticipants",parameters:r})},_dialogSetup:function(){return{id:"conversationAddParticipants",options:{title:e.get("wcf.conversation.edit.addParticipants")},source:null}}},s}),define("WoltLabSuite/Core/Conversation/Ui/Subject/Editor",["Ajax","EventKey","Language","Ui/Dialog","Ui/Notification"],function(t,e,n,i,a){"use strict";var s=0,o=null;return{beginEdit:function(t){s=t,i.open(this)},_saveEdit:function(e){e.preventDefault();var i=o.nextElementSibling;i&&i.classList.contains("innerError")&&elRemove(i);var a=o.value.trim();""===a?(i=elCreate("small"),i.className="innerError",i.textContent=n.get("wcf.global.form.error.empty"),o.parentNode.insertBefore(i,o.nextElementSibling)):t.api(this,{parameters:{subject:a},objectIDs:[s]})},_getCurrentValue:function(){var t="";return elBySelAll('.jsConversationSubject[data-conversation-id="'+s+'"], .conversationLink[data-conversation-id="'+s+'"]',void 0,function(e){t=e.textContent}),t},_ajaxSuccess:function(t){i.close(this),elBySelAll('.jsConversationSubject[data-conversation-id="'+s+'"], .conversationLink[data-conversation-id="'+s+'"]',void 0,function(e){e.textContent=t.returnValues.subject}),a.show()},_dialogSetup:function(){return{id:"dialogConversationSubjectEditor",options:{onSetup:function(t){o=elById("jsConversationSubject"),o.addEventListener("keyup",function(t){e.Enter(t)&&this._saveEdit(t)}.bind(this)),elBySel(".jsButtonSave",t).addEventListener(WCF_CLICK_EVENT,this._saveEdit.bind(this))}.bind(this),onShow:function(){o.value=this._getCurrentValue()}.bind(this),title:n.get("wcf.conversation.edit.subject")},source:'<dl><dt><label for="jsConversationSubject">'+n.get("wcf.global.subject")+'</label></dt><dd><input type="text" id="jsConversationSubject" class="long" maxlength="255"></dd></dl><div class="formSubmit"><button class="buttonPrimary jsButtonSave">'+n.get("wcf.global.button.save")+"</button></div>"}},_ajaxSetup:function(){return{data:{actionName:"editSubject",className:"wcf\\data\\conversation\\ConversationAction"}}}}});
\ No newline at end of file
+define("WoltLabSuite/Core/Conversation/Ui/Participant/Add",["Ajax","Language","Ui/Dialog","Ui/Notification","WoltLabSuite/Core/Ui/ItemList/User"],function(t,e,n,i,a){"use strict";function s(t){this.init(t)}return s.prototype={init:function(e){this._conversationId=e,t.api(this,{actionName:"getAddParticipantsForm"})},_ajaxSetup:function(){return{data:{className:"wcf\\data\\conversation\\ConversationAction",objectIDs:[this._conversationId]}}},_ajaxSuccess:function(t){switch(t.actionName){case"addParticipants":this._handleResponse(t);break;case"getAddParticipantsForm":this._render(t)}},_handleResponse:function(t){if(t.returnValues.errorMessage){var e=elCreate("small");e.className="innerError",e.textContent=t.returnValues.errorMessage;var a=elById("participantsInput").closest(".inputItemList");a.parentNode.insertBefore(e,a.nextSibling);var s=e.nextElementSibling;return void(s&&s.classList.contains("innerError")&&elRemove(s))}t.returnValues.count&&i.show(t.returnValues.successMessage,window.location.reload.bind(window.location)),n.close(this)},_render:function(t){n.open(this,t.returnValues.template);var e=elById("addParticipants");e.disabled=!0,a.init("participantsInput",{callbackChange:function(t,n){e.disabled=0===n.length},excludedSearchValues:t.returnValues.excludedSearchValues,maxItems:t.returnValues.maxItems,includeUserGroups:t.returnValues.canAddGroupParticipants&&t.returnValues.restrictUserGroupIDs.length>0,restrictUserGroupIDs:t.returnValues.restrictUserGroupIDs,csvPerType:!0}),e.addEventListener("click",this._submit.bind(this))},_submit:function(){for(var e=a.getValues("participantsInput"),i=[],s=[],r=0,o=e.length;r<o;r++)"group"===e[r].type?s.push(e[r].objectId):i.push(e[r].value);var c={participants:i,participantsGroupIDs:s},u=elBySel('input[name="messageVisibility"]:checked, input[name="messageVisibility"][type="hidden"]',n.getDialog(this).content);u&&(c.visibility=u.value),t.api(this,{actionName:"addParticipants",parameters:c})},_dialogSetup:function(){return{id:"conversationAddParticipants",options:{title:e.get("wcf.conversation.edit.addParticipants")},source:null}}},s}),define("WoltLabSuite/Core/Conversation/Ui/Subject/Editor",["Ajax","EventKey","Language","Ui/Dialog","Ui/Notification"],function(t,e,n,i,a){"use strict";var s=0,r=null;return{beginEdit:function(t){s=t,i.open(this)},_saveEdit:function(e){e.preventDefault();var i=r.nextElementSibling;i&&i.classList.contains("innerError")&&elRemove(i);var a=r.value.trim();""===a?(i=elCreate("small"),i.className="innerError",i.textContent=n.get("wcf.global.form.error.empty"),r.parentNode.insertBefore(i,r.nextElementSibling)):t.api(this,{parameters:{subject:a},objectIDs:[s]})},_getCurrentValue:function(){var t="";return elBySelAll('.jsConversationSubject[data-conversation-id="'+s+'"], .conversationLink[data-conversation-id="'+s+'"]',void 0,function(e){t=e.textContent}),t},_ajaxSuccess:function(t){i.close(this),elBySelAll('.jsConversationSubject[data-conversation-id="'+s+'"], .conversationLink[data-conversation-id="'+s+'"]',void 0,function(e){e.textContent=t.returnValues.subject}),a.show()},_dialogSetup:function(){return{id:"dialogConversationSubjectEditor",options:{onSetup:function(t){r=elById("jsConversationSubject"),r.addEventListener("keyup",function(t){e.Enter(t)&&this._saveEdit(t)}.bind(this)),elBySel(".jsButtonSave",t).addEventListener(WCF_CLICK_EVENT,this._saveEdit.bind(this))}.bind(this),onShow:function(){r.value=this._getCurrentValue()}.bind(this),title:n.get("wcf.conversation.edit.subject")},source:'<dl><dt><label for="jsConversationSubject">'+n.get("wcf.global.subject")+'</label></dt><dd><input type="text" id="jsConversationSubject" class="long" maxlength="255"></dd></dl><div class="formSubmit"><button class="buttonPrimary jsButtonSave">'+n.get("wcf.global.button.save")+"</button></div>"}},_ajaxSetup:function(){return{data:{actionName:"editSubject",className:"wcf\\data\\conversation\\ConversationAction"}}}}});
\ No newline at end of file
index 3fd7ecc284ac293fdd847c017d7735d049ccec07..03df94295a43bc406722482b626e7c3942dbfa44 100644 (file)
@@ -2,7 +2,7 @@
  * Adds participants to an existing conversation.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @module     WoltLabSuite/Core/Conversation/Ui/Participant/Add
  */
@@ -103,7 +103,10 @@ define(['Ajax', 'Language', 'Ui/Dialog', 'Ui/Notification', 'WoltLabSuite/Core/U
                        UiItemListUser.init('participantsInput', {
                                callbackChange: function(elementId, values) { buttonSubmit.disabled = (values.length === 0); },
                                excludedSearchValues: data.returnValues.excludedSearchValues,
-                               maxItems: data.returnValues.maxItems
+                               maxItems: data.returnValues.maxItems,
+                               includeUserGroups: data.returnValues.canAddGroupParticipants && data.returnValues.restrictUserGroupIDs.length > 0,
+                               restrictUserGroupIDs: data.returnValues.restrictUserGroupIDs,
+                               csvPerType: true
                        });
                        
                        buttonSubmit.addEventListener('click', this._submit.bind(this));
@@ -113,13 +116,15 @@ define(['Ajax', 'Language', 'Ui/Dialog', 'Ui/Notification', 'WoltLabSuite/Core/U
                 * Sends a request to add participants.
                 */
                _submit: function() {
-                       var values = UiItemListUser.getValues('participantsInput'), participants = [];
+                       var values = UiItemListUser.getValues('participantsInput'), participants = [], participantsGroupIDs = [];
                        for (var i = 0, length = values.length; i < length; i++) {
-                               participants.push(values[i].value);
+                               if (values[i].type === 'group') participantsGroupIDs.push(values[i].objectId);
+                               else participants.push(values[i].value);
                        }
                        
                        var parameters = {
-                               participants: participants
+                               participants: participants,
+                               participantsGroupIDs: participantsGroupIDs
                        };
                        
                        var visibility = elBySel('input[name="messageVisibility"]:checked, input[name="messageVisibility"][type="hidden"]', UiDialog.getDialog(this).content);
index 222c95e743310334f49a9146744b1b37a442f9bb..5456ff13f74e922ea00b46891dcbae5386fcc0ad 100644 (file)
@@ -2,7 +2,7 @@
  * Provides the editor for conversation subjects.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @module     WoltLabSuite/Core/Conversation/Ui/Subject/Editor
  */
index e82e82e2422b1b84ba4cedac8337694b2970948d..51b93fc19330700ca1a852138b2237ea8186455b 100644 (file)
@@ -1,9 +1,11 @@
 <?php
 namespace wcf\data\conversation;
 use wcf\data\conversation\message\ConversationMessage;
+use wcf\data\user\group\UserGroup;
 use wcf\data\user\UserProfile;
 use wcf\data\DatabaseObject;
 use wcf\data\ITitledLinkObject;
+use wcf\system\cache\runtime\UserProfileRuntimeCache;
 use wcf\system\conversation\ConversationHandler;
 use wcf\system\database\util\PreparedStatementConditionBuilder;
 use wcf\system\exception\UserInputException;
@@ -17,7 +19,7 @@ use wcf\util\ArrayUtil;
  * Represents a conversation.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Conversation
  * 
@@ -341,12 +343,14 @@ class Conversation extends DatabaseObject implements IRouteController, ITitledLi
         * Returns a list of the usernames of all participants.
         *
         * @param       boolean         $excludeSelf
+        * @param       boolean         $leftByOwnChoice                           
         * @return      string[]
         */
-       public function getParticipantNames($excludeSelf = false) {
+       public function getParticipantNames($excludeSelf = false, $leftByOwnChoice = false) {
                $conditions = new PreparedStatementConditionBuilder();
                $conditions->add("conversationID = ?", [$this->conversationID]);
                if ($excludeSelf) $conditions->add("conversation_to_user.participantID <> ?", [WCF::getUser()->userID]);
+               if ($leftByOwnChoice) $conditions->add("conversation_to_user.leftByOwnChoice = ?", [1]);
 
                $sql = "SELECT          user_table.username
                        FROM            wcf".WCF_N."_conversation_to_user conversation_to_user
@@ -524,6 +528,66 @@ class Conversation extends DatabaseObject implements IRouteController, ITitledLi
                return $result;
        }
        
+       /**
+        * Validates the group participants.
+        *
+        * @param       mixed           $participants
+        * @param       string          $field
+        * @param       integer[]       $existingParticipants
+        * @return      array           $result
+        */
+       public static function validateGroupParticipants($participants, $field = 'participants', array $existingParticipants = []) {
+               $groupIDs = is_array($participants) ? $participants : ArrayUtil::toIntegerArray(explode(',', $participants));
+               $validGroupIDs = [];
+               $result = [];
+               
+               foreach ($groupIDs as $groupID) {
+                       $group = UserGroup::getGroupByID($groupID);
+                       /** @noinspection PhpUndefinedFieldInspection */
+                       if ($group !== null && $group->canBeAddedAsConversationParticipant) {
+                               $validGroupIDs[] = $groupID;
+                       }
+               }
+               
+               if (!empty($validGroupIDs)) {
+                       $userIDs = [];
+                       $conditionBuilder = new PreparedStatementConditionBuilder();
+                       $conditionBuilder->add('groupID IN (?)', [$validGroupIDs]);
+                       $sql = "SELECT  DISTINCT userID
+                               FROM    wcf".WCF_N."_user_to_group
+                               ".$conditionBuilder;
+                       $statement = WCF::getDB()->prepareStatement($sql);
+                       $statement->execute($conditionBuilder->getParameters());
+                       while ($userID = $statement->fetchColumn()) $userIDs[] = $userID;
+                       
+                       if (!empty($userIDs)) {
+                               $users = UserProfileRuntimeCache::getInstance()->getObjects($userIDs);
+                               UserStorageHandler::getInstance()->loadStorage($userIDs);
+                               
+                               foreach ($users as $user) {
+                                       // user is author
+                                       if ($user->userID == WCF::getUser()->userID) {
+                                               continue;
+                                       }
+                                       else if (in_array($user->userID, $existingParticipants)) {
+                                               continue;
+                                       }
+                                       
+                                       try {
+                                               // validate user
+                                               self::validateParticipant($user, $field);
+                                               
+                                               // no error
+                                               $result[] = $user->userID;
+                                       }
+                                       catch (UserInputException $e) {}
+                               }
+                       }
+               }
+               
+               return $result;
+       }
+       
        /**
         * Validates the given participant.
         * 
index 35c7289ab1cf22ae53a7bb344a0f6b0fb57ced90..deac774bdd7b051097f8cb1b823a1a940e6d5e58 100644 (file)
@@ -7,9 +7,11 @@ use wcf\data\conversation\message\SimplifiedViewableConversationMessageList;
 use wcf\data\AbstractDatabaseObjectAction;
 use wcf\data\IClipboardAction;
 use wcf\data\IVisitableObjectAction;
+use wcf\data\user\group\UserGroup;
 use wcf\system\clipboard\ClipboardHandler;
 use wcf\system\conversation\ConversationHandler;
 use wcf\system\database\util\PreparedStatementConditionBuilder;
+use wcf\system\event\EventHandler;
 use wcf\system\exception\PermissionDeniedException;
 use wcf\system\exception\UserInputException;
 use wcf\system\log\modification\ConversationModificationLogHandler;
@@ -24,7 +26,7 @@ use wcf\system\WCF;
  * Executes conversation-related actions.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Conversation
  * 
@@ -41,7 +43,7 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
         * conversation object
         * @var ConversationEditor
         */
-       protected $conversation;
+       public $conversation;
        
        /**
         * list of conversation data modifications
@@ -326,7 +328,7 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                }
                
                $returnValues = [
-                       'totalCount' => ConversationHandler::getInstance()->getUnreadConversationCount(null, true)
+                       'totalCount' => ConversationHandler::getInstance()->getUnreadConversationCount($this->parameters['userID'], true)
                ];
                
                if (count($conversationIDs) == 1) {
@@ -776,10 +778,19 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
         * @return      array
         */
        public function getAddParticipantsForm() {
+               $restrictUserGroupIDs = [];
+               foreach (UserGroup::getAllGroups() as $group) {
+                       if ($group->canBeAddedAsConversationParticipant) {
+                               $restrictUserGroupIDs[] = $group->groupID;
+                       }
+               }
+               
                return [
-                       'excludedSearchValues' => $this->conversation->getParticipantNames(),
+                       'excludedSearchValues' => $this->conversation->getParticipantNames(false, true),
                        'maxItems' => WCF::getSession()->getPermission('user.conversation.maxParticipants') - $this->conversation->participants,
-                       'template' => WCF::getTPL()->fetch('conversationAddParticipants', 'wcf', ['conversation' => $this->conversation])
+                       'canAddGroupParticipants' => WCF::getSession()->getPermission('user.conversation.canAddGroupParticipants'),
+                       'template' => WCF::getTPL()->fetch('conversationAddParticipants', 'wcf', ['conversation' => $this->conversation]),
+                       'restrictUserGroupIDs' => $restrictUserGroupIDs,
                ];
        }
        
@@ -790,7 +801,8 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                $this->validateGetAddParticipantsForm();
                
                // validate participants
-               $this->readStringArray('participants');
+               $this->readStringArray('participants', true);
+               $this->readIntegerArray('participantsGroupIDs', true);
                
                if (!$this->conversation->getDecoratedObject()->isDraft) {
                        $this->readString('visibility');
@@ -812,6 +824,16 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
        public function addParticipants() {
                try {
                        $participantIDs = Conversation::validateParticipants($this->parameters['participants'], 'participants', $this->conversation->getParticipantIDs(true));
+                       if (!empty($this->parameters['participantsGroupIDs']) && WCF::getSession()->getPermission('user.conversation.canAddGroupParticipants')) {
+                               $participantIDs = array_merge($participantIDs, Conversation::validateGroupParticipants($this->parameters['participantsGroupIDs'], 'participants', $this->conversation->getParticipantIDs(true)));
+                               $participantIDs = array_unique($participantIDs);
+                       }
+                       
+                       $parameters = [
+                               'participantIDs' => $participantIDs,
+                       ];
+                       EventHandler::getInstance()->fireAction($this, 'addParticipants_validateParticipants', $parameters);
+                       $participantIDs = $parameters['participantIDs'];
                }
                catch (UserInputException $e) {
                        $errorMessage = '';
index 143fd6179c38e72e1faf3aa08e7888dbe9c1e5b1..3b49e5731341e1094a27171d4721449cbb3b9df9 100644 (file)
@@ -9,7 +9,7 @@ use wcf\system\WCF;
  * Extends the conversation object with functions to create, update and delete conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Conversation
  * 
@@ -78,7 +78,7 @@ class ConversationEditor extends DatabaseObjectEditor {
                                                        (conversationID, participantID, username, isInvisible, joinedAt)
                                VALUES                  (?, ?, ?, ?, ?)
                                ON DUPLICATE KEY
-                               UPDATE                  hideConversation = 0";
+                               UPDATE                  hideConversation = 0, leftAt = 0, leftByOwnChoice = 1";
                        $statement = WCF::getDB()->prepareStatement($sql);
                        
                        foreach ($participantIDs as $userID) {
@@ -182,13 +182,15 @@ class ConversationEditor extends DatabaseObjectEditor {
                
                $sql = "UPDATE  wcf".WCF_N."_conversation_to_user
                        SET     leftAt = ?,
-                               lastMessageID = ?
+                               lastMessageID = ?,
+                               leftByOwnChoice = ?
                        WHERE   conversationID = ?
                                AND participantID = ?";
                $statement = WCF::getDB()->prepareStatement($sql);
                $statement->execute([
                        TIME_NOW,
                        $lastMessageID ?: null,
+                       0,
                        $this->conversationID,
                        $userID
                ]);
index 7401db8aca493e4ac4e8f94d587b7874ae30be52..80d99ba38dbc65e7023237a11988d3af5dadad19 100644 (file)
@@ -6,7 +6,7 @@ use wcf\data\DatabaseObjectList;
  * Represents a list of conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Conversation
  *
index 5d53658096c3601f5993d17c0a9634eb74926ea2..60eb827facb5dc3a80f14db8389e3d738b1dc83c 100644 (file)
@@ -8,7 +8,7 @@ use wcf\system\WCF;
  * Represents a list of conversation participants.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Conversation
  */
index 5e490e827d539d445c6a00210781cacbb10c63e8..062a1ef2ede3c734a18565d523732d36150800b7 100644 (file)
@@ -8,7 +8,7 @@ use wcf\system\request\LinkHandler;
  * Represents a conversation for RSS feeds.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Conversation
  *
index 8849de573e6d45c2be04ace3929416ac0839d8cc..4ace14d79de0e7b666b2b171bad812f6d6c1725c 100644 (file)
@@ -6,7 +6,7 @@ use wcf\system\WCF;
  * Represents a list of conversations for RSS feeds.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Conversation
  *
index 2c01d01be188d6e762a667c43435f976985dab2b..717c1ebf326c8bc9168cdac854a965d36ec33407 100644 (file)
@@ -10,7 +10,7 @@ use wcf\system\WCF;
  * Represents a list of conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Conversation
  * 
index cae866601714993b14c8e79de157871a12ae47c6..f4da146c0c6f5243df36b068f5730131a494f63e 100644 (file)
@@ -14,7 +14,7 @@ use wcf\system\WCF;
  * Represents a viewable conversation.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Conversation
  * 
index 5b0f0ae66dd984c1a166ab23da7c5fd58b46b853..fdc6ef87b37ee8f611dc9d31cb60af429ce6d881 100644 (file)
@@ -7,7 +7,7 @@ use wcf\system\WCF;
  * Represents a conversation label.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Conversation\Label
  * 
index 947d6f99be80916330e49ce647c5e12803a90623..7e310c920726f1b8052aaf2c28a8ceec0c69be99 100644 (file)
@@ -15,7 +15,7 @@ use wcf\util\StringUtil;
  * Executes label-related actions.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Conversation\Label
  * 
index 3b6887e83d116523656d1787244aa69aa7a132ad..ee834edf2e49fcf659d836f2c8a0952b92f2914e 100644 (file)
@@ -6,7 +6,7 @@ use wcf\data\DatabaseObjectEditor;
  * Extends the label object with functions to create, update and delete labels.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Conversation\Label
  * 
index 3f67aa397c7a307cbe0e4b953e3e94c60e3dcc63..51a09accea779bc43f061868247adbc2470beb8b 100644 (file)
@@ -6,7 +6,7 @@ use wcf\data\DatabaseObjectList;
  * Represents a list of conversation labels.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Conversation\Label
  * 
index 56d7bd1b843da2414f8b5f579de3aabf30171ece..0cf90a970ae05a237b8b09b6a21773bda1f606e5 100644 (file)
@@ -14,7 +14,7 @@ use wcf\util\StringUtil;
  * Represents a conversation message.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Conversation\Message
  *
index e10e3b4e065dd0438fd620ff874db2e891a3f47e..3189829abd63ff8c2d25aa781d1c1dd8853cb526 100644 (file)
@@ -31,7 +31,7 @@ use wcf\util\StringUtil;
  * Executes conversation message-related actions.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Conversation\Message
  * 
index a578dde02cc23383eb9ce2d0ccbd27ea67141752..cf31ba22134bcabb90a7b79441850131740e5d20 100644 (file)
@@ -6,7 +6,7 @@ use wcf\data\DatabaseObjectEditor;
  * Extends the message object with functions to create, update and delete messages.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Conversation\Message
  * 
index 8ef24c4482cb258e77a184fd2b17b13508ba4b07..a22dc4f7e2489186fe234e370dcd208d8acbe781 100644 (file)
@@ -6,7 +6,7 @@ use wcf\data\DatabaseObjectList;
  * Represents a list of conversation messages.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Conversation\Message
  *
index ab941fe56e60e08c3a26e48ed31cc2255ac45b95..03dcfba677eca1214095bbb8b5ef633984076ddf 100644 (file)
@@ -9,7 +9,7 @@ use wcf\system\search\SearchResultTextParser;
  * Represents a list of search result.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Conversation\Message
  * 
index d4fb79846ca5f702b6f23c84081062d1bb08956c..e06bd8934dfb26db4223aadda830c68504a35038 100644 (file)
@@ -5,7 +5,7 @@ namespace wcf\data\conversation\message;
  * Represents a list of search results.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Conversation\Message
  *
index 5a18904ced390bc291fcef749ae7349fe72a77d6..0dc22237c6166cbe889446ba856a89a2ee32e654 100644 (file)
@@ -6,7 +6,7 @@ namespace wcf\data\conversation\message;
  * Disables the loading of attachments and embedded objects by default.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Conversation\Message
  */
index 4aefd6a2fdb7638d5c478f891dab5a7453e66edb..f02e9a6ea194fe75faa258002034b875af014609 100644 (file)
@@ -9,7 +9,7 @@ use wcf\system\cache\runtime\UserProfileRuntimeCache;
  * Represents a viewable conversation message.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Conversation\Message
  * 
index 6409f5a82209945d3e98ac67625a6f01e0e7984b..148da58883ebe5e983c15058cafe9fda26b4dc72 100644 (file)
@@ -10,7 +10,7 @@ use wcf\system\message\embedded\object\MessageEmbeddedObjectManager;
  * Represents a list of viewable conversation messages.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Conversation\Message
  *
index 0d11c5a47c6d761f5fea3a7a45ce3b6282e8964f..6c7c4f38fd4edacab11e3395e277461679c3e674 100644 (file)
@@ -8,7 +8,7 @@ use wcf\system\WCF;
  * Represents a list of modification logs for conversation log page.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Modification\Log
  *
index 3582bf57af2c59e91f187d2f17d354ab76b1bf18..c28aea784a841fa5e2de84cb60227c19cddbffcc 100644 (file)
@@ -10,7 +10,7 @@ use wcf\system\WCF;
  * Provides a viewable conversation modification log.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Data\Modification\Log
  *
index 6e5d26237135116fb945810bd47bbc83e1f1e53f..37c16fb695d7702106f6ad10be3764ef1723c4d3 100644 (file)
@@ -2,6 +2,8 @@
 namespace wcf\form;
 use wcf\data\conversation\Conversation;
 use wcf\data\conversation\ConversationAction;
+use wcf\data\user\group\UserGroup;
+use wcf\system\cache\builder\UserGroupCacheBuilder;
 use wcf\system\cache\runtime\UserProfileRuntimeCache;
 use wcf\system\conversation\ConversationHandler;
 use wcf\system\exception\IllegalLinkException;
@@ -12,6 +14,7 @@ use wcf\system\message\quote\MessageQuoteManager;
 use wcf\system\page\PageLocationManager;
 use wcf\system\request\LinkHandler;
 use wcf\system\WCF;
+use wcf\util\ArrayUtil;
 use wcf\util\HeaderUtil;
 use wcf\util\StringUtil;
 
@@ -19,7 +22,7 @@ use wcf\util\StringUtil;
  * Shows the conversation form.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Form
  */
@@ -61,6 +64,18 @@ class ConversationAddForm extends MessageForm {
         */
        public $invisibleParticipants = '';
        
+       /**
+        * user group participants (comma separated ids)
+        * @var string
+        */
+       public $participantsGroupIDs = '';
+       
+       /**
+        * invisible user group participants (comma separated ids)
+        * @var string
+        */
+       public $invisibleParticipantsGroupIDs = '';
+       
        /**
         * draft status
         * @var integer
@@ -135,6 +150,10 @@ class ConversationAddForm extends MessageForm {
                if (isset($_POST['participantCanInvite'])) $this->participantCanInvite = (bool) $_POST['participantCanInvite'];
                if (isset($_POST['participants'])) $this->participants = StringUtil::trim($_POST['participants']);
                if (isset($_POST['invisibleParticipants'])) $this->invisibleParticipants = StringUtil::trim($_POST['invisibleParticipants']);
+               if (WCF::getSession()->getPermission('user.conversation.canAddGroupParticipants')) {
+                       if (isset($_POST['participantsGroupIDs'])) $this->participantsGroupIDs = StringUtil::trim($_POST['participantsGroupIDs']);
+                       if (isset($_POST['invisibleParticipantsGroupIDs'])) $this->invisibleParticipantsGroupIDs = StringUtil::trim($_POST['invisibleParticipantsGroupIDs']);
+               }
                
                // quotes
                MessageQuoteManager::getInstance()->readFormParameters();
@@ -144,12 +163,12 @@ class ConversationAddForm extends MessageForm {
         * @inheritDoc
         */
        public function validate() {
-               if (empty($this->participants) && empty($this->invisibleParticipants) && !$this->draft) {
+               if (empty($this->participants) && empty($this->invisibleParticipants) && empty($this->participantsGroupIDs) && empty($this->invisibleParticipantsGroupIDs) && !$this->draft) {
                        throw new UserInputException('participants');
                }
                
                // check, if user is allowed to set invisible participants
-               if (!WCF::getSession()->getPermission('user.conversation.canAddInvisibleParticipants') && !empty($this->invisibleParticipants)) {
+               if (!WCF::getSession()->getPermission('user.conversation.canAddInvisibleParticipants') && (!empty($this->invisibleParticipants) || !empty($this->invisibleParticipantsGroupIDs))) {
                        throw new UserInputException('participants', 'invisibleParticipantsNoPermission');
                }
                
@@ -160,6 +179,14 @@ class ConversationAddForm extends MessageForm {
                
                $this->participantIDs = Conversation::validateParticipants($this->participants);
                $this->invisibleParticipantIDs = Conversation::validateParticipants($this->invisibleParticipants, 'invisibleParticipants');
+               if (!empty($this->participantsGroupIDs)) {
+                       $this->participantIDs = array_merge($this->participantIDs, Conversation::validateGroupParticipants($this->participantsGroupIDs));
+                       $this->participantIDs = array_unique($this->participantIDs);
+               }
+               if (!empty($this->invisibleParticipantsGroupIDs)) {
+                       $this->invisibleParticipantIDs = array_merge($this->invisibleParticipantIDs, Conversation::validateGroupParticipants($this->invisibleParticipantsGroupIDs, 'invisibleParticipants'));
+                       $this->invisibleParticipantIDs = array_unique($this->invisibleParticipantIDs);
+               }
                
                // remove duplicates
                $intersection = array_intersect($this->participantIDs, $this->invisibleParticipantIDs);
@@ -242,11 +269,19 @@ class ConversationAddForm extends MessageForm {
                
                MessageQuoteManager::getInstance()->assignVariables();
                
+               $allowedUserGroupIDs = [];
+               foreach (UserGroupCacheBuilder::getInstance()->getData([], 'groups') as $group) {
+                       if ($group->canBeAddedAsConversationParticipant) $allowedUserGroupIDs[] = $group->groupID;
+               }
+               
                WCF::getTPL()->assign([
                        'participantCanInvite' => $this->participantCanInvite,
                        'participants' => $this->participants,
+                       'participantsData' => $this->getParticipantsData(),
                        'invisibleParticipants' => $this->invisibleParticipants,
-                       'action' => 'add'
+                       'invisibleParticipantsData' => $this->getParticipantsData(true),
+                       'action' => 'add',
+                       'allowedUserGroupIDs' => $allowedUserGroupIDs
                ]);
        }
        
@@ -260,4 +295,29 @@ class ConversationAddForm extends MessageForm {
                
                parent::show();
        }
+       
+       private function getParticipantsData($invisible = false) {
+               $result = [];
+               $participants = ArrayUtil::trim(explode(',', ($invisible ? $this->invisibleParticipants : $this->participants)));
+               foreach ($participants as $username) {
+                       $result[] = [
+                               'objectId' => 0,
+                               'value' => $username,
+                               'type' => 'user'
+                       ];
+               }
+               
+               $participants = ArrayUtil::toIntegerArray(explode(',', ($invisible ? $this->invisibleParticipantsGroupIDs : $this->participantsGroupIDs)));
+               foreach ($participants as $groupID) {
+                       $group = UserGroup::getGroupByID($groupID);
+                       if (!$group) continue;
+                       $result[] = [
+                               'objectId' => $groupID,
+                               'value' => $group->getName(),
+                               'type' => 'group'
+                       ];
+               }
+               
+               return $result;
+       }
 }
index 9e1e454be4afd99cdebe37ac3c39a1748131dba1..5efac9285f8cb63cc31fb72e3ff66dbf58942385 100644 (file)
@@ -14,7 +14,7 @@ use wcf\util\HeaderUtil;
  * Allows the editing of conversation drafts.
  *
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Form
  */
index 45d2824f2d4edc45885d15910e198f0e0df4a959..39c0d4c98558c219d3f4048324490ba1bbc2dd1d 100644 (file)
@@ -7,7 +7,7 @@ use wcf\system\WCF;
  * Shows most recent conversations.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Page
  */
index f82c92dd50f960f86eeb7c2cbb3ce31fde013784..59f7eb5e2a1d6a7c26c1850e2948890850e01a4d 100644 (file)
@@ -14,7 +14,7 @@ use wcf\util\ArrayUtil;
  * Shows a list of conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Page
  * 
@@ -292,7 +292,8 @@ class ConversationListPage extends SortablePage {
                        'draftCount' => $this->draftCount,
                        'hiddenCount' => $this->hiddenCount,
                        'outboxCount' => $this->outboxCount,
-                       'participants' => $this->participants
+                       'participants' => $this->participants,
+                       'validSortFields' => $this->validSortFields,
                ]);
        }
 }
index bde44f5f9c69c5af425b332321f0d5bfa951b0b8..e0a73afad8622d46f60cb4aba05daa13215b8a78 100644 (file)
@@ -10,6 +10,7 @@ use wcf\data\conversation\ConversationParticipantList;
 use wcf\data\conversation\ViewableConversation;
 use wcf\data\modification\log\ConversationLogModificationLogList;
 use wcf\data\smiley\SmileyCache;
+use wcf\data\user\UserProfile;
 use wcf\system\attachment\AttachmentHandler;
 use wcf\system\bbcode\BBCodeHandler;
 use wcf\system\exception\IllegalLinkException;
@@ -18,6 +19,7 @@ use wcf\system\message\quote\MessageQuoteManager;
 use wcf\system\page\PageLocationManager;
 use wcf\system\page\ParentPageLocation;
 use wcf\system\request\LinkHandler;
+use wcf\system\user\signature\SignatureCache;
 use wcf\system\WCF;
 use wcf\util\HeaderUtil;
 use wcf\util\StringUtil;
@@ -26,7 +28,7 @@ use wcf\util\StringUtil;
  * Shows a conversation.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Page
  * 
@@ -181,7 +183,13 @@ class ConversationPage extends MultipleLinkPage {
                PageLocationManager::getInstance()->addParentLocation('com.woltlab.wcf.conversation.ConversationList');
                
                // update last visit time count
-               if ($this->conversation->isNew() && $this->objectList->getMaxPostTime() > $this->conversation->lastVisitTime) {
+               if (
+                       $this->conversation->isNew()
+                       && (
+                               $this->objectList->getMaxPostTime() > $this->conversation->lastVisitTime
+                               || ($this->conversation->joinedAt && !count($this->objectList))
+                       )
+               ) {
                        $visitTime = $this->objectList->getMaxPostTime();
                        if ($visitTime == $this->conversation->lastPostTime) $visitTime = TIME_NOW;
                        $conversationAction = new ConversationAction([$this->conversation->getDecoratedObject()], 'markAsRead', ['visitTime' => $visitTime]);
@@ -199,6 +207,26 @@ class ConversationPage extends MultipleLinkPage {
                }
                MessageQuoteManager::getInstance()->initObjects('com.woltlab.wcf.conversation.message', $messageIDs);
                
+               $userIDs = [];
+               foreach ($this->objectList as $message) {
+                       if ($message->userID) {
+                               $userIDs[] = $message->userID;
+                       }
+               }
+               
+               // fetch special trophies
+               if (MODULE_TROPHY) {
+                       if (!empty($userIDs)) {
+                               UserProfile::prepareSpecialTrophies(array_unique($userIDs));
+                       }
+               }
+               
+               if (MODULE_USER_SIGNATURE) {
+                       if (!empty($userIDs)) {
+                               SignatureCache::getInstance()->cacheUserSignature($userIDs);
+                       }
+               }
+               
                // set attachment permissions
                if ($this->objectList->getAttachmentList() !== null) {
                        $this->objectList->getAttachmentList()->setPermissions([
index 07c479508cd58f6b89a13a08d99e4c9067195599..6bdaec1ea61f8aa4b6bed6ba86670387a6bd3ccf 100644 (file)
@@ -10,7 +10,7 @@ use wcf\util\ArrayUtil;
  * Attachment object type implementation for conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Attachment
  * 
index 6f1c17e83e24a26350daf94704476da72e21185c..ac0ebacaea77223646413b4af7c863652682ea50 100644 (file)
@@ -7,7 +7,7 @@ use wcf\data\conversation\ConversationList;
  * Runtime cache implementation for conversations.
  *
  * @author     Matthias Schmidt
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Cache\Runtime
  * @since      3.0
index 10fd8f9a3cec7e480f2e24624218969769454c5a..85fe28b4be072af7a17792d445aaad11d228e355 100644 (file)
@@ -8,7 +8,7 @@ use wcf\system\WCF;
  * Runtime cache implementation for conversation fetched using UserConversationList.
  *
  * @author     Matthias Schmidt
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Cache\Runtime
  * @since      3.0
index eb2df1655c0e8df3353bac108f268fe3158e69e2..31719040054b3643c9e09daff1eddd1bf05c8523 100644 (file)
@@ -10,7 +10,7 @@ use wcf\system\WCF;
  * Prepares clipboard editor items for conversations.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Clipboard\Action
  */
index 74a94b254ae9d9f841690bd861a73450975727e8..b4115698c1ca5da8438dc85f9a651cd382e8b295 100644 (file)
@@ -11,7 +11,7 @@ use wcf\system\WCF;
  * Handles the number of conversations and unread conversations of the active user.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Conversation
  */
diff --git a/files/lib/system/event/listener/ConversationPruneIpAddressesCronjobListener.class.php b/files/lib/system/event/listener/ConversationPruneIpAddressesCronjobListener.class.php
new file mode 100644 (file)
index 0000000..eb18eb0
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+namespace wcf\system\event\listener;
+use wcf\system\cronjob\PruneIpAddressesCronjob;
+
+/**
+ * Prunes the stored ip addresses.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2019 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core\System\Event\Listener
+ * @since       5.2
+ */
+class ConversationPruneIpAddressesCronjobListener implements IParameterizedEventListener {
+       /**
+        * @inheritDoc
+        */
+       public function execute($eventObj, $className, $eventName, array &$parameters) {
+               /** @var PruneIpAddressesCronjob $eventObj */
+               $eventObj->columns['wcf'.WCF_N.'_conversation_message']['ipAddress'] = 'time';
+       }
+}
index e049119b81fc18987be02b1aa24ea6913f2340a3..debf3bd6aa4f1e52f27c8c8ef0a0000430c77223 100644 (file)
@@ -5,7 +5,7 @@ namespace wcf\system\event\listener;
  * Updates the stored username during user rename.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Event\Listener
  */
index 241d23b187b930f1a01a6a48edb66620c8f6ea18..a0d7fd89e7e3a35e765dba392b6be7eab7b7d5cb 100644 (file)
@@ -5,7 +5,7 @@ namespace wcf\system\event\listener;
  * Merges user conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Event\Listener
  */
diff --git a/files/lib/system/event/listener/UserGroupAddCanBeAddedAsConversationParticipantListener.class.php b/files/lib/system/event/listener/UserGroupAddCanBeAddedAsConversationParticipantListener.class.php
new file mode 100644 (file)
index 0000000..88ddad1
--- /dev/null
@@ -0,0 +1,81 @@
+<?php
+namespace wcf\system\event\listener;
+use wcf\acp\form\UserGroupAddForm;
+use wcf\acp\form\UserGroupEditForm;
+use wcf\data\user\group\UserGroup;
+use wcf\system\WCF;
+
+/**
+ * Handles 'canBeAddedAsConversationParticipant' setting.
+ *
+ * @author     Marcel Werk
+ * @copyright  2001-2019 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core\System\Event\Listener
+ */
+class UserGroupAddCanBeAddedAsConversationParticipantListener implements IParameterizedEventListener {
+       /**
+        * instance of UserGroupAddForm
+        * @var UserGroupAddForm|UserGroupEditForm
+        */
+       protected $eventObj;
+       
+       /**
+        * true if group can be added as participant
+        * @var boolean
+        */
+       protected $canBeAddedAsConversationParticipant = 0;
+       
+       /**
+        * @inheritDoc
+        */
+       public function execute($eventObj, $className, $eventName, array &$parameters) {
+               $this->eventObj = $eventObj;
+               
+               if ($this->eventObj instanceof UserGroupEditForm && is_object($this->eventObj->group)) {
+                       switch ($this->eventObj->group->groupType) {
+                               case UserGroup::EVERYONE:
+                               case UserGroup::GUESTS:
+                               case UserGroup::USERS:
+                                       return;
+                       }
+               }
+               
+               $this->$eventName();
+       }
+       
+       /**
+        * Handles the assignVariables event.
+        */
+       protected function assignVariables() {
+               WCF::getTPL()->assign([
+                       'canBeAddedAsConversationParticipant' => $this->canBeAddedAsConversationParticipant
+               ]);
+       }
+       
+       /**
+        * Handles the readData event.
+        * This is only called in UserGroupEditForm.
+        */
+       protected function readData() {
+               if (empty($_POST)) {
+                       $this->canBeAddedAsConversationParticipant = $this->eventObj->group->canBeAddedAsConversationParticipant;
+               }
+       }
+       
+       /**
+        * Handles the readFormParameters event.
+        */
+       protected function readFormParameters() {
+               if (isset($_POST['canBeAddedAsConversationParticipant'])) $this->canBeAddedAsConversationParticipant = intval($_POST['canBeAddedAsConversationParticipant']);
+       }
+       
+       /**
+        * Handles the save event.
+        */
+       protected function save() {
+               $this->eventObj->additionalFields = array_merge($this->eventObj->additionalFields, [
+                       'canBeAddedAsConversationParticipant' => $this->canBeAddedAsConversationParticipant
+               ]);
+       }
+}
index 9cc01e912aa657614f67463fc45d8eadef33d12c..cdd783195c8fd86f513c217cb8bbe3ba72c235de 100644 (file)
@@ -8,7 +8,7 @@ use wcf\data\object\type\ObjectTypeCache;
  * Imports conversation attachments.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Importer
  */
index 64c9ab89a2b942932ebfe4925d7ef072b0d39839..c0ae2c78d3bea78d84aa1aae6d59ff9bae4e0067 100644 (file)
@@ -7,7 +7,7 @@ use wcf\data\conversation\ConversationEditor;
  * Imports conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Importer
  */
index 4ec4a71ecb31dda7bb3d744554e847fff9528541..64fbac9f875cb083aa9be3986cb044f1f16459bf 100644 (file)
@@ -7,7 +7,7 @@ use wcf\data\conversation\label\ConversationLabelAction;
  * Imports conversation labels.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Importer
  */
index 2e829b4662280b4f50e347579e0e502abd3501b6..7bc0dda7fb8e9de6c8be2d8e61170008d7d5716b 100644 (file)
@@ -7,7 +7,7 @@ use wcf\data\conversation\message\ConversationMessageEditor;
  * Imports conversation messages.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Importer
  */
index 3fab0da92a97d1d2938e3e539a38caaee776552b..85b489492dcb2cba6d9f934535999bfaf0bb824a 100644 (file)
@@ -6,7 +6,7 @@ use wcf\system\WCF;
  * Imports conversation users.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Importer
  */
index caaa160853f0572e3e4d42e84d86cac72537e5c4..f59796ee86f17754e90a32026cd31ab538f534d7 100644 (file)
@@ -8,11 +8,11 @@ use wcf\data\user\UserList;
  * Handles conversation modification logs.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Log\Modification
  */
-class ConversationModificationLogHandler extends AbstractModificationLogHandler {
+class ConversationModificationLogHandler extends VoidExtendedModificationLogHandler {
        /**
         * @inheritDoc
         */
index 3e9e619246adaa4163c12f2afd84a1146cfe8986..fea113298cd4e89e42b37d01e4e96c7243e623f7 100644 (file)
@@ -7,7 +7,7 @@ use wcf\data\conversation\ConversationList;
  * IMessageQuoteHandler implementation for conversation messages.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Message\Quote
  */
index 747ddf87a30a98f1f9007ba0bc3bfab5a0c8aeb6..33cb07fe3e997b3ebb2fc0c3a906be8a327a9932 100644 (file)
@@ -16,7 +16,7 @@ use wcf\system\WCF;
  * An implementation of IModerationQueueReportHandler for conversation messages.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Moderation\Queue
  */
index 03c48f82ebce0db363adb1f42bd7e3380c560af1..c6580f62bf94679e6df98a68a2e2ccbcbbc3defa 100644 (file)
@@ -7,7 +7,7 @@ use wcf\system\WCF;
  * Page handler implementation for the conversation list.
  *
  * @author     Matthias Schmidt
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Page\Handler
  * @since      3.0
index 56f20039a9f18bfac8cc2ba42176cb6c0611cca1..a2b59ccaf31419988402778896c1d06adb25c1e7 100644 (file)
@@ -7,7 +7,7 @@ namespace wcf\system\page\handler;
  * Only use this class when you need the online location handling for a board-related page.
  *
  * @author     Matthias Schmidt
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Page\Handler
  * @since      3.0
index 29b8d7cdf90c547d25d7d40b49da29db30042fb9..96731a11691725d8c1f19ca181e5ecf09fd6a30c 100644 (file)
@@ -10,7 +10,7 @@ use wcf\system\WCF;
  * Implementation of the online location-related page handler methods for conversations.
  * 
  * @author     Matthias Schmidt
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Page\Handler
  * @since      3.0
index 9b50aa59f9bef82e0dc9f42b9246079efbb643b7..132ee0bc797d749f7aac6ae759abcedb489a47b9 100644 (file)
@@ -12,7 +12,7 @@ use wcf\system\WCF;
  * An implementation of ISearchableObjectType for searching in conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Search
  */
index a5f071603848c087393505111688ead5356b1a38..11d30576fb322aa43b6983aa892bc14f01bf0eb5 100644 (file)
@@ -5,7 +5,7 @@ namespace wcf\system\stat;
  * Stat handler implementation for conversation messages.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Stat
  */
index 27e6d71022f7da866ff3a8f255f841f0b74caf9e..d96c93e3b5393fd7e7102bd1997d8b602bc11eb5 100644 (file)
@@ -5,7 +5,7 @@ namespace wcf\system\stat;
  * Stat handler implementation for conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Stat
  */
diff --git a/files/lib/system/user/content/provider/ConversationMessageUserContentProvider.class.php b/files/lib/system/user/content/provider/ConversationMessageUserContentProvider.class.php
new file mode 100644 (file)
index 0000000..0797970
--- /dev/null
@@ -0,0 +1,21 @@
+<?php
+namespace wcf\system\user\content\provider;
+use wcf\data\conversation\message\ConversationMessage;
+
+/**
+ * User content provider for conversation messages.
+ *
+ * @author     Joshua Ruesweg
+ * @copyright  2001-2019 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core\System\User\Content\Provider
+ * @since      5.2
+ */
+class ConversationMessageUserContentProvider extends AbstractDatabaseUserContentProvider {
+       /**
+        * @inheritdoc
+        */
+       public static function getDatabaseObjectClass() {
+               return ConversationMessage::class;
+       }
+}
diff --git a/files/lib/system/user/content/provider/ConversationUserContentProvider.class.php b/files/lib/system/user/content/provider/ConversationUserContentProvider.class.php
new file mode 100644 (file)
index 0000000..322b562
--- /dev/null
@@ -0,0 +1,21 @@
+<?php
+namespace wcf\system\user\content\provider;
+use wcf\data\conversation\Conversation;
+
+/**
+ * User content provider for conversations.
+ *
+ * @author     Joshua Ruesweg
+ * @copyright  2001-2019 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core\System\User\Content\Provider
+ * @since      5.2
+ */
+class ConversationUserContentProvider extends AbstractDatabaseUserContentProvider {
+       /**
+        * @inheritdoc
+        */
+       public static function getDatabaseObjectClass() {
+               return Conversation::class;
+       }
+}
index b7b682bace182991ccb0afbb154e623eb828b97f..398bd12edb816cbc393fc28bb93c70c310b6cf19 100644 (file)
@@ -9,7 +9,7 @@ use wcf\system\user\notification\object\ConversationMessageUserNotificationObjec
  * User notification event for conversation messages.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\User\Notification\Event
  * 
@@ -74,6 +74,21 @@ class ConversationMessageUserNotificationEvent extends AbstractUserNotificationE
                ];
        }
        
+       /**
+        * @inheritDoc
+        * @since       5.2
+        */
+       public function getEmailTitle() {
+               if (count($this->getAuthors()) > 1) {
+                       return parent::getEmailTitle();
+               }
+               
+               return $this->getLanguage()->getDynamicVariable('wcf.user.notification.conversation.message.mail.title', [
+                       'author' => $this->author,
+                       'message' => $this->userNotificationObject
+               ]);
+       }
+       
        /**
         * @inheritDoc
         */
index 8245a30c4a8e7fe080bb752d49e70909cd657b28..d70007e2d34ee00dc6a2fe70ded6a9765d5dcd45 100644 (file)
@@ -8,7 +8,7 @@ use wcf\system\user\notification\object\ConversationUserNotificationObject;
  * User notification event for conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\User\Notification\Event
  * 
@@ -47,6 +47,17 @@ class ConversationUserNotificationEvent extends AbstractUserNotificationEvent im
                ];
        }
        
+       /**
+        * @inheritDoc
+        * @since       5.2
+        */
+       public function getEmailTitle() {
+               return $this->getLanguage()->getDynamicVariable('wcf.user.notification.conversation.mail.title', [
+                       'author' => $this->author,
+                       'conversation' => $this->userNotificationObject
+               ]);
+       }
+       
        /**
         * @inheritDoc
         */
index cd4985d86d0613d6d658f0ffe91a8b84328bfd4a..e27da9e42ab9c4adb8a514802e4a325b8eddc7b0 100644 (file)
@@ -11,7 +11,7 @@ use wcf\data\user\UserProfile;
  * user notification events.
  *
  * @author     Matthias Schmidt
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\User\Notification\Event
  * @since      3.1
index 1ac4588a5ba4784306f17ea7e022f960fa7a8544..a43089225d097157ef2a28975f2f76f9307c2e40 100644 (file)
@@ -8,7 +8,7 @@ use wcf\system\request\LinkHandler;
  * Notification object for conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\User\Notification\Object
  *
index 945b6031b69029653f5d9d0db2b6ad0b97a60586..8f35d6bc81060f209e629d687758f6a98216b1b4 100644 (file)
@@ -8,7 +8,7 @@ use wcf\system\request\LinkHandler;
  * Notification object for conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\User\Notification\Object
  * 
index bd03fe81e66a13b2d18dd98eca8827ce0454f0e3..16c9e42e26720b2fc9c49eb03f764fe586bbf7a9 100644 (file)
@@ -8,7 +8,7 @@ use wcf\system\user\notification\object\ConversationMessageUserNotificationObjec
  * Represents a conversation message notification object type.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\User\Notification\Object\Type
  */
index 5212a5620de47f712c6ff3b349a763561d061c44..90853b645626b091bacdb93d6a56e2253e58631e 100644 (file)
@@ -9,7 +9,7 @@ use wcf\system\WCF;
  * Represents a conversation notification object type.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\User\Notification\Object\Type
  */
index 48c236b95d322da903fd089de751ed25ac23e36d..0b85755a0446636fb00519d72d43d03c499a5661 100644 (file)
@@ -13,7 +13,7 @@ use wcf\system\WCF;
  * Worker implementation for updating conversation messages.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Worker
  * 
index 769efbcaddf26c27f1861772086a6aae771e9982..66615b6030c4b20749120ca1f76ab9af9e43354a 100644 (file)
@@ -10,7 +10,7 @@ use wcf\system\WCF;
  * Worker implementation for updating conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Worker
  * 
index 4f05fdee0098b721621c3dfe5df5e37a38134601..2a8cd2fbdc5419d57e41f1f6dc8bd188868c4cd2 100644 (file)
@@ -32,6 +32,7 @@ CREATE TABLE wcf1_conversation_to_user (
        joinedAt INT(10) NOT NULL DEFAULT 0,
        leftAt INT(10) NOT NULL DEFAULT 0,
        lastMessageID INT(10) NULL,
+       leftByOwnChoice TINYINT(1) NOT NULL DEFAULT 1,
        
        UNIQUE KEY (participantID, conversationID),
        KEY (participantID, hideConversation)
@@ -73,6 +74,8 @@ CREATE TABLE wcf1_conversation_label_to_object (
        UNIQUE KEY (labelID, conversationID)
 );
 
+ALTER TABLE wcf1_user_group ADD canBeAddedAsConversationParticipant TINYINT(1) NOT NULL DEFAULT 0;
+
 ALTER TABLE wcf1_conversation ADD FOREIGN KEY (userID) REFERENCES wcf1_user (userID) ON DELETE SET NULL;
 ALTER TABLE wcf1_conversation ADD FOREIGN KEY (lastPosterID) REFERENCES wcf1_user (userID) ON DELETE SET NULL;
 ALTER TABLE wcf1_conversation ADD FOREIGN KEY (firstMessageID) REFERENCES wcf1_conversation_message (messageID) ON DELETE SET NULL;
index 2bc7315544a5f4a4e4f7c98490c2f1c85bc1f287..ef5b2641551456f374c8e741664240b90efd835f 100644 (file)
@@ -1,5 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<language xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/vortex/language.xsd" languagecode="de">
+<language xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/2019/language.xsd" languagecode="de">
+       <category name="wcf.acp.content">
+               <item name="wcf.acp.content.provider.com.woltlab.wcf.conversation"><![CDATA[Konversationen]]></item>
+               <item name="wcf.acp.content.provider.com.woltlab.wcf.conversation.message"><![CDATA[Konversations-Nachrichten]]></item>
+       </category>
        <category name="wcf.acp.group">
                <item name="wcf.acp.group.option.category.user.conversation"><![CDATA[Konversationen]]></item>
                <item name="wcf.acp.group.option.category.mod.conversation"><![CDATA[Konversationen]]></item>
                <item name="wcf.acp.group.option.user.conversation.allowedAttachmentExtensions"><![CDATA[Erlaubte Dateiendungen]]></item>
                <item name="wcf.acp.group.option.user.conversation.allowedAttachmentExtensions.description"><![CDATA[Eine Dateiendung pro Zeile]]></item>
                <item name="wcf.acp.group.option.user.conversation.maxAttachmentCount"><![CDATA[Maximale Dateianhänge pro Nachricht]]></item>
-               <item name="wcf.acp.group.option.user.conversation.maxAttachmentCount.description"><![CDATA[]]></item>
+               <item name="wcf.acp.group.option.user.conversation.maxAttachmentCount.description"/>
                <item name="wcf.acp.group.option.user.conversation.canEditMessage"><![CDATA[Kann eigene Nachrichten bearbeiten]]></item>
                <item name="wcf.acp.group.option.user.conversation.canEditMessage.description"><![CDATA[Mitglieder dieser Benutzergruppe können eigene Nachrichten in Konversationen nachträglich verändern, auch wenn diese bereits vom Empfänger gelesen wurden.]]></item>
+               <item name="wcf.acp.group.option.user.conversation.canAddGroupParticipants"><![CDATA[Kann Benutzergruppen als Teilnehmer hinzufügen]]></item>
+               <item name="wcf.acp.group.canBeAddedAsConversationParticipant"><![CDATA[Benutzergruppe kann als Teilnehmer in Konversationen hinzufügt werden]]></item>
                <item name="wcf.acp.group.option.user.conversation.maxStartedConversationsPer24Hours"><![CDATA[Maximale Anzahl gestarteter Konversation innerhalb von 24 Stunden]]></item>
                <item name="wcf.acp.group.option.user.conversation.maxStartedConversationsPer24Hours.description"><![CDATA[Beschränkt die Anzahl der Konversationen die ein Benutzer innerhalb von 24 Stunden starten darf. [-1 für unbegrenzt]]]></item>
        </category>
-       
        <category name="wcf.acp.option">
                <item name="wcf.acp.option.category.message.conversation"><![CDATA[Konversationen]]></item>
                <item name="wcf.acp.option.conversation_list_default_sort_field"><![CDATA[Sortierung]]></item>
-               <item name="wcf.acp.option.conversation_list_default_sort_field.description"><![CDATA[]]></item>
+               <item name="wcf.acp.option.conversation_list_default_sort_field.description"/>
                <item name="wcf.acp.option.conversation_list_default_sort_order"><![CDATA[Reihenfolge]]></item>
-               <item name="wcf.acp.option.conversation_list_default_sort_order.description"><![CDATA[]]></item>
+               <item name="wcf.acp.option.conversation_list_default_sort_order.description"/>
                <item name="wcf.acp.option.conversation_messages_per_page"><![CDATA[Nachrichten pro Seite]]></item>
                <item name="wcf.acp.option.conversations_per_page"><![CDATA[Konversationen pro Seite]]></item>
                <item name="wcf.acp.option.module_conversation"><![CDATA[Konversationen]]></item>
        </category>
-       
        <category name="wcf.acp.rebuildData">
                <item name="wcf.acp.rebuildData.com.woltlab.wcf.conversation"><![CDATA[Konversationen aktualisieren]]></item>
                <item name="wcf.acp.rebuildData.com.woltlab.wcf.conversation.description"><![CDATA[Aktualisiert Zähler der Konversationen]]></item>
                <item name="wcf.acp.rebuildData.com.woltlab.wcf.conversation.message"><![CDATA[Konversationsnachrichten aktualisieren]]></item>
                <item name="wcf.acp.rebuildData.com.woltlab.wcf.conversation.message.description"><![CDATA[Aktualisiert den Suchindex für Konversationsnachrichten]]></item>
        </category>
-       
        <category name="wcf.acp.stat">
                <item name="wcf.acp.stat.com.woltlab.wcf.conversation"><![CDATA[Konversationen]]></item>
                <item name="wcf.acp.stat.com.woltlab.wcf.conversation.message"><![CDATA[Konversations-Nachrichten]]></item>
                <item name="wcf.acp.stat.category.com.woltlab.wcf.conversation"><![CDATA[Konversationen]]></item>
        </category>
-       
        <category name="wcf.clipboard">
                <item name="wcf.clipboard.item.com.woltlab.wcf.conversation.conversation.assignLabel"><![CDATA[Label zuweisen ({#$count})]]></item>
                <item name="wcf.clipboard.item.com.woltlab.wcf.conversation.conversation.close"><![CDATA[Schließen ({#$count})]]></item>
@@ -64,7 +66,6 @@
                <item name="wcf.clipboard.item.com.woltlab.wcf.conversation.conversation.restore"><![CDATA[Als aktiv markieren ({#$count})]]></item>
                <item name="wcf.clipboard.label.com.woltlab.wcf.conversation.conversation.marked"><![CDATA[{if $count == 1}Eine Konversation{else}{#$count} Konversationen{/if}]]></item>
        </category>
-       
        <category name="wcf.conversation">
                <item name="wcf.conversation.add"><![CDATA[Neue Konversation starten]]></item>
                <item name="wcf.conversation.button.add"><![CDATA[Konversation starten]]></item>
@@ -88,7 +89,6 @@
                <item name="wcf.conversation.lastPostTime"><![CDATA[Letzte Antwort]]></item>
                <item name="wcf.conversation.lastVisitTime"><![CDATA[Konversation gelesen]]></item>
                <item name="wcf.conversation.leave.title"><![CDATA[Teilnahme verwalten]]></item>
-               <item name="wcf.conversation.markAllAsRead.confirmMessage"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Willst du{else}Wollen Sie{/if} wirklich alle Konversationen als gelesen markieren?]]></item>
                <item name="wcf.conversation.message"><![CDATA[Nachricht]]></item>
                <item name="wcf.conversation.message.button.add"><![CDATA[Antworten]]></item>
                <item name="wcf.conversation.message.edit"><![CDATA[Nachricht bearbeiten]]></item>
                <item name="wcf.conversation.visibility.new"><![CDATA[Nur neue Nachrichten]]></item>
                <item name="wcf.conversation.visibility.new.description"><![CDATA[Die neuen Teilnehmer sehen nur neue Nachrichten, alle vorherigen Nachrichten werden nicht angezeigt.]]></item>
                <item name="wcf.conversation.visibility.previousMessages"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Du wurdest{else}Sie wurden{/if} einer laufenden Konversation hinzugefügt, vorherige Nachrichten werden {if LANGUAGE_USE_INFORMAL_VARIANT}dir{else}Ihnen{/if} nicht angezeigt.]]></item>
+               <item name="wcf.conversation.time"><![CDATA[Erstellung]]></item>
+               <item name="wcf.conversation.username"><![CDATA[Autor]]></item>
                <item name="wcf.conversation.error.floodControl"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Du hast{else}Sie haben{/if} innerhalb der letzten 24 Stunden bereits {if $limit == 1}eine Konversation{else}{#$limit} Konversationen{/if} gestartet. Bitte {if LANGUAGE_USE_INFORMAL_VARIANT}warte{else}warten Sie{/if} bis zum <strong>{@$notBefore|time}</strong>, bevor {if LANGUAGE_USE_INFORMAL_VARIANT}du{else}Sie{/if} eine neue Konversation {if LANGUAGE_USE_INFORMAL_VARIANT}startest{else}starten{/if}.]]></item>
        </category>
-       
        <category name="wcf.conversation.edit">
                <item name="wcf.conversation.edit.addParticipants"><![CDATA[Teilnehmer hinzufügen]]></item>
                <item name="wcf.conversation.edit.addParticipants.success"><![CDATA[{if $count == 1}Ein{else}{#$count}{/if} Teilnehmer erfolgreich hinzugefügt]]></item>
                <item name="wcf.conversation.edit.open"><![CDATA[Öffnen]]></item>
                <item name="wcf.conversation.edit.subject"><![CDATA[Betreff bearbeiten]]></item>
        </category>
-       
        <category name="wcf.conversation.label">
                <item name="wcf.conversation.label"><![CDATA[Filter nach Label]]></item>
                <item name="wcf.conversation.label.cssClassName"><![CDATA[Aussehen]]></item>
                <item name="wcf.conversation.label.placeholder"><![CDATA[Label]]></item>
                <item name="wcf.conversation.label.assignLabels"><![CDATA[Label zuweisen]]></item>
        </category>
-       
        <category name="wcf.conversation.log">
                <item name="wcf.conversation.log.conversation.open"><![CDATA[Hat die Konversation wieder geöffnet.]]></item>
                <item name="wcf.conversation.log.conversation.close"><![CDATA[Hat die Konversation für neue Nachrichten geschlossen.]]></item>
                <item name="wcf.conversation.log.conversation.addParticipants"><![CDATA[Hat folgende Teilnehmer 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[Hat folgenden Teilnehmer 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.acp.dataImport">
                <item name="wcf.acp.dataImport.data.com.woltlab.wcf.conversation"><![CDATA[Konversationen]]></item>
                <item name="wcf.acp.dataImport.data.com.woltlab.wcf.conversation.label"><![CDATA[Labels]]></item>
                <item name="wcf.acp.dataImport.data.com.woltlab.wcf.conversation.user"><![CDATA[Teilnehmer]]></item>
                <item name="wcf.acp.dataImport.data.com.woltlab.wcf.conversation.attachment"><![CDATA[Dateianhänge]]></item>
        </category>
-       
        <category name="wcf.moderation">
                <item name="wcf.moderation.type.com.woltlab.wcf.conversation.message"><![CDATA[Konversation]]></item>
        </category>
-       
        <category name="wcf.page">
                <item name="wcf.page.onlineLocation.com.woltlab.wcf.conversation.Conversation"><![CDATA[Konversation <a href="{link controller='Conversation' object=$conversation}{/link}" class="conversationLink" data-conversation-id="{@$conversation->conversationID}">{$conversation->subject}</a>]]></item>
        </category>
-       
        <category name="wcf.search">
                <item name="wcf.search.type.com.woltlab.wcf.conversation"><![CDATA[Diese Konversation]]></item>
                <item name="wcf.search.type.com.woltlab.wcf.conversation.message"><![CDATA[Konversationen]]></item>
                <item name="wcf.search.object.com.woltlab.wcf.conversation.message"><![CDATA[Konversation]]></item>
        </category>
-       
        <category name="wcf.user.notification">
                <item name="wcf.user.notification.conversation.message.message"><![CDATA[{@$author->getAnchorTag()} hat auf die Konversation <a href="{link controller='Conversation' object=$message->getConversation()}{/link}">{$message->getConversation()->getTitle()}</a> geantwortet.]]></item>
                <item name="wcf.user.notification.conversation.message.message.stacked"><![CDATA[{if $count < 4}{@$authors[0]->getAnchorTag()}{if $count == 2} und {else}, {/if}{@$authors[1]->getAnchorTag()}{if $count == 3} und {@$authors[2]->getAnchorTag()}{/if}{else}{@$authors[0]->getAnchorTag()} und {#$count} weitere Benutzer{/if} haben auf die Konversation <a href="{link controller='Conversation' object=$message->getConversation()}{/link}">{$message->getConversation()->getTitle()}</a> geantwortet.]]></item>
                <item name="wcf.user.notification.conversation.message.title.stacked"><![CDATA[{#$count} Teilnehmer haben auf eine Konversation geantwortet]]></item>
                <item name="wcf.user.notification.conversation.message.mail.plaintext"><![CDATA[{@$authorList} {if $count == 1 && !$guestTimesTriggered}hat{else}haben{/if} auf die Konversation „{@$event->getUserNotificationObject()->getConversation()->subject}“ [URL:{link controller='Conversation' object=$event->getUserNotificationObject()->getConversation() isEmail=true}{/link}] geantwortet{if $count == 1 && !$guestTimesTriggered}:{else}.{/if}]]></item>
                <item name="wcf.user.notification.conversation.message.mail.html"><![CDATA[<p>{@$authorList} {if $count == 1 && !$guestTimesTriggered}hat{else}haben{/if} auf die Konversation <a href="{link controller='Conversation' object=$event->getUserNotificationObject()->getConversation() isHtmlEmail=true}{/link}">{$event->getUserNotificationObject()->getConversation()->subject}</a> geantwortet:</p>]]></item>
+               <item name="wcf.user.notification.conversation.message.mail.title"><![CDATA["{@$author->username}" hat auf die Konversation "{@$message->getConversation()->subject}" geantwortet]]></item>
                <item name="wcf.user.notification.conversation.message"><![CDATA[{@$author->getAnchorTag()} hat die Konversation <a href="{link controller='Conversation' object=$conversation}{/link}">{$conversation->subject}</a> gestartet.]]></item>
                <item name="wcf.user.notification.conversation.title"><![CDATA[Neue Konversation]]></item>
                <item name="wcf.user.notification.conversation.mail.plaintext"><![CDATA[{@$event->getAuthor()->username} [URL:{link controller='User' object=$event->getAuthor() isEmail=true}{/link}] hat die Konversation „{@$event->getUserNotificationObject()->subject}“ [URL:{link controller='Conversation' object=$event->getUserNotificationObject() isEmail=true}{/link}] gestartet:]]></item>
                <item name="wcf.user.notification.conversation.mail.html"><![CDATA[<p><a href="{link controller='User' object=$event->getAuthor() isHtmlEmail=true}{/link}">{$event->getAuthor()->username}</a> hat die Konversation <a href="{link controller='Conversation' object=$event->getUserNotificationObject() isHtmlEmail=true}{/link}">{$event->getUserNotificationObject()->subject}</a> gestartet:</p>]]></item>
+               <item name="wcf.user.notification.conversation.mail.title"><![CDATA[Neue Konversation von "{@$author->username}"]]></item>
                <item name="wcf.user.notification.com.woltlab.wcf.conversation"><![CDATA[Konversationen]]></item>
                <item name="wcf.user.notification.com.woltlab.wcf.conversation.notification.conversation"><![CDATA[Neue Konversation]]></item>
                <item name="wcf.user.notification.com.woltlab.wcf.conversation.message.notification.conversationMessage"><![CDATA[Antwort auf bestehende Konversation]]></item>
        </category>
-       
        <category name="wcf.user.option">
                <item name="wcf.user.option.conversationMessagesPerPage"><![CDATA[Nachrichten pro Seite]]></item>
                <item name="wcf.user.option.conversationsPerPage"><![CDATA[Konversationen pro Seite]]></item>
index ce956170de3ef88335a622e6c10223b2d263d902..ff09df9f1d89e6de15d40c82632027b0257e4d92 100644 (file)
@@ -1,5 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<language xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/vortex/language.xsd" languagecode="en">
+<language xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/2019/language.xsd" languagecode="en">
+       <category name="wcf.acp.content">
+               <item name="wcf.acp.content.provider.com.woltlab.wcf.conversation"><![CDATA[Conversations]]></item>
+               <item name="wcf.acp.content.provider.com.woltlab.wcf.conversation.message"><![CDATA[Conversation Messages]]></item>
+       </category>
        <category name="wcf.acp.group">
                <item name="wcf.acp.group.option.category.user.conversation"><![CDATA[Conversations]]></item>
                <item name="wcf.acp.group.option.category.mod.conversation"><![CDATA[Conversations]]></item>
                <item name="wcf.acp.group.option.user.conversation.maxAttachmentCount.description"><![CDATA[The maximum number of attachments allowed per message.]]></item>
                <item name="wcf.acp.group.option.user.conversation.canEditMessage"><![CDATA[Can edit their messages]]></item>
                <item name="wcf.acp.group.option.user.conversation.canEditMessage.description"><![CDATA[Users can edit their messages, regardless if they have been read by one or more recipients.]]></item>
+               <item name="wcf.acp.group.option.user.conversation.canAddGroupParticipants"><![CDATA[Can add user groups as participants]]></item>
+               <item name="wcf.acp.group.canBeAddedAsConversationParticipant"><![CDATA[User group can be added as participant in conversations]]></item>
                <item name="wcf.acp.group.option.user.conversation.maxStartedConversationsPer24Hours"><![CDATA[Maximum Number of Started Conversations per 24 Hours]]></item>
                <item name="wcf.acp.group.option.user.conversation.maxStartedConversationsPer24Hours.description"><![CDATA[Limits the number of conversations that a user can start within 24 hours. Use -1 for infinite.]]></item>
        </category>
-       
        <category name="wcf.acp.option">
                <item name="wcf.acp.option.category.message.conversation"><![CDATA[Conversations]]></item>
                <item name="wcf.acp.option.conversation_list_default_sort_field"><![CDATA[Sort by]]></item>
                <item name="wcf.acp.option.conversations_per_page"><![CDATA[Conversations per Page]]></item>
                <item name="wcf.acp.option.module_conversation"><![CDATA[Conversations]]></item>
        </category>
-       
        <category name="wcf.acp.rebuildData">
                <item name="wcf.acp.rebuildData.com.woltlab.wcf.conversation"><![CDATA[Rebuild Conversations]]></item>
                <item name="wcf.acp.rebuildData.com.woltlab.wcf.conversation.description"><![CDATA[Rebuilds the conversation counters.]]></item>
                <item name="wcf.acp.rebuildData.com.woltlab.wcf.conversation.message"><![CDATA[Rebuild Conversation Messages]]></item>
                <item name="wcf.acp.rebuildData.com.woltlab.wcf.conversation.message.description"><![CDATA[Rebuilds the search index for the conversation messages.]]></item>
        </category>
-       
        <category name="wcf.acp.stat">
                <item name="wcf.acp.stat.com.woltlab.wcf.conversation"><![CDATA[Conversations]]></item>
                <item name="wcf.acp.stat.com.woltlab.wcf.conversation.message"><![CDATA[Conversation Messages]]></item>
                <item name="wcf.acp.stat.category.com.woltlab.wcf.conversation"><![CDATA[Conversations]]></item>
        </category>
-       
        <category name="wcf.clipboard">
                <item name="wcf.clipboard.item.com.woltlab.wcf.conversation.conversation.assignLabel"><![CDATA[Assign Label ({#$count})]]></item>
                <item name="wcf.clipboard.item.com.woltlab.wcf.conversation.conversation.close"><![CDATA[Close ({#$count})]]></item>
@@ -64,7 +66,6 @@
                <item name="wcf.clipboard.item.com.woltlab.wcf.conversation.conversation.restore"><![CDATA[Mark as Active ({#$count})]]></item>
                <item name="wcf.clipboard.label.com.woltlab.wcf.conversation.conversation.marked"><![CDATA[{if $count == 1}One Conversation{else}{#$count} Conversations{/if}]]></item>
        </category>
-       
        <category name="wcf.conversation">
                <item name="wcf.conversation.add"><![CDATA[Create Conversation]]></item>
                <item name="wcf.conversation.button.add"><![CDATA[Create Conversation]]></item>
                <item name="wcf.conversation.lastPostTime"><![CDATA[Last Reply]]></item>
                <item name="wcf.conversation.lastVisitTime"><![CDATA[Conversation Read]]></item>
                <item name="wcf.conversation.leave.title"><![CDATA[Manage Participation]]></item>
-               <item name="wcf.conversation.markAllAsRead.confirmMessage"><![CDATA[Do you really want to mark all conversations as read?]]></item>
                <item name="wcf.conversation.message"><![CDATA[Message]]></item>
                <item name="wcf.conversation.message.button.add"><![CDATA[Reply]]></item>
                <item name="wcf.conversation.message.edit"><![CDATA[Edit Message]]></item>
-               <item name="wcf.conversation.noConversations"><![CDATA[There are not any conversations at the moment.]]></item>
+               <item name="wcf.conversation.noConversations"><![CDATA[There are no conversations at the moment.]]></item>
                <item name="wcf.conversation.noMoreItems"><![CDATA[You have no recent conversations.]]></item>
                <item name="wcf.conversation.participantCanInvite"><![CDATA[Participants can add new participants]]></item>
                <item name="wcf.conversation.participants"><![CDATA[Participants]]></item>
                <item name="wcf.conversation.visibility.new"><![CDATA[New messages only]]></item>
                <item name="wcf.conversation.visibility.new.description"><![CDATA[The new participants will see new messages only, older messages will be hidden from them.]]></item>
                <item name="wcf.conversation.visibility.previousMessages"><![CDATA[You have been added to an existing conversation, previously written messages are hidden.]]></item>
+               <item name="wcf.conversation.time"><![CDATA[Creation]]></item>
+               <item name="wcf.conversation.username"><![CDATA[Author]]></item>
                <item name="wcf.conversation.error.floodControl"><![CDATA[You have already started {if $limit == 1}one conversation{else}{#$limit} conversations{/if} in the past 24 hours. Please wait until <strong>{@$notBefore|time}</strong> before you start a new conversation.]]></item>
        </category>
-       
        <category name="wcf.conversation.edit">
                <item name="wcf.conversation.edit.addParticipants"><![CDATA[Add Participants]]></item>
                <item name="wcf.conversation.edit.addParticipants.success"><![CDATA[Added {#$count} participant{if $count != 1}s{/if}]]></item>
                <item name="wcf.conversation.edit.open"><![CDATA[Open]]></item>
                <item name="wcf.conversation.edit.subject"><![CDATA[Edit Subject]]></item>
        </category>
-       
        <category name="wcf.conversation.label">
                <item name="wcf.conversation.label"><![CDATA[Filter by Label]]></item>
                <item name="wcf.conversation.label.cssClassName"><![CDATA[Appearance]]></item>
                <item name="wcf.conversation.label.placeholder"><![CDATA[Label]]></item>
                <item name="wcf.conversation.label.assignLabels"><![CDATA[Assign Label]]></item>
        </category>
-       
        <category name="wcf.conversation.log">
                <item name="wcf.conversation.log.conversation.open"><![CDATA[Opened the conversation again.]]></item>
                <item name="wcf.conversation.log.conversation.close"><![CDATA[Closed the conversation.]]></item>
                <item name="wcf.conversation.log.conversation.addParticipants"><![CDATA[Added the following participants: {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[Removed a participant: <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.acp.dataImport">
                <item name="wcf.acp.dataImport.data.com.woltlab.wcf.conversation"><![CDATA[Conversations]]></item>
                <item name="wcf.acp.dataImport.data.com.woltlab.wcf.conversation.label"><![CDATA[Labels]]></item>
                <item name="wcf.acp.dataImport.data.com.woltlab.wcf.conversation.user"><![CDATA[Participants]]></item>
                <item name="wcf.acp.dataImport.data.com.woltlab.wcf.conversation.attachment"><![CDATA[Attachments]]></item>
        </category>
-       
        <category name="wcf.moderation">
                <item name="wcf.moderation.type.com.woltlab.wcf.conversation.message"><![CDATA[Conversation]]></item>
        </category>
-       
        <category name="wcf.page">
                <item name="wcf.page.onlineLocation.com.woltlab.wcf.conversation.Conversation"><![CDATA[Conversation <a href="{link controller='Conversation' object=$conversation}{/link}" class="conversationLink" data-conversation-id="{@$conversation->conversationID}">{$conversation->subject}</a>]]></item>
        </category>
-       
        <category name="wcf.search">
                <item name="wcf.search.type.com.woltlab.wcf.conversation"><![CDATA[This Conversation]]></item>
                <item name="wcf.search.type.com.woltlab.wcf.conversation.message"><![CDATA[Conversations]]></item>
                <item name="wcf.search.object.com.woltlab.wcf.conversation.message"><![CDATA[Conversation]]></item>
        </category>
-       
        <category name="wcf.user.notification">
                <item name="wcf.user.notification.conversation.message.message"><![CDATA[{@$author->getAnchorTag()} replied to the conversation <a href="{link controller='Conversation' object=$message->getConversation()}{/link}">{$message->getConversation()->getTitle()}</a>.]]></item>
                <item name="wcf.user.notification.conversation.message.message.stacked"><![CDATA[{if $count < 4}{@$authors[0]->getAnchorTag()}{if $count == 2} and {else}, {/if}{@$authors[1]->getAnchorTag()}{if $count == 3} and {@$authors[2]->getAnchorTag()}{/if}{else}{@$authors[0]->getAnchorTag()} and {#$count} other users{/if} replied to the conversation <a href="{link controller='Conversation' object=$message->getConversation()}{/link}">{$message->getConversation()->getTitle()}</a>.]]></item>
                <item name="wcf.user.notification.conversation.message.title.stacked"><![CDATA[{#$count} participants replied to a conversation]]></item>
                <item name="wcf.user.notification.conversation.message.mail.plaintext"><![CDATA[{@$authorList} replied to the conversation “{@$event->getUserNotificationObject()->getConversation()->subject}” [URL:{link controller='Conversation' object=$event->getUserNotificationObject()->getConversation() isEmail=true}{/link}]{if $count == 1 && !$guestTimesTriggered}:{else}.{/if}]]></item>
                <item name="wcf.user.notification.conversation.message.mail.html"><![CDATA[<p>{@$authorList} replied to the conversation <a href="{link controller='Conversation' object=$event->getUserNotificationObject()->getConversation() isHtmlEmail=true}{/link}">{$event->getUserNotificationObject()->getConversation()->subject}</a>:</p>]]></item>
+               <item name="wcf.user.notification.conversation.message.mail.title"><![CDATA["{@$author->username}" replied to the conversation "{@$message->getConversation()->subject}"]]></item>
                <item name="wcf.user.notification.conversation.message"><![CDATA[{@$author->getAnchorTag()} started the conversation <a href="{link controller='Conversation' object=$conversation}{/link}">{$conversation->subject}</a>.]]></item>
                <item name="wcf.user.notification.conversation.title"><![CDATA[New Conversation]]></item>
                <item name="wcf.user.notification.conversation.mail.plaintext"><![CDATA[{@$event->getAuthor()->username} [URL:{link controller='User' object=$event->getAuthor() isEmail=true}{/link}] started the conversation “{@$event->getUserNotificationObject()->subject}” [URL:{link controller='Conversation' object=$event->getUserNotificationObject() isEmail=true}{/link}]:]]></item>
                <item name="wcf.user.notification.conversation.mail.html"><![CDATA[<p><a href="{link controller='User' object=$event->getAuthor() isHtmlEmail=true}{/link}">{$event->getAuthor()->username}</a> started the conversation <a href="{link controller='Conversation' object=$event->getUserNotificationObject() isHtmlEmail=true}{/link}">{$event->getUserNotificationObject()->subject}</a>:</p>]]></item>
+               <item name="wcf.user.notification.conversation.mail.title"><![CDATA[New Conversation from "{@$author->username}"]]></item>
                <item name="wcf.user.notification.com.woltlab.wcf.conversation"><![CDATA[Conversations]]></item>
                <item name="wcf.user.notification.com.woltlab.wcf.conversation.notification.conversation"><![CDATA[Notify me of new conversations]]></item>
                <item name="wcf.user.notification.com.woltlab.wcf.conversation.message.notification.conversationMessage"><![CDATA[Notify me of new replies in conversations]]></item>
        </category>
-       
        <category name="wcf.user.option">
                <item name="wcf.user.option.conversationMessagesPerPage"><![CDATA[Messages per Page]]></item>
                <item name="wcf.user.option.conversationsPerPage"><![CDATA[Conversations per Page]]></item>
index a95701193bcfde8ccf4af61f8e6f061b35ce4845..4a62a48482df74ea25a102d458845020beed4087 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/vortex/objectType.xsd">
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/2019/objectType.xsd">
        <import>
                <type>
                        <name>com.woltlab.wcf.conversation.message</name>
@@ -7,25 +7,21 @@
                        <classname>wcf\system\search\ConversationMessageSearch</classname>
                        <searchindex>wcf1_conversation_message_search_index</searchindex>
                </type>
-               
                <type>
                        <name>com.woltlab.wcf.conversation.message</name>
                        <definitionname>com.woltlab.wcf.attachment.objectType</definitionname>
                        <classname>wcf\system\attachment\ConversationMessageAttachmentObjectType</classname>
                        <private>1</private>
                </type>
-               
                <type>
                        <name>com.woltlab.wcf.conversation.message</name>
                        <definitionname>com.woltlab.wcf.message</definitionname>
                </type>
-               
                <type>
                        <name>com.woltlab.wcf.conversation.conversation</name>
                        <definitionname>com.woltlab.wcf.clipboardItem</definitionname>
                        <listclassname>wcf\data\conversation\ConversationList</listclassname>
                </type>
-               
                <type>
                        <name>com.woltlab.wcf.conversation.notification</name>
                        <definitionname>com.woltlab.wcf.notification.objectType</definitionname>
                        <classname>wcf\system\user\notification\object\type\ConversationMessageNotificationObjectType</classname>
                        <category>com.woltlab.wcf.conversation</category>
                </type>
-               
                <type>
                        <name>com.woltlab.wcf.conversation.message</name>
                        <definitionname>com.woltlab.wcf.message.quote</definitionname>
                        <classname>wcf\system\message\quote\ConversationMessageQuoteHandler</classname>
                </type>
-               
                <type>
                        <name>com.woltlab.wcf.conversation.message</name>
                        <definitionname>com.woltlab.wcf.moderation.report</definitionname>
                        <classname>wcf\system\moderation\queue\report\ConversationMessageModerationQueueReportHandler</classname>
                </type>
-               
                <!-- Modification Log -->
                <type>
                        <name>com.woltlab.wcf.conversation.conversation</name>
                        <definitionname>com.woltlab.wcf.modifiableContent</definitionname>
+                       <classname>wcf\system\log\modification\ConversationModificationLogHandler</classname>
                </type>
                <!-- /Modification Log -->
-               
                <!-- importers -->
                <type>
                        <name>com.woltlab.wcf.conversation</name>
@@ -85,7 +78,6 @@
                        <classname>wcf\system\importer\ConversationAttachmentImporter</classname>
                </type>
                <!-- /importers -->
-               
                <!-- rebuild data workers -->
                <type>
                        <name>com.woltlab.wcf.conversation</name>
@@ -99,7 +91,6 @@
                        <nicevalue>-5</nicevalue>
                </type>
                <!-- /rebuild data workers -->
-               
                <!-- stat handlers -->
                <type>
                        <name>com.woltlab.wcf.conversation</name>
                        <categoryname>com.woltlab.wcf.conversation</categoryname>
                </type>
                <!-- /stat handlers -->
+               <!-- user content provider -->
+               <type>
+                       <name>com.woltlab.wcf.conversation</name>
+                       <definitionname>com.woltlab.wcf.content.userContentProvider</definitionname>
+                       <classname>wcf\system\user\content\provider\ConversationUserContentProvider</classname>
+               </type>
+               <type>
+                       <name>com.woltlab.wcf.conversation.message</name>
+                       <definitionname>com.woltlab.wcf.content.userContentProvider</definitionname>
+                       <classname>wcf\system\user\content\provider\ConversationMessageUserContentProvider</classname>
+               </type>
+               <!-- /user content provider -->
        </import>
 </data>
index fc87ab95ded24c9fa3e0e9de14a78a3ce11327e0..72d786aa4526d2b31b68544ea75182d00c1e1ea9 100644 (file)
@@ -1,5 +1,5 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/vortex/option.xsd">
+<?xml version="1.0" encoding="UTF-8"?>
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/2019/option.xsd">
        <import>
                <categories>
                        <category name="message.conversation">
@@ -7,14 +7,12 @@
                                <options>module_conversation</options>
                        </category>
                </categories>
-               
                <options>
                        <option name="module_conversation">
                                <categoryname>module.community</categoryname>
                                <optiontype>boolean</optiontype>
                                <defaultvalue>1</defaultvalue>
                        </option>
-                       
                        <option name="conversations_per_page">
                                <categoryname>message.conversation</categoryname>
                                <optiontype>integer</optiontype>
@@ -29,7 +27,6 @@
                                <minvalue>5</minvalue>
                                <maxvalue>40</maxvalue>
                        </option>
-                       
                        <option name="conversation_list_default_sort_field">
                                <categoryname>message.conversation</categoryname>
                                <optiontype>select</optiontype>
@@ -46,8 +43,4 @@ DESC:wcf.global.sortOrder.descending</selectoptions>
                        </option>
                </options>
        </import>
-       
-       <delete>
-               <option name="conversation_reply_show_messages_max" />
-       </delete>
-</data>
\ No newline at end of file
+</data>
index 41cbe71a359a64625526bc1eb58096e96e0c1d6d..489efffed6a89dd109df6174ae5af0981bc393e2 100644 (file)
@@ -1,34 +1,33 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<package name="com.woltlab.wcf.conversation" xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/tornado/package.xsd">
+<package name="com.woltlab.wcf.conversation" xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/2019/package.xsd">
        <packageinformation>
                <packagename>WoltLab Suite Core: Conversations</packagename>
+               <packagename language="de">WoltLab Suite Core: Konversationen</packagename>
                <packagedescription>Private conversations between multiple users</packagedescription>
-               <version>3.1.17</version>
-               <date>2020-08-28</date>
+               <packagedescription language="de">Private Konversationen zwischen mehreren Benutzern</packagedescription>
+               <version>5.2.13</version>
+               <date>2021-03-03</date>
        </packageinformation>
        
        <authorinformation>
                <author>WoltLab GmbH</author>
-               <authorurl>http://www.woltlab.com</authorurl>
+               <authorurl>https://www.woltlab.com</authorurl>
        </authorinformation>
        
        <requiredpackages>
-               <requiredpackage minversion="3.1.17">com.woltlab.wcf</requiredpackage>
+               <requiredpackage minversion="5.2.13">com.woltlab.wcf</requiredpackage>
        </requiredpackages>
        
        <excludedpackages>
-               <excludedpackage version="5.2.0 Alpha 1">com.woltlab.wcf</excludedpackage>
+               <excludedpackage version="5.3.0 Alpha 1">com.woltlab.wcf</excludedpackage>
        </excludedpackages>
        
-       <compatibility>
-               <api version="2018" />
-       </compatibility>
-       
        <instructions type="install">
                <instruction type="file" />
                <instruction type="userGroupOption" />
                <instruction type="sql" run="standalone" />
                <instruction type="template" />
+               <instruction type="acpTemplate" />
                <instruction type="option" />
                <instruction type="templateListener" />
                <instruction type="language" />
                <instruction type="page" />
        </instructions>
        
-       <instructions type="update" fromversion="3.0.*">
-               <instruction type="file" />
-               <instruction type="template" />
+       <instructions type="update" fromversion="3.1.*">
+               <instruction type="acpTemplate" run="standalone" />
+               <instruction type="file" run="standalone" />
+               <instruction type="template" run="standalone" />
                
-               <instruction type="script" run="standalone">acp/update_com.woltlab.wcf.conversation_3.1_addColumn.php</instruction>
-               
-               <instruction type="sql">update_3.1.sql</instruction>
+               <instruction type="script">acp/update_com.woltlab.wcf.conversation_5.2.php</instruction>
                
                <instruction type="language" />
                
+               <instruction type="clipboardAction" />
+               <instruction type="coreObject" />
+               <instruction type="eventListener" />
+               <instruction type="objectType" />
                <instruction type="option" />
                <instruction type="page" />
+               <instruction type="templateListener" />
                <instruction type="userGroupOption" />
+               <instruction type="userNotificationEvent" />
+               <instruction type="userOption" />
        </instructions>
        
-       <instructions type="update" fromversion="3.1.16">
-               <instruction type="file">files_update.tar</instruction>
+       <instructions type="update" fromversion="5.2.10">
+               <instruction type="language" />
        </instructions>
 </package>
index c2e6a39e6eb2f682b87e8c673af9fc3713b16985..97c628b7d6a69930823b37ebe4a6af0eea6d1459 100644 (file)
--- a/page.xml
+++ b/page.xml
@@ -1,14 +1,13 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/tornado/page.xsd">
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/2019/page.xsd">
        <import>
                <page identifier="com.woltlab.wcf.conversation.ConversationList">
+                       <pageType>system</pageType>
                        <controller>wcf\page\ConversationListPage</controller>
-                       <handler>wcf\system\page\handler\ConversationListPageHandler</handler>
                        <name language="de">Konversationenliste</name>
                        <name language="en">Conversation List</name>
-                       <pageType>system</pageType>
+                       <handler>wcf\system\page\handler\ConversationListPageHandler</handler>
                        <excludeFromLandingPage>1</excludeFromLandingPage>
-                       
                        <content language="en">
                                <title>Conversations</title>
                        </content>
                        </content>
                </page>
                <page identifier="com.woltlab.wcf.conversation.Conversation">
+                       <pageType>system</pageType>
                        <controller>wcf\page\ConversationPage</controller>
-                       <handler>wcf\system\page\handler\DefaultConversationRelatedPageHandler</handler>
                        <name language="de">Konversation</name>
                        <name language="en">Conversation</name>
-                       <pageType>system</pageType>
-                       <requireObjectID>1</requireObjectID>
+                       <handler>wcf\system\page\handler\DefaultConversationRelatedPageHandler</handler>
                        <hasFixedParent>1</hasFixedParent>
                        <parent>com.woltlab.wcf.conversation.ConversationList</parent>
+                       <requireObjectID>1</requireObjectID>
                </page>
                <page identifier="com.woltlab.wcf.conversation.ConversationAdd">
+                       <pageType>system</pageType>
                        <controller>wcf\form\ConversationAddForm</controller>
                        <name language="de">Konversation starten</name>
                        <name language="en">New Conversation</name>
-                       <pageType>system</pageType>
                        <hasFixedParent>1</hasFixedParent>
                        <parent>com.woltlab.wcf.conversation.ConversationList</parent>
                        <excludeFromLandingPage>1</excludeFromLandingPage>
-                       
                        <content language="en">
                                <title>New Conversation</title>
                        </content>
                        </content>
                </page>
                <page identifier="com.woltlab.wcf.conversation.ConversationDraftEdit">
+                       <pageType>system</pageType>
                        <controller>wcf\form\ConversationDraftEditForm</controller>
                        <name language="de">Konversations-Entwurf bearbeiten</name>
                        <name language="en">Edit Conversation Draft</name>
-                       <pageType>system</pageType>
-                       <requireObjectID>1</requireObjectID>
                        <hasFixedParent>1</hasFixedParent>
                        <parent>com.woltlab.wcf.conversation.ConversationList</parent>
-                       
+                       <requireObjectID>1</requireObjectID>
                        <content language="en">
                                <title>Edit Conversation Draft</title>
                        </content>
index c2a032f62c3e0e6dced439efe65b4ce60c3f5837..226f7eb204c6712047ba6d3ace1348709dd39f2c 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/vortex/templateListener.xsd">
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/2019/templateListener.xsd">
        <import>
                <templatelistener name="userPanel">
                        <environment>user</environment>
@@ -7,7 +7,6 @@
                        <eventname>menuItems</eventname>
                        <templatecode><![CDATA[{include file='__userPanelConversationDropdown'}]]></templatecode>
                </templatelistener>
-               
                <templatelistener name="userInformationButtons">
                        <environment>user</environment>
                        <templatename>userInformationButtons</templatename>
                        <templatecode><![CDATA[{include file='__userInformationStartConversation'}]]></templatecode>
                </templatelistener>
                
-               <templatelistener name="userButtons">
-                       <environment>user</environment>
-                       <templatename>user</templatename>
-                       <eventname>buttons</eventname>
-                       <templatecode><![CDATA[{include file='__userStartConversation'}]]></templatecode>
-               </templatelistener>
-               
                <templatelistener name="searchAreaConversationSettings">
                        <environment>user</environment>
                        <templatename>pageHeaderSearch</templatename>
                        <eventname>settings</eventname>
                        <templatecode><![CDATA[{include file='__searchAreaConversationSettings'}]]></templatecode>
                </templatelistener>
-               
                <templatelistener name="userProfileStartConversation">
                        <environment>user</environment>
                        <templatename>user</templatename>
                        <eventname>menuInteraction</eventname>
                        <templatecode><![CDATA[{include file='__userProfileStartConversation'}]]></templatecode>
                </templatelistener>
-               
                <templatelistener name="mobileMenuConversation">
                        <environment>user</environment>
                        <templatename>pageMenuMobile</templatename>
                        <eventname>userMenuItems</eventname>
                        <templatecode><![CDATA[{include file='__mobileMenuConversation'}]]></templatecode>
                </templatelistener>
+               <templatelistener name="userGroupAddCanBeAddedAsConversationParticipant">
+                       <environment>admin</environment>
+                       <templatename>userGroupAdd</templatename>
+                       <eventname>dataFields</eventname>
+                       <templatecode><![CDATA[{include file='__userGroupAddCanBeAddedAsConversationParticipant'}]]></templatecode>
+               </templatelistener>
        </import>
-       
        <delete>
-               <templatelistener name="userPanel">
-                       <environment>user</environment>
-                       <templatename>userPanel</templatename>
-                       <eventname>menuItems</eventname>
-               </templatelistener>
-                
-               <templatelistener name="searchAreaConversationSettings">
+               <templatelistener name="userButtons">
                        <environment>user</environment>
-                       <templatename>searchArea</templatename>
-                       <eventname>settings</eventname>
+                       <templatename>user</templatename>
+                       <eventname>buttons</eventname>
                </templatelistener>
        </delete>
 </data>
index 7e1a9c607ade2aed67c670419dc4b6a8cc9931e1..6f8836c706c668c69ca68bd60fb7e7e4c93b19cb 100644 (file)
@@ -6,7 +6,6 @@
                        <script data-relocate="true">
                                $(function() {
                                        new WCF.User.Panel.Conversation({
-                                               markAllAsReadConfirmMessage: '{lang}wcf.conversation.markAllAsRead.confirmMessage{/lang}',
                                                newConversation: '{lang}wcf.conversation.add{/lang}',
                                                newConversationLink: '{link controller='ConversationAdd' encode=false}{/link}',
                                                noItems: '{lang}wcf.conversation.noMoreItems{/lang}',
@@ -18,4 +17,4 @@
                        </script>
                {/if}
        </li>
-{/if}
\ No newline at end of file
+{/if}
diff --git a/templates/__userStartConversation.tpl b/templates/__userStartConversation.tpl
deleted file mode 100644 (file)
index a6935a0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{if MODULE_CONVERSATION && $__wcf->user->userID && $__wcf->session->getPermission('user.conversation.canUseConversation') && $__wcf->session->getPermission('user.conversation.canStartConversation') && $user->userID != $__wcf->user->userID}<li><a class="button jsTooltip" href="{link controller='ConversationAdd'}userID={@$user->userID}{/link}" title="{lang}wcf.conversation.button.add{/lang}"><span class="icon icon16 fa-comments"></span> <span class="invisible">{lang}wcf.conversation.button.add{/lang}</span></a></li>{/if}
\ No newline at end of file
index 9b735c37d73b80f1cb8a43961b167fba92e9b1c1..3d3d5478a2f438397d29b2380386bfe87f4cf38b 100644 (file)
@@ -51,7 +51,7 @@
                <nav class="contentHeaderNavigation">
                        <ul class="conversation jsConversationInlineEditorContainer" data-conversation-id="{@$conversation->conversationID}" data-label-ids="[ {implode from=$conversation->getAssignedLabels() item=label}{@$label->labelID}{/implode} ]" data-is-closed="{@$conversation->isClosed}" data-can-close-conversation="{if $conversation->userID == $__wcf->getUser()->userID}1{else}0{/if}" data-can-add-participants="{if $conversation->canAddParticipants()}1{else}0{/if}" data-is-draft="{if $conversation->isDraft}1{else}0{/if}">
                                <li class="jsOnly"><a href="{if $conversation->isDraft}{link controller='ConversationDraftEdit' id=$conversation->conversationID}{/link}{else}#{/if}" class="button jsConversationInlineEditor"><span class="icon icon16 fa-pencil"></span> <span>{lang}wcf.global.button.edit{/lang}</span></a></li>
-                               {if $conversation->canReply()}<li class="jsOnly"><a href="#" class="button buttonPrimary jsQuickReply"><span class="icon icon16 fa-plus"></span> <span>{lang}wcf.conversation.message.button.add{/lang}</span></a></li>{/if}
+                               {if $conversation->canReply()}<li class="jsOnly"><a href="#" class="button buttonPrimary jsQuickReply"><span class="icon icon16 fa-reply"></span> <span>{lang}wcf.conversation.message.button.add{/lang}</span></a></li>{/if}
                                {event name='contentHeaderNavigation'}
                        </ul>
                </nav>
@@ -97,7 +97,7 @@
 
 <div class="section">
        <ul class="messageList">
-               {if $pageNo == 1 && !$conversation->joinedAt|empty}<li><p class="info">{lang}wcf.conversation.visibility.previousMessages{/lang}</p></li>{/if}
+               {if $pageNo == 1 && !$conversation->joinedAt|empty}<li><p class="info" role="status">{lang}wcf.conversation.visibility.previousMessages{/lang}</p></li>{/if}
                {include file='conversationMessageList'}
                {hascontent}
                        <li class="messageListPagination">
                        </li>
                {/hascontent}
                {if $conversation->canReply()}{include file='conversationQuickReply'}{/if}
-               {if $pageNo == $pages && !$conversation->leftAt|empty}<li><p class="info">{lang}wcf.conversation.visibility.nextMessages{/lang}</p></li>{/if}
+               {if $pageNo == $pages && !$conversation->leftAt|empty}<li><p class="info" role="status">{lang}wcf.conversation.visibility.nextMessages{/lang}</p></li>{/if}
        </ul>
 </div>
 
                        new WCF.Moderation.Report.Content('com.woltlab.wcf.conversation.message', '.jsReportConversationMessage');
                {/if}
                new WCF.Conversation.RemoveParticipant({@$conversation->conversationID});
-               new WCF.Message.BBCode.CodeViewer();
        });
 </script>
 
index 21b7d7e182c4bf4944d919a558db6b2e4048712c..cc9a1b266598c68ac92c14b039cea85aca40ef7a 100644 (file)
@@ -33,7 +33,7 @@
                <dl{if $errorField == 'participants'} class="formError"{/if}>
                        <dt><label for="participants">{lang}wcf.conversation.participants{/lang}</label></dt>
                        <dd>
-                               <input type="text" id="participants" name="participants" class="long" value="{$participants}">
+                               <input type="text" id="participants" name="participants" class="long" value="">
                                {if $errorField == 'participants'}
                                        <small class="innerError">
                                                {if $errorType == 'empty'}
@@ -55,7 +55,7 @@
                        <dl{if $errorField == 'invisibleParticipants'} class="formError"{/if}>
                                <dt><label for="invisibleParticipants">{lang}wcf.conversation.invisibleParticipants{/lang}</label></dt>
                                <dd>
-                                       <input type="text" id="invisibleParticipants" name="invisibleParticipants" class="long" value="{$invisibleParticipants}">
+                                       <input type="text" id="invisibleParticipants" name="invisibleParticipants" class="long" value="">
                                        {if $errorField == 'invisibleParticipants'}
                                                <small class="innerError">
                                                        {if $errorType == 'empty'}
 <script data-relocate="true">
        require(['WoltLabSuite/Core/Ui/ItemList/User'], function(UiItemListUser) {
                UiItemListUser.init('participants', {
-                       maxItems: {@$__wcf->getSession()->getPermission('user.conversation.maxParticipants')}
+                       maxItems: {@$__wcf->getSession()->getPermission('user.conversation.maxParticipants')},
+                       includeUserGroups: {if $__wcf->getSession()->getPermission('user.conversation.canAddGroupParticipants')}true{else}false{/if},
+                       restrictUserGroupIDs: [-1, {implode from=$allowedUserGroupIDs item=allowedUserGroupID}{@$allowedUserGroupID}{/implode}],
+                       csvPerType: true,
+                       callbackSetupValues: function() {
+                               return [
+                                       {implode from=$participantsData item=participant}
+                                               { objectId: {@$participant['objectId']}, value: '{@$participant['value']|encodeJS}', type: '{@$participant['type']}' }
+                                       {/implode}
+                               ];
+                       }
                });
                
                UiItemListUser.init('invisibleParticipants', {
-                       maxItems: {@$__wcf->getSession()->getPermission('user.conversation.maxParticipants')}
+                       maxItems: {@$__wcf->getSession()->getPermission('user.conversation.maxParticipants')},
+                       includeUserGroups: {if $__wcf->getSession()->getPermission('user.conversation.canAddGroupParticipants')}true{else}false{/if},
+                       restrictUserGroupIDs: [-1, {implode from=$allowedUserGroupIDs item=allowedUserGroupID}{@$allowedUserGroupID}{/implode}],
+                       csvPerType: true,
+                       callbackSetupValues: function() {
+                               return [
+                                       {implode from=$invisibleParticipantsData item=participant}
+                                               { objectId: {@$participant['objectId']}, value: '{@$participant['value']|encodeJS}', type: '{@$participant['type']}' }
+                                       {/implode}
+                               ];
+                       }
                });
        });
        
index 55be1e83815b30b0e5b5deba93c0e32e7df83ce5..cca3719d6b4714d91067145c1afc840cf49db3b8 100644 (file)
@@ -7,8 +7,8 @@
 </dl>
 {if !$conversation->isDraft}
        {if $conversation->canAddParticipantsUnrestricted()}
-               <dl class="jsRestrictVisibility">
-                       <dt>{lang}wcf.conversation.visibility{/lang}</dt>
+               <dl role="group" aria-labelledby="messageVisibilityLabel" class="jsRestrictVisibility">
+                       <dt><label id="messageVisibilityLabel">{lang}wcf.conversation.visibility{/lang}</label></dt>
                        <dd>
                                <label><input type="radio" name="messageVisibility" value="all" checked> {lang}wcf.conversation.visibility.all{/lang}</label>
                                <small>{lang}wcf.conversation.visibility.all.description{/lang}</small>
index 7ef21e749bd6de63a360ddb3d32baad9bd9cccfd..b915eef36eb7ca15cb3efbfa25b585d71a54a81c 100644 (file)
@@ -24,7 +24,7 @@
        <dl>
                <dt>{lang}wcf.conversation.label.cssClassName{/lang}</dt>
                <dd>
-                       <ul id="labelManagementList">
+                       <ul role="group" aria-label="{lang}wcf.conversation.label.cssClassName{/lang}" id="labelManagementList">
                                {foreach from=$cssClassNames item=cssClassName}
                                        <li><label>
                                                <input type="radio" name="cssClassName" value="{@$cssClassName}"{if $cssClassName == 'none'} checked{/if}>
index 36458bd45fd3abb41722c21cad7095da97373567..7350529203dc69c23003946bc58ce3bfc75fd891 100644 (file)
@@ -1,4 +1,4 @@
-<dl class="wide">
+<dl role="group" aria-label="{lang}wcf.conversation.hideConversation{/lang}" class="wide">
        {if $hideConversation == 1}
                <dd>
                        <label><input type="radio" name="hideConversation" value="0"> {lang}wcf.conversation.hideConversation.restore{/lang}</label>
@@ -17,4 +17,4 @@
 
 <div class="formSubmit">
        <button id="hideConversation" class="buttonPrimary">{lang}wcf.global.button.submit{/lang}</button>
-</div>
\ No newline at end of file
+</div>
index 86f5f5b02ce86ff41f34d8e6d19c30cfd99d7d5f..d2f4f7b377a2c302fa7491c1dfc1f1274d9ce710 100644 (file)
 {/hascontent}
 
 {if !$items}
-       <p class="info">{lang}wcf.conversation.noConversations{/lang}</p>
+       <p class="info" role="status">{lang}wcf.conversation.noConversations{/lang}</p>
 {else}
        <div class="section tabularBox messageGroupList conversationList jsClipboardContainer" data-type="com.woltlab.wcf.conversation.conversation">
                <ol class="tabularList">
                        <li class="tabularListRow tabularListRowHead">
                                <ol class="tabularListColumns">
                                        <li class="columnMark jsOnly"><label><input type="checkbox" class="jsClipboardMarkAll"></label></li>
-                                       <li class="columnSubject{if $sortField === 'subject'} active {@$sortOrder}{/if}"><a href="{link controller='ConversationList'}{if $filter}filter={@$filter}&{/if}{if !$participants|empty}participants={implode from=$participants item=participant}{$participant|rawurlencode}{/implode}&{/if}pageNo={@$pageNo}&sortField=subject&sortOrder={if $sortField == 'subject' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{if $labelID}&labelID={@$labelID}{/if}{/link}">{lang}wcf.global.subject{/lang}</a></li>
-                                       <li class="columnStats{if $sortField == 'replies'} active {@$sortOrder}{/if}"><a href="{link controller='ConversationList'}{if $filter}filter={@$filter}&{/if}{if !$participants|empty}participants={implode from=$participants item=participant}{$participant|rawurlencode}{/implode}&{/if}pageNo={@$pageNo}&sortField=replies&sortOrder={if $sortField == 'replies' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{if $labelID}&labelID={@$labelID}{/if}{/link}">{lang}wcf.conversation.replies{/lang}</a></li>
-                                       <li class="columnLastPost{if $sortField === 'lastPostTime'} active {@$sortOrder}{/if}"><a href="{link controller='ConversationList'}{if $filter}filter={@$filter}&{/if}{if !$participants|empty}participants={implode from=$participants item=participant}{$participant|rawurlencode}{/implode}&{/if}pageNo={@$pageNo}&sortField=lastPostTime&sortOrder={if $sortField == 'lastPostTime' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{if $labelID}&labelID={@$labelID}{/if}{/link}">{lang}wcf.conversation.lastPostTime{/lang}</a></li>
                                        
-                                       {event name='columnHeads'}
+                                       <li class="columnSort">
+                                               <ul class="inlineList">
+                                                       <li>
+                                                               <a rel="nofollow" href="{link controller='ConversationList'}{if $filter}filter={@$filter}&{/if}{if !$participants|empty}participants={implode from=$participants item=participant}{$participant|rawurlencode}{/implode}&{/if}pageNo={@$pageNo}&sortField={$sortField}&sortOrder={if $sortOrder == 'ASC'}DESC{else}ASC{/if}{if $labelID}&labelID={@$labelID}{/if}{/link}">
+                                                                       <span class="icon icon16 fa-sort-amount-{$sortOrder|strtolower} jsTooltip" title="{lang}wcf.global.sorting{/lang} ({lang}wcf.global.sortOrder.{if $sortOrder === 'ASC'}ascending{else}descending{/if}{/lang})"></span>
+                                                               </a>
+                                                       </li>
+                                                       <li>
+                                                               <div class="dropdown">
+                                                                       <span class="dropdownToggle">{if $sortField == 'subject'}{lang}wcf.global.subject{/lang}{else}{lang}wcf.conversation.{$sortField}{/lang}{/if}</span>
+                                                                       
+                                                                       <ul class="dropdownMenu">
+                                                                               {foreach from=$validSortFields item=_sortField}
+                                                                                       <li{if $_sortField === $sortField} class="active"{/if}><a rel="nofollow" href="{link controller='ConversationList'}{if $filter}filter={@$filter}&{/if}{if !$participants|empty}participants={implode from=$participants item=participant}{$participant|rawurlencode}{/implode}&{/if}pageNo={@$pageNo}&sortField={$_sortField}&sortOrder={if $sortField === $_sortField}{if $sortOrder === 'DESC'}ASC{else}DESC{/if}{else}{$sortOrder}{/if}{if $labelID}&labelID={@$labelID}{/if}{/link}">{if $_sortField == 'subject'}{lang}wcf.global.subject{/lang}{else}{lang}wcf.conversation.{$_sortField}{/lang}{/if}</a></li>
+                                                                               {/foreach}
+                                                                       </ul>
+                                                               </div>
+                                                       </li>
+                                               </ul>
+                                       </li>
                                </ol>
                        </li>
                        
                                                                {/if}
                                                        </h3>
                                                        
-                                                       <aside class="statusDisplay">
+                                                       <aside class="statusDisplay" role="presentation">
                                                                <ul class="statusIcons">
                                                                        {if $conversation->isClosed}<li><span class="icon icon16 fa-lock jsIconLock jsTooltip" title="{lang}wcf.global.state.closed{/lang}"></span></li>{/if}
                                                                        {if $conversation->attachments}<li><span class="icon icon16 fa-paperclip jsIconAttachment jsTooltip" title="{lang}wcf.conversation.attachments{/lang}"></span></li>{/if}
                                                        <ul class="inlineList dotSeparated small messageGroupInfo">
                                                                <li class="messageGroupAuthor">{if $conversation->userID}<a href="{link controller='User' object=$conversation->getUserProfile()->getDecoratedObject()}{/link}" class="userLink" data-user-id="{@$conversation->userID}">{$conversation->username}</a>{else}{$conversation->username}{/if}</li>
                                                                <li class="messageGroupTime">{@$conversation->time|time}</li>
-                                                               <li class="messageGroupEditLink jsOnly"><a class="jsConversationInlineEditor">{lang}wcf.global.button.edit{/lang}</a></li>
+                                                               <li class="messageGroupEditLink jsOnly"><a href="#" class="jsConversationInlineEditor">{lang}wcf.global.button.edit{/lang}</a></li>
                                                                {event name='messageGroupInfo'}
                                                        </ul>
                                                        
                                                                <dd>{@$conversation->participants|shortUnit}</dd>
                                                        </dl>
                                                        
-                                                       <div class="messageGroupListStatsSimple">{@$conversation->replies|shortUnit}</div>
+                                                       <div class="messageGroupListStatsSimple" aria-label="{lang}wcf.conversation.replies{/lang}">{@$conversation->replies|shortUnit}</div>
                                                </li>
                                                <li class="columnLastPost">
                                                        {if $conversation->replies != 0 && $conversation->lastPostTime}
index 7b57a9bd994f5ba8d174f8f09b63806834707199..3574d4cedc7e3f06cb250fd1dbff3a4eee50a56a 100644 (file)
@@ -6,7 +6,7 @@
                                <div class="messageContent">
                                        <div class="messageHeader">
                                                <div class="box32 messageHeaderWrapper">
-                                                       <a href="{link controller='User' object=$modificationLogEntry->getUserProfile()}{/link}">{@$modificationLogEntry->getUserProfile()->getAvatar()->getImageTag(32)}</a>
+                                                       <a href="{link controller='User' object=$modificationLogEntry->getUserProfile()}{/link}" aria-hidden="true">{@$modificationLogEntry->getUserProfile()->getAvatar()->getImageTag(32)}</a>
                                                        
                                                        <div class="messageHeaderBox">
                                                                <h2 class="messageTitle">
index ae29f11e906bc07315d21ce64288faf3fb3b224c..e159aea59288691a97c97f00b204245f45d280c5 100644 (file)
@@ -1,6 +1,6 @@
 <div class="box48">
        {if $message->getUserProfile()->getAvatar()}
-               <a href="{link controller='User' object=$message->getUserProfile()->getDecoratedObject()}{/link}">{@$message->getUserProfile()->getAvatar()->getImageTag(48)}</a>
+               <a href="{link controller='User' object=$message->getUserProfile()->getDecoratedObject()}{/link}" aria-hidden="true">{@$message->getUserProfile()->getAvatar()->getImageTag(48)}</a>
        {/if}
 
        <div>
index c2da4183ebe58c6f29ae48bd56837e30eda8f183..90f31a624380f5e2e4cb1b1baacf97e20d9b5e39 100644 (file)
@@ -5,7 +5,7 @@
                <div class="messageContent messageQuickReplyContent"{if $pageNo < $pages} data-placeholder="{lang}wcf.conversation.reply{/lang}"{/if}>
                        <div class="messageBody">
                                {if !$conversation->isDraft && !$conversation->hasOtherParticipants()}
-                                       <p class="warning" style="margin-bottom: 14px">{lang}wcf.conversation.noParticipantsWarning{/lang}</p>
+                                       <p class="warning"  role="status" style="margin-bottom: 14px">{lang}wcf.conversation.noParticipantsWarning{/lang}</p>
                                {/if}
                                
                                <textarea id="text" name="text" class="wysiwygTextarea"
index 8a0baa61dd334f4e2f6539b0c5be41270eb4a361..ca88a212a0a2d596df63fffe0a019baae4053120 100644 (file)
@@ -3,7 +3,7 @@
                <header class="messageHeader">
                        <div class="box32 messageHeaderWrapper">
                                {if $message->userID}
-                                       <a href="{link controller='User' object=$message->getUserProfile()->getDecoratedObject()}{/link}">{@$message->getUserProfile()->getAvatar()->getImageTag(32)}</a>
+                                       <a href="{link controller='User' object=$message->getUserProfile()->getDecoratedObject()}{/link}" aria-hidden="true">{@$message->getUserProfile()->getAvatar()->getImageTag(32)}</a>
                                {else}
                                        <span>{@$message->getUserProfile()->getAvatar()->getImageTag(32)}</span>
                                {/if}
diff --git a/update_3.1.sql b/update_3.1.sql
deleted file mode 100644 (file)
index 955887e..0000000
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE wcf1_conversation_to_user ADD FOREIGN KEY (lastMessageID) REFERENCES wcf1_conversation_message (messageID) ON DELETE SET NULL;
index 3052601202d02bc95cc4a11999471e5886a9b1aa..fc7b4455e758483e655192794ff7cf9a01cccbbc 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/vortex/userGroupOption.xsd">
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/2019/userGroupOption.xsd">
        <import>
                <categories>
                        <category name="user.conversation">
                                <options>module_conversation</options>
                        </category>
                </categories>
-               
                <options>
                        <!-- mod.conversation -->
                        <option name="mod.conversation.canModerateConversation">
                                <categoryname>mod.conversation</categoryname>
                                <optiontype>boolean</optiontype>
                                <defaultvalue>0</defaultvalue>
-                               <admindefaultvalue>1</admindefaultvalue>
                                <options>module_conversation</options>
+                               <admindefaultvalue>1</admindefaultvalue>
                                <usersonly>1</usersonly>
                        </option>
                        <option name="mod.conversation.canAlwaysInviteUsers">
                                <categoryname>mod.conversation</categoryname>
                                <optiontype>boolean</optiontype>
                                <defaultvalue>0</defaultvalue>
-                               <admindefaultvalue>1</admindefaultvalue>
                                <options>module_conversation</options>
+                               <admindefaultvalue>1</admindefaultvalue>
                                <usersonly>1</usersonly>
                        </option>
                        <!-- /mod.conversation -->
-                       
                        <!-- user.conversation -->
                        <option name="user.conversation.canUseConversation">
                                <categoryname>user.conversation</categoryname>
                                <defaultvalue>1</defaultvalue>
                                <usersonly>1</usersonly>
                        </option>
+                       <option name="user.conversation.canAddGroupParticipants">
+                               <categoryname>user.conversation</categoryname>
+                               <optiontype>boolean</optiontype>
+                               <defaultvalue>0</defaultvalue>
+                               <usersonly>1</usersonly>
+                               <admindefaultvalue>1</admindefaultvalue>
+                       </option>
+                       
                        <option name="user.conversation.maxParticipants">
                                <categoryname>user.conversation</categoryname>
                                <optiontype>integer</optiontype>
                                <categoryname>user.conversation</categoryname>
                                <optiontype>integer</optiontype>
                                <defaultvalue>10000</defaultvalue>
-                               <admindefaultvalue>100000</admindefaultvalue>
                                <minvalue>1000</minvalue>
+                               <admindefaultvalue>100000</admindefaultvalue>
                                <usersonly>1</usersonly>
                        </option>
-                       
                        <option name="user.conversation.canUploadAttachment">
                                <categoryname>user.conversation</categoryname>
                                <optiontype>boolean</optiontype>
@@ -132,8 +137,8 @@ zip
 txt
 pdf</defaultvalue>
                                <options>module_attachment</options>
-                               <wildcard>*</wildcard>
                                <usersonly>1</usersonly>
+                               <wildcard>*</wildcard>
                        </option>
                        <option name="user.conversation.maxAttachmentCount">
                                <categoryname>user.conversation</categoryname>
@@ -144,8 +149,6 @@ pdf</defaultvalue>
                                <maxvalue>100</maxvalue>
                                <usersonly>1</usersonly>
                        </option>
-                       <!-- /user.conversation -->
                </options>
        </import>
 </data>
-
index b4cab952f6ead71d9c260955e48f3d4dde278d9e..377bcf0630937cf6a7da69bdf53d0ad7e9bcde10 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/vortex/userNotificationEvent.xsd">
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/2019/userNotificationEvent.xsd">
        <import>
                <event>
                        <name>conversation</name>
@@ -7,7 +7,6 @@
                        <classname>wcf\system\user\notification\event\ConversationUserNotificationEvent</classname>
                        <options>module_conversation</options>
                </event>
-               
                <event>
                        <name>conversationMessage</name>
                        <objecttype>com.woltlab.wcf.conversation.message.notification</objecttype>
index 85b1e7f9ca88a2af4c2c11cf1bc2435c3ca7b397..5ed9b4f78ef20baf45dd6dcbda676c651cf6193f 100644 (file)
@@ -1,43 +1,42 @@
-<?xml version="1.0" encoding="utf-8"?>
-<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/vortex/userOption.xsd">
+<?xml version="1.0" encoding="UTF-8"?>
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/2019/userOption.xsd">
        <import>
                <options>
                        <option name="canSendConversation">
                                <categoryname>settings.privacy.messaging</categoryname>
                                <optiontype>select</optiontype>
-                               <editable>3</editable>
+                               <defaultvalue>0</defaultvalue>
+                               <options>module_conversation</options>
                                <selectoptions>0:wcf.user.access.registered
 1:wcf.user.access.following
 2:wcf.user.access.nobody</selectoptions>
-                               <defaultvalue>0</defaultvalue>
-                               <options>module_conversation</options>
+                               <editable>3</editable>
                        </option>
-                       
                        <option name="conversationsPerPage">
                                <categoryname>settings.general.appearance</categoryname>
                                <optiontype>select</optiontype>
-                               <editable>3</editable>
                                <defaultvalue>0</defaultvalue>
+                               <options>module_conversation</options>
                                <selectoptions>0:wcf.global.defaultValue
 5
 10
 20
 30
 40</selectoptions>
-                               <options>module_conversation</options>
+                               <editable>3</editable>
                        </option>
                        <option name="conversationMessagesPerPage">
                                <categoryname>settings.general.appearance</categoryname>
                                <optiontype>select</optiontype>
-                               <editable>3</editable>
                                <defaultvalue>0</defaultvalue>
+                               <options>module_conversation</options>
                                <selectoptions>0:wcf.global.defaultValue
 5
 10
 20
 30
 40</selectoptions>
-                               <options>module_conversation</options>
+                               <editable>3</editable>
                        </option>
                </options>
        </import>