Migrate `WCF.ACP.User.Group.Copy` to TypeScript
authorCyperghost <olaf_schmitz_1@t-online.de>
Tue, 3 Dec 2024 09:16:36 +0000 (10:16 +0100)
committerCyperghost <olaf_schmitz_1@t-online.de>
Tue, 3 Dec 2024 09:16:36 +0000 (10:16 +0100)
ts/WoltLabSuite/Core/Acp/Ui/User/Group/Copy.ts [new file with mode: 0644]
wcfsetup/install/files/acp/js/WCF.ACP.js
wcfsetup/install/files/acp/templates/userGroupAdd.tpl
wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/User/Group/Copy.js [new file with mode: 0644]
wcfsetup/install/files/lib/acp/action/UserGroupCopyAction.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/user/group/UserGroupAction.class.php
wcfsetup/install/files/lib/system/user/group/command/CopyUserGroup.class.php [new file with mode: 0644]

diff --git a/ts/WoltLabSuite/Core/Acp/Ui/User/Group/Copy.ts b/ts/WoltLabSuite/Core/Acp/Ui/User/Group/Copy.ts
new file mode 100644 (file)
index 0000000..45866e4
--- /dev/null
@@ -0,0 +1,28 @@
+/**
+ * Handles the dialog to copy a user group.
+ *
+ * @author  Olaf Braun
+ * @copyright  2001-2024 WoltLab GmbH
+ * @license  GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ */
+
+import { dialogFactory } from "WoltLabSuite/Core/Component/Dialog";
+
+interface CopyResponse {
+  groupID: number;
+  redirectURL: string;
+}
+
+export function init() {
+  const button = document.querySelector<HTMLElement>(".jsButtonUserGroupCopy");
+  button?.addEventListener("click", () => {
+    void dialogFactory()
+      .usingFormBuilder()
+      .fromEndpoint<CopyResponse>(button.dataset.endpoint!)
+      .then((result) => {
+        if (result.ok) {
+          window.location.href = result.result.redirectURL;
+        }
+      });
+  });
+}
index 4a45c8774880dd2da8e8053485cb46b056c4c7bd..567ad9ef13780b90e6a4693c653621e003f41457 100644 (file)
@@ -1283,64 +1283,6 @@ WCF.ACP.User.BanHandler = {
        }
 };
 
-/**
- * Namespace for user group management.
- */
-WCF.ACP.User.Group = { };
-
-/**
- * Handles copying user groups.
- */
-WCF.ACP.User.Group.Copy = Class.extend({
-       /**
-        * id of the copied group
-        * @var integer
-        */
-       _groupID: 0,
-       
-       /**
-        * Initializes a new instance of WCF.ACP.User.Group.Copy.
-        * 
-        * @param       integer         groupID
-        */
-       init: function(groupID) {
-               this._groupID = groupID;
-               
-               $('.jsButtonUserGroupCopy').click($.proxy(this._click, this));
-       },
-       
-       /**
-        * Handles clicking on a 'copy user group' button.
-        */
-       _click: function() {
-               var $template = $('<div class="section" />');
-               $template.append($('<dl class="wide"><dt /><dd><label><input type="checkbox" id="copyMembers" value="1" /> ' + WCF.Language.get('wcf.acp.group.copy.copyMembers') + '</label><small>' + WCF.Language.get('wcf.acp.group.copy.copyMembers.description') + '</small></dd></dl>'));
-               $template.append($('<dl class="wide"><dt /><dd><label><input type="checkbox" id="copyUserGroupOptions" value="1" /> ' + WCF.Language.get('wcf.acp.group.copy.copyUserGroupOptions') + '</label><small>' + WCF.Language.get('wcf.acp.group.copy.copyUserGroupOptions.description') + '</small></dd></dl>'));
-               $template.append($('<dl class="wide"><dt /><dd><label><input type="checkbox" id="copyACLOptions" value="1" /> ' + WCF.Language.get('wcf.acp.group.copy.copyACLOptions') + '</label><small>' + WCF.Language.get('wcf.acp.group.copy.copyACLOptions.description') + '</small></dd></dl>'));
-               
-               WCF.System.Confirmation.show(WCF.Language.get('wcf.acp.group.copy.confirmMessage'), $.proxy(function(action) {
-                       if (action === 'confirm') {
-                               new WCF.Action.Proxy({
-                                       autoSend: true,
-                                       data: {
-                                               actionName: 'copy',
-                                               className: 'wcf\\data\\user\\group\\UserGroupAction',
-                                               objectIDs: [ this._groupID ],
-                                               parameters: {
-                                                       copyACLOptions: $('#copyACLOptions').is(':checked'),
-                                                       copyMembers: $('#copyMembers').is(':checked'),
-                                                       copyUserGroupOptions: $('#copyUserGroupOptions').is(':checked')
-                                               }
-                                       },
-                                       success: function(data) {
-                                               window.location = data.returnValues.redirectURL;
-                                       }
-                               });
-                       }
-               }, this), '', $template, true);
-       }
-});
-
 /**
  * Generic implementation to enable users.
  */
index c7b0ece1436afbca271ce95f735afda4da66a9f8..c4f27aa586d38cc70c6a942d7c2547d86aad992e 100644 (file)
@@ -1,23 +1,15 @@
 {include file='header' pageTitle='wcf.acp.group.'|concat:$action}
 
 <script data-relocate="true">
+       {if $action == 'edit' && $group->canCopy()}
+               require(['WoltLabSuite/Core/Acp/Ui/User/Group/Copy'], ({ init }) => {
+                       init();
+               });
+       {/if}
+
        $(function() {
                new WCF.Option.Handler();
                
-               {if $action == 'edit' && $group->canCopy()}
-                       WCF.Language.addObject({
-                               'wcf.acp.group.copy.confirmMessage': '{jslang}wcf.acp.group.copy.confirmMessage{/jslang}',
-                               'wcf.acp.group.copy.copyACLOptions': '{jslang}wcf.acp.group.copy.copyACLOptions{/jslang}',
-                               'wcf.acp.group.copy.copyACLOptions.description': '{jslang}wcf.acp.group.copy.copyACLOptions.description{/jslang}',
-                               'wcf.acp.group.copy.copyMembers': '{jslang}wcf.acp.group.copy.copyMembers{/jslang}',
-                               'wcf.acp.group.copy.copyMembers.description': '{jslang}wcf.acp.group.copy.copyMembers.description{/jslang}',
-                               'wcf.acp.group.copy.copyUserGroupOptions': '{jslang}wcf.acp.group.copy.copyUserGroupOptions{/jslang}',
-                               'wcf.acp.group.copy.copyUserGroupOptions.description': '{jslang}wcf.acp.group.copy.copyUserGroupOptions.description{/jslang}'
-                       });
-                       
-                       new WCF.ACP.User.Group.Copy({@$groupID});
-               {/if}
-               
                {if $action === 'add' && $isBlankForm}
                        elBySelAll('.jsBbcodeSelectOptionHtml input[type="checkbox"]', undefined, function (checkbox) {
                                checkbox.checked = true;
@@ -54,7 +46,7 @@
                                {/if}
                                
                                {if $group->canCopy()}
-                                       <li><a class="jsButtonUserGroupCopy button">{icon name='copy'} <span>{lang}wcf.acp.group.button.copy{/lang}</span></a></li>
+                                       <li><button class="jsButtonUserGroupCopy button" data-endpoint="{link controller="UserGroupCopy" id=$groupID}{/link}">{icon name='copy'} <span>{lang}wcf.acp.group.button.copy{/lang}</span></button></li>
                                {/if}
                        {/if}
                        
diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/User/Group/Copy.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/User/Group/Copy.js
new file mode 100644 (file)
index 0000000..0fca6a7
--- /dev/null
@@ -0,0 +1,25 @@
+/**
+ * Handles the dialog to copy a user group.
+ *
+ * @author  Olaf Braun
+ * @copyright  2001-2024 WoltLab GmbH
+ * @license  GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ */
+define(["require", "exports", "WoltLabSuite/Core/Component/Dialog"], function (require, exports, Dialog_1) {
+    "use strict";
+    Object.defineProperty(exports, "__esModule", { value: true });
+    exports.init = init;
+    function init() {
+        const button = document.querySelector(".jsButtonUserGroupCopy");
+        button?.addEventListener("click", () => {
+            void (0, Dialog_1.dialogFactory)()
+                .usingFormBuilder()
+                .fromEndpoint(button.dataset.endpoint)
+                .then((result) => {
+                if (result.ok) {
+                    window.location.href = result.result.redirectURL;
+                }
+            });
+        });
+    }
+});
diff --git a/wcfsetup/install/files/lib/acp/action/UserGroupCopyAction.class.php b/wcfsetup/install/files/lib/acp/action/UserGroupCopyAction.class.php
new file mode 100644 (file)
index 0000000..68557d5
--- /dev/null
@@ -0,0 +1,116 @@
+<?php
+
+namespace wcf\acp\action;
+
+use CuyZ\Valinor\Mapper\MappingError;
+use Laminas\Diactoros\Response\JsonResponse;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+use wcf\acp\form\UserGroupEditForm;
+use wcf\data\user\group\UserGroup;
+use wcf\http\Helper;
+use wcf\system\exception\IllegalLinkException;
+use wcf\system\form\builder\container\FormContainer;
+use wcf\system\form\builder\field\BooleanFormField;
+use wcf\system\form\builder\Psr15DialogForm;
+use wcf\system\request\LinkHandler;
+use wcf\system\user\group\command\CopyUserGroup;
+use wcf\system\WCF;
+
+/**
+ * Form for copying a user group.
+ *
+ * @author      Olaf Braun
+ * @copyright   2001-2024 WoltLab GmbH
+ * @license     GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ */
+final class UserGroupCopyAction implements RequestHandlerInterface
+{
+    #[\Override]
+    public function handle(ServerRequestInterface $request): ResponseInterface
+    {
+        WCF::getSession()->checkPermissions([
+            'admin.user.canAddGroup',
+            'admin.user.canEditGroup',
+        ]);
+
+        try {
+            $parameters = Helper::mapQueryParameters(
+                $request->getQueryParams(),
+                <<<'EOT'
+                array {
+                    id: positive-int
+                }
+                EOT,
+            );
+        } catch (MappingError) {
+            throw new IllegalLinkException();
+        }
+
+        $userGroup = new UserGroup($parameters['id']);
+        if (!$userGroup->groupID) {
+            throw new IllegalLinkException();
+        }
+
+        $form = $this->getForm();
+
+        if ($request->getMethod() === 'GET') {
+            return $form->toResponse();
+        } elseif ($request->getMethod() === 'POST') {
+            $response = $form->validateRequest($request);
+            if ($response !== null) {
+                return $response;
+            }
+
+            $data = $form->getData();
+
+            $group = (new CopyUserGroup(
+                $userGroup,
+                $data['data']['copyUserGroupOptions'],
+                $data['data']['copyMembers'],
+                $data['data']['copyACLOptions']
+            ))();
+
+            return new JsonResponse([
+                'result' => [
+                    'groupID' => $group->groupID,
+                    'redirectURL' => LinkHandler::getInstance()->getControllerLink(UserGroupEditForm::class, [
+                        'id' => $group->groupID,
+                    ]),
+                ]
+            ]);
+        } else {
+            throw new \LogicException('Unreachable');
+        }
+    }
+
+    private function getForm(): Psr15DialogForm
+    {
+        $form = new Psr15DialogForm(
+            UserGroupCopyAction::class,
+            WCF::getLanguage()->get('wcf.acp.dashboard.configure')
+        );
+        $form->appendChildren([
+            FormContainer::create('section')
+                ->appendChildren([
+                    BooleanFormField::create('copyMembers')
+                        ->label('wcf.acp.group.copy.copyMembers')
+                        ->description('wcf.acp.group.copy.copyMembers.description')
+                        ->value(false),
+                    BooleanFormField::create('copyUserGroupOptions')
+                        ->label('wcf.acp.group.copy.copyUserGroupOptions')
+                        ->description('wcf.acp.group.copy.copyUserGroupOptions.description')
+                        ->value(false),
+                    BooleanFormField::create('copyACLOptions')
+                        ->label('wcf.acp.group.copy.copyACLOptions')
+                        ->description('wcf.acp.group.copy.copyACLOptions.description')
+                        ->value(false),
+                ])
+        ]);
+
+        $form->build();
+
+        return $form;
+    }
+}
index e779da14164e609b0f44c08504943597c74711a6..b66c737f847c7d6c87c3b0cd9375853cede49d28 100644 (file)
@@ -3,11 +3,6 @@
 namespace wcf\data\user\group;
 
 use wcf\data\AbstractDatabaseObjectAction;
-use wcf\system\cache\CacheHandler;
-use wcf\system\exception\PermissionDeniedException;
-use wcf\system\language\LanguageFactory;
-use wcf\system\request\LinkHandler;
-use wcf\system\WCF;
 
 /**
  * Executes user group-related actions.
@@ -26,12 +21,6 @@ class UserGroupAction extends AbstractDatabaseObjectAction
      */
     public $className = UserGroupEditor::class;
 
-    /**
-     * editor object for the copied user group
-     * @var UserGroupEditor
-     */
-    public $groupEditor;
-
     /**
      * @inheritDoc
      */
@@ -50,7 +39,7 @@ class UserGroupAction extends AbstractDatabaseObjectAction
     /**
      * @inheritDoc
      */
-    protected $requireACP = ['copy', 'create', 'delete', 'update'];
+    protected $requireACP = ['create', 'delete', 'update'];
 
     /**
      * @inheritDoc
@@ -83,145 +72,4 @@ class UserGroupAction extends AbstractDatabaseObjectAction
             $object->updateGroupOptions($this->parameters['options']);
         }
     }
-
-    /**
-     * Validates the 'copy' action.
-     */
-    public function validateCopy()
-    {
-        WCF::getSession()->checkPermissions([
-            'admin.user.canAddGroup',
-            'admin.user.canEditGroup',
-        ]);
-
-        $this->readBoolean('copyACLOptions');
-        $this->readBoolean('copyMembers');
-        $this->readBoolean('copyUserGroupOptions');
-
-        $this->groupEditor = $this->getSingleObject();
-        if (!$this->groupEditor->canCopy()) {
-            throw new PermissionDeniedException();
-        }
-    }
-
-    /**
-     * Copies a user group.
-     */
-    public function copy()
-    {
-        // fetch user group option values
-        if ($this->parameters['copyUserGroupOptions']) {
-            $sql = "SELECT  optionID, optionValue
-                    FROM    wcf1_user_group_option_value
-                    WHERE   groupID = ?";
-            $statement = WCF::getDB()->prepare($sql);
-            $statement->execute([$this->groupEditor->groupID]);
-        } else {
-            $sql = "SELECT  optionID, defaultValue AS optionValue
-                    FROM    wcf1_user_group_option";
-            $statement = WCF::getDB()->prepare($sql);
-            $statement->execute();
-        }
-
-        $optionValues = $statement->fetchMap('optionID', 'optionValue');
-
-        $groupType = $this->groupEditor->groupType;
-        // When copying special user groups of which only one may exist,
-        // change the group type to 'other'.
-        if (\in_array($groupType, [UserGroup::EVERYONE, UserGroup::GUESTS, UserGroup::USERS, UserGroup::OWNER])) {
-            $groupType = UserGroup::OTHER;
-        }
-
-        /** @var UserGroup $group */
-        $group = (new self([], 'create', [
-            'data' => [
-                'groupName' => $this->groupEditor->groupName,
-                'groupDescription' => $this->groupEditor->groupDescription,
-                'priority' => $this->groupEditor->priority,
-                'userOnlineMarking' => $this->groupEditor->userOnlineMarking,
-                'showOnTeamPage' => $this->groupEditor->showOnTeamPage,
-                'groupType' => $groupType,
-            ],
-            'options' => $optionValues,
-        ]))->executeAction()['returnValues'];
-        $groupEditor = new UserGroupEditor($group);
-
-        // update group name
-        $groupName = $this->groupEditor->groupName;
-        if (\preg_match('~^wcf\.acp\.group\.group\d+$~', $this->groupEditor->groupName)) {
-            $groupName = 'wcf.acp.group.group' . $group->groupID;
-
-            // create group name language item
-            $sql = "INSERT INTO wcf1_language_item
-                                (languageID, languageItem, languageItemValue, languageItemOriginIsSystem, languageCategoryID, packageID)
-                    SELECT      languageID, '" . $groupName . "', CONCAT(languageItemValue, ' (2)'), 0, languageCategoryID, packageID
-                    FROM        wcf1_language_item
-                    WHERE       languageItem = ?";
-            $statement = WCF::getDB()->prepare($sql);
-            $statement->execute([$this->groupEditor->groupName]);
-        } else {
-            $groupName .= ' (2)';
-        }
-
-        // update group name
-        $groupDescription = $this->groupEditor->groupName;
-        if (\preg_match('~^wcf\.acp\.group\.groupDescription\d+$~', $this->groupEditor->groupDescription)) {
-            $groupDescription = 'wcf.acp.group.groupDescription' . $group->groupID;
-
-            // create group name language item
-            $sql = "INSERT INTO wcf1_language_item
-                                (languageID, languageItem, languageItemValue, languageItemOriginIsSystem, languageCategoryID, packageID)
-                    SELECT      languageID, '" . $groupDescription . "', languageItemValue, 0, languageCategoryID, packageID
-                    FROM        wcf1_language_item
-                    WHERE       languageItem = ?";
-            $statement = WCF::getDB()->prepare($sql);
-            $statement->execute([$this->groupEditor->groupDescription]);
-        }
-
-        $groupEditor->update([
-            'groupDescription' => $groupDescription,
-            'groupName' => $groupName,
-        ]);
-
-        // copy members
-        if ($this->parameters['copyMembers']) {
-            $sql = "INSERT INTO wcf1_user_to_group
-                                (userID, groupID)
-                    SELECT      userID, " . $group->groupID . "
-                    FROM        wcf1_user_to_group
-                    WHERE       groupID = ?";
-            $statement = WCF::getDB()->prepare($sql);
-            $statement->execute([$this->groupEditor->groupID]);
-        }
-
-        // copy acl options
-        if ($this->parameters['copyACLOptions']) {
-            $sql = "INSERT INTO wcf1_acl_option_to_group
-                                (optionID, objectID, groupID, optionValue)
-                    SELECT      optionID, objectID, " . $group->groupID . ", optionValue
-                    FROM        wcf1_acl_option_to_group
-                    WHERE       groupID = ?";
-            $statement = WCF::getDB()->prepare($sql);
-            $statement->execute([$this->groupEditor->groupID]);
-
-            // it is likely that applications or plugins use caches
-            // for acl option values like for the labels which have
-            // to be renewed after copying the acl options; because
-            // there is no other way to delete these caches, we simply
-            // delete all caches
-            CacheHandler::getInstance()->flushAll();
-        }
-
-        // reset language cache
-        LanguageFactory::getInstance()->deleteLanguageCache();
-
-        UserGroupEditor::resetCache();
-
-        return [
-            'groupID' => $group->groupID,
-            'redirectURL' => LinkHandler::getInstance()->getLink('UserGroupEdit', [
-                'id' => $group->groupID,
-            ]),
-        ];
-    }
 }
diff --git a/wcfsetup/install/files/lib/system/user/group/command/CopyUserGroup.class.php b/wcfsetup/install/files/lib/system/user/group/command/CopyUserGroup.class.php
new file mode 100644 (file)
index 0000000..3e73ecb
--- /dev/null
@@ -0,0 +1,141 @@
+<?php
+
+namespace wcf\system\user\group\command;
+
+use wcf\data\user\group\UserGroup;
+use wcf\data\user\group\UserGroupAction;
+use wcf\data\user\group\UserGroupEditor;
+use wcf\system\cache\CacheHandler;
+use wcf\system\language\LanguageFactory;
+use wcf\system\WCF;
+
+/**
+ * Copies a user group.
+ *
+ * @author      Olaf Braun
+ * @copyright   2001-2024 WoltLab GmbH
+ * @license     GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ */
+final class CopyUserGroup
+{
+    public function __construct(
+        public readonly UserGroup $userGroup,
+        public readonly bool $copyUserGroupOptions,
+        public readonly bool $copyMembers,
+        public readonly bool $copyACLOptions
+    ) {
+    }
+
+    public function __invoke()
+    {
+        // fetch user group option values
+        if ($this->copyUserGroupOptions) {
+            $sql = "SELECT  optionID, optionValue
+                    FROM    wcf1_user_group_option_value
+                    WHERE   groupID = ?";
+            $statement = WCF::getDB()->prepare($sql);
+            $statement->execute([$this->userGroup->groupID]);
+        } else {
+            $sql = "SELECT  optionID, defaultValue AS optionValue
+                    FROM    wcf1_user_group_option";
+            $statement = WCF::getDB()->prepare($sql);
+            $statement->execute();
+        }
+
+        $optionValues = $statement->fetchMap('optionID', 'optionValue');
+
+        $groupType = $this->userGroup->groupType;
+        // When copying special user groups of which only one may exist,
+        // change the group type to 'other'.
+        if (\in_array($groupType, [UserGroup::EVERYONE, UserGroup::GUESTS, UserGroup::USERS, UserGroup::OWNER])) {
+            $groupType = UserGroup::OTHER;
+        }
+
+        /** @var UserGroup $group */
+        $group = (new UserGroupAction([], 'create', [
+            'data' => [
+                'groupName' => $this->userGroup->groupName,
+                'groupDescription' => $this->userGroup->groupDescription,
+                'priority' => $this->userGroup->priority,
+                'userOnlineMarking' => $this->userGroup->userOnlineMarking,
+                'showOnTeamPage' => $this->userGroup->showOnTeamPage,
+                'groupType' => $groupType,
+            ],
+            'options' => $optionValues,
+        ]))->executeAction()['returnValues'];
+        $groupEditor = new UserGroupEditor($group);
+
+        // update group name
+        $groupName = $this->userGroup->groupName;
+        if (\preg_match('~^wcf\.acp\.group\.group\d+$~', $this->userGroup->groupName)) {
+            $groupName = 'wcf.acp.group.group' . $group->groupID;
+
+            // create group name language item
+            $sql = "INSERT INTO wcf1_language_item
+                                (languageID, languageItem, languageItemValue, languageItemOriginIsSystem, languageCategoryID, packageID)
+                    SELECT      languageID, '" . $groupName . "', CONCAT(languageItemValue, ' (2)'), 0, languageCategoryID, packageID
+                    FROM        wcf1_language_item
+                    WHERE       languageItem = ?";
+            $statement = WCF::getDB()->prepare($sql);
+            $statement->execute([$this->userGroup->groupName]);
+        } else {
+            $groupName .= ' (2)';
+        }
+
+        // update group name
+        $groupDescription = $this->userGroup->groupName;
+        if (\preg_match('~^wcf\.acp\.group\.groupDescription\d+$~', $this->userGroup->groupDescription)) {
+            $groupDescription = 'wcf.acp.group.groupDescription' . $group->groupID;
+
+            // create group name language item
+            $sql = "INSERT INTO wcf1_language_item
+                                (languageID, languageItem, languageItemValue, languageItemOriginIsSystem, languageCategoryID, packageID)
+                    SELECT      languageID, '" . $groupDescription . "', languageItemValue, 0, languageCategoryID, packageID
+                    FROM        wcf1_language_item
+                    WHERE       languageItem = ?";
+            $statement = WCF::getDB()->prepare($sql);
+            $statement->execute([$this->userGroup->groupDescription]);
+        }
+
+        $groupEditor->update([
+            'groupDescription' => $groupDescription,
+            'groupName' => $groupName,
+        ]);
+
+        // copy members
+        if ($this->copyMembers) {
+            $sql = "INSERT INTO wcf1_user_to_group
+                                (userID, groupID)
+                    SELECT      userID, " . $group->groupID . "
+                    FROM        wcf1_user_to_group
+                    WHERE       groupID = ?";
+            $statement = WCF::getDB()->prepare($sql);
+            $statement->execute([$this->userGroup->groupID]);
+        }
+
+        // copy acl options
+        if ($this->copyACLOptions) {
+            $sql = "INSERT INTO wcf1_acl_option_to_group
+                                (optionID, objectID, groupID, optionValue)
+                    SELECT      optionID, objectID, " . $group->groupID . ", optionValue
+                    FROM        wcf1_acl_option_to_group
+                    WHERE       groupID = ?";
+            $statement = WCF::getDB()->prepare($sql);
+            $statement->execute([$this->userGroup->groupID]);
+
+            // it is likely that applications or plugins use caches
+            // for acl option values like for the labels which have
+            // to be renewed after copying the acl options; because
+            // there is no other way to delete these caches, we simply
+            // delete all caches
+            CacheHandler::getInstance()->flushAll();
+        }
+
+        // reset language cache
+        LanguageFactory::getInstance()->deleteLanguageCache();
+
+        UserGroupEditor::resetCache();
+
+        return $group;
+    }
+}