--- /dev/null
+/**
+ * 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;
+ }
+ });
+ });
+}
}
};
-/**
- * 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.
*/
{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;
{/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}
--- /dev/null
+/**
+ * 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;
+ }
+ });
+ });
+ }
+});
--- /dev/null
+<?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;
+ }
+}
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.
*/
public $className = UserGroupEditor::class;
- /**
- * editor object for the copied user group
- * @var UserGroupEditor
- */
- public $groupEditor;
-
/**
* @inheritDoc
*/
/**
* @inheritDoc
*/
- protected $requireACP = ['copy', 'create', 'delete', 'update'];
+ protected $requireACP = ['create', 'delete', 'update'];
/**
* @inheritDoc
$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,
- ]),
- ];
- }
}
--- /dev/null
+<?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;
+ }
+}