Skip to content

Commit

Permalink
Merge branch 'moderatorsFeedbackReminder330-695' into 'stable-3_3_0'
Browse files Browse the repository at this point in the history
Envia lembretes de moderação a moderadores

See merge request softwares-pkp/plugins_ojs/scieloModerationStages!18
  • Loading branch information
JhonathanLepidus committed Aug 26, 2024
2 parents 00655c7 + 4b9bcd0 commit 48c0d2f
Show file tree
Hide file tree
Showing 13 changed files with 595 additions and 8 deletions.
4 changes: 2 additions & 2 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ variables:

include:
- project: 'documentacao-e-tarefas/modelosparaintegracaocontinua'
ref: main
ref: stable-3_3_0
file:
- 'templates/groups/pkp_plugin.yml'
- 'templates/groups/ops_plugins_unit_tests_model.yml'
- 'templates/groups/ops/unit_tests.yml'
52 changes: 52 additions & 0 deletions ScieloModerationStagesPlugin.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ public function register($category, $path, $mainContextId = null)
HookRegistry::register('LoadComponentHandler', array($this, 'setupScieloModerationStagesHandler'));

HookRegistry::register('TemplateManager::display', array($this, 'addJavaScriptAndStylesheet'));

HookRegistry::register('AcronPlugin::parseCronTab', array($this, 'addTasksToCrontab'));
$this->addHandlerURLToJavaScript();
}

Expand Down Expand Up @@ -72,6 +74,13 @@ public function addJavaScriptAndStylesheet($hookName, $params)
return false;
}

public function addTasksToCrontab($hookName, $params)
{
$taskFilesPath = &$params[0];
$taskFilesPath[] = $this->getPluginPath() . DIRECTORY_SEPARATOR . 'scheduledTasks.xml';
return false;
}

public function getDisplayName()
{
return __('plugins.generic.scieloModerationStages.displayName');
Expand All @@ -82,6 +91,49 @@ public function getDescription()
return __('plugins.generic.scieloModerationStages.description');
}

public function getActions($request, $actionArgs)
{
$router = $request->getRouter();
import('lib.pkp.classes.linkAction.request.AjaxModal');
return array_merge(
[
new LinkAction(
'settings',
new AjaxModal(
$router->url($request, null, null, 'manage', null, ['verb' => 'settings', 'plugin' => $this->getName(), 'category' => 'generic']),
__('plugins.generic.scieloModerationStages.settings.title')
),
__('manager.plugins.settings'),
null
),
],
parent::getActions($request, $actionArgs)
);
}

public function manage($args, $request)
{
$context = $request->getContext();
$contextId = ($context == null) ? 0 : $context->getId();

switch ($request->getUserVar('verb')) {
case 'settings':
$this->import('ScieloModerationStagesSettingsForm');
$form = new ScieloModerationStagesSettingsForm($this, $contextId);
if ($request->getUserVar('save')) {
$form->readInputData();
if ($form->validate()) {
$form->execute();
return new JSONMessage(true);
}
} else {
$form->initData();
}
return new JSONMessage(true, $form->fetch($request));
}
return parent::manage($args, $request);
}

public function setupScieloModerationStagesHandler($hookName, $params)
{
$component = &$params[0];
Expand Down
57 changes: 57 additions & 0 deletions ScieloModerationStagesSettingsForm.inc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

import('lib.pkp.classes.form.Form');

class ScieloModerationStagesSettingsForm extends Form
{
public const CONFIG_VARS = array(
'preModerationTimeLimit' => 'int',
);

public $contextId;
public $plugin;

public function __construct($plugin, $contextId)
{
$this->contextId = $contextId;
$this->plugin = $plugin;
parent::__construct($plugin->getTemplateResource('settingsForm.tpl'));

$this->addCheck(new FormValidatorCustom($this, 'preModerationTimeLimit', 'required', 'plugins.generic.scieloModerationStages.settings.timeLimitError', function ($timeLimit) {
return is_numeric($timeLimit) && intval($timeLimit) > 0;
}));
}

public function initData()
{
$contextId = $this->contextId;
$plugin = &$this->plugin;

foreach (self::CONFIG_VARS as $configVar => $type) {
$this->setData($configVar, $plugin->getSetting($contextId, $configVar));
}
}

public function readInputData()
{
$this->readUserVars(array_keys(self::CONFIG_VARS));
}

public function fetch($request, $template = null, $display = false)
{
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign('pluginName', $this->plugin->getName());
$templateMgr->assign('applicationName', Application::get()->getName());
return parent::fetch($request, $template, $display);
}

public function execute(...$functionArgs)
{
$plugin = &$this->plugin;
$contextId = $this->contextId;

foreach (self::CONFIG_VARS as $configVar => $type) {
$plugin->updateSetting($contextId, $configVar, $this->getData($configVar), $type);
}
}
}
70 changes: 70 additions & 0 deletions classes/ModerationReminderEmailBuilder.inc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php

import('lib.pkp.classes.mail.Mail');

class ModerationReminderEmailBuilder
{
private $context;
private $moderator;
private $submissions;

public function __construct($context, $moderator, $submissions)
{
$this->context = $context;
$this->moderator = $moderator;
$this->submissions = $submissions;
}

public function buildEmail(): Mail
{
$email = new Mail();

$email->setFrom($this->context->getContactEmail(), $this->context->getContactName());
$email->addRecipient($this->moderator->getEmail(), $this->moderator->getFullName());
$email->addCc($this->context->getContactEmail(), $this->context->getContactName());

$email->setSubject(__('plugins.generic.scieloModerationStages.emails.moderationReminder.subject'));

$bodyParams = [
'moderatorName' => $this->moderator->getFullName(),
'submissions' => $this->getSubmissionsString()
];
$email->setBody(__('plugins.generic.scieloModerationStages.emails.moderationReminder.body', $bodyParams));

return $email;
}

private function getSubmissionsString(): string
{
$submissionsString = '';
$request = Application::get()->getRequest();
$dispatcher = Application::get()->getDispatcher();
$request->setDispatcher($dispatcher);

foreach ($this->submissions as $submission) {
$submissionLink = $request->getDispatcher()->url($request, ROUTE_PAGE, null, 'workflow', 'access', [$submission->getId()]);
$submissionDaysString = $this->getSubmissionDaysString($submission);

$submissionsString .= "<p><a href=\"$submissionLink\">$submissionLink</a> - $submissionDaysString</p>";
}

return $submissionsString;
}

private function getSubmissionDaysString($submission): string
{
$dateSubmitted = new DateTime($submission->getData('dateSubmitted'));
$today = new DateTime();
$daysBetween = (int) $today->diff($dateSubmitted)->format('%a');

if ($daysBetween < 1) {
return __('plugins.generic.scieloModerationStages.submissionMade.lessThanADayAgo');
}

if ($daysBetween == 1) {
return __('plugins.generic.scieloModerationStages.submissionMade.aDayAgo');
}

return __('plugins.generic.scieloModerationStages.submissionMade.nDaysAgo', ['numberOfDays' => $daysBetween]);
}
}
17 changes: 16 additions & 1 deletion classes/ModerationStageDAO.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

class ModerationStageDAO extends DAO
{
public function getSubmissionModerationStage($submissionId): ?int
public function getSubmissionModerationStage(int $submissionId): ?int
{
$result = Capsule::table('submission_settings')
->where('submission_id', $submissionId)
Expand All @@ -26,4 +26,19 @@ public function getSubmissionModerationStage($submissionId): ?int

return !is_null($result) ? get_object_vars($result)['setting_value'] : null;
}

public function getPreModerationIsOverdue(int $submissionId, int $timeLimit): bool
{
$result = Capsule::table('submissions')
->where('submission_id', '=', $submissionId)
->select('date_submitted')
->first();
$dateSubmitted = get_object_vars($result)['date_submitted'];
$dateSubmitted = new DateTime($dateSubmitted);

$limitDaysAgo = new DateTime();
$limitDaysAgo->modify("-$timeLimit days");

return $dateSubmitted < $limitDaysAgo;
}
}
121 changes: 121 additions & 0 deletions classes/tasks/SendModerationReminders.inc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?php

import('lib.pkp.classes.scheduledTask.ScheduledTask');
import('plugins.generic.scieloModerationStages.classes.ModerationStage');
import('plugins.generic.scieloModerationStages.classes.ModerationStageDAO');
import('plugins.generic.scieloModerationStages.classes.ModerationReminderEmailBuilder');

class SendModerationReminders extends ScheduledTask
{
private $plugin;

public function executeActions()
{
PluginRegistry::loadCategory('generic');
$this->plugin = PluginRegistry::getPlugin('generic', 'scielomoderationstagesplugin');

$context = Application::get()->getRequest()->getContext();
$responsiblesAssignments = $this->getResponsiblesAssignments($context->getId());
$preModerationAssignments = $this->filterPreModerationAssignments($responsiblesAssignments);

if (empty($preModerationAssignments)) {
return true;
}

$usersWithOverduePreModeration = $this->getUsersWithOverduePreModeration($context->getId(), $preModerationAssignments);
$mapModeratorsAndOverdueSubmissions = $this->mapModeratorsAndOverdueSubmissions($usersWithOverduePreModeration, $preModerationAssignments);

foreach ($mapModeratorsAndOverdueSubmissions as $userId => $submissions) {
$moderator = DAORegistry::getDAO('UserDAO')->getById($userId);
$moderationReminderEmailBuilder = new ModerationReminderEmailBuilder($context, $moderator, $submissions);

$reminderEmail = $moderationReminderEmailBuilder->buildEmail();
$reminderEmail->send();
}

return true;
}

private function getResponsiblesAssignments(int $contextId)
{
$userGroupDao = DAORegistry::getDAO('UserGroupDAO');
$contextUserGroups = $userGroupDao->getByContextId($contextId)->toArray();

foreach ($contextUserGroups as $userGroup) {
$userGroupAbbrev = strtolower($userGroupDao->getSetting($userGroup->getId(), 'abbrev', 'en_US'));

if ($userGroupAbbrev === 'resp') {
$responsiblesUserGroup = $userGroup;
break;
}
}

if (!$responsiblesUserGroup) {
return [];
}

$stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO');
$responsiblesAssignments = $stageAssignmentDao->getByUserGroupId($responsiblesUserGroup->getId(), $contextId);

return $responsiblesAssignments->toArray();
}

private function filterPreModerationAssignments($responsiblesAssignments): array
{
$moderationStageDao = new ModerationStageDAO();
$preModerationAssignments = [];

foreach ($responsiblesAssignments as $assignment) {
$submissionId = $assignment->getData('submissionId');
$submissionModerationStage = $moderationStageDao->getSubmissionModerationStage($submissionId);

if ($submissionModerationStage === SCIELO_MODERATION_STAGE_CONTENT) {
$preModerationAssignments[] = $assignment;
}
}

return $preModerationAssignments;
}

private function getUsersWithOverduePreModeration($contextId, $preModerationAssignments): array
{
$usersIds = [];
$preModerationTimeLimit = $this->plugin->getSetting($contextId, 'preModerationTimeLimit');
$moderationStageDao = new ModerationStageDAO();

foreach ($preModerationAssignments as $assignment) {
$submissionId = $assignment->getData('submissionId');
$preModerationIsOverdue = $moderationStageDao->getPreModerationIsOverdue($submissionId, $preModerationTimeLimit);

if ($preModerationIsOverdue) {
$usersIds[] = $assignment->getData('userId');
}
}

return $usersIds;
}

private function mapModeratorsAndOverdueSubmissions($moderators, $preModerationAssignments)
{
$moderatorsMap = [];
$submissionDao = DAORegistry::getDAO('SubmissionDAO');

foreach ($moderators as $moderatorId) {
foreach ($preModerationAssignments as $assignment) {
if ($moderatorId != $assignment->getData('userId')) {
continue;
}

$submission = $submissionDao->getById($assignment->getData('submissionId'));

if (isset($moderatorsMap[$moderatorId])) {
$moderatorsMap[$moderatorId] = array_merge($moderatorsMap[$moderatorId], [$submission]);
} else {
$moderatorsMap[$moderatorId] = [$submission];
}
}
}

return $moderatorsMap;
}
}
Loading

0 comments on commit 48c0d2f

Please sign in to comment.