first commit
This commit is contained in:
@@ -0,0 +1,262 @@
|
||||
<?php
|
||||
/**
|
||||
* @file classes/mailable/Repository.php
|
||||
*
|
||||
* Copyright (c) 2014-2022 Simon Fraser University
|
||||
* Copyright (c) 2000-2022 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class Repository
|
||||
*
|
||||
* @brief A repository to find and edit Mailables.
|
||||
*/
|
||||
|
||||
namespace PKP\mail;
|
||||
|
||||
use APP\core\Application;
|
||||
use APP\facades\Repo;
|
||||
use Illuminate\Support\Collection;
|
||||
use PKP\context\Context;
|
||||
use PKP\core\PKPString;
|
||||
use PKP\mail\mailables\DecisionNotifyOtherAuthors;
|
||||
use PKP\mail\mailables\EditReviewNotify;
|
||||
use PKP\mail\mailables\ReviewCompleteNotifyEditors;
|
||||
use PKP\mail\mailables\StatisticsReportNotify;
|
||||
use PKP\mail\mailables\SubmissionAcknowledgement;
|
||||
use PKP\mail\mailables\SubmissionAcknowledgementNotAuthor;
|
||||
use PKP\mail\mailables\SubmissionNeedsEditor;
|
||||
use PKP\mail\mailables\SubmissionSavedForLater;
|
||||
use PKP\mail\traits\Configurable;
|
||||
use PKP\plugins\Hook;
|
||||
|
||||
class Repository
|
||||
{
|
||||
/**
|
||||
* Get a list of mailables
|
||||
*
|
||||
* @param string $searchPhrase Only include mailables with a name or description matching this search phrase
|
||||
* @param ?bool $includeDisabled Whether or not to include mailables not used in this context, based on the context settings
|
||||
*
|
||||
* @return Collection<int,string> The fully-qualified class name of each mailable
|
||||
*/
|
||||
public function getMany(
|
||||
Context $context,
|
||||
?string $searchPhrase = null,
|
||||
?bool $includeDisabled = false,
|
||||
?bool $includeConfigurableOnly = false
|
||||
): Collection
|
||||
{
|
||||
$mailables = $this->map();
|
||||
Hook::call('Mailer::Mailables', [$mailables, $context]);
|
||||
|
||||
return $mailables
|
||||
->filter(fn (string $class) => !$searchPhrase || $this->containsSearchPhrase($class, $searchPhrase))
|
||||
->filter(function (string $class) use ($context, $includeDisabled) {
|
||||
return $includeDisabled || $this->isMailableEnabled($class, $context);
|
||||
})
|
||||
->filter(function (string $class) use ($context, $includeConfigurableOnly) {
|
||||
return !$includeConfigurableOnly || $this->isMailableConfigurable($class, $context);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple check if mailable's name and description contains a search phrase
|
||||
* doesn't look up in associated email templates
|
||||
*
|
||||
* @param string $className The fully-qualified class name of the Mailable
|
||||
*/
|
||||
protected function containsSearchPhrase(string $className, string $searchPhrase): bool
|
||||
{
|
||||
$searchPhrase = PKPString::strtolower($searchPhrase);
|
||||
|
||||
/** @var Mailable $className */
|
||||
return str_contains(PKPString::strtolower($className::getName()), $searchPhrase) ||
|
||||
str_contains(PKPString::strtolower($className::getDescription()), $searchPhrase);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a mailable by its email template key
|
||||
*
|
||||
* @return ?string The fully-qualified class name of the mailable
|
||||
*/
|
||||
public function get(string $emailTemplateKey, Context $context): ?string
|
||||
{
|
||||
/** @var ?string $mailable */
|
||||
$mailable = $this->getMany($context)
|
||||
->first(fn (string $mailable) => $mailable::getEmailTemplateKey() === $emailTemplateKey);
|
||||
|
||||
if (!$mailable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $mailable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a summary of a mailable's properties
|
||||
*/
|
||||
public function summarizeMailable(string $class): array
|
||||
{
|
||||
$dataDescriptions = $class::getDataDescriptions();
|
||||
ksort($dataDescriptions);
|
||||
|
||||
return [
|
||||
'_href' => Application::get()->getRequest()->getDispatcher()->url(
|
||||
Application::get()->getRequest(),
|
||||
Application::ROUTE_API,
|
||||
Application::get()->getRequest()->getContext()->getPath(),
|
||||
'mailables/' . $class::getEmailTemplateKey(),
|
||||
),
|
||||
'dataDescriptions' => $dataDescriptions,
|
||||
'description' => $class::getDescription(),
|
||||
'emailTemplateKey' => $class::getEmailTemplateKey(),
|
||||
'fromRoleIds' => $class::getFromRoleIds(),
|
||||
'groupIds' => $class::getGroupIds(),
|
||||
'name' => $class::getName(),
|
||||
'supportsTemplates' => $class::getSupportsTemplates(),
|
||||
'toRoleIds' => $class::getToRoleIds(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a full description of a mailable's properties, including any
|
||||
* assigned email templates
|
||||
*/
|
||||
public function describeMailable(string $class, int $contextId): array
|
||||
{
|
||||
$data = $this->summarizeMailable($class);
|
||||
|
||||
if (!$class::getSupportsTemplates()) {
|
||||
$data['emailTemplates'] = [];
|
||||
} else {
|
||||
$templates = Repo::emailTemplate()
|
||||
->getCollector($contextId)
|
||||
->alternateTo([$class::getEmailTemplateKey()])
|
||||
->getMany();
|
||||
|
||||
$defaultTemplate = Repo::emailTemplate()->getByKey($contextId, $class::getEmailTemplateKey());
|
||||
|
||||
$data['emailTemplates'] = Repo::emailTemplate()
|
||||
->getSchemaMap()
|
||||
->summarizeMany(
|
||||
collect(
|
||||
array_merge(
|
||||
[$defaultTemplate],
|
||||
$templates->values()->toArray()
|
||||
)
|
||||
)
|
||||
)
|
||||
->values();
|
||||
}
|
||||
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a mailable is enabled on this context
|
||||
*/
|
||||
protected function isMailableEnabled(string $class, Context $context): bool
|
||||
{
|
||||
if ($class === StatisticsReportNotify::class) {
|
||||
return (bool) $context->getData('editorialStatsEmail');
|
||||
} elseif (in_array($class, [SubmissionAcknowledgement::class, SubmissionAcknowledgementNotAuthor::class])) {
|
||||
$setting = $context->getData('submissionAcknowledgement');
|
||||
if ($setting === Context::SUBMISSION_ACKNOWLEDGEMENT_ALL_AUTHORS) {
|
||||
return true;
|
||||
} elseif ($setting === Context::SUBMISSION_ACKNOWLEDGEMENT_OFF) {
|
||||
return false;
|
||||
} elseif ($class === SubmissionAcknowledgementNotAuthor::class) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} elseif ($class === DecisionNotifyOtherAuthors::class) {
|
||||
return $context->getData('notifyAllAuthors');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if mailable can be configured
|
||||
*/
|
||||
protected function isMailableConfigurable(string $class, Context $context): bool
|
||||
{
|
||||
if (!in_array(Configurable::class, class_uses_recursive($class))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mailables may not have associated email templates due to pkp/pkp-lib#9109 and pkp/pkp-lib#9217,
|
||||
* don't allow to configure them
|
||||
*/
|
||||
if (in_array($class, [
|
||||
EditReviewNotify::class,
|
||||
ReviewCompleteNotifyEditors::class,
|
||||
SubmissionSavedForLater::class,
|
||||
SubmissionNeedsEditor::class,
|
||||
])) {
|
||||
$template = Repo::emailTemplate()->getByKey($context->getId(), $class::getEmailTemplateKey());
|
||||
if (!$template) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mailables used in this app
|
||||
*/
|
||||
public function map(): Collection
|
||||
{
|
||||
return collect([
|
||||
mailables\AnnouncementNotify::class,
|
||||
mailables\DecisionAcceptNotifyAuthor::class,
|
||||
mailables\DecisionBackFromCopyeditingNotifyAuthor::class,
|
||||
mailables\DecisionBackFromProductionNotifyAuthor::class,
|
||||
mailables\DecisionCancelReviewRoundNotifyAuthor::class,
|
||||
mailables\DecisionDeclineNotifyAuthor::class,
|
||||
mailables\DecisionInitialDeclineNotifyAuthor::class,
|
||||
mailables\DecisionNewReviewRoundNotifyAuthor::class,
|
||||
mailables\DecisionNotifyOtherAuthors::class,
|
||||
mailables\DecisionNotifyReviewer::class,
|
||||
mailables\DecisionRequestRevisionsNotifyAuthor::class,
|
||||
mailables\DecisionResubmitNotifyAuthor::class,
|
||||
mailables\DecisionRevertDeclineNotifyAuthor::class,
|
||||
mailables\DecisionRevertInitialDeclineNotifyAuthor::class,
|
||||
mailables\DecisionSendExternalReviewNotifyAuthor::class,
|
||||
mailables\DecisionSendToProductionNotifyAuthor::class,
|
||||
mailables\DecisionSkipExternalReviewNotifyAuthor::class,
|
||||
mailables\DiscussionCopyediting::class,
|
||||
mailables\DiscussionProduction::class,
|
||||
mailables\DiscussionReview::class,
|
||||
mailables\DiscussionSubmission::class,
|
||||
mailables\EditorAssigned::class,
|
||||
mailables\EditReviewNotify::class,
|
||||
mailables\EditorialReminder::class,
|
||||
mailables\PasswordResetRequested::class,
|
||||
mailables\PublicationVersionNotify::class,
|
||||
mailables\RecommendationNotifyEditors::class,
|
||||
mailables\ReviewAcknowledgement::class,
|
||||
mailables\ReviewCompleteNotifyEditors::class,
|
||||
mailables\ReviewConfirm::class,
|
||||
mailables\ReviewDecline::class,
|
||||
mailables\ReviewRemind::class,
|
||||
mailables\ReviewRemindAuto::class,
|
||||
mailables\ReviewRequest::class,
|
||||
mailables\ReviewRequestSubsequent::class,
|
||||
mailables\ReviewResponseRemindAuto::class,
|
||||
mailables\ReviewerRegister::class,
|
||||
mailables\ReviewerReinstate::class,
|
||||
mailables\ReviewerResendRequest::class,
|
||||
mailables\ReviewerUnassign::class,
|
||||
mailables\RevisedVersionNotify::class,
|
||||
mailables\StatisticsReportNotify::class,
|
||||
mailables\SubmissionAcknowledgement::class,
|
||||
mailables\SubmissionAcknowledgementNotAuthor::class,
|
||||
mailables\UserCreated::class,
|
||||
mailables\ValidateEmailContext::class,
|
||||
mailables\ValidateEmailSite::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user