324 lines
12 KiB
PHP
324 lines
12 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @file classes/context/SubEditorsDAO.php
|
|
*
|
|
* Copyright (c) 2014-2021 Simon Fraser University
|
|
* Copyright (c) 2003-2021 John Willinsky
|
|
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
|
*
|
|
* @class SubEditorsDAO
|
|
*
|
|
* @ingroup context
|
|
*
|
|
* @brief Base class associating sections, series and categories to sub editors.
|
|
*/
|
|
|
|
namespace PKP\context;
|
|
|
|
use APP\core\Application;
|
|
use APP\facades\Repo;
|
|
use APP\notification\Notification;
|
|
use APP\notification\NotificationManager;
|
|
use APP\submission\Submission;
|
|
use Exception;
|
|
use Illuminate\Support\Arr;
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Mail;
|
|
use PKP\db\DAORegistry;
|
|
use PKP\log\SubmissionEmailLogDAO;
|
|
use PKP\log\SubmissionEmailLogEntry;
|
|
use PKP\mail\mailables\EditorAssigned;
|
|
use PKP\notification\NotificationSubscriptionSettingsDAO;
|
|
use PKP\security\Role;
|
|
use PKP\stageAssignment\StageAssignment;
|
|
use PKP\stageAssignment\StageAssignmentDAO;
|
|
use PKP\userGroup\UserGroup;
|
|
|
|
class SubEditorsDAO extends \PKP\db\DAO
|
|
{
|
|
/**
|
|
* Insert a new sub editor.
|
|
*
|
|
* @param int $contextId
|
|
* @param int $assocId
|
|
* @param int $userId
|
|
*/
|
|
public function insertEditor($contextId, $assocId, $userId, $assocType, int $userGroupId)
|
|
{
|
|
return $this->update(
|
|
'INSERT INTO subeditor_submission_group
|
|
(context_id, assoc_id, user_id, assoc_type, user_group_id)
|
|
VALUES
|
|
(?, ?, ?, ?, ?)',
|
|
[
|
|
(int) $contextId,
|
|
(int) $assocId,
|
|
(int) $userId,
|
|
(int) $assocType,
|
|
$userGroupId,
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Delete a sub editor.
|
|
*
|
|
* @param int $contextId
|
|
* @param int $assocId
|
|
* @param int $userId
|
|
* @param int $assocType Application::ASSOC_TYPE_SECTION or Application::ASSOC_TYPE_CATEGORY
|
|
*/
|
|
public function deleteEditor($contextId, $assocId, $userId, $assocType)
|
|
{
|
|
$this->update(
|
|
'DELETE FROM subeditor_submission_group WHERE context_id = ? AND section_id = ? AND user_id = ? AND assoc_type = ?',
|
|
[
|
|
(int) $contextId,
|
|
(int) $assocId,
|
|
(int) $userId,
|
|
(int) $assocType,
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Retrieve a list of all sub editors assigned to the specified submission group.
|
|
*
|
|
* @param int[] $assocIds Section or category ids
|
|
* @param int $assocType Application::ASSOC_TYPE_SECTION or Application::ASSOC_TYPE_CATEGORY
|
|
*
|
|
* @return Collection result rows with userId and userGroupId columns
|
|
*/
|
|
public function getBySubmissionGroupIds(array $assocIds, int $assocType, int $contextId): Collection
|
|
{
|
|
return DB::table('subeditor_submission_group')
|
|
->where('assoc_type', '=', $assocType)
|
|
->where('context_id', '=', $contextId)
|
|
->whereIn('assoc_id', $assocIds)
|
|
->get(['user_id as userId', 'user_group_id as userGroupId']);
|
|
}
|
|
|
|
/**
|
|
* Delete all sub editors for a specified submission group in a context.
|
|
*
|
|
* @param int $assocId
|
|
* @param int $assocType Application::ASSOC_TYPE_SECTION or Application::ASSOC_TYPE_CATEGORY
|
|
* @param int $contextId
|
|
*/
|
|
public function deleteBySubmissionGroupId($assocId, $assocType, $contextId = null)
|
|
{
|
|
$params = [(int) $assocId, (int) $assocType];
|
|
if ($contextId) {
|
|
$params[] = (int) $contextId;
|
|
}
|
|
$this->update(
|
|
'DELETE FROM subeditor_submission_group WHERE assoc_id = ? AND assoc_type = ?' .
|
|
($contextId ? ' AND context_id = ?' : ''),
|
|
$params
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Delete all submission group assignments for the specified user.
|
|
*/
|
|
public function deleteByUserId(int $userId)
|
|
{
|
|
/**
|
|
* This warning was added in 3.4 due to a change in the function signature.
|
|
* It can be removed with the next LTS release.
|
|
*
|
|
* @deprecated 3.4
|
|
*/
|
|
if (func_num_args() !== 1) {
|
|
throw new Exception('Invalid number of arguments passed to ' . self::class . '::' . __FUNCTION__);
|
|
}
|
|
|
|
DB::table('subeditor_submission_group')
|
|
->where('user_id', '=', $userId)
|
|
->delete();
|
|
}
|
|
|
|
/**
|
|
* Delete all submission group assignments for a user group
|
|
*/
|
|
public function deleteByUserGroupId(int $userGroupId)
|
|
{
|
|
DB::table('subeditor_submission_group')
|
|
->where('user_group_id', '=', $userGroupId)
|
|
->delete();
|
|
}
|
|
|
|
/**
|
|
* Check if a user is assigned to a specified submission group.
|
|
*
|
|
* @param int $contextId
|
|
* @param int $assocId
|
|
* @param int $userId
|
|
* @param int $assocType optional Application::ASSOC_TYPE_SECTION or Application::ASSOC_TYPE_CATEGORY
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function editorExists($contextId, $assocId, $userId, $assocType)
|
|
{
|
|
$result = $this->retrieve(
|
|
'SELECT COUNT(*) AS row_count FROM subeditor_submission_group WHERE context_id = ? AND section_id = ? AND user_id = ? AND assoc_id = ?',
|
|
[(int) $contextId, (int) $assocId, (int) $userId, (int) $assocType]
|
|
);
|
|
$row = $result->current();
|
|
return $row ? (bool) $row->row_count : false;
|
|
}
|
|
|
|
/**
|
|
* Assign editors to a submission
|
|
*
|
|
* Creates a stage assignment for each editorial user
|
|
* configured in the section and category settings.
|
|
*
|
|
* @return Collection The user ids for editors that were assigned
|
|
*/
|
|
public function assignEditors(Submission $submission, Context $context): Collection
|
|
{
|
|
$publication = $submission->getCurrentPublication();
|
|
$sectionIdPropName = Application::getSectionIdPropName();
|
|
|
|
$assignments = $this->getBySubmissionGroupIds(
|
|
[$publication->getData($sectionIdPropName)],
|
|
Application::ASSOC_TYPE_SECTION,
|
|
$submission->getData('contextId')
|
|
);
|
|
|
|
if (!empty($publication->getData('categoryIds'))) {
|
|
$assignedToCategory = $this->getBySubmissionGroupIds(
|
|
$publication->getData('categoryIds'),
|
|
Application::ASSOC_TYPE_CATEGORY,
|
|
$submission->getData('contextId')
|
|
);
|
|
$assignments = $assignments->merge($assignedToCategory);
|
|
}
|
|
|
|
// Remove duplicate assignments for the same user in the
|
|
// same user group by structuring the array with a key
|
|
// that will cause duplicates to be overwritten
|
|
$assignments = collect($assignments)->mapWithKeys(fn ($assignment, $key) => [$assignment->userId . '-' . $assignment->userGroupId => $assignment]);
|
|
|
|
$userGroups = Repo::userGroup()
|
|
->getCollector()
|
|
->filterByContextIds([$submission->getData('contextId')])
|
|
->getMany();
|
|
|
|
$userGroupIds = $userGroups->keys();
|
|
|
|
$assignments = $assignments->filter(function ($assignment) use ($userGroupIds) {
|
|
return Repo::userGroup()->userInGroup($assignment->userId, $assignment->userGroupId)
|
|
&& $userGroupIds->contains($assignment->userGroupId);
|
|
});
|
|
|
|
/** @var StageAssignmentDAO $stageAssignmentDao */
|
|
$stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO');
|
|
foreach ($assignments as $assignment) {
|
|
$userGroup = $userGroups->first(fn (UserGroup $userGroup) => $userGroup->getId() == $assignment->userGroupId);
|
|
$stageAssignmentDao->build($submission->getId(), $assignment->userGroupId, $assignment->userId, $userGroup->getRecommendOnly());
|
|
}
|
|
|
|
// Update assignment notifications
|
|
$notificationManager = new NotificationManager();
|
|
$notificationManager->updateNotification(
|
|
Application::get()->getRequest(),
|
|
$notificationManager->getDecisionStageNotifications(),
|
|
null,
|
|
Application::ASSOC_TYPE_SUBMISSION,
|
|
$submission->getId()
|
|
);
|
|
|
|
// Send a notification to assigned users
|
|
foreach ($assignments as $assignment) {
|
|
$notificationManager->createNotification(
|
|
Application::get()->getRequest(),
|
|
$assignment->userId,
|
|
Notification::NOTIFICATION_TYPE_SUBMISSION_SUBMITTED,
|
|
$submission->getContextId(),
|
|
Application::ASSOC_TYPE_SUBMISSION,
|
|
$submission->getId()
|
|
);
|
|
}
|
|
|
|
// Send an email to assigned editors
|
|
$editorAssignments = $stageAssignmentDao->getBySubmissionAndRoleIds(
|
|
$submission->getId(),
|
|
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SUB_EDITOR],
|
|
WORKFLOW_STAGE_ID_SUBMISSION
|
|
)->toArray();
|
|
|
|
$emailTemplate = Repo::emailTemplate()->getByKey($context->getId(), EditorAssigned::getEmailTemplateKey());
|
|
if (count($editorAssignments) && $emailTemplate) {
|
|
// Never notify the same user twice, even if they are assigned in multiple roles
|
|
$notifiedEditors = [];
|
|
|
|
/** @var NotificationSubscriptionSettingsDAO $notificationSubscriptionSettingsDao */
|
|
$notificationSubscriptionSettingsDao = DAORegistry::getDAO('NotificationSubscriptionSettingsDAO');
|
|
$mailable = new EditorAssigned($context, $submission);
|
|
$mailable
|
|
->from($context->getData('contactEmail'), $context->getData('contactName'))
|
|
->subject($emailTemplate->getLocalizedData('subject') ?? '')
|
|
->body($emailTemplate->getLocalizedData('body') ?? '');
|
|
|
|
/** @var StageAssignment $editorAssignment */
|
|
foreach ($editorAssignments as $editorAssignment) {
|
|
$unsubscribed = in_array(
|
|
Notification::NOTIFICATION_TYPE_SUBMISSION_SUBMITTED,
|
|
$notificationSubscriptionSettingsDao->getNotificationSubscriptionSettings(
|
|
NotificationSubscriptionSettingsDAO::BLOCKED_EMAIL_NOTIFICATION_KEY,
|
|
$editorAssignment->getUserId(),
|
|
$context->getId()
|
|
)
|
|
);
|
|
|
|
if ($unsubscribed || in_array($editorAssignment->getUserId(), $notifiedEditors)) {
|
|
continue;
|
|
}
|
|
|
|
$notifiedEditors[] = $editorAssignment->getUserId();
|
|
|
|
$recipient = Repo::user()->get($editorAssignment->getUserId());
|
|
$mailable->recipients([$recipient]);
|
|
|
|
Mail::send($mailable);
|
|
|
|
/** @var SubmissionEmailLogDAO $logDao */
|
|
$logDao = DAORegistry::getDAO('SubmissionEmailLogDAO');
|
|
$logDao->logMailable(
|
|
SubmissionEmailLogEntry::SUBMISSION_EMAIL_EDITOR_ASSIGN,
|
|
$mailable,
|
|
$submission
|
|
);
|
|
}
|
|
}
|
|
|
|
return $assignments->map(fn ($assignment) => $assignment->userId);
|
|
}
|
|
|
|
/**
|
|
* Get the section assigned sub editor's associated user groups ids for given section
|
|
*
|
|
* @return Collection Collection A list of user group IDs for each user, keyed by user ID.
|
|
*/
|
|
public function getAssignedUserGroupIds(int $contextId, int $assocType, int $assocId, int|array $userIds): Collection
|
|
{
|
|
return DB::table('subeditor_submission_group')
|
|
->select(['user_id', 'user_group_id'])
|
|
->where('assoc_type', $assocType)
|
|
->where('context_id', $contextId)
|
|
->where('assoc_id', $assocId)
|
|
->whereIn('user_id', Arr::wrap($userIds))
|
|
->get()
|
|
->groupBy('user_id')
|
|
->map(fn ($userGroups) => $userGroups->pluck('user_group_id'));
|
|
}
|
|
}
|
|
|
|
if (!PKP_STRICT_MODE) {
|
|
class_alias('\PKP\context\SubEditorsDAO', '\SubEditorsDAO');
|
|
}
|