Add `type` to `wcf1_user_ignore`
authorTim Düsterhus <duesterhus@woltlab.com>
Wed, 10 Mar 2021 11:21:51 +0000 (12:21 +0100)
committerTim Düsterhus <duesterhus@woltlab.com>
Thu, 22 Apr 2021 10:03:45 +0000 (12:03 +0200)
ts/WoltLabSuite/Core/Ui/User/Profile/Menu/Item/Ignore.ts
wcfsetup/install/files/acp/database/update_com.woltlab.wcf_5.4.php
wcfsetup/install/files/js/WoltLabSuite/Core/Ui/User/Profile/Menu/Item/Ignore.js
wcfsetup/install/files/lib/data/user/ignore/UserIgnore.class.php
wcfsetup/install/files/lib/data/user/ignore/UserIgnoreAction.class.php
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml
wcfsetup/setup/db/install.sql

index debe11bb5917e41a21df44820b2a6ad305a521ce..5e89335cf2e2138624daeb7b2d1b9279cb3bca8b 100644 (file)
@@ -1,41 +1,47 @@
 import * as Core from "../../../../../Core";
 import * as Language from "../../../../../Language";
-import { AjaxCallbackSetup, ResponseData } from "../../../../../Ajax/Data";
 import * as UiNotification from "../../../../Notification";
 import UiUserProfileMenuItemAbstract from "./Abstract";
+import FormBuilderDialog from "../../../../../Form/Builder/Dialog";
 
-interface AjaxResponse extends ResponseData {
-  returnValues: {
-    isIgnoredUser: 1 | 0;
-  };
+interface AjaxResponse {
+  isIgnoredUser: 1 | 0;
 }
 
 class UiUserProfileMenuItemIgnore extends UiUserProfileMenuItemAbstract {
+  private readonly dialog: FormBuilderDialog;
+
   constructor(userId: number, isActive: boolean) {
     super(userId, isActive);
+
+    this.dialog = new FormBuilderDialog("ignoreDialog", "wcf\\data\\user\\ignore\\UserIgnoreAction", "getDialog", {
+      dialog: {
+        title: Language.get("wcf.user.button.ignore"),
+      },
+      actionParameters: {
+        userID: this._userId,
+      },
+      submitActionName: "submitDialog",
+      successCallback: (r: AjaxResponse) => this._ajaxSuccess(r),
+      destroyOnClose: true,
+    });
   }
 
   _getLabel(): string {
     return Language.get("wcf.user.button." + (this._isActive ? "un" : "") + "ignore");
   }
 
-  _getAjaxActionName(): string {
-    return this._isActive ? "unignore" : "ignore";
-  }
-
   _ajaxSuccess(data: AjaxResponse): void {
-    this._isActive = !!data.returnValues.isIgnoredUser;
+    this._isActive = !!data.isIgnoredUser;
     this._updateButton();
 
     UiNotification.show();
   }
 
-  _ajaxSetup(): ReturnType<AjaxCallbackSetup> {
-    return {
-      data: {
-        className: "wcf\\data\\user\\ignore\\UserIgnoreAction",
-      },
-    };
+  protected _toggle(event: MouseEvent): void {
+    event.preventDefault();
+
+    this.dialog.open();
   }
 }
 
index ed946e355a0c755fac299149b64eefce401e5844..dbad31b28ede5e85ab74126e6b48d1e3e9aac9d2 100644 (file)
@@ -19,6 +19,7 @@ use wcf\system\database\table\column\NotNullInt10DatabaseTableColumn;
 use wcf\system\database\table\column\NotNullVarchar255DatabaseTableColumn;
 use wcf\system\database\table\column\ObjectIdDatabaseTableColumn;
 use wcf\system\database\table\column\TextDatabaseTableColumn;
+use wcf\system\database\table\column\TinyintDatabaseTableColumn;
 use wcf\system\database\table\column\VarbinaryDatabaseTableColumn;
 use wcf\system\database\table\column\VarcharDatabaseTableColumn;
 use wcf\system\database\table\DatabaseTable;
@@ -115,6 +116,14 @@ return [
             DefaultFalseBooleanDatabaseTableColumn::create('requireMultifactor'),
         ]),
 
+    PartialDatabaseTable::create('wcf1_user_ignore')
+        ->columns([
+            TinyintDatabaseTableColumn::create('type')
+                ->length(1)
+                ->notNull()
+                ->defaultValue(1),
+        ]),
+
     DatabaseTable::create('wcf1_user_multifactor')
         ->columns([
             ObjectIdDatabaseTableColumn::create('setupID'),
index 63c5cfda39d5c0e50f9fa73ec2ac1286a38cd676..5854d6efd335290204e285a7a93190c7f9920e1f 100644 (file)
@@ -1,30 +1,36 @@
-define(["require", "exports", "tslib", "../../../../../Core", "../../../../../Language", "../../../../Notification", "./Abstract"], function (require, exports, tslib_1, Core, Language, UiNotification, Abstract_1) {
+define(["require", "exports", "tslib", "../../../../../Core", "../../../../../Language", "../../../../Notification", "./Abstract", "../../../../../Form/Builder/Dialog"], function (require, exports, tslib_1, Core, Language, UiNotification, Abstract_1, Dialog_1) {
     "use strict";
     Core = tslib_1.__importStar(Core);
     Language = tslib_1.__importStar(Language);
     UiNotification = tslib_1.__importStar(UiNotification);
     Abstract_1 = tslib_1.__importDefault(Abstract_1);
+    Dialog_1 = tslib_1.__importDefault(Dialog_1);
     class UiUserProfileMenuItemIgnore extends Abstract_1.default {
         constructor(userId, isActive) {
             super(userId, isActive);
+            this.dialog = new Dialog_1.default("ignoreDialog", "wcf\\data\\user\\ignore\\UserIgnoreAction", "getDialog", {
+                dialog: {
+                    title: Language.get("wcf.user.button.ignore"),
+                },
+                actionParameters: {
+                    userID: this._userId,
+                },
+                submitActionName: "submitDialog",
+                successCallback: (r) => this._ajaxSuccess(r),
+                destroyOnClose: true,
+            });
         }
         _getLabel() {
             return Language.get("wcf.user.button." + (this._isActive ? "un" : "") + "ignore");
         }
-        _getAjaxActionName() {
-            return this._isActive ? "unignore" : "ignore";
-        }
         _ajaxSuccess(data) {
-            this._isActive = !!data.returnValues.isIgnoredUser;
+            this._isActive = !!data.isIgnoredUser;
             this._updateButton();
             UiNotification.show();
         }
-        _ajaxSetup() {
-            return {
-                data: {
-                    className: "wcf\\data\\user\\ignore\\UserIgnoreAction",
-                },
-            };
+        _toggle(event) {
+            event.preventDefault();
+            this.dialog.open();
         }
     }
     Core.enableLegacyInheritance(UiUserProfileMenuItemIgnore);
index 089b6548206435516f278ced209e34b852551a0f..2b5c3bf3a51df85fcb223b061bf6d96ab43eea1a 100644 (file)
@@ -17,9 +17,16 @@ use wcf\system\WCF;
  * @property-read   int $userID         id of the ignoring user
  * @property-read   int $ignoreUserID       id of the ignored user
  * @property-read   int $time           time at which ignore relation has been established
+ * @property-read   int $type           one of the TYPE_* class constants
  */
 class UserIgnore extends DatabaseObject
 {
+    public const TYPE_NO_IGNORE = 0;
+
+    public const TYPE_BLOCK_DIRECT_CONTACT = 1;
+
+    public const TYPE_HIDE_MESSAGES = 2;
+
     /**
      * Returns a UserIgnore object for given ignored user id.
      *
index e98d4bcce686fdbd73386460f165a816d3da8721..32fe88f96cbcbc774212ea80eaf2cc996b6b01fb 100644 (file)
@@ -5,10 +5,17 @@ namespace wcf\data\user\ignore;
 use wcf\data\AbstractDatabaseObjectAction;
 use wcf\data\user\follow\UserFollow;
 use wcf\data\user\follow\UserFollowEditor;
+use wcf\data\user\User;
 use wcf\system\cache\runtime\UserProfileRuntimeCache;
 use wcf\system\exception\IllegalLinkException;
 use wcf\system\exception\PermissionDeniedException;
 use wcf\system\exception\UserInputException;
+use wcf\system\form\builder\data\processor\CustomFormDataProcessor;
+use wcf\system\form\builder\DialogFormDocument;
+use wcf\system\form\builder\field\RadioButtonFormField;
+use wcf\system\form\builder\field\validation\FormFieldValidationError;
+use wcf\system\form\builder\field\validation\FormFieldValidator;
+use wcf\system\form\builder\IFormDocument;
 use wcf\system\user\storage\UserStorageHandler;
 use wcf\system\WCF;
 
@@ -26,6 +33,8 @@ use wcf\system\WCF;
  */
 class UserIgnoreAction extends AbstractDatabaseObjectAction
 {
+    protected $form;
+
     /**
      * Validates the 'ignore' action.
      */
@@ -42,6 +51,18 @@ class UserIgnoreAction extends AbstractDatabaseObjectAction
         if ($userProfile->getPermission('user.profile.cannotBeIgnored')) {
             throw new PermissionDeniedException();
         }
+
+        $this->readInteger('type', true, 'data');
+
+        if (
+            $this->parameters['data']['type']
+            && !\in_array($this->parameters['data']['type'], [
+                UserIgnore::TYPE_BLOCK_DIRECT_CONTACT,
+                UserIgnore::TYPE_HIDE_MESSAGES,
+            ])
+        ) {
+            throw new UserInputException('type', 'invalid');
+        }
     }
 
     /**
@@ -51,12 +72,22 @@ class UserIgnoreAction extends AbstractDatabaseObjectAction
      */
     public function ignore()
     {
-        /** @var UserIgnore $ignore */
-        $ignore = UserIgnoreEditor::createOrIgnore([
-            'ignoreUserID' => $this->parameters['data']['userID'],
-            'time' => TIME_NOW,
-            'userID' => WCF::getUser()->userID,
-        ]);
+        $ignore = new UserIgnoreEditor(UserIgnore::getIgnore($this->parameters['data']['userID']));
+        $type = $this->parameters['data']['type'] ?? UserIgnore::TYPE_BLOCK_DIRECT_CONTACT;
+
+        if ($ignore->ignoreID) {
+            $ignore->update([
+                'type' => $type,
+                'time' => TIME_NOW,
+            ]);
+        } else {
+            $ignore = UserIgnoreEditor::createOrIgnore([
+                'ignoreUserID' => $this->parameters['data']['userID'],
+                'type' => $type,
+                'time' => TIME_NOW,
+                'userID' => WCF::getUser()->userID,
+            ]);
+        }
 
         if ($ignore !== null) {
             UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'ignoredUserIDs');
@@ -121,6 +152,126 @@ class UserIgnoreAction extends AbstractDatabaseObjectAction
         return ['isIgnoredUser' => 0];
     }
 
+    public function validateGetDialog()
+    {
+        $this->readInteger('userID');
+
+        $userProfile = UserProfileRuntimeCache::getInstance()->getObject($this->parameters['userID']);
+        if ($userProfile === null || $userProfile->userID == WCF::getUser()->userID) {
+            throw new IllegalLinkException();
+        }
+
+        $ignore = UserIgnore::getIgnore($this->parameters['userID']);
+
+        // Check if the user is not yet ignored and cannot be ignored.
+        if (!$ignore && $userProfile->getPermission('user.profile.cannotBeIgnored')) {
+            throw new PermissionDeniedException();
+        }
+    }
+
+    public function getDialog()
+    {
+        $form = $this->getForm();
+
+        return [
+            'dialog' => $form->getHtml(),
+            'formId' => $form->getId(),
+        ];
+    }
+
+    public function validateSubmitDialog()
+    {
+        $this->validateGetDialog();
+
+        $this->readString('formId');
+
+        $this->getForm()->requestData($this->parameters['data'] ?? []);
+        $this->getForm()->readValues();
+    }
+
+    public function submitDialog()
+    {
+        $this->getForm()->validate();
+
+        if ($this->getForm()->hasValidationErrors()) {
+            return [
+                'dialog' => $this->getForm()->getHtml(),
+                'formId' => $this->getForm()->getId(),
+            ];
+        }
+
+        $formData = $this->getForm()->getData();
+
+        if ($formData['data']['type'] === UserIgnore::TYPE_NO_IGNORE) {
+            return (new self([], 'unignore', [
+                'data' => [
+                    'userID' => $this->parameters['userID'],
+                ],
+            ]))->executeAction()['returnValues'];
+        } else {
+            return (new self([], 'ignore', [
+                'data' => [
+                    'userID' => $this->parameters['userID'],
+                    'type' => $formData['data']['type'],
+                ],
+            ]))->executeAction()['returnValues'];
+        }
+    }
+
+    protected function getForm(): IFormDocument
+    {
+        if ($this->form === null) {
+            $id = 'userIgnore';
+            $this->form = DialogFormDocument::create($id)
+                ->ajax()
+                ->prefix($id);
+
+            $ignore = UserIgnore::getIgnore($this->parameters['userID']);
+
+            $this->form->appendChildren([
+                RadioButtonFormField::create('type')
+                    ->label(WCF::getLanguage()->get('wcf.user.ignore.type'))
+                    ->options([
+                        UserIgnore::TYPE_NO_IGNORE => WCF::getLanguage()
+                            ->get('wcf.user.ignore.type.noIgnore'),
+                        UserIgnore::TYPE_BLOCK_DIRECT_CONTACT => WCF::getLanguage()
+                            ->get('wcf.user.ignore.type.blockDirectContact'),
+                        UserIgnore::TYPE_HIDE_MESSAGES => WCF::getLanguage()
+                            ->get('wcf.user.ignore.type.hideMessages'),
+                    ])
+                    ->value($ignore->type ?: 0)
+                    ->addValidator(new FormFieldValidator('type', function (RadioButtonFormField $formField) {
+                        $userProfile = UserProfileRuntimeCache::getInstance()->getObject($this->parameters['userID']);
+                        if ($userProfile->getPermission('user.profile.cannotBeIgnored')) {
+                            if ($formField->getValue() != UserIgnore::TYPE_NO_IGNORE) {
+                                $formField->addValidationError(
+                                    new FormFieldValidationError(
+                                        'cannotBeIgnored',
+                                        'wcf.user.ignore.error.cannotBeIgnored'
+                                    )
+                                );
+                            }
+                        }
+                    })),
+            ]);
+
+            $this->form->getDataHandler()->addProcessor(
+                new CustomFormDataProcessor(
+                    'type',
+                    static function (IFormDocument $document, array $parameters) {
+                        $parameters['data']['type'] = \intval($parameters['data']['type']);
+
+                        return $parameters;
+                    }
+                )
+            );
+
+            $this->form->build();
+        }
+
+        return $this->form;
+    }
+
     /**
      * @inheritDoc
      */
index d570edb19988773786fabdcd268b7575f35d3051..6247b20154697665774d51dc1742e38326d085c0 100644 (file)
@@ -4800,6 +4800,11 @@ sich{/if} nicht bei uns registriert {if LANGUAGE_USE_INFORMAL_VARIANT}hast{else}
                <item name="wcf.user.reauthentication.explanation"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Du betrittst einen besonders geschützten Bereich. Aus Sicherheitsgründen ist es notwendig, dass du dich durch Eingabe deines Kennworts erneut authentifizierst.{else}Sie betreten einen besonders geschützten Bereich. Aus Sicherheitsgründen ist es notwendig, dass Sie sich durch Eingabe Ihres Kennworts erneut authentifizieren.{/if}]]></item>
                <item name="wcf.user.reauthentication.loginAs"><![CDATA[Angemeldet als]]></item>
                <item name="wcf.user.reauthentication.logoutAndChangeUser"><![CDATA[Nicht {$__wcf->user->username}? <a href="{link controller='FullLogout' application='wcf'}t={csrfToken type='url'}{/link}">Abmelden und Benutzer wechseln</a>.]]></item>
+               <item name="wcf.user.ignore.type"><![CDATA[Benutzer blockieren]]></item>
+               <item name="wcf.user.ignore.type.noIgnore"><![CDATA[Nicht Blockieren]]></item>
+               <item name="wcf.user.ignore.type.blockDirectContact"><![CDATA[Direkten Kontakt blockieren]]></item>
+               <item name="wcf.user.ignore.type.hideMessages"><![CDATA[Erstellte Inhalte ausblenden]]></item>
+               <item name="wcf.user.ignore.error.cannotBeIgnored"><![CDATA[Der Benutzer kann nicht blockiert werden.]]></item>
        </category>
        <category name="wcf.user.menu">
                <item name="wcf.user.menu.community"><![CDATA[Community]]></item>
index b3caad7bd1e4c15bb4bd0fe57dab07302d54c6b8..f845c08de1222458c2523bf55a21469f81ea2ab3 100644 (file)
@@ -4798,6 +4798,11 @@ not register with us.]]></item>
                <item name="wcf.user.reauthentication.explanation"><![CDATA[You are entering a security-sensitive area. For security reasons it is required that you re-authenticate yourself by entering your password.]]></item>
                <item name="wcf.user.reauthentication.loginAs"><![CDATA[Logged in as]]></item>
                <item name="wcf.user.reauthentication.logoutAndChangeUser"><![CDATA[Not {$__wcf->user->username}? <a href="{link controller='FullLogout' application='wcf'}t={csrfToken type='url'}{/link}">Logout and change user</a>.]]></item>
+               <item name="wcf.user.ignore.type"><![CDATA[Block User]]></item>
+               <item name="wcf.user.ignore.type.noIgnore"><![CDATA[Do Not Block]]></item>
+               <item name="wcf.user.ignore.type.blockDirectContact"><![CDATA[Block Direct Contact]]></item>
+               <item name="wcf.user.ignore.type.hideMessages"><![CDATA[Hide Created Messages]]></item>
+               <item name="wcf.user.ignore.error.cannotBeIgnored"><![CDATA[The user cannot be blocked.]]></item>
        </category>
        <category name="wcf.user.menu">
                <item name="wcf.user.menu.community"><![CDATA[Community]]></item>
index a09f77ed396669b3567bb5e513604f3534b03317..6f6bc13d9f11a82fac9592fb7ad3fb3e96f1a123 100644 (file)
@@ -1672,6 +1672,7 @@ CREATE TABLE wcf1_user_ignore (
        userID INT(10) NOT NULL,
        ignoreUserID INT(10) NOT NULL,
        time INT(10) NOT NULL DEFAULT 0,
+       type TINYINT(1) NOT NULL DEFAULT 1,
        UNIQUE KEY (userID, ignoreUserID)
 );