From 23d575956b3cf8d687a1ce7f8d4f4dc154f5ff50 Mon Sep 17 00:00:00 2001 From: Matthias Schmidt Date: Mon, 15 Jun 2015 20:03:19 +0200 Subject: [PATCH] Add abstract object bulk processing (WIP) MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit …and replace the current user bulk processing form with the new system. --- com.woltlab.wcf/objectType.xml | 126 +++++ com.woltlab.wcf/objectTypeDefinition.xml | 15 + .../files/acp/templates/bulkProcessing.tpl | 86 +++ .../exportMailAddressUserBulkProcessing.tpl | 40 ++ .../templates/sendMailUserBulkProcessing.tpl | 55 ++ .../acp/templates/userBulkProcessing.tpl | 347 ------------ .../files/acp/templates/userConditions.tpl | 4 +- .../userGroupListUserBulkProcessing.tpl | 9 + .../form/AbstractBulkProcessingForm.class.php | 213 ++++++++ .../acp/form/UserBulkProcessingForm.class.php | 517 +----------------- ...bstractBulkProcessableObjectType.class.php | 83 +++ .../AbstractBulkProcessingAction.class.php | 50 ++ .../IBulkProcessableObjectType.class.php | 45 ++ .../IBulkProcessingAction.class.php | 60 ++ ...AbstractUserBulkProcessingAction.class.php | 62 +++ ...erGroupsUserBulkProcessingAction.class.php | 129 +++++ ...erGroupsUserBulkProcessingAction.class.php | 27 + .../DeleteUserBulkProcessingAction.class.php | 44 ++ ...lAddressUserBulkProcessingAction.class.php | 107 ++++ ...erGroupsUserBulkProcessingAction.class.php | 41 ++ ...SendMailUserBulkProcessingAction.class.php | 113 ++++ .../UserBulkProcessableObjectType.class.php | 21 + ...tractObjectTextPropertyCondition.class.php | 101 ++++ .../condition/AbstractTextCondition.class.php | 4 +- .../AbstractTimestampCondition.class.php | 209 +++++++ .../condition/IObjectCondition.class.php | 26 + .../condition/IObjectListCondition.class.php | 25 + .../TObjectListUserCondition.class.php | 24 + .../condition/TObjectUserCondition.class.php | 23 + .../condition/UserAvatarCondition.class.php | 22 +- .../condition/UserEmailCondition.class.php | 14 +- .../condition/UserGroupCondition.class.php | 20 +- .../UserIntegerPropertyCondition.class.php | 20 +- .../condition/UserLanguageCondition.class.php | 14 +- .../condition/UserOptionsCondition.class.php | 16 +- .../UserRegistrationDateCondition.class.php | 20 +- ...egistrationDateIntervalCondition.class.php | 20 +- .../condition/UserStateCondition.class.php | 20 +- .../UserTimestampPropertyCondition.class.php | 49 ++ .../condition/UserUsernameCondition.class.php | 14 +- wcfsetup/install/lang/de.xml | 18 +- wcfsetup/install/lang/en.xml | 15 +- 42 files changed, 1927 insertions(+), 941 deletions(-) create mode 100644 wcfsetup/install/files/acp/templates/bulkProcessing.tpl create mode 100644 wcfsetup/install/files/acp/templates/exportMailAddressUserBulkProcessing.tpl create mode 100644 wcfsetup/install/files/acp/templates/sendMailUserBulkProcessing.tpl delete mode 100644 wcfsetup/install/files/acp/templates/userBulkProcessing.tpl create mode 100644 wcfsetup/install/files/acp/templates/userGroupListUserBulkProcessing.tpl create mode 100644 wcfsetup/install/files/lib/acp/form/AbstractBulkProcessingForm.class.php create mode 100644 wcfsetup/install/files/lib/system/bulk/processing/AbstractBulkProcessableObjectType.class.php create mode 100644 wcfsetup/install/files/lib/system/bulk/processing/AbstractBulkProcessingAction.class.php create mode 100644 wcfsetup/install/files/lib/system/bulk/processing/IBulkProcessableObjectType.class.php create mode 100644 wcfsetup/install/files/lib/system/bulk/processing/IBulkProcessingAction.class.php create mode 100644 wcfsetup/install/files/lib/system/bulk/processing/user/AbstractUserBulkProcessingAction.class.php create mode 100644 wcfsetup/install/files/lib/system/bulk/processing/user/AbstractUserGroupsUserBulkProcessingAction.class.php create mode 100644 wcfsetup/install/files/lib/system/bulk/processing/user/AssignToUserGroupsUserBulkProcessingAction.class.php create mode 100644 wcfsetup/install/files/lib/system/bulk/processing/user/DeleteUserBulkProcessingAction.class.php create mode 100644 wcfsetup/install/files/lib/system/bulk/processing/user/ExportMailAddressUserBulkProcessingAction.class.php create mode 100644 wcfsetup/install/files/lib/system/bulk/processing/user/RemoveFromUserGroupsUserBulkProcessingAction.class.php create mode 100644 wcfsetup/install/files/lib/system/bulk/processing/user/SendMailUserBulkProcessingAction.class.php create mode 100644 wcfsetup/install/files/lib/system/bulk/processing/user/UserBulkProcessableObjectType.class.php create mode 100644 wcfsetup/install/files/lib/system/condition/AbstractObjectTextPropertyCondition.class.php create mode 100644 wcfsetup/install/files/lib/system/condition/AbstractTimestampCondition.class.php create mode 100644 wcfsetup/install/files/lib/system/condition/IObjectCondition.class.php create mode 100644 wcfsetup/install/files/lib/system/condition/IObjectListCondition.class.php create mode 100644 wcfsetup/install/files/lib/system/condition/TObjectListUserCondition.class.php create mode 100644 wcfsetup/install/files/lib/system/condition/TObjectUserCondition.class.php create mode 100644 wcfsetup/install/files/lib/system/condition/UserTimestampPropertyCondition.class.php diff --git a/com.woltlab.wcf/objectType.xml b/com.woltlab.wcf/objectType.xml index 0b2ef40b9c..cc1534a73c 100644 --- a/com.woltlab.wcf/objectType.xml +++ b/com.woltlab.wcf/objectType.xml @@ -996,5 +996,131 @@ com.woltlab.wcf.payment.type + + + + com.woltlab.wcf.bulkProcessing.user + com.woltlab.wcf.bulkProcessableObject + + + + + + + com.woltlab.wcf.delete + com.woltlab.wcf.bulkProcessing.user.action + + delete + admin.user.canDeleteUser + + + com.woltlab.wcf.assignToUserGroups + com.woltlab.wcf.bulkProcessing.user.action + + assignToUserGroups + admin.user.canEditUser + + + com.woltlab.wcf.removeFromUserGroups + com.woltlab.wcf.bulkProcessing.user.action + + removeFromUserGroups + admin.user.canEditUser + + + com.woltlab.wcf.sendMail + com.woltlab.wcf.bulkProcessing.user.action + + sendMail + admin.user.canMailUser + + + com.woltlab.wcf.exportMailAddress + com.woltlab.wcf.bulkProcessing.user.action + + exportMailAddress + admin.user.canMailUser + + + + + + com.woltlab.wcf.username + com.woltlab.wcf.bulkProcessing.user.condition + + general + + + com.woltlab.wcf.email + com.woltlab.wcf.bulkProcessing.user.condition + + general + + + com.woltlab.wcf.userGroup + com.woltlab.wcf.bulkProcessing.user.condition + + general + + + com.woltlab.wcf.languages + com.woltlab.wcf.bulkProcessing.user.condition + + general + + + com.woltlab.wcf.registrationDate + com.woltlab.wcf.bulkProcessing.user.condition + + general + + + com.woltlab.wcf.registrationDateInterval + com.woltlab.wcf.bulkProcessing.user.condition + + general + + + com.woltlab.wcf.lastActivityTime + com.woltlab.wcf.bulkProcessing.user.condition + + general + lastActivityTime + + + com.woltlab.wcf.avatar + com.woltlab.wcf.bulkProcessing.user.condition + + general + + + com.woltlab.wcf.state + com.woltlab.wcf.bulkProcessing.user.condition + + general + + + com.woltlab.wcf.activityPoints + com.woltlab.wcf.bulkProcessing.user.condition + + contents + activityPoints + 0 + + + com.woltlab.wcf.likesReceived + com.woltlab.wcf.bulkProcessing.user.condition + + contents + likesReceived + 0 + + + com.woltlab.wcf.userOptions + com.woltlab.wcf.bulkProcessing.user.condition + + userOptions + + diff --git a/com.woltlab.wcf/objectTypeDefinition.xml b/com.woltlab.wcf/objectTypeDefinition.xml index ef7e89931c..c2e7b7ee10 100644 --- a/com.woltlab.wcf/objectTypeDefinition.xml +++ b/com.woltlab.wcf/objectTypeDefinition.xml @@ -196,6 +196,21 @@ com.woltlab.wcf.payment.type + + + com.woltlab.wcf.bulkProcessableObject + + + + + com.woltlab.wcf.bulkProcessing.user.condition + + + + + com.woltlab.wcf.bulkProcessing.user.action + + diff --git a/wcfsetup/install/files/acp/templates/bulkProcessing.tpl b/wcfsetup/install/files/acp/templates/bulkProcessing.tpl new file mode 100644 index 0000000000..a5760ff023 --- /dev/null +++ b/wcfsetup/install/files/acp/templates/bulkProcessing.tpl @@ -0,0 +1,86 @@ +{include file='header' pageTitle=$objectType->getProcessor()->getLanguageItemPrefix()} + + + +
+

{lang}{$objectType->getProcessor()->getLanguageItemPrefix()}{/lang}

+
+ +{include file='formError'} + +

{hascontent}{content}{lang __optional=true}{$objectType->getProcessor()->getLanguageItemPrefix()}.warning{/lang}{/content}{hascontentelse}{lang}wcf.global.bulkProcessing.warning{/lang}{/hascontent}

+ +{if $success|isset} +

{lang}{$objectType->getProcessor()->getLanguageItemPrefix()}.success{/lang}

+{/if} + +
+
+
+ {lang}{$objectType->getProcessor()->getLanguageItemPrefix()}.action{/lang} + +
+
+
+ {foreach from=$actions item=actionObjectType} + + {/foreach} + + {if $errorField == 'action'} + + {lang}wcf.global.form.error.{@$errorType}{/lang} + + {/if} +
+
+
+ + {foreach from=$actions item=actionObjectType} + {if $actionObjectType->getProcessor()->getHTML()} +
action != $action}style="display: none;"{/if}> + {lang}{$objectType->getProcessor()->getLanguageItemPrefix()}.{@$actionObjectType->action}{/lang} + + {@$actionObjectType->getProcessor()->getHTML()} +
+ {/if} + {/foreach} +
+ +
+

{lang}{$objectType->getProcessor()->getLanguageItemPrefix()}.conditions{/lang}

+ {hascontent}{content}{lang __optional=true}{$objectType->getProcessor()->getLanguageItemPrefix()}.conditions.descriptions{/lang}{/content}{/hascontent} +
+ + {@$objectType->getProcessor()->getConditionHTML()} + +
+ + {@SECURITY_TOKEN_INPUT_TAG} +
+
+ +{include file='footer'} diff --git a/wcfsetup/install/files/acp/templates/exportMailAddressUserBulkProcessing.tpl b/wcfsetup/install/files/acp/templates/exportMailAddressUserBulkProcessing.tpl new file mode 100644 index 0000000000..7f6a311ea2 --- /dev/null +++ b/wcfsetup/install/files/acp/templates/exportMailAddressUserBulkProcessing.tpl @@ -0,0 +1,40 @@ +
+
+
+ + +
+
+ + + + + + diff --git a/wcfsetup/install/files/acp/templates/sendMailUserBulkProcessing.tpl b/wcfsetup/install/files/acp/templates/sendMailUserBulkProcessing.tpl new file mode 100644 index 0000000000..960422c985 --- /dev/null +++ b/wcfsetup/install/files/acp/templates/sendMailUserBulkProcessing.tpl @@ -0,0 +1,55 @@ + +
+
+ + {if $errorField == 'subject'} + + {if $errorType == 'empty'}{lang}wcf.global.form.error.empty{/lang}{/if} + + {/if} +
+ + + +
+
+ + {if $errorField == 'from'} + + {if $errorType == 'empty'}{lang}wcf.global.form.error.empty{/lang}{/if} + + {/if} + {lang}wcf.acp.user.sendMail.from.description{/lang} +
+ + + +
+
+ + {if $errorField == 'text'} + + {if $errorType == 'empty'}{lang}wcf.global.form.error.empty{/lang}{/if} + + {/if} +
+ + +
+
+
+ +
+
+ +{if !$mailID|empty} + +{/if} diff --git a/wcfsetup/install/files/acp/templates/userBulkProcessing.tpl b/wcfsetup/install/files/acp/templates/userBulkProcessing.tpl deleted file mode 100644 index 9681e22b6f..0000000000 --- a/wcfsetup/install/files/acp/templates/userBulkProcessing.tpl +++ /dev/null @@ -1,347 +0,0 @@ -{include file='header' pageTitle='wcf.acp.user.bulkProcessing'} - -{if $mailID|isset} - -{/if} - - - -
-

{lang}wcf.acp.user.bulkProcessing{/lang}

-
- -{include file='formError'} - -

{lang}wcf.acp.user.bulkProcessing.warning{/lang}

- -{if $affectedUsers|isset} -

{lang}wcf.acp.user.bulkProcessing.success{/lang}

-{/if} - -
- {hascontent} - - {/hascontent} -
- -
-
- - -
-
- {lang}wcf.acp.user.search.conditions{/lang} - -
-
-
- -
-
- - {if $__wcf->session->getPermission('admin.user.canEditMailAddress')} -
-
-
- -
-
- {/if} - - {if $availableGroups|count} -
-
-
- {htmlCheckboxes options=$availableGroups name='groupIDs' selected=$groupIDs} - - -
-
- {/if} - - {if $availableLanguages|count > 1} -
-
-
- {htmlCheckboxes options=$availableLanguages name='languageIDs' selected=$languageIDs disableEncoding=true} -
-
- {/if} - -
-
-
- - -
-
- -
-
-
- - -
-
- - {event name='conditionFields'} -
- -
- {lang}wcf.acp.user.search.conditions.states{/lang} - -
-
-
- - - - - - {event name='states'} -
-
- - {event name='stateFields'} -
- - {event name='conditionFieldsets'} -
- - {if $options|count} -
-
- {lang}wcf.acp.user.search.conditions.profile{/lang} - - {include file='optionFieldList' langPrefix='wcf.user.option.'} -
- - {event name='profileFieldsets'} -
- {/if} - -
- - {lang}wcf.acp.user.bulkProcessing.action{/lang} - -
-
-
- {if $__wcf->session->getPermission('admin.user.canMailUser')} - - - {/if} - {if $__wcf->session->getPermission('admin.user.canEditUser')} - - {/if} - {if $__wcf->session->getPermission('admin.user.canDeleteUser')} - - {/if} - - {event name='actions'} - - {if $errorField == 'action'} - - {if $errorType == 'empty'}{lang}wcf.global.form.error.empty{/lang}{/if} - - {/if} -
-
- - - {if $__wcf->session->getPermission('admin.user.canMailUser')} -
-
- {lang}wcf.acp.user.sendMail.mail{/lang} - - -
-
- - {if $errorField == 'subject'} - - {if $errorType == 'empty'}{lang}wcf.global.form.error.empty{/lang}{/if} - - {/if} -
- - - -
-
- - {if $errorField == 'from'} - - {if $errorType == 'empty'}{lang}wcf.global.form.error.empty{/lang}{/if} - - {/if} - {lang}wcf.acp.user.sendMail.from.description{/lang} -
- - - -
-
- - {if $errorField == 'text'} - - {if $errorType == 'empty'}{lang}wcf.global.form.error.empty{/lang}{/if} - - {/if} -
- - -
-
-
- -
-
-
-
- -
-
- {lang}wcf.acp.user.exportEmailAddress.format{/lang} - -
-
-
- - -
-
- -
-
-
- -
-
- -
-
-
- -
-
-
-
- {/if} - - {if $__wcf->session->getPermission('admin.user.canEditUser')} -
-
- {lang}wcf.acp.user.groups{/lang} - -
-
- - {htmlCheckboxes options=$availableGroups name=assignToGroupIDs selected=$assignToGroupIDs} - {if $errorField == 'assignToGroupIDs'} - - {if $errorType == 'empty'}{lang}wcf.global.form.error.empty{/lang}{/if} - - {/if} - -
-
-
- {/if} - - {event name='actionFieldsets'} -
-
- -
- - {@SECURITY_TOKEN_INPUT_TAG} -
-
- -{include file='footer'} diff --git a/wcfsetup/install/files/acp/templates/userConditions.tpl b/wcfsetup/install/files/acp/templates/userConditions.tpl index d1382ad246..1fdcb12201 100644 --- a/wcfsetup/install/files/acp/templates/userConditions.tpl +++ b/wcfsetup/install/files/acp/templates/userConditions.tpl @@ -1,3 +1,5 @@ +{if !$groupedObjectTypes|isset && $conditions|isset}{assign var='groupedObjectTypes' value=$conditions}{/if} +
{foreach from=$groupedObjectTypes key='conditionGroup' item='conditionObjectTypes'} -
+
{if $conditionGroup != 'userOptions'}
{lang}wcf.user.condition.conditionGroup.{$conditionGroup}{/lang} diff --git a/wcfsetup/install/files/acp/templates/userGroupListUserBulkProcessing.tpl b/wcfsetup/install/files/acp/templates/userGroupListUserBulkProcessing.tpl new file mode 100644 index 0000000000..bd640a32f3 --- /dev/null +++ b/wcfsetup/install/files/acp/templates/userGroupListUserBulkProcessing.tpl @@ -0,0 +1,9 @@ +
+
+ + {htmlCheckboxes options=$availableUserGroups name=$inputName selected=$selectedUserGroupIDs} + {if $errorField == $inputName} + {lang}wcf.global.form.error.{$errorType}{/lang} + {/if} + +
diff --git a/wcfsetup/install/files/lib/acp/form/AbstractBulkProcessingForm.class.php b/wcfsetup/install/files/lib/acp/form/AbstractBulkProcessingForm.class.php new file mode 100644 index 0000000000..349ee1d2de --- /dev/null +++ b/wcfsetup/install/files/lib/acp/form/AbstractBulkProcessingForm.class.php @@ -0,0 +1,213 @@ + + * @package com.woltlab.wcf + * @subpackage acp.form + * @category Community Framework + */ +abstract class AbstractBulkProcessingForm extends AbstractForm { + /** + * object action object type types + * @var array<\wcf\data\object\type\ObjectType> + */ + public $actions = array(); + + /** + * number of objects affected by bulk processing + * @var integer + */ + public $affectedObjectCount = 0; + + /** + * object condition object type types + * @var array<\wcf\data\object\type\ObjectType> + */ + public $conditions = array(); + + /** + * list with bulk processed objects + * @var \wcf\data\DatabaseObjectList + */ + public $objectList = null; + + /** + * bulk processable object type + * @var \wcf\data\object\type\ObjectType + */ + public $objectType = null; + + /** + * name of the bulk processable object type + * @var string + */ + public $objectTypeName = ''; + + /** + * @see \wcf\page\Abstractpage::$templateName + */ + public $templateName = 'bulkProcessing'; + + /** + * @see \wcf\page\IPage::assignVariables() + */ + public function assignVariables() { + parent::assignVariables(); + + $classParts = explode('\\', get_class($this)); + + WCF::getTPL()->assign([ + 'actions' => $this->actions, + 'affectedObjectCount' => $this->affectedObjectCount, + 'controller' => str_replace('Form', '', array_pop($classParts)), + 'conditions' => $this->conditions, + 'objectType' => $this->objectType + ]); + } + + /** + * @see \wcf\page\IPage::readData() + */ + public function readData() { + // read bulk processable object type + $this->objectType = ObjectTypeCache::getInstance()->getObjectTypeByName('com.woltlab.wcf.bulkProcessableObject', $this->objectTypeName); + if ($this->objectType === null) { + throw new SystemException("Unknown bulk processable object type '".$this->objectTypeName."'"); + } + + // read conditions + if (ObjectTypeCache::getInstance()->getDefinitionByName($this->objectType->getProcessor()->getConditionObjectTypeDefinition()) === null) { + throw new SystemException("Unknown condition object type definition '".$this->objectType->getProcessor()->getConditionObjectTypeDefinition()."'"); + } + $conditionObjectTypes = ObjectTypeCache::getInstance()->getObjectTypes($this->objectType->getProcessor()->getConditionObjectTypeDefinition()); + if (empty($conditionObjectTypes)) { + throw new IllegalLinkException(); + } + + foreach ($conditionObjectTypes as $objectType) { + if ($objectType->conditiongroup) { + if (!isset($this->conditions[$objectType->conditiongroup])) { + $this->conditions[$objectType->conditiongroup] = [ ]; + } + + $this->conditions[$objectType->conditiongroup][$objectType->objectTypeID] = $objectType; + } + else { + $this->conditions[''][$objectType->objectTypeID] = $objectType; + } + } + + // read actions + if (ObjectTypeCache::getInstance()->getDefinitionByName($this->objectType->getProcessor()->getActionObjectTypeDefinition()) === null) { + throw new SystemException("Unknown action object type definition '".$this->objectType->getProcessor()->getActionObjectTypeDefinition()."'"); + } + + $actions = ObjectTypeCache::getInstance()->getObjectTypes($this->objectType->getProcessor()->getActionObjectTypeDefinition()); + foreach ($actions as $objectType) { + if (isset($this->actions[$objectType->action])) { + throw new SystemException("Duplicate action with name '".$objectType->action."'"); + } + + if ($objectType->validateOptions() && $objectType->validatePermissions()) { + $this->actions[$objectType->action] = $objectType; + } + } + if (empty($this->actions)) { + throw new IllegalLinkException(); + } + + parent::readData(); + } + + /** + * @see \wcf\form\IForm::readFormParameters() + */ + public function readFormParameters() { + parent::readFormParameters(); + + foreach ($this->conditions as $groupedObjectTypes) { + foreach ($groupedObjectTypes as $objectType) { + $objectType->getProcessor()->readFormParameters(); + } + } + + if (isset($this->actions[$this->action])) { + $this->actions[$this->action]->getProcessor()->readFormParameters(); + } + } + + /** + * @see \wcf\form\IForm::save() + */ + public function save() { + $this->objectList = $this->actions[$this->action]->getProcessor()->getObjectList(); + + parent::save(); + + // read objects + foreach ($this->conditions as $groupedObjectTypes) { + foreach ($groupedObjectTypes as $objectType) { + $data = $objectType->getProcessor()->getData(); + if ($data !== null) { + $objectType->getProcessor()->addObjectListCondition($this->objectList, $data); + } + } + } + $this->objectList->readObjects(); + + // execute action + $this->actions[$this->action]->getProcessor()->executeAction($this->objectList); + + $this->affectedObjectCount = count($this->objectList); + + $this->saved(); + + // reset fields + $this->actions[$this->action]->getProcessor()->reset(); + + foreach ($this->conditions as $groupedObjectTypes) { + foreach ($groupedObjectTypes as $objectType) { + $objectType->getProcessor()->reset(); + } + } + $this->action = ''; + + WCF::getTPL()->assign('success', true); + } + + /** + * @see \wcf\form\IForm::validate() + */ + public function validate() { + parent::validate(); + + // validate action + if (empty($this->action)) { + throw new UserInputException('action'); + } + + if (!isset($this->actions[$this->action])) { + throw new UserInputException('action', 'noValidSelection'); + } + + $this->actions[$this->action]->getProcessor()->validate(); + + // validate conditions + foreach ($this->conditions as $groupedObjectTypes) { + foreach ($groupedObjectTypes as $objectType) { + $objectType->getProcessor()->validate(); + } + } + } +} diff --git a/wcfsetup/install/files/lib/acp/form/UserBulkProcessingForm.class.php b/wcfsetup/install/files/lib/acp/form/UserBulkProcessingForm.class.php index 8091c4c44d..7b15382c75 100644 --- a/wcfsetup/install/files/lib/acp/form/UserBulkProcessingForm.class.php +++ b/wcfsetup/install/files/lib/acp/form/UserBulkProcessingForm.class.php @@ -1,529 +1,24 @@ * @package com.woltlab.wcf * @subpackage acp.form * @category Community Framework */ -class UserBulkProcessingForm extends UserOptionListForm { +class UserBulkProcessingForm extends AbstractBulkProcessingForm { /** - * @see \wcf\page\AbstractPage::$neededPermissions + * @see \wcf\page\AbstractPage::$activeMenuItem */ - public $neededPermissions = array('admin.user.canEditUser', 'admin.user.canDeleteUser', 'admin.user.canMailUser'); + public $activeMenuItem = 'wcf.acp.menu.link.user.bulkProcessing'; /** - * searched username - * @var string + * @see \wcf\acp\form\AbstractBulkProcessingForm::$objectTypeName */ - public $username = ''; - - /** - * searched email adress - * @var string - */ - public $email = ''; - - /** - * ids of the searched user group ids - * @var array - */ - public $groupIDs = array(); - - /** - * ids of the users' languages - * @var array - */ - public $languageIDs = array(); - - /** - * indicates if the user may not be in the user groups with the selected - * ids - * @var integer - */ - public $invertGroupIDs = 0; - - /** - * registration start date - * @var string - */ - public $registrationDateStart = ''; - - /** - * registration start date - * @var string - */ - public $registrationDateEnd = ''; - - /** - * banned state - * @var boolean - */ - public $banned = 0; - - /** - * not banned state - * @var boolean - */ - public $notBanned = 0; - - /** - * last activity start time - * @var string - */ - public $lastActivityTimeStart = ''; - - /** - * last activity end time - * @var string - */ - public $lastActivityTimeEnd = ''; - - /** - * enabled state - * @var boolean - */ - public $enabled = 0; - - /** - * disabled state - * @var boolean - */ - public $disabled = 0; - - // assign to group - public $assignToGroupIDs = array(); - - // export mail address - public $fileType = 'csv'; - public $separator = ','; - public $textSeparator = '"'; - - // send mail - public $subject = ''; - public $text = ''; - public $from = ''; - public $enableHTML = 0; - - // data - public $availableGroups = array(); - public $options = array(); - public $availableActions = array('sendMail', 'exportMailAddress', 'assignToGroup', 'delete'); - public $affectedUsers = 0; - - /** - * conditions builder object - * @var \wcf\system\database\condition\PreparedStatementConditionBuilder - */ - public $conditions = null; - - /** - * options of the active category - * @var array - */ - public $activeOptions = array(); - - /** - * @see \wcf\form\IForm::readFormParameters() - */ - public function readFormParameters() { - parent::readFormParameters(); - - if (isset($_POST['username'])) $this->username = StringUtil::trim($_POST['username']); - if (isset($_POST['email'])) $this->email = StringUtil::trim($_POST['email']); - if (isset($_POST['groupIDs']) && is_array($_POST['groupIDs'])) $this->groupIDs = ArrayUtil::toIntegerArray($_POST['groupIDs']); - if (isset($_POST['languageIDs']) && is_array($_POST['languageIDs'])) $this->languageIDs = ArrayUtil::toIntegerArray($_POST['languageIDs']); - if (isset($_POST['invertGroupIDs'])) $this->invertGroupIDs = intval($_POST['invertGroupIDs']); - if (isset($_POST['registrationDateStart'])) $this->registrationDateStart = $_POST['registrationDateStart']; - if (isset($_POST['registrationDateEnd'])) $this->registrationDateEnd = $_POST['registrationDateEnd']; - if (isset($_POST['banned'])) $this->banned = intval($_POST['banned']); - if (isset($_POST['notBanned'])) $this->notBanned = intval($_POST['notBanned']); - if (isset($_POST['lastActivityTimeStart'])) $this->lastActivityTimeStart = $_POST['lastActivityTimeStart']; - if (isset($_POST['lastActivityTimeEnd'])) $this->lastActivityTimeEnd = $_POST['lastActivityTimeEnd']; - if (isset($_POST['enabled'])) $this->enabled = intval($_POST['enabled']); - if (isset($_POST['disabled'])) $this->disabled = intval($_POST['disabled']); - - // assign to group - if (isset($_POST['assignToGroupIDs']) && is_array($_POST['assignToGroupIDs'])) $this->assignToGroupIDs = ArrayUtil::toIntegerArray($_POST['assignToGroupIDs']); - // export mail address - if (isset($_POST['fileType']) && $_POST['fileType'] == 'xml') $this->fileType = $_POST['fileType']; - if (isset($_POST['separator'])) $this->separator = $_POST['separator']; - if (isset($_POST['textSeparator'])) $this->textSeparator = $_POST['textSeparator']; - // send mail - if (isset($_POST['subject'])) $this->subject = StringUtil::trim($_POST['subject']); - if (isset($_POST['text'])) $this->text = StringUtil::trim($_POST['text']); - if (isset($_POST['from'])) $this->from = StringUtil::trim($_POST['from']); - if (isset($_POST['enableHTML'])) $this->enableHTML = intval($_POST['enableHTML']); - } - - /** - * @see \wcf\form\IForm::validate() - */ - public function validate() { - AbstractForm::validate(); - - // action - if (!in_array($this->action, $this->availableActions)) { - throw new UserInputException('action'); - } - - // assign to group - if ($this->action == 'assignToGroup') { - if (empty($this->assignToGroupIDs)) { - throw new UserInputException('assignToGroupIDs'); - } - } - - // send mail - if ($this->action == 'sendMail') { - if (empty($this->subject)) { - throw new UserInputException('subject'); - } - - if (empty($this->text)) { - throw new UserInputException('text'); - } - - if (empty($this->from)) { - throw new UserInputException('from'); - } - } - } - - /** - * @see \wcf\form\IForm::save() - */ - public function save() { - parent::save(); - - // build conditions - $this->conditions = new PreparedStatementConditionBuilder(); - - // deny self delete - if ($this->action == 'delete') { - $this->conditions->add("user_table.userID <> ?", array(WCF::getUser()->userID)); - } - - // static fields - if (!empty($this->username)) { - $this->conditions->add("user_table.username LIKE ?", array('%'.addcslashes($this->username, '_%').'%')); - } - if (!empty($this->email)) { - $this->conditions->add("user_table.email LIKE ?", array('%'.addcslashes($this->email, '_%').'%')); - } - if (!empty($this->groupIDs)) { - $this->conditions->add("user_table.userID ".($this->invertGroupIDs == 1 ? 'NOT ' : '')."IN (SELECT userID FROM wcf".WCF_N."_user_to_group WHERE groupID IN (?))", array($this->groupIDs)); - } - if (!empty($this->languageIDs)) { - $this->conditions->add("user_table.languageID IN (?)", array($this->languageIDs)); - } - - // registration date - if ($startDate = @strtotime($this->registrationDateStart)) { - $this->conditions->add('user_table.registrationDate >= ?', array($startDate)); - } - if ($endDate = @strtotime($this->registrationDateEnd)) { - $this->conditions->add('user_table.registrationDate <= ?', array($endDate)); - } - - if ($this->banned) { - $this->conditions->add('user_table.banned = ?', array(1)); - } - if ($this->notBanned) { - $this->conditions->add('user_table.banned = ?', array(0)); - } - - // last activity time - if ($startDate = @strtotime($this->lastActivityTimeStart)) { - $this->conditions->add('user_table.lastActivityTime >= ?', array($startDate)); - } - if ($endDate = @strtotime($this->lastActivityTimeEnd)) { - $this->conditions->add('user_table.lastActivityTime <= ?', array($endDate)); - } - - if ($this->enabled) { - $this->conditions->add('user_table.activationCode = ?', array(0)); - } - if ($this->disabled) { - $this->conditions->add('user_table.activationCode <> ?', array(0)); - } - - // dynamic fields - foreach ($this->activeOptions as $name => $option) { - $value = isset($this->values[$option['optionName']]) ? $this->values[$option['optionName']] : null; - $this->getTypeObject($option['optionType'])->getCondition($this->conditions, $option, $value); - } - - // call buildConditions event - EventHandler::getInstance()->fireAction($this, 'buildConditions'); - - // execute action - switch ($this->action) { - case 'sendMail': - WCF::getSession()->checkPermissions(array('admin.user.canMailUser')); - // get user ids - $userIDs = array(); - $sql = "SELECT user_table.userID - FROM wcf".WCF_N."_user user_table - LEFT JOIN wcf".WCF_N."_user_option_value option_value - ON (option_value.userID = user_table.userID)". - $this->conditions; - $statement = WCF::getDB()->prepareStatement($sql); - $statement->execute($this->conditions->getParameters()); - while ($row = $statement->fetchArray()) { - $userIDs[] = $row['userID']; - $this->affectedUsers++; - } - - if (!empty($userIDs)) { - // save config in session - $userMailData = WCF::getSession()->getVar('userMailData'); - if ($userMailData === null) $userMailData = array(); - $mailID = count($userMailData); - $userMailData[$mailID] = array( - 'action' => '', - 'userIDs' => $userIDs, - 'groupIDs' => '', - 'subject' => $this->subject, - 'text' => $this->text, - 'from' => $this->from, - 'enableHTML' => $this->enableHTML - ); - WCF::getSession()->register('userMailData', $userMailData); - - WCF::getTPL()->assign('mailID', $mailID); - } - break; - - case 'exportMailAddress': - WCF::getSession()->checkPermissions(array('admin.user.canMailUser')); - // send content type - header('Content-Type: text/'.$this->fileType.'; charset=UTF-8'); - header('Content-Disposition: attachment; filename="export.'.$this->fileType.'"'); - - if ($this->fileType == 'xml') { - echo "\n\n"; - } - - // count users - $sql = "SELECT COUNT(*) AS count - FROM wcf".WCF_N."_user user_table - LEFT JOIN wcf".WCF_N."_user_option_value option_value - ON (option_value.userID = user_table.userID) - ".$this->conditions; - $statement = WCF::getDB()->prepareStatement($sql); - $statement->execute($this->conditions->getParameters()); - $count = $statement->fetchArray(); - - // get users - $sql = "SELECT user_table.email - FROM wcf".WCF_N."_user user_table - LEFT JOIN wcf".WCF_N."_user_option_value option_value - ON (option_value.userID = user_table.userID) - ".$this->conditions." - ORDER BY user_table.email"; - $statement = WCF::getDB()->prepareStatement($sql); - $statement->execute($this->conditions->getParameters()); - - $i = 0; - while ($row = $statement->fetchArray()) { - if ($this->fileType == 'xml') echo "
\n"; - else echo $this->textSeparator . $row['email'] . $this->textSeparator . ($i < $count['count'] ? $this->separator : ''); - $i++; - $this->affectedUsers++; - } - - if ($this->fileType == 'xml') { - echo "
"; - } - $this->saved(); - exit; - break; - - case 'assignToGroup': - WCF::getSession()->checkPermissions(array('admin.user.canEditUser')); - - $_this = $this; - $userIDs = $this->fetchUsers(function($userID, array $userData) use ($_this) { - $user = new UserEditor(new User(null, $userData)); - $user->addToGroups($_this->assignToGroupIDs, false, false); - }); - - if (!empty($userIDs)) { - UserStorageHandler::getInstance()->reset($userIDs, 'groupIDs', 1); - } - break; - - case 'delete': - WCF::getSession()->checkPermissions(array('admin.user.canDeleteUser')); - - $userIDs = $this->fetchUsers(); - - if (!empty($userIDs)) { - $userAction = new UserAction($userIDs, 'delete'); - $userAction->executeAction(); - } - break; - } - $this->saved(); - - WCF::getTPL()->assign('affectedUsers', $this->affectedUsers); - } - - /** - * Fetches a list of users. - * - * @param mixed $loopFunction - * @return array - */ - public function fetchUsers($loopFunction = null) { - // select users - $sql = "SELECT user_table.* - FROM wcf".WCF_N."_user user_table - LEFT JOIN wcf".WCF_N."_user_option_value option_value - ON (option_value.userID = user_table.userID) - ".$this->conditions; - $statement = WCF::getDB()->prepareStatement($sql); - $statement->execute($this->conditions->getParameters()); - - $users = array(); - while ($row = $statement->fetchArray()) { - $users[$row['userID']] = $row; - } - if (empty($users)) return array(); - - // select group ids - $conditions = new PreparedStatementConditionBuilder(); - $conditions->add("userID IN (?)", array(array_keys($users))); - - $sql = "SELECT userID, groupID - FROM wcf".WCF_N."_user_to_group - ".$conditions; - $statement = WCF::getDB()->prepareStatement($sql); - $statement->execute($conditions->getParameters()); - - $groupIDs = array(); - while ($row = $statement->fetchArray()) { - if (!isset($groupIDs[$row['userID']])) { - $groupIDs[$row['userID']] = array(); - } - - $groupIDs[$row['userID']][] = $row['groupID']; - } - - foreach ($users as $userID => $userData) { - if (!empty($groupIDs[$userID]) && !UserGroup::isAccessibleGroup($groupIDs[$userID])) { - throw new PermissionDeniedException(); - } - - if ($loopFunction !== null) { - $loopFunction($userID, $userData); - } - - $userIDs[] = $userID; - $this->affectedUsers++; - } - - return $userIDs; - } - - /** - * @see \wcf\page\IPage::readData() - */ - public function readData() { - parent::readData(); - - if (empty($_POST)) { - if (MAIL_USE_FORMATTED_ADDRESS) { - $this->from = MAIL_FROM_NAME.' <'.MAIL_FROM_ADDRESS.'>'; - } - else { - $this->from = MAIL_FROM_ADDRESS; - } - } - - $this->availableGroups = $this->getAvailableGroups(); - - foreach ($this->activeOptions as $name => $option) { - if (isset($this->values[$name])) { - $this->activeOptions[$name]['optionValue'] = $this->values[$name]; - } - } - - $this->options = $this->optionHandler->getCategoryOptions('profile'); - } - - /** - * @see \wcf\page\IPage::assignVariables() - */ - public function assignVariables() { - parent::assignVariables(); - - WCF::getTPL()->assign(array( - 'username' => $this->username, - 'email' => $this->email, - 'groupIDs' => $this->groupIDs, - 'languageIDs' => $this->languageIDs, - 'invertGroupIDs' => $this->invertGroupIDs, - 'registrationDateStart' => $this->registrationDateStart, - 'registrationDateEnd' => $this->registrationDateEnd, - 'banned' => $this->banned, - 'notBanned' => $this->notBanned, - 'lastActivityTimeStart' => $this->lastActivityTimeStart, - 'lastActivityTimeEnd' => $this->lastActivityTimeEnd, - 'enabled' => $this->enabled, - 'disabled' => $this->disabled, - - 'availableGroups' => $this->availableGroups, - 'availableLanguages' => LanguageFactory::getInstance()->getLanguages(), - 'options' => $this->options, - 'availableActions' => $this->availableActions, - // assign to group - 'assignToGroupIDs' => $this->assignToGroupIDs, - // export mail address - 'separator' => $this->separator, - 'textSeparator' => $this->textSeparator, - 'fileType' => $this->fileType, - // send mail - 'subject' => $this->subject, - 'text' => $this->text, - 'from' => $this->from, - 'enableHTML' => $this->enableHTML - )); - } - - /** - * @see \wcf\form\IForm::show() - */ - public function show() { - // set active menu item - ACPMenu::getInstance()->setActiveMenuItem('wcf.acp.menu.link.user.bulkProcessing'); - - // check master password - WCFACP::checkMasterPassword(); - - // show form - parent::show(); - } + public $objectTypeName = 'com.woltlab.wcf.bulkProcessing.user'; } diff --git a/wcfsetup/install/files/lib/system/bulk/processing/AbstractBulkProcessableObjectType.class.php b/wcfsetup/install/files/lib/system/bulk/processing/AbstractBulkProcessableObjectType.class.php new file mode 100644 index 0000000000..218f56d340 --- /dev/null +++ b/wcfsetup/install/files/lib/system/bulk/processing/AbstractBulkProcessableObjectType.class.php @@ -0,0 +1,83 @@ + + * @package com.woltlab.wcf + * @subpackage system.bulk.processing + * @category Community Framework + */ +class AbstractBulkProcessableObjectType extends AbstractObjectTypeProcessor implements IBulkProcessableObjectType { + /** + * name of the object type definition for the bulk actions + * @var string + */ + protected $actionObjectTypeDefinition = ''; + + /** + * name of the object type definition for the object conditions + * @var string + */ + protected $conditionObjectTypeDefinition = ''; + + /** + * name of the prefix of the language items used in the interface + * @var string + */ + protected $languageItemPrefix = ''; + + /** + * name of the conditions template + * @var string + */ + protected $templateName = ''; + + /** + * @see \wcf\system\bulk\processing\IBulkProcessableObjectType::getActionObjectTypeDefinition() + */ + public function getActionObjectTypeDefinition() { + if (empty($this->actionObjectTypeDefinition)) { + $this->actionObjectTypeDefinition = $this->object->objectType.'.action'; + } + + return $this->actionObjectTypeDefinition; + } + + /** + * @see \wcf\system\bulk\processing\IBulkProcessableObjectType::getConditionHTML() + */ + public function getConditionHTML() { + return WCF::getTPL()->fetch($this->templateName, explode('\\', get_class($this))[0]); + } + + /** + * @see \wcf\system\bulk\processing\IBulkProcessableObjectType::getConditionObjectTypeDefinition() + */ + public function getConditionObjectTypeDefinition() { + if (empty($this->conditionObjectTypeDefinition)) { + $this->conditionObjectTypeDefinition = $this->object->objectType.'.condition'; + } + + return $this->conditionObjectTypeDefinition; + } + + /** + * @see \wcf\system\bulk\processing\IBulkProcessableObjectType::getLanguageItemPrefix() + */ + public function getLanguageItemPrefix() { + if (empty($this->languageItemPrefix)) { + $application = explode('\\', get_class($this))[0]; + $objectTypePieces = explode('.', $this->object->objectType); + + $this->languageItemPrefix = $application.'.acp.'.end($objectTypePieces).'.bulkProcessing'; + } + + return $this->languageItemPrefix; + } +} diff --git a/wcfsetup/install/files/lib/system/bulk/processing/AbstractBulkProcessingAction.class.php b/wcfsetup/install/files/lib/system/bulk/processing/AbstractBulkProcessingAction.class.php new file mode 100644 index 0000000000..83e4e44681 --- /dev/null +++ b/wcfsetup/install/files/lib/system/bulk/processing/AbstractBulkProcessingAction.class.php @@ -0,0 +1,50 @@ + + * @package com.woltlab.wcf + * @subpackage system.bulk.processing + * @category Community Framework + */ +abstract class AbstractBulkProcessingAction extends AbstractObjectTypeProcessor implements IBulkProcessingAction { + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::getHTML() + */ + public function getHTML() { + return ''; + } + + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::isAvailable() + */ + public function isAvailable() { + return true; + } + + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::readFormParameters() + */ + public function readFormParameters() { + // does nothing + } + + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::reset() + */ + public function reset() { + // does nothing + } + + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::validate() + */ + public function validate() { + // does nothing + } +} diff --git a/wcfsetup/install/files/lib/system/bulk/processing/IBulkProcessableObjectType.class.php b/wcfsetup/install/files/lib/system/bulk/processing/IBulkProcessableObjectType.class.php new file mode 100644 index 0000000000..1382aad537 --- /dev/null +++ b/wcfsetup/install/files/lib/system/bulk/processing/IBulkProcessableObjectType.class.php @@ -0,0 +1,45 @@ + + * @package com.woltlab.wcf + * @subpackage system.bulk.processing + * @category Community Framework + */ +interface IBulkProcessableObjectType { + /** + * Returns the name of the object type definition for the bulk actions. + * + * @return string + */ + public function getActionObjectTypeDefinition(); + + /** + * Returns the output for setting up the conditions for the bulk processable + * object. + * + * @return string + */ + public function getConditionHTML(); + + /** + * Returns the name of the object type definition for the object conditions. + * + * @return string + */ + public function getConditionObjectTypeDefinition(); + + /** + * Returns the name of the prefix of the language items used in the interface. + * + * The returned prefix has not trailing dot. + * + * @return string + */ + public function getLanguageItemPrefix(); +} diff --git a/wcfsetup/install/files/lib/system/bulk/processing/IBulkProcessingAction.class.php b/wcfsetup/install/files/lib/system/bulk/processing/IBulkProcessingAction.class.php new file mode 100644 index 0000000000..1e97090975 --- /dev/null +++ b/wcfsetup/install/files/lib/system/bulk/processing/IBulkProcessingAction.class.php @@ -0,0 +1,60 @@ + + * @package com.woltlab.wcf + * @subpackage system.bulk.processing + * @category Community Framework + */ +interface IBulkProcessingAction { + /** + * Executes the bulk processing action on all objects in the given object + * list. + * + * @param \wcf\data\DatabaseObjectList $objectList + */ + public function executeAction(DatabaseObjectList $objectList); + + /** + * Returns the output for setting additional action parameters. + * + * @return string + */ + public function getHTML(); + + /** + * Returns an object list which will be populated with conditions to read + * the processed objects. + * + * @return \wcf\data\DatabaseObjectList + */ + public function getObjectList(); + + /** + * Returns true if the action is available for the active user. + * + * @return boolean + */ + public function isAvailable(); + + /** + * Reads additional parameters to execute the action. + */ + public function readFormParameters(); + + /** + * Resets the internally stored additional action parameters. + */ + public function reset(); + + /** + * Validates the additional action parameters. + */ + public function validate(); +} diff --git a/wcfsetup/install/files/lib/system/bulk/processing/user/AbstractUserBulkProcessingAction.class.php b/wcfsetup/install/files/lib/system/bulk/processing/user/AbstractUserBulkProcessingAction.class.php new file mode 100644 index 0000000000..1168852a52 --- /dev/null +++ b/wcfsetup/install/files/lib/system/bulk/processing/user/AbstractUserBulkProcessingAction.class.php @@ -0,0 +1,62 @@ + + * @package com.woltlab.wcf + * @subpackage system.bulk.processing.user + * @category Community Framework + */ +abstract class AbstractUserBulkProcessingAction extends AbstractBulkProcessingAction { + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::getObjectList() + */ + public function getObjectList() { + return new UserList(); + } + + /** + * Returns all users who the active user can access due to their user group + * assocition. + * + * @param \wcf\data\user\UserList $userList + */ + protected function getAccessibleUsers(UserList $userList) { + // fetch user group ids of all users + $conditionBuilder = new PreparedStatementConditionBuilder(); + $conditionBuilder->add('userID IN (?)', [ $userList->getObjectIDs() ]); + + $sql = "SELECT userID, groupID + FROM wcf".WCF_N."_user_to_group + ".$conditionBuilder; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute($conditionBuilder->getParameters()); + + $groupIDs = [ ]; + while ($row = $statement->fetchArray()) { + if (!isset($groupIDs[$row['userID']])) { + $groupIDs[$row['userID']] = [ ]; + } + + $groupIDs[$row['userID']][] = $row['groupID']; + } + + $users = [ ]; + foreach ($userList as $user) { + if (empty($groupIDs[$user->userID]) || UserGroup::isAccessibleGroup($groupIDs[$user->userID])) { + $users[$user->userID] = $user; + } + } + + return $users; + } +} diff --git a/wcfsetup/install/files/lib/system/bulk/processing/user/AbstractUserGroupsUserBulkProcessingAction.class.php b/wcfsetup/install/files/lib/system/bulk/processing/user/AbstractUserGroupsUserBulkProcessingAction.class.php new file mode 100644 index 0000000000..49c797bd9c --- /dev/null +++ b/wcfsetup/install/files/lib/system/bulk/processing/user/AbstractUserGroupsUserBulkProcessingAction.class.php @@ -0,0 +1,129 @@ + + * @package com.woltlab.wcf + * @subpackage system.bulk.processing.user + * @category Community Framework + */ +abstract class AbstractUserGroupsUserBulkProcessingAction extends AbstractUserBulkProcessingAction { + /** + * list of available user groups + * @var array<\wcf\data\user\group\UserGroup> + */ + public $availableUserGroups = [ ]; + + /** + * name of the inputs used to store the selected user group ids + * @var string + */ + public $inputName = ''; + + /** + * ids of selected user groups + * @var array + */ + public $userGroupIDs = [ ]; + + /** + * @see \wcf\data\DatabaseObjectDecorator::__construct() + */ + public function __construct(DatabaseObject $object) { + parent::__construct($object); + + $this->availableUserGroups = UserGroup::getAccessibleGroups([ ], [ UserGroup::GUESTS, UserGroup::EVERYONE, UserGroup::USERS ]); + + uasort($this->availableUserGroups, function(UserGroup $groupA, UserGroup $groupB) { + return strcmp($groupA->getName(), $groupB->getName()); + }); + } + + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::executeAction() + */ + public function executeAction(DatabaseObjectList $objectList) { + if (!($objectList instanceof UserList)) return; + + $users = $this->getAccessibleUsers($objectList); + + if (!empty($users)) { + WCF::getDB()->beginTransaction(); + foreach ($users as $user) { + $user = new UserEditor($user); + $this->executeUserAction($user); + } + WCF::getDB()->commitTransaction(); + + UserStorageHandler::getInstance()->reset(array_keys($users), 'groupIDs'); + } + } + + /** + * Execute the action for the given user. + * + * @param \wcf\data\user\UserEditor $user + */ + abstract protected function executeUserAction(UserEditor $user); + + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::getHTML() + */ + public function getHTML() { + return WCF::getTPL()->fetch('userGroupListUserBulkProcessing', 'wcf', [ + 'availableUserGroups' => $this->availableUserGroups, + 'inputName' => $this->inputName, + 'selectedUserGroupIDs' => $this->userGroupIDs + ]); + } + + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::isAvailable() + */ + public function isAvailable() { + return !empty($this->availableUserGroups); + } + + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::readFormParameters() + */ + public function readFormParameters() { + if (isset($_POST[$this->inputName])) $this->userGroupIDs = ArrayUtil::toIntegerArray($_POST[$this->inputName]); + } + + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::reset() + */ + public function reset() { + $this->userGroupIDs = [ ]; + } + + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::validate() + */ + public function validate() { + if (empty($this->userGroupIDs)) { + throw new UserInputException($this->inputName); + } + + foreach ($this->userGroupIDs as $groupID) { + if (!isset($this->availableUserGroups[$groupID])) { + throw new UserInputException($this->inputName, 'noValidSelection'); + } + } + } +} diff --git a/wcfsetup/install/files/lib/system/bulk/processing/user/AssignToUserGroupsUserBulkProcessingAction.class.php b/wcfsetup/install/files/lib/system/bulk/processing/user/AssignToUserGroupsUserBulkProcessingAction.class.php new file mode 100644 index 0000000000..d8f25b0532 --- /dev/null +++ b/wcfsetup/install/files/lib/system/bulk/processing/user/AssignToUserGroupsUserBulkProcessingAction.class.php @@ -0,0 +1,27 @@ + + * @package com.woltlab.wcf + * @subpackage system.bulk.processing.user + * @category Community Framework + */ +class AssignToUserGroupsUserBulkProcessingAction extends AbstractUserGroupsUserBulkProcessingAction { + /** + * @see \wcf\system\bulk\processing\user\AbstractUserGroupsUserBulkProcessingAction::$inputName + */ + public $inputName = 'assignToUserGroupIDs'; + + /** + * @see \wcf\system\bulk\processing\user\AbstractUserGroupsUserBulkProcessingAction::executeUserAction() + */ + protected function executeUserAction(UserEditor $user) { + $user->addToGroups($this->userGroupIDs, false, false); + } +} diff --git a/wcfsetup/install/files/lib/system/bulk/processing/user/DeleteUserBulkProcessingAction.class.php b/wcfsetup/install/files/lib/system/bulk/processing/user/DeleteUserBulkProcessingAction.class.php new file mode 100644 index 0000000000..b684ef27dd --- /dev/null +++ b/wcfsetup/install/files/lib/system/bulk/processing/user/DeleteUserBulkProcessingAction.class.php @@ -0,0 +1,44 @@ + + * @package com.woltlab.wcf + * @subpackage system.bulk.processing.user + * @category Community Framework + */ +class DeleteUserBulkProcessingAction extends AbstractUserBulkProcessingAction { + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::executeAction() + */ + public function executeAction(DatabaseObjectList $objectList) { + if (!($objectList instanceof UserList)) return; + + $users = $this->getAccessibleUsers($objectList); + + if (!empty($users)) { + $userAction = new UserAction($users, 'delete'); + $userAction->executeAction(); + } + } + + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::getObjectList() + */ + public function getObjectList() { + $userList = parent::getObjectList(); + + // deny self deletion + $userList->getConditionBuilder()->add('user_table.userID <> ?', array(WCF::getUser()->userID)); + + return $userList; + } +} diff --git a/wcfsetup/install/files/lib/system/bulk/processing/user/ExportMailAddressUserBulkProcessingAction.class.php b/wcfsetup/install/files/lib/system/bulk/processing/user/ExportMailAddressUserBulkProcessingAction.class.php new file mode 100644 index 0000000000..7fa1f44d48 --- /dev/null +++ b/wcfsetup/install/files/lib/system/bulk/processing/user/ExportMailAddressUserBulkProcessingAction.class.php @@ -0,0 +1,107 @@ + + * @package com.woltlab.wcf + * @subpackage system.bulk.processing.user + * @category Community Framework + */ +class ExportMailAddressUserBulkProcessingAction extends AbstractUserBulkProcessingAction { + /** + * type of the file the email addresses will be saved in (csv or xml) + * @var string + */ + public $fileType = 'csv'; + + /** + * separates the exported email addresses + * @var string + */ + public $separator = ','; + + /** + * encloses the exported email addresses + * @var string + */ + public $textSeparator = '"'; + + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::executeAction() + */ + public function executeAction(DatabaseObjectList $objectList) { + if (!($objectList instanceof UserList)) return; + + // send content type + header('Content-Type: text/'.$this->fileType.'; charset=UTF-8'); + header('Content-Disposition: attachment; filename="export.'.$this->fileType.'"'); + + if ($this->fileType == 'xml') { + echo "\n\n"; + } + + $userCount = count($objectList); + $i = 0; + foreach ($objectList as $user) { + if ($this->fileType == 'xml') { + echo "
email)."]]>
\n"; + } + else { + echo $this->textSeparator.$user->email.$this->textSeparator.($i < $userCount ? $this->separator : ''); + } + + $i++; + } + + if ($this->fileType == 'xml') { + echo "
"; + } + } + + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::getHTML() + */ + public function getHTML() { + return WCF::getTPL()->fetch('exportMailAddressUserBulkProcessing', 'wcf', [ + 'fileType' => $this->fileType, + 'separator' => $this->separator, + 'textSeparator' => $this->textSeparator + ]); + } + + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::getObjectList() + */ + public function getObjectList() { + $userList = parent::getObjectList(); + + $userList->sqlOrderBy = 'user_table.email'; + + return $userList; + } + + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::readFormParameters() + */ + public function readFormParameters() { + if (isset($_POST['fileType']) && $_POST['fileType'] == 'xml') $this->fileType = $_POST['fileType']; + if (isset($_POST['separator'])) $this->separator = $_POST['separator']; + if (isset($_POST['textSeparator'])) $this->textSeparator = $_POST['textSeparator']; + } + + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::reset() + */ + public function reset() { + exit; + } +} diff --git a/wcfsetup/install/files/lib/system/bulk/processing/user/RemoveFromUserGroupsUserBulkProcessingAction.class.php b/wcfsetup/install/files/lib/system/bulk/processing/user/RemoveFromUserGroupsUserBulkProcessingAction.class.php new file mode 100644 index 0000000000..cd11567a74 --- /dev/null +++ b/wcfsetup/install/files/lib/system/bulk/processing/user/RemoveFromUserGroupsUserBulkProcessingAction.class.php @@ -0,0 +1,41 @@ + + * @package com.woltlab.wcf + * @subpackage system.bulk.processing.user + * @category Community Framework + */ +class RemoveFromUserGroupsUserBulkProcessingAction extends AbstractUserGroupsUserBulkProcessingAction { + /** + * @see \wcf\system\bulk\processing\user\AbstractUserGroupsUserBulkProcessingAction::$inputName + */ + public $inputName = 'removeFromUserGroupIDs'; + + /** + * @see \wcf\system\bulk\processing\user\AbstractUserGroupsUserBulkProcessingAction::executeUserAction() + */ + protected function executeUserAction(UserEditor $user) { + $user->removeFromGroups($this->userGroupIDs); + } + + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::getObjectList() + */ + public function getObjectList() { + $userList = parent::getObjectList(); + + // the active user may not remove themselves from any user group + // to avoid potential permission issues + $userList->getConditionBuilder()->add('user_table.userID <> ?', array(WCF::getUser()->userID)); + + return $userList; + } +} diff --git a/wcfsetup/install/files/lib/system/bulk/processing/user/SendMailUserBulkProcessingAction.class.php b/wcfsetup/install/files/lib/system/bulk/processing/user/SendMailUserBulkProcessingAction.class.php new file mode 100644 index 0000000000..16d38b492a --- /dev/null +++ b/wcfsetup/install/files/lib/system/bulk/processing/user/SendMailUserBulkProcessingAction.class.php @@ -0,0 +1,113 @@ + + * @package com.woltlab.wcf + * @subpackage system.bulk.processing.user + * @category Community Framework + */ +class SendMailUserBulkProcessingAction extends AbstractUserBulkProcessingAction { + /** + * email text + * @var string + */ + public $email = ''; + + /** + * is 1 if HTML for the email is enabled + * @var integer + */ + public $enableHTML = 0; + + /** + * sender + * @var string + */ + public $from = ''; + + /** + * identifier for the mail worker + * @var string + */ + public $mailID = ''; + + /** + * email text + * @var string + */ + public $text = ''; + + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::executeAction() + */ + public function executeAction(DatabaseObjectList $objectList) { + if (!($objectList instanceof UserList)) return; + + if (count($objectList)) { + // save config in session + $userMailData = WCF::getSession()->getVar('userMailData'); + if ($userMailData === null) $userMailData = array(); + $this->mailID = count($userMailData); + $userMailData[$this->mailID] = array( + 'action' => '', + 'enableHTML' => $this->enableHTML, + 'from' => $this->from, + 'groupIDs' => '', + 'subject' => $this->subject, + 'text' => $this->text, + 'userIDs' => $objectList->getObjectIDs() + ); + WCF::getSession()->register('userMailData', $userMailData); + } + } + + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::getHTML() + */ + public function getHTML() { + return WCF::getTPL()->fetch('sendMailUserBulkProcessing', 'wcf', [ + 'enableHTML' => $this->enableHTML, + 'from' => $this->from, + 'mailID' => $this->mailID, + 'subject' => $this->subject, + 'text' => $this->text + ]); + } + + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::readFormParameters() + */ + public function readFormParameters() { + if (isset($_POST['enableHTML'])) $this->enableHTML = intval($_POST['enableHTML']); + if (isset($_POST['from'])) $this->from = StringUtil::trim($_POST['from']); + if (isset($_POST['subject'])) $this->subject = StringUtil::trim($_POST['subject']); + if (isset($_POST['text'])) $this->text = StringUtil::trim($_POST['text']); + } + + /** + * @see \wcf\system\bulk\processing\IBulkProcessingAction::validate() + */ + public function validate() { + if (empty($this->subject)) { + throw new UserInputException('subject'); + } + + if (empty($this->text)) { + throw new UserInputException('text'); + } + + if (empty($this->from)) { + throw new UserInputException('from'); + } + } +} diff --git a/wcfsetup/install/files/lib/system/bulk/processing/user/UserBulkProcessableObjectType.class.php b/wcfsetup/install/files/lib/system/bulk/processing/user/UserBulkProcessableObjectType.class.php new file mode 100644 index 0000000000..fe7e211508 --- /dev/null +++ b/wcfsetup/install/files/lib/system/bulk/processing/user/UserBulkProcessableObjectType.class.php @@ -0,0 +1,21 @@ + + * @package com.woltlab.wcf + * @subpackage system.bulk.processing.user + * @category Community Framework + */ +class UserBulkProcessableObjectType extends AbstractBulkProcessableObjectType { + /** + * @see \wcf\system\bulk\processing\AbstractBulkProcessableObjectType::$templateName + */ + protected $templateName = 'userConditions'; +} diff --git a/wcfsetup/install/files/lib/system/condition/AbstractObjectTextPropertyCondition.class.php b/wcfsetup/install/files/lib/system/condition/AbstractObjectTextPropertyCondition.class.php new file mode 100644 index 0000000000..a9b8c0e767 --- /dev/null +++ b/wcfsetup/install/files/lib/system/condition/AbstractObjectTextPropertyCondition.class.php @@ -0,0 +1,101 @@ + + * @package com.woltlab.wcf + * @subpackage system.condition + * @category Community Framework + */ +abstract class AbstractObjectTextPropertyCondition extends AbstractTextCondition implements IObjectCondition, IObjectListCondition { + /** + * name of the relevant database object class + * @var string + */ + protected $className = ''; + + /** + * is true if the entered value should be split by commas to search for + * multiple values + * @var boolean + */ + protected $supportsMultipleValues = false; + + /** + * name of the relevant object property + * @var string + */ + protected $propertyName = ''; + + /** + * @see \wcf\system\condition\IObjectListCondition::addObjectListCondition() + */ + public function addObjectListCondition(DatabaseObjectList $objectList, array $conditionData) { + if (!ClassUtil::isInstanceOf($objectList, $this->getListClassName())) return; + + if ($this->supportsMultipleValues) { + $objectList->getConditionBuilder()->add($objectList->getDatabaseTableAlias().'.'.$this->getPropertyName().' IN (?)', [ $conditionData[$this->fieldName] ]); + } + else { + $objectList->getConditionBuilder()->add($objectList->getDatabaseTableAlias().'.'.$this->getPropertyName().' = ?', [ $conditionData[$this->fieldName] ]); + } + } + + /** + * @see \wcf\system\condition\IObjectCondition::checkObject() + */ + public function checkObject(DatabaseObject $object, array $conditionData) { + if (!ClassUtil::isInstanceOf($object, $this->getClassName())) return; + + return in_array($object->{$this->getPropertyName()}, $conditionData[$this->fieldName]); + } + + /** + * Returns the name of the relevant database object class. + * + * @return string + */ + protected function getClassName() { + return $this->className; + } + + /** + * @see \wcf\system\condition\ICondition::getData() + */ + public function getData() { + $value = parent::getData(); + if ($value === null || !$this->supportsMultipleValues) { + return $value; + } + + return [ + $this->fieldName => preg_split('/\s*,\s*/', $value, -1, PREG_SPLIT_NO_EMPTY) + ]; + } + + /** + * Returns the name of the relevant database object list class. + * + * @return string + */ + protected function getListClassName() { + return $this->className.'List'; + } + + /** + * Returns the name of the relevant object property. + * + * @return string + */ + protected function getPropertyName() { + return $this->propertyName; + } +} diff --git a/wcfsetup/install/files/lib/system/condition/AbstractTextCondition.class.php b/wcfsetup/install/files/lib/system/condition/AbstractTextCondition.class.php index a28f3f374b..4caaa3acf1 100644 --- a/wcfsetup/install/files/lib/system/condition/AbstractTextCondition.class.php +++ b/wcfsetup/install/files/lib/system/condition/AbstractTextCondition.class.php @@ -31,9 +31,9 @@ abstract class AbstractTextCondition extends AbstractSingleFieldCondition { */ public function getData() { if (mb_strlen($this->fieldValue)) { - return array( + return [ $this->fieldName => $this->fieldValue - ); + ]; } return null; diff --git a/wcfsetup/install/files/lib/system/condition/AbstractTimestampCondition.class.php b/wcfsetup/install/files/lib/system/condition/AbstractTimestampCondition.class.php new file mode 100644 index 0000000000..7972e5448c --- /dev/null +++ b/wcfsetup/install/files/lib/system/condition/AbstractTimestampCondition.class.php @@ -0,0 +1,209 @@ + + * @package com.woltlab.wcf + * @subpackage system.condition + * @category Community Framework + */ +abstract class AbstractTimestampCondition extends AbstractSingleFieldCondition implements IObjectCondition, IObjectListCondition { + /** + * name of the relevant database object class + * @var string + */ + protected $className = ''; + + /** + * registration start date + * @var string + */ + protected $endTime = ''; + + /** + * name of the relevant object property + * @var string + */ + protected $propertyName = ''; + + /** + * registration start date + * @var string + */ + protected $startTime = ''; + + /** + * @see \wcf\system\condition\IObjectListCondition::addObjectListCondition() + */ + public function addObjectListCondition(DatabaseObjectList $objectList, array $conditionData) { + if (!ClassUtil::isInstanceOf($objectList, $this->getListClassName())) return; + + $objectList->getConditionBuilder()->add($objectList->getDatabaseTableAlias().'.'.$this->getPropertyName().' <> ?', [ 0 ]); + if (isset($conditionData['endTime'])) { + $objectList->getConditionBuilder()->add($objectList->getDatabaseTableAlias().'.'.$this->getPropertyName().' < ?', [ strtotime($conditionData['endTime']) + 86400 ]); + } + if (isset($conditionData['startTime'])) { + $objectList->getConditionBuilder()->add($objectList->getDatabaseTableAlias().'.'.$this->getPropertyName().' >= ?', [ strtotime($conditionData['startTime']) ]); + } + } + + /** + * @see \wcf\system\condition\IObjectCondition::checkObject() + */ + public function checkObject(DatabaseObject $object, array $conditionData) { + if (!ClassUtil::isInstanceOf($object, $this->getClassName())) return; + + if (isset($conditionData['startTime']) && $object->{$this->getPropertyName()} < strtotime($conditionData['startTime'])) { + return false; + } + if (isset($conditionData['endTimeTime']) && $object->{$this->getPropertyName()} >= strtotime($conditionData['endTime']) + 86400) { + return false; + } + + return true; + } + + /** + * Returns the name of the relevant database object class. + * + * @return string + */ + protected function getClassName() { + return $this->className; + } + + /** + * @see \wcf\system\condition\ICondition::getData() + */ + public function getData() { + $data = array(); + + if (strlen($this->startTime)) { + $data['startTime'] = $this->startTime; + } + if (strlen($this->endTime)) { + $data['endTime'] = $this->endTime; + } + + if (!empty($data)) { + return $data; + } + + return null; + } + + /** + * @see \wcf\system\condition\AbstractSingleFieldCondition::getFieldElement() + */ + protected function getFieldElement() { + $start = WCF::getLanguage()->get('wcf.date.period.start'); + $end = WCF::getLanguage()->get('wcf.date.period.end'); + + return << + +HTML; + } + + /** + * @see \wcf\system\condition\AbstractSingleFieldCondition::getLabel() + */ + protected function getLabel() { + return WCF::getLanguage()->get($this->getLanguageItemPrefix().'.'.$this->getPropertyName()); + } + + /** + * Returns the prefix of the language items used for the condition. + * + * @return string + */ + abstract protected function getLanguageItemPrefix(); + + /** + * Returns the name of the relevant database object list class. + * + * @return string + */ + protected function getListClassName() { + return $this->className.'List'; + } + + /** + * Returns the name of the relevant object property. + * + * @return string + */ + protected function getPropertyName() { + return $this->propertyName; + } + + /** + * @see \wcf\system\condition\ICondition::readFormParameters() + */ + public function readFormParameters() { + if (isset($_POST[$this->getPropertyName().'EndTime'])) $this->endTime = $_POST[$this->getPropertyName().'EndTime']; + if (isset($_POST[$this->getPropertyName().'StartTime'])) $this->startTime = $_POST[$this->getPropertyName().'StartTime']; + } + + /** + * @see \wcf\system\condition\ICondition::reset() + */ + public function reset() { + $this->endTime = ''; + $this->startTime = ''; + } + + /** + * @see \wcf\system\condition\ICondition::setData() + */ + public function setData(Condition $condition) { + if ($condition->endTime) { + $this->endTime = $condition->endTime; + } + if ($condition->startTime) { + $this->startTime = $condition->startTime; + } + } + + /** + * @see \wcf\system\condition\ICondition::validate() + */ + public function validate() { + $endTime = $startTime = null; + if (strlen($this->startTime)) { + $startTime = @strtotime($this->startTime); + if ($startTime === false) { + $this->errorMessage = $this->getLanguageItemPrefix().'.'.$this->getPropertyName().'.error.startNotValid'; + + throw new UserInputException($this->getPropertyName(), 'startNotValid'); + } + } + if (strlen($this->endTime)) { + $endTime = @strtotime($this->endTime); + if ($endTime === false) { + $this->errorMessage = $this->getLanguageItemPrefix().'.'.$this->getPropertyName().'.error.endNotValid'; + + throw new UserInputException($this->getPropertyName(), 'endNotValid'); + } + } + + if ($endTime !== null && $startTime !== null && $endTime < $startTime) { + $this->errorMessage = $this->getLanguageItemPrefix().'.'.$this->getPropertyName().'.error.endBeforeStart'; + + throw new UserInputException($this->getPropertyName(), 'endBeforeStart'); + } + } +} diff --git a/wcfsetup/install/files/lib/system/condition/IObjectCondition.class.php b/wcfsetup/install/files/lib/system/condition/IObjectCondition.class.php new file mode 100644 index 0000000000..baca51987c --- /dev/null +++ b/wcfsetup/install/files/lib/system/condition/IObjectCondition.class.php @@ -0,0 +1,26 @@ + + * @package com.woltlab.wcf + * @subpackage system.condition + * @category Community Framework + */ +interface IObjectCondition extends ICondition { + /** + * Returns true if the given object fulfills the condition specified by + * the given condition data returned by \wcf\system\condition\ICondition::getData(). + * + * @param \wcf\data\DatabaseObject $object + * @param array $conditionData + * @return boolean + */ + public function checkObject(DatabaseObject $object, array $conditionData); +} diff --git a/wcfsetup/install/files/lib/system/condition/IObjectListCondition.class.php b/wcfsetup/install/files/lib/system/condition/IObjectListCondition.class.php new file mode 100644 index 0000000000..f0272c983b --- /dev/null +++ b/wcfsetup/install/files/lib/system/condition/IObjectListCondition.class.php @@ -0,0 +1,25 @@ + + * @package com.woltlab.wcf + * @subpackage system.condition + * @category Community Framework + */ +interface IObjectListCondition extends ICondition { + /** + * Adds a condition to the given object list based on the given condition + * data returned by \wcf\system\condition\ICondition::getData(). + * + * @param \wcf\data\DatabaseObjectList $objectList + * @param array $conditionData + */ + public function addObjectListCondition(DatabaseObjectList $objectList, array $conditionData); +} diff --git a/wcfsetup/install/files/lib/system/condition/TObjectListUserCondition.class.php b/wcfsetup/install/files/lib/system/condition/TObjectListUserCondition.class.php new file mode 100644 index 0000000000..13dad870b4 --- /dev/null +++ b/wcfsetup/install/files/lib/system/condition/TObjectListUserCondition.class.php @@ -0,0 +1,24 @@ + + * @package com.woltlab.wcf + * @subpackage system.condition + * @category Community Framework + */ +trait TObjectListUserCondition { + /** + * @see \wcf\system\condition\IUserCondition::addUserCondition() + */ + public function addUserCondition(Condition $condition, UserList $userList) { + $this->addObjectListCondition($userList, $condition->conditionData); + } +} diff --git a/wcfsetup/install/files/lib/system/condition/TObjectUserCondition.class.php b/wcfsetup/install/files/lib/system/condition/TObjectUserCondition.class.php new file mode 100644 index 0000000000..6b587d4c67 --- /dev/null +++ b/wcfsetup/install/files/lib/system/condition/TObjectUserCondition.class.php @@ -0,0 +1,23 @@ + + * @package com.woltlab.wcf + * @subpackage system.condition + * @category Community Framework + */ +trait TObjectUserCondition { + /** + * @see \wcf\system\condition\IUserCondition::checkUser() + */ + public function checkUser(Condition $condition, User $user) { + $this->checkObject($user, $condition->conditionData); + } +} diff --git a/wcfsetup/install/files/lib/system/condition/UserAvatarCondition.class.php b/wcfsetup/install/files/lib/system/condition/UserAvatarCondition.class.php index 634fbc29a4..47c9cfded3 100644 --- a/wcfsetup/install/files/lib/system/condition/UserAvatarCondition.class.php +++ b/wcfsetup/install/files/lib/system/condition/UserAvatarCondition.class.php @@ -2,7 +2,7 @@ namespace wcf\system\condition; use wcf\data\condition\Condition; use wcf\data\user\User; -use wcf\data\user\UserList; +use wcf\data\DatabaseObjectList; use wcf\system\WCF; /** @@ -15,7 +15,9 @@ use wcf\system\WCF; * @subpackage system.condition * @category Community Framework */ -class UserAvatarCondition extends AbstractSelectCondition implements IContentCondition, IUserCondition { +class UserAvatarCondition extends AbstractSelectCondition implements IContentCondition, IObjectListCondition, IUserCondition { + use TObjectListUserCondition; + /** * @see wcf\system\condition\AbstractSelectCondition::$fieldName */ @@ -45,21 +47,23 @@ class UserAvatarCondition extends AbstractSelectCondition implements IContentCon const GRAVATAR = 2; /** - * @see \wcf\system\condition\IUserCondition::addUserCondition() + * @see \wcf\system\condition\IObjectListCondition::addObjectListCondition() */ - public function addUserCondition(Condition $condition, UserList $userList) { - switch ($condition->userAvatar) { + public function addObjectListCondition(DatabaseObjectList $objectList, array $conditionData) { + if (!($objectList instanceof UserList)) return; + + switch ($conditionData['userAvatar']) { case self::NO_AVATAR: - $userList->getConditionBuilder()->add('user_table.avatarID IS NULL'); - $userList->getConditionBuilder()->add('user_table.enableGravatar = ?', array(0)); + $objectList->getConditionBuilder()->add('user_table.avatarID IS NULL'); + $objectList->getConditionBuilder()->add('user_table.enableGravatar = ?', array(0)); break; case self::AVATAR: - $userList->getConditionBuilder()->add('user_table.avatarID IS NOT NULL'); + $objectList->getConditionBuilder()->add('user_table.avatarID IS NOT NULL'); break; case self::GRAVATAR: - $userList->getConditionBuilder()->add('user_table.enableGravatar = ?', array(1)); + $objectList->getConditionBuilder()->add('user_table.enableGravatar = ?', array(1)); break; } } diff --git a/wcfsetup/install/files/lib/system/condition/UserEmailCondition.class.php b/wcfsetup/install/files/lib/system/condition/UserEmailCondition.class.php index be0bd018f7..d30cb9ef3a 100644 --- a/wcfsetup/install/files/lib/system/condition/UserEmailCondition.class.php +++ b/wcfsetup/install/files/lib/system/condition/UserEmailCondition.class.php @@ -2,7 +2,7 @@ namespace wcf\system\condition; use wcf\data\condition\Condition; use wcf\data\user\User; -use wcf\data\user\UserList; +use wcf\data\DatabaseObjectList; use wcf\system\WCF; /** @@ -15,7 +15,9 @@ use wcf\system\WCF; * @subpackage system.condition * @category Community Framework */ -class UserEmailCondition extends AbstractTextCondition implements IContentCondition, IUserCondition { +class UserEmailCondition extends AbstractTextCondition implements IContentCondition, IObjectListCondition, IUserCondition { + use TObjectListUserCondition; + /** * @see \wcf\system\condition\AbstractTextCondition::$fieldName */ @@ -27,10 +29,12 @@ class UserEmailCondition extends AbstractTextCondition implements IContentCondit protected $label = 'wcf.user.email'; /** - * @see \wcf\system\condition\IUserCondition::addUserCondition() + * @see \wcf\system\condition\IObjectListCondition::addObjectListCondition() */ - public function addUserCondition(Condition $condition, UserList $userList) { - $userList->getConditionBuilder()->add('user_table.email LIKE ?', array('%'.addcslashes($condition->email, '_%').'%')); + public function addObjectListCondition(DatabaseObjectList $objectList, array $conditionData) { + if (!($objectList instanceof UserList)) return; + + $objectList->getConditionBuilder()->add('user_table.email LIKE ?', array('%'.addcslashes($conditionData['email'], '_%').'%')); } /** diff --git a/wcfsetup/install/files/lib/system/condition/UserGroupCondition.class.php b/wcfsetup/install/files/lib/system/condition/UserGroupCondition.class.php index 8a50bbddb7..d190e2f36a 100644 --- a/wcfsetup/install/files/lib/system/condition/UserGroupCondition.class.php +++ b/wcfsetup/install/files/lib/system/condition/UserGroupCondition.class.php @@ -3,7 +3,7 @@ namespace wcf\system\condition; use wcf\data\condition\Condition; use wcf\data\user\group\UserGroup; use wcf\data\user\User; -use wcf\data\user\UserList; +use wcf\data\DatabaseObjectList; use wcf\system\exception\UserInputException; use wcf\system\WCF; use wcf\util\ArrayUtil; @@ -19,7 +19,9 @@ use wcf\util\ArrayUtil; * @subpackage system.condition * @category Community Framework */ -class UserGroupCondition extends AbstractMultipleFieldsCondition implements IContentCondition, IUserCondition { +class UserGroupCondition extends AbstractMultipleFieldsCondition implements IContentCondition, IObjectListCondition, IUserCondition { + use TObjectListUserCondition; + /** * @see \wcf\system\condition\AbstractMultipleFieldsCondition::$descriptions */ @@ -55,14 +57,16 @@ class UserGroupCondition extends AbstractMultipleFieldsCondition implements ICon protected $userGroups = null; /** - * @see \wcf\system\condition\IUserCondition::addUserCondition() + * @see \wcf\system\condition\IObjectListCondition::addObjectListCondition() */ - public function addUserCondition(Condition $condition, UserList $userList) { - if ($condition->groupIDs !== null) { - $userList->getConditionBuilder()->add('user_table.userID IN (SELECT userID FROM wcf'.WCF_N.'_user_to_group WHERE groupID IN (?) GROUP BY userID HAVING COUNT(userID) = ?)', array($condition->groupIDs, count($condition->groupIDs))); + public function addObjectListCondition(DatabaseObjectList $objectList, array $conditionData) { + if (!($objectList instanceof UserList)) return; + + if (isset($conditionData['groupIDs'])) { + $objectList->getConditionBuilder()->add('user_table.userID IN (SELECT userID FROM wcf'.WCF_N.'_user_to_group WHERE groupID IN (?) GROUP BY userID HAVING COUNT(userID) = ?)', array($conditionData['groupIDs'], count($conditionData['groupIDs']))); } - if ($condition->notGroupIDs !== null) { - $userList->getConditionBuilder()->add('user_table.userID NOT IN (SELECT userID FROM wcf'.WCF_N.'_user_to_group WHERE groupID IN (?))', array($condition->notGroupIDs)); + if (isset($conditionData['notGroupIDs'])) { + $objectList->getConditionBuilder()->add('user_table.userID NOT IN (SELECT userID FROM wcf'.WCF_N.'_user_to_group WHERE groupID IN (?))', array($conditionData['notGroupIDs'])); } } diff --git a/wcfsetup/install/files/lib/system/condition/UserIntegerPropertyCondition.class.php b/wcfsetup/install/files/lib/system/condition/UserIntegerPropertyCondition.class.php index 4dcc9adbed..c36e797ece 100644 --- a/wcfsetup/install/files/lib/system/condition/UserIntegerPropertyCondition.class.php +++ b/wcfsetup/install/files/lib/system/condition/UserIntegerPropertyCondition.class.php @@ -2,7 +2,7 @@ namespace wcf\system\condition; use wcf\data\condition\Condition; use wcf\data\user\User; -use wcf\data\user\UserList; +use wcf\data\DatabaseObjectList; use wcf\system\WCF; /** @@ -15,16 +15,20 @@ use wcf\system\WCF; * @subpackage system.condition * @category Community Framework */ -class UserIntegerPropertyCondition extends AbstractIntegerCondition implements IContentCondition, IUserCondition { +class UserIntegerPropertyCondition extends AbstractIntegerCondition implements IContentCondition, IObjectListCondition, IUserCondition { + use TObjectListUserCondition; + /** - * @see \wcf\system\condition\IUserCondition::addUserCondition() + * @see \wcf\system\condition\IObjectListCondition::addObjectListCondition() */ - public function addUserCondition(Condition $condition, UserList $userList) { - if ($condition->greaterThan !== null) { - $userList->getConditionBuilder()->add('user_table.'.$this->getDecoratedObject()->propertyname.' > ?', array($condition->greaterThan)); + public function addObjectListCondition(DatabaseObjectList $objectList, array $conditionData) { + if (!($objectList instanceof UserList)) return; + + if (isset($conditionData['greaterThan'])) { + $objectList->getConditionBuilder()->add('user_table.'.$this->getDecoratedObject()->propertyname.' > ?', array($conditionData['greaterThan'])); } - if ($condition->lessThan !== null) { - $userList->getConditionBuilder()->add('user_table.'.$this->getDecoratedObject()->propertyname.' < ?', array($condition->lessThan)); + if (isset($conditionData['lessThan'])) { + $objectList->getConditionBuilder()->add('user_table.'.$this->getDecoratedObject()->propertyname.' < ?', array($conditionData['lessThan'])); } } diff --git a/wcfsetup/install/files/lib/system/condition/UserLanguageCondition.class.php b/wcfsetup/install/files/lib/system/condition/UserLanguageCondition.class.php index 9bf72984ff..a8ad6bc71c 100644 --- a/wcfsetup/install/files/lib/system/condition/UserLanguageCondition.class.php +++ b/wcfsetup/install/files/lib/system/condition/UserLanguageCondition.class.php @@ -2,7 +2,7 @@ namespace wcf\system\condition; use wcf\data\condition\Condition; use wcf\data\user\User; -use wcf\data\user\UserList; +use wcf\data\DatabaseObjectList; use wcf\system\exception\UserInputException; use wcf\system\language\LanguageFactory; use wcf\system\WCF; @@ -18,7 +18,9 @@ use wcf\util\ArrayUtil; * @subpackage system.condition * @category Community Framework */ -class UserLanguageCondition extends AbstractSingleFieldCondition implements IContentCondition, IUserCondition { +class UserLanguageCondition extends AbstractSingleFieldCondition implements IContentCondition, IObjectListCondition, IUserCondition { + use TObjectListUserCondition; + /** * @see \wcf\system\condition\AbstractSingleFieldCondition::$label */ @@ -31,10 +33,12 @@ class UserLanguageCondition extends AbstractSingleFieldCondition implements ICon protected $languageIDs = array(); /** - * @see \wcf\system\condition\IUserCondition::addUserCondition() + * @see \wcf\system\condition\IObjectListCondition::addObjectListCondition() */ - public function addUserCondition(Condition $condition, UserList $userList) { - $userList->getConditionBuilder()->add('user_table.languageID IN (?)', array($condition->conditionData['languageIDs'])); + public function addObjectListCondition(DatabaseObjectList $objectList, array $conditionData) { + if (!($objectList instanceof UserList)) return; + + $objectList->getConditionBuilder()->add('user_table.languageID IN (?)', array($conditionData['languageIDs'])); } /** diff --git a/wcfsetup/install/files/lib/system/condition/UserOptionsCondition.class.php b/wcfsetup/install/files/lib/system/condition/UserOptionsCondition.class.php index 8b0821075d..0ba429ff88 100644 --- a/wcfsetup/install/files/lib/system/condition/UserOptionsCondition.class.php +++ b/wcfsetup/install/files/lib/system/condition/UserOptionsCondition.class.php @@ -2,8 +2,8 @@ namespace wcf\system\condition; use wcf\data\condition\Condition; use wcf\data\user\User; -use wcf\data\user\UserList; use wcf\data\DatabaseObject; +use wcf\data\DatabaseObjectList; use wcf\system\option\user\UserOptionHandler; use wcf\system\WCF; @@ -17,7 +17,9 @@ use wcf\system\WCF; * @subpackage system.condition * @category Community Framework */ -class UserOptionsCondition extends AbstractMultipleFieldsCondition implements IContentCondition, IUserCondition { +class UserOptionsCondition extends AbstractMultipleFieldsCondition implements IContentCondition, IObjectListCondition, IUserCondition { + use TObjectListUserCondition; + /** * user option handler object * @var \wcf\system\option\user\UserOptionHandler @@ -36,16 +38,18 @@ class UserOptionsCondition extends AbstractMultipleFieldsCondition implements IC } /** - * @see \wcf\system\condition\IUserCondition::addUserCondition() + * @see \wcf\system\condition\IObjectListCondition::addObjectListCondition() */ - public function addUserCondition(Condition $condition, UserList $userList) { - $optionValues = $condition->optionValues; + public function addObjectListCondition(DatabaseObjectList $objectList, array $conditionData) { + if (!($objectList instanceof UserList)) return; + + $optionValues = $conditionData['optionValues']; foreach ($this->optionHandler->getCategoryOptions('profile') as $option) { $option = $option['object']; if (isset($optionValues[$option->optionName])) { - $this->optionHandler->getTypeObject($option->optionType)->addCondition($userList, $option, $optionValues[$option->optionName]); + $this->optionHandler->getTypeObject($option->optionType)->addCondition($objectList, $option, $optionValues[$option->optionName]); } } } diff --git a/wcfsetup/install/files/lib/system/condition/UserRegistrationDateCondition.class.php b/wcfsetup/install/files/lib/system/condition/UserRegistrationDateCondition.class.php index 626595ca46..0f9bb3e73d 100644 --- a/wcfsetup/install/files/lib/system/condition/UserRegistrationDateCondition.class.php +++ b/wcfsetup/install/files/lib/system/condition/UserRegistrationDateCondition.class.php @@ -2,7 +2,7 @@ namespace wcf\system\condition; use wcf\data\condition\Condition; use wcf\data\user\User; -use wcf\data\user\UserList; +use wcf\data\DatabaseObjectList; use wcf\system\exception\UserInputException; use wcf\system\WCF; @@ -16,7 +16,9 @@ use wcf\system\WCF; * @subpackage system.condition * @category Community Framework */ -class UserRegistrationDateCondition extends AbstractSingleFieldCondition implements IContentCondition, IUserCondition { +class UserRegistrationDateCondition extends AbstractSingleFieldCondition implements IContentCondition, IObjectListCondition, IUserCondition { + use TObjectListUserCondition; + /** * @see \wcf\system\condition\AbstractSingleFieldCondition::$label */ @@ -35,14 +37,16 @@ class UserRegistrationDateCondition extends AbstractSingleFieldCondition impleme protected $registrationDateStart = ''; /** - * @see \wcf\system\condition\IUserCondition::addUserCondition() + * @see \wcf\system\condition\IObjectListCondition::addObjectListCondition() */ - public function addUserCondition(Condition $condition, UserList $userList) { - if ($condition->registrationDateEnd !== null) { - $userList->getConditionBuilder()->add('user_table.registrationDate < ?', array(strtotime($condition->registrationDateEnd) + 86400)); + public function addObjectListCondition(DatabaseObjectList $objectList, array $conditionData) { + if (!($objectList instanceof UserList)) return; + + if (isset($conditionData['registrationDateEnd'])) { + $userList->getConditionBuilder()->add('user_table.registrationDate < ?', array(strtotime($conditionData['registrationDateEnd']) + 86400)); } - if ($condition->registrationDateStart !== null) { - $userList->getConditionBuilder()->add('user_table.registrationDate >= ?', array(strtotime($condition->registrationDateStart))); + if (isset($conditionData['registrationDateStart'])) { + $userList->getConditionBuilder()->add('user_table.registrationDate >= ?', array(strtotime($conditionData['registrationDateStart']))); } } diff --git a/wcfsetup/install/files/lib/system/condition/UserRegistrationDateIntervalCondition.class.php b/wcfsetup/install/files/lib/system/condition/UserRegistrationDateIntervalCondition.class.php index 59a54f508b..e78d3ea666 100644 --- a/wcfsetup/install/files/lib/system/condition/UserRegistrationDateIntervalCondition.class.php +++ b/wcfsetup/install/files/lib/system/condition/UserRegistrationDateIntervalCondition.class.php @@ -2,7 +2,7 @@ namespace wcf\system\condition; use wcf\data\condition\Condition; use wcf\data\user\User; -use wcf\data\user\UserList; +use wcf\data\DatabaseObjectList; use wcf\system\WCF; /** @@ -16,7 +16,9 @@ use wcf\system\WCF; * @subpackage system.condition * @category Community Framework */ -class UserRegistrationDateIntervalCondition extends AbstractIntegerCondition implements IContentCondition, IUserCondition { +class UserRegistrationDateIntervalCondition extends AbstractIntegerCondition implements IContentCondition, IObjectListCondition, IUserCondition { + use TObjectListUserCondition; + /** * @see \wcf\system\condition\AbstractMultipleFieldsCondition::$languageItemPrefix */ @@ -28,14 +30,16 @@ class UserRegistrationDateIntervalCondition extends AbstractIntegerCondition imp protected $minValue = 0; /** - * @see \wcf\system\condition\IUserCondition::addUserCondition() + * @see \wcf\system\condition\IObjectListCondition::addObjectListCondition() */ - public function addUserCondition(Condition $condition, UserList $userList) { - if ($condition->greaterThan !== null) { - $userList->getConditionBuilder()->add('user_table.registrationDate < ?', array(TIME_NOW - $condition->greaterThan * 86400)); + public function addObjectListCondition(DatabaseObjectList $objectList, array $conditionData) { + if (!($objectList instanceof UserList)) return; + + if ($conditionData['greaterThan'] !== null) { + $userList->getConditionBuilder()->add('user_table.registrationDate < ?', array(TIME_NOW - $conditionData['greaterThan'] * 86400)); } - if ($condition->lessThan !== null) { - $userList->getConditionBuilder()->add('user_table.registrationDate > ?', array(TIME_NOW - $condition->lessThan * 86400)); + if ($conditionData['lessThan'] !== null) { + $userList->getConditionBuilder()->add('user_table.registrationDate > ?', array(TIME_NOW - $conditionData['lessThan'] * 86400)); } } diff --git a/wcfsetup/install/files/lib/system/condition/UserStateCondition.class.php b/wcfsetup/install/files/lib/system/condition/UserStateCondition.class.php index 4924d9649b..2e5d8a263f 100644 --- a/wcfsetup/install/files/lib/system/condition/UserStateCondition.class.php +++ b/wcfsetup/install/files/lib/system/condition/UserStateCondition.class.php @@ -2,7 +2,7 @@ namespace wcf\system\condition; use wcf\data\condition\Condition; use wcf\data\user\User; -use wcf\data\user\UserList; +use wcf\data\DatabaseObjectList; use wcf\system\exception\UserInputException; use wcf\system\WCF; @@ -16,7 +16,9 @@ use wcf\system\WCF; * @subpackage system.condition * @category Community Framework */ -class UserStateCondition extends AbstractSingleFieldCondition implements IContentCondition, IUserCondition { +class UserStateCondition extends AbstractSingleFieldCondition implements IContentCondition, IObjectListCondition, IUserCondition { + use TObjectListUserCondition; + /** * @see \wcf\system\condition\AbstractSingleFieldCondition::$label */ @@ -47,15 +49,17 @@ class UserStateCondition extends AbstractSingleFieldCondition implements IConten protected $userIsNotBanned = 0; /** - * @see \wcf\system\condition\IUserCondition::addUserCondition() + * @see \wcf\system\condition\IObjectListCondition::addObjectListCondition() */ - public function addUserCondition(Condition $condition, UserList $userList) { - if ($condition->userIsBanned !== null) { - $userList->getConditionBuilder()->add('user_table.banned = ?', array($condition->userIsBanned)); + public function addObjectListCondition(DatabaseObjectList $objectList, array $conditionData) { + if (!($objectList instanceof UserList)) return; + + if (isset($conditionData['userIsBanned'])) { + $userList->getConditionBuilder()->add('user_table.banned = ?', array($conditionData['userIsBanned'])); } - if ($condition->userIsEnabled !== null) { - if ($condition->userIsEnabled) { + if ($conditionData['userIsEnabled']) { + if ($conditionData['userIsEnabled']) { $userList->getConditionBuilder()->add('user_table.activationCode = ?', array(0)); } else { diff --git a/wcfsetup/install/files/lib/system/condition/UserTimestampPropertyCondition.class.php b/wcfsetup/install/files/lib/system/condition/UserTimestampPropertyCondition.class.php new file mode 100644 index 0000000000..fc286fbf19 --- /dev/null +++ b/wcfsetup/install/files/lib/system/condition/UserTimestampPropertyCondition.class.php @@ -0,0 +1,49 @@ + + * @package com.woltlab.wcf + * @subpackage system.condition + * @category Community Framework + */ +class UserTimestampPropertyCondition extends AbstractTimestampCondition implements IContentCondition, IUserCondition { + use TObjectUserCondition; + use TObjectListUserCondition; + + /** + * @see \wcf\system\condition\AbstractTimestampCondition::$className + */ + protected $className = User::class; + + /** + * @see \wcf\system\condition\AbstractTimestampCondition::getLanguageItemPrefix() + */ + protected function getLanguageItemPrefix() { + return 'wcf.user.condition'; + } + + /** + * @see \wcf\system\condition\AbstractTimestampCondition::getPropertyName() + */ + protected function getPropertyName() { + return $this->getDecoratedObject()->propertyname; + } + + /** + * @see \wcf\system\condition\IContentCondition::showContent() + */ + public function showContent(Condition $condition) { + if (!WCF::getUser()->userID) return false; + + return $this->checkUser($condition, WCF::getUser()); + } +} diff --git a/wcfsetup/install/files/lib/system/condition/UserUsernameCondition.class.php b/wcfsetup/install/files/lib/system/condition/UserUsernameCondition.class.php index efe6e449c1..d07b7e244a 100644 --- a/wcfsetup/install/files/lib/system/condition/UserUsernameCondition.class.php +++ b/wcfsetup/install/files/lib/system/condition/UserUsernameCondition.class.php @@ -2,7 +2,7 @@ namespace wcf\system\condition; use wcf\data\condition\Condition; use wcf\data\user\User; -use wcf\data\user\UserList; +use wcf\data\DatabaseObjectList; use wcf\system\WCF; /** @@ -15,7 +15,9 @@ use wcf\system\WCF; * @subpackage system.condition * @category Community Framework */ -class UserUsernameCondition extends AbstractTextCondition implements IContentCondition, IUserCondition { +class UserUsernameCondition extends AbstractTextCondition implements IContentCondition, IObjectListCondition, IUserCondition { + use TObjectListUserCondition; + /** * @see \wcf\system\condition\AbstractTextCondition::$fieldName */ @@ -27,10 +29,12 @@ class UserUsernameCondition extends AbstractTextCondition implements IContentCon protected $label = 'wcf.user.username'; /** - * @see \wcf\system\condition\IUserCondition::addUserCondition() + * @see \wcf\system\condition\IObjectListCondition::addObjectListCondition() */ - public function addUserCondition(Condition $condition, UserList $userList) { - $userList->getConditionBuilder()->add('user_table.username LIKE ?', array('%'.addcslashes($condition->username, '_%').'%')); + public function addObjectListCondition(DatabaseObjectList $objectList, array $conditionData) { + if (!($objectList instanceof UserList)) return; + + $objectList->getConditionBuilder()->add('user_table.username LIKE ?', array('%'.addcslashes($conditionData['username'], '_%').'%')); } /** diff --git a/wcfsetup/install/lang/de.xml b/wcfsetup/install/lang/de.xml index 10dd23556d..c838057ba9 100644 --- a/wcfsetup/install/lang/de.xml +++ b/wcfsetup/install/lang/de.xml @@ -1592,11 +1592,6 @@ GmbH=Gesellschaft mit beschränkter Haftung]]> - - - - - ohne zusätzliche Sicherheitsabfrage bei allen Benutzern aus, die unter die eingestellten Bedingungen fallen.]]> @@ -1735,6 +1730,17 @@ Sie können jetzt den vollen Funktionsumfang der Seite nutzen.]]> + + + + + + + + + + + ohne zusätzliche Sicherheitsabfrage bei allen Benutzern aus, die unter die eingestellten Bedingungen fallen.]]> @@ -2246,6 +2252,7 @@ Fehler sind beispielsweise: + ohne zusätzliche Sicherheitsabfrage aus!]]> @@ -3118,6 +3125,7 @@ Sollten Sie sich nicht auf der Website: {@PAGE_TITLE|language} angemeldet haben, + diff --git a/wcfsetup/install/lang/en.xml b/wcfsetup/install/lang/en.xml index 750a9a7a8b..9067773a95 100644 --- a/wcfsetup/install/lang/en.xml +++ b/wcfsetup/install/lang/en.xml @@ -1591,11 +1591,6 @@ GmbH=Gesellschaft mit beschränkter Haftung]]> - - - - - @@ -1735,6 +1730,16 @@ You can now fully access the website.]]> + + + + + + + + + + -- 2.20.1