diff --git a/api/v1/emailTemplates/PKPEmailTemplateController.php b/api/v1/emailTemplates/PKPEmailTemplateController.php index b0bfce34567..ea8dfb34d0a 100644 --- a/api/v1/emailTemplates/PKPEmailTemplateController.php +++ b/api/v1/emailTemplates/PKPEmailTemplateController.php @@ -201,6 +201,10 @@ public function add(Request $illuminateRequest): JsonResponse $emailTemplate = Repo::emailTemplate()->newDataObject($params); Repo::emailTemplate()->add($emailTemplate); + + if($params['userGroupIds']) { + Repo::emailTemplate()->updateTemplateAccessGroups($emailTemplate, $params['userGroupIds'], $requestContext->getId()); + } $emailTemplate = Repo::emailTemplate()->getByKey($emailTemplate->getData('contextId'), $emailTemplate->getData('key')); return response()->json(Repo::emailTemplate()->getSchemaMap()->map($emailTemplate), Response::HTTP_OK); @@ -238,6 +242,11 @@ public function edit(Request $illuminateRequest): JsonResponse $params['contextId'] = $requestContext->getId(); } + + // If the user submitted an empty list (meaning all user groups were unchecked), the empty array is converted to null in the request's data. + // Convert back to an empty array. + $params['userGroupIds'] = $params['userGroupIds'] ?: []; + $errors = Repo::emailTemplate()->validate( $emailTemplate, $params, diff --git a/classes/components/forms/FieldEmailTemplateUnrestricted.php b/classes/components/forms/FieldEmailTemplateUnrestricted.php new file mode 100644 index 00000000000..80e62146b57 --- /dev/null +++ b/classes/components/forms/FieldEmailTemplateUnrestricted.php @@ -0,0 +1,33 @@ +label; + return $config; + } +} diff --git a/classes/components/forms/emailTemplate/EmailTemplateForm.php b/classes/components/forms/emailTemplate/EmailTemplateForm.php index 7e42bd2c211..9011049e67d 100644 --- a/classes/components/forms/emailTemplate/EmailTemplateForm.php +++ b/classes/components/forms/emailTemplate/EmailTemplateForm.php @@ -15,6 +15,7 @@ namespace PKP\components\forms\emailTemplate; +use PKP\components\forms\FieldEmailTemplateUnrestricted; use PKP\components\forms\FieldEmailTemplateUserGroupSettings; use PKP\components\forms\FieldPreparedContent; use PKP\components\forms\FieldText; @@ -47,9 +48,16 @@ public function __construct(string $action, array $locales) 'isMultilingual' => true, 'toolbar' => 'bold italic superscript subscript | link | blockquote bullist numlist', 'plugins' => 'paste,link,lists', - ]))->addField(new FieldEmailTemplateUserGroupSettings('userGroupIds', [ + ]))->addField( + new FieldEmailTemplateUnrestricted('isUnrestricted'), + [ + 'type' => 'checkbox' + ] + ) + ->addField(new FieldEmailTemplateUserGroupSettings('userGroupIds', [ + 'type' => 'checkbox', 'label' => __('workflow.userGroup.allowed'), - 'type' => 'checkbox' + ])); } } diff --git a/classes/decision/steps/Email.php b/classes/decision/steps/Email.php index ab3200d6a9d..f8114728531 100644 --- a/classes/decision/steps/Email.php +++ b/classes/decision/steps/Email.php @@ -21,6 +21,7 @@ use PKP\facades\Locale; use PKP\mail\Mailable; use PKP\user\User; +use Role; use stdClass; class Email extends Step @@ -124,6 +125,12 @@ protected function getEmailTemplates(): array { $request = Application::get()->getRequest(); $context = $request->getContext(); + $userRoles = array_map(fn (Role $role) => $role->getId(), $request->getUser()->getRoles($context->getId())); + + // Ensure user has access to mailable before proceeding + if(empty(array_intersect($this->mailable::getFromRoleIds(), $userRoles))) { + return []; + } $emailTemplates = collect(); if ($this->mailable::getEmailTemplateKey()) { diff --git a/classes/emailTemplate/DAO.php b/classes/emailTemplate/DAO.php index 66e1587c990..828185ec303 100644 --- a/classes/emailTemplate/DAO.php +++ b/classes/emailTemplate/DAO.php @@ -450,31 +450,5 @@ protected function getUniqueKey(EmailTemplate $emailTemplate): string } - public function updateTemplateAccessGroups(EmailTemplate $emailTemplate, array $newUserGroupIds, $contextId) - { - // Delete old entries for user groups IDs not found in new list of user group IDs - DB::table('email_template_role_access') - ->where('email_key', $emailTemplate->getData('key')) - ->where('context_id', $contextId) - ->whereNotIn('user_group_id', $newUserGroupIds) - ->delete(); - - foreach ($newUserGroupIds as $id) { - DB::table('email_template_role_access') - ->updateOrInsert( - [ // The where conditions (keys that should match) - 'email_key' => $emailTemplate->getData('key'), - 'user_group_id' => $id, - 'context_id' => $contextId - ], - [ // The data to insert or update (values to set) - 'email_key' => $emailTemplate->getData('key'), - 'user_group_id' => $id, - 'context_id' => $contextId, - ] - ); - } - - } } diff --git a/classes/emailTemplate/Repository.php b/classes/emailTemplate/Repository.php index 41f1a2790c3..077597f7bf1 100644 --- a/classes/emailTemplate/Repository.php +++ b/classes/emailTemplate/Repository.php @@ -172,11 +172,12 @@ public function add(EmailTemplate $emailTemplate): string /** @copydoc DAO::update() */ public function edit(EmailTemplate $emailTemplate, array $params, $contextId) { + $userGroupIds = $params['userGroupIds']; + unset($params['userGroupIds']); $newEmailTemplate = clone $emailTemplate; $newEmailTemplate->setAllData(array_merge($newEmailTemplate->_data, $params)); - $userGroupIds = $params['userGroupIds']; - unset($params['userGroupIds']); + Hook::call('EmailTemplate::edit', [$newEmailTemplate, $emailTemplate, $params]); @@ -186,9 +187,7 @@ public function edit(EmailTemplate $emailTemplate, array $params, $contextId) $this->dao->insert($newEmailTemplate); } - if($userGroupIds) { - $this->dao->updateTemplateAccessGroups($emailTemplate, $userGroupIds, $contextId); - } + $this->updateTemplateAccessGroups($emailTemplate, $userGroupIds, $contextId); } /** @copydoc DAO::delete() */ @@ -278,4 +277,36 @@ public function filterTemplatesByUserAccess(array $templates, User $user, int $c return collect(array_filter($templates, fn (EmailTemplate $template) => $this->isTemplateAccessibleToUser($user, $template, $contextId))); } + /** + * Pass empty array to delete all existing user groups for a template + */ + public function updateTemplateAccessGroups(EmailTemplate $emailTemplate, array $newUserGroupIds, int $contextId): void + { + $isUnrestricted = in_array(null, $newUserGroupIds); + // remove any null values + // Delete old entries for user groups IDs not found in new list of user group IDs + DB::table('email_template_role_access') + ->where('email_key', $emailTemplate->getData('key')) + ->where('context_id', $contextId) + ->whereNotIn('user_group_id', $newUserGroupIds) + ->delete(); + + foreach ($newUserGroupIds as $id) { + DB::table('email_template_role_access') + ->updateOrInsert( + [ // The where conditions (keys that should match) + 'email_key' => $emailTemplate->getData('key'), + 'user_group_id' => $id, + 'context_id' => $contextId + ], + [ // The data to insert or update (values to set) + 'email_key' => $emailTemplate->getData('key'), + 'user_group_id' => $id, + 'context_id' => $contextId, + ] + ); + } + + } + } diff --git a/classes/emailTemplate/maps/Schema.php b/classes/emailTemplate/maps/Schema.php index 299dcb292c0..595871486c8 100644 --- a/classes/emailTemplate/maps/Schema.php +++ b/classes/emailTemplate/maps/Schema.php @@ -77,7 +77,7 @@ public function summarizeMany(Enumerable $collection, string $mailableClass = nu } /** - * Map schema properties of an Announcement to an assoc array + * Map schema properties of an Email Template to an assoc array */ protected function mapByProperties(array $props, EmailTemplate $item, string $mailableClass = null): array { diff --git a/classes/mail/Repository.php b/classes/mail/Repository.php index 4f69043a989..36d2f02d412 100644 --- a/classes/mail/Repository.php +++ b/classes/mail/Repository.php @@ -229,12 +229,7 @@ protected function isMailableConfigurable(string $class, Context $context): bool */ public function isGroupsAssignableToTemplates(Mailable|string $mailable): bool { - return !empty(array_intersect($mailable::getGroupIds(), [ - Mailable::GROUP_SUBMISSION, - Mailable::GROUP_REVIEW, - Mailable::GROUP_COPYEDITING, - Mailable::GROUP_PRODUCTION, - ])); + return !in_array(Mailable::FROM_SYSTEM, $mailable::getFromRoleIds()); } /** diff --git a/schemas/emailTemplate.json b/schemas/emailTemplate.json index e496a69b166..017be1187ba 100644 --- a/schemas/emailTemplate.json +++ b/schemas/emailTemplate.json @@ -68,6 +68,11 @@ "validation": [ "nullable" ] + }, + "isUnrestricted": { + "type": "boolean", + "description": "Boolean indicating if an email template is available to all user groups within the roles associated with the template's mailable", + "apiSummary": true } } }