Skip to content

Commit

Permalink
Merge pull request #3 from pkp/master
Browse files Browse the repository at this point in the history
Update fork for OJS 3.3
  • Loading branch information
israelcefrin authored Dec 10, 2020
2 parents 235cef7 + b32509e commit edb53e1
Show file tree
Hide file tree
Showing 2,536 changed files with 272,023 additions and 109,688 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Steps to reproduce the behavior:
4. See error

**What application are you using?**
OJS or OMP version X.X.X
OJS, OMP or OPS version X.X.X

**Additional information**
Please add any screenshots, logs or other information we can use to investigate this bug report.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
PKP Web Application Library
=======

The PKP Web Application Library (PKP-WAL) is a library shared by [Open Journal Systems (OJS)](http://github.com/pkp/ojs), [Open Conference Systems (OCS)](http://github.com/pkp/ocs), [Open Monograph Press (OMP)](http://github.com/pkp/omp), and [Open Harvester Systems (OHS)](http://github.com/pkp/harvester). It is distributed with those applications in the `lib/pkp` subdirectory.
The PKP Web Application Library (PKP-WAL) is a library shared by [Open Journal Systems (OJS)](https://github.com/pkp/ojs), [Open Conference Systems (OCS)](https://github.com/pkp/ocs), [Open Monograph Press (OMP)](http://github.com/pkp/omp), [Open Preprint Systems (OPS)](https://github.com/pkp/ops) and [Open Harvester Systems (OHS)](https://github.com/pkp/harvester). It is distributed with those applications in the `lib/pkp` subdirectory.

Issues (bugs) for all of those applications should be [created against this repository](https://github.com/pkp/pkp-lib/issues).

## Issues
Issues (bugs) for any of the PKP applications should be created here. If you're not sure whether you're encountering a bug or not, consider posting in the [PKP Community Forum](http://forum.pkp.sfu.ca/).
Issues (bugs) for any of the PKP applications should be created here. If you're not sure whether you're encountering a bug or not, consider posting in the [PKP Community Forum](https://forum.pkp.sfu.ca/).

Before creating a new issue, please [search the existing ones](https://github.com/pkp/pkp-lib/issues) to make sure you're not creating a duplicate.

* [Create a new OMP issue](https://github.com/pkp/pkp-lib/issues/new?title=[OMP])
* [Create a new OJS issue](https://github.com/pkp/pkp-lib/issues/new?title=[OJS])
* [Create a new OPS issue](https://github.com/pkp/pkp-lib/issues/new?title=[OPS])
* [Create a new OCS issue](https://github.com/pkp/pkp-lib/issues/new?title=[OCS])
* [Create a new OHS issue](https://github.com/pkp/pkp-lib/issues/new?title=[OHS])

Expand Down
230 changes: 230 additions & 0 deletions api/v1/_email/PKPEmailHandler.inc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
<?php

/**
* @file api/v1/_email/PKPEmailHandler.inc.php
*
* Copyright (c) 2014-2020 Simon Fraser University
* Copyright (c) 2003-2020 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class PKPEmailHandler
* @ingroup api_v1_announcement
*
* @brief Handle API requests for announcement operations.
*
*/
use \Illuminate\Queue\Capsule\Manager as Queue;
use Illuminate\Database\Capsule\Manager as Capsule;
use \Psr\Http\Message\ServerRequestInterface;

import('lib.pkp.classes.handler.APIHandler');
import('classes.core.Services');

class PKPEmailHandler extends APIHandler {

/** Number of emails to send in each job */
const EMAILS_PER_JOB = 100;

/**
* Constructor
*/
public function __construct() {
$this->_handlerPath = '_email';
$this->_endpoints = [
'POST' => [
[
'pattern' => $this->getEndpointPattern(),
'handler' => [$this, 'create'],
'roles' => [ROLE_ID_SITE_ADMIN, ROLE_ID_MANAGER],
],
],
'PUT' => [
[
'pattern' => $this->getEndpointPattern() . '/{queueId}',
'handler' => [$this, 'process'],
'roles' => [ROLE_ID_SITE_ADMIN, ROLE_ID_MANAGER],
],
],
];
parent::__construct();
}

/**
* @copydoc PKPHandler::authorize
*/
public function authorize($request, &$args, $roleAssignments) {
import('lib.pkp.classes.security.authorization.PolicySet');
$rolePolicy = new PolicySet(COMBINING_PERMIT_OVERRIDES);

import('lib.pkp.classes.security.authorization.RoleBasedHandlerOperationPolicy');
foreach ($roleAssignments as $role => $operations) {
$rolePolicy->addPolicy(new RoleBasedHandlerOperationPolicy($request, $role, $operations));
}
$this->addPolicy($rolePolicy);

return parent::authorize($request, $args, $roleAssignments);
}

/**
* Create a jobs queue to send a bulk email to users in one or
* more user groups
*
* @param ServerRequestInterface $slimRequest
* @param APIResponse $response
* @param array $args arguments
* @return APIResponse
*/
public function create(ServerRequestInterface $slimRequest, APIResponse $response, array $args) {
$context = $this->getRequest()->getContext();
$contextId = $context->getId();

$requestParams = $slimRequest->getParsedBody();

$params = [];
foreach ($requestParams as $param => $val) {
switch ($param) {
case 'userGroupIds':
if (!is_array($val)) {
$val = strlen(trim($val))
? explode(',', $val)
: [];
}
$params[$param] = array_map('intval', $val);
break;
case 'body':
case 'subject':
$params[$param] = $val;
break;
case 'copy':
$params[$param] = (bool) $val;
break;
}
}

$errors = [];
if (empty($params['body'])) {
$errors['body'] = [__('api.emails.400.missingBody')];
}

if (empty($params['subject'])) {
$errors['subject'] = [__('api.emails.400.missingSubject')];
}

if (empty($params['userGroupIds'])) {
$errors['userGroupIds'] = [__('api.emails.400.missingUserGroups')];
}

if ($errors) {
return $response->withJson($errors, 400);
}

$userGroupDao = DAORegistry::getDAO('UserGroupDAO');
foreach ($params['userGroupIds'] as $userGroupId) {
if (!$userGroupDao->contextHasGroup($contextId, $userGroupId)) {
return $response->withJson([
'userGroupIds' => [__('api.emails.403.notAllowedUserGroup')],
], 403);
}
}

// Only permit emails to be sent to active users in this context
$params['status'] = 'active';
$params['contextId'] = $contextId;

$userIds = Services::get('user')->getIds($params);
$subject = $params['subject'];
$body = $params['body'];
$fromEmail = $context->getData('contactEmail');
$fromName = $context->getData('contactName');
$queueId = 'email_' . uniqid();

if (!empty($params['copy'])) {
$currentUserId = $this->getRequest()->getUser()->getId();
if (!in_array($currentUserId, $userIds)) {
$userIds[] = $currentUserId;
}
}

$batches = array_chunk($userIds, self::EMAILS_PER_JOB);
foreach ($batches as $userIds) {
Queue::push(function() use ($userIds, $contextId, $subject, $body, $fromEmail, $fromName) {
import('lib.pkp.classes.mail.Mail');
$users = Services::get('user')->getMany([
'contextId' => $contextId,
'userIds' => $userIds,
]);
foreach ($users as $user) {
$mail = new Mail();
$mail->setFrom($fromEmail, $fromName);
$mail->setRecipients([
[
'name' => $user->getFullName(),
'email' => $user->getEmail(),
],
]);
$mail->setSubject($subject);
$mail->setBody($body);
$mail->send();
}
}, [], $queueId, 'persistent');
}

return $response->withJson([
'queueId' => $queueId,
'totalJobs' => count($batches),
], 200);
}

/**
* Process a jobs queue for sending a bulk email
*
* @param ServerRequestInterface $slimRequest
* @param APIResponse $response
* @param array $args arguments
* @return APIResponse
*/
public function process(ServerRequestInterface $slimRequest, APIResponse $response, array $args) {
$countRunning = Capsule::table('jobs')
->where('queue', $args['queueId'])
->whereNotNull('reserved_at')
->count();
$countPending = $this->countPending($args['queueId']);

// Don't run another job if one is already running.
// This should ensure jobs are run one after the other and
// prevent long-running jobs from running simultaneously
// and piling onto the server like a DDOS attack.
if (!$countRunning && $countPending) {
$laravelContainer = Registry::get('laravelContainer');
$worker = new Illuminate\Queue\Worker(
$laravelContainer['queue'],
$laravelContainer['events'],
$laravelContainer['exception.handler'],
function() {
return false; // is not down for maintenance
}
);
$options = new Illuminate\Queue\WorkerOptions();
$worker->runNextJob('persistent', $args['queueId'], $options);

// Update count of pending jobs
$countPending = $this->countPending($args['queueId']);
}

return $response->withJson([
'pendingJobs' => $countPending,
], 200);
}

/**
* Return a count of the pending jobs in a given queue
*
* @param string $queueId
* @return int
*/
protected function countPending(string $queueId) : int {
return Capsule::table('jobs')
->where('queue', $queueId)
->count();
}
}
8 changes: 4 additions & 4 deletions api/v1/_payments/PKPBackendPaymentsSettingsHandler.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
/**
* @file api/v1/_payments/PKPBackendPaymentsSettingsHandler.inc.php
*
* Copyright (c) 2014-2019 Simon Fraser University
* Copyright (c) 2003-2019 John Willinsky
* Distributed under the GNU GPL v2. For full terms see the file docs/COPYING.
* Copyright (c) 2014-2020 Simon Fraser University
* Copyright (c) 2003-2020 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class PKPBackendPaymentsSettingsHandler
* @ingroup api_v1_backend
Expand Down Expand Up @@ -84,7 +84,7 @@ public function edit($slimRequest, $response, $args) {
$errors = $contextService->validate(
VALIDATE_ACTION_EDIT,
['currency' => $params['currency']],
$context->getSupportedLocales(),
$context->getSupportedFormLocales(),
$context->getPrimaryLocale()
);
if (!empty($errors)) {
Expand Down
33 changes: 13 additions & 20 deletions api/v1/_submissions/PKPBackendSubmissionsHandler.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
/**
* @file api/v1/_submissions/PKPBackendSubmissionsHandler.inc.php
*
* Copyright (c) 2014-2019 Simon Fraser University
* Copyright (c) 2003-2019 John Willinsky
* Distributed under the GNU GPL v2. For full terms see the file docs/COPYING.
* Copyright (c) 2014-2020 Simon Fraser University
* Copyright (c) 2003-2020 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class PKPBackendSubmissionsHandler
* @ingroup api_v1_backend
Expand Down Expand Up @@ -89,7 +89,7 @@ public function getMany($slimRequest, $response, $args) {
$userRoles = $this->getAuthorizedContextObject(ASSOC_TYPE_USER_ROLES);
$canAccessUnassignedSubmission = !empty(array_intersect(array(ROLE_ID_SITE_ADMIN, ROLE_ID_MANAGER), $userRoles));
if (!$canAccessUnassignedSubmission) {
$defaultParams['assignedTo'] = $currentUser->getId();
$defaultParams['assignedTo'] = [$currentUser->getId()];
}

$params = array_merge($defaultParams, $slimRequest->getQueryParams());
Expand All @@ -101,15 +101,15 @@ public function getMany($slimRequest, $response, $args) {
// Always convert status and stageIds to array
case 'status':
case 'stageIds':
if (is_string($val) && strpos($val, ',') > -1) {
case 'assignedTo':
if (is_string($val)) {
$val = explode(',', $val);
} elseif (!is_array($val)) {
$val = array($val);
}
$params[$param] = array_map('intval', $val);
break;

case 'assignedTo':
case 'daysInactive':
case 'offset':
$params[$param] = (int) $val;
Expand Down Expand Up @@ -143,25 +143,24 @@ public function getMany($slimRequest, $response, $args) {

// Prevent users from viewing submissions they're not assigned to,
// except for journal managers and admins.
if (!$canAccessUnassignedSubmission && $params['assignedTo'] != $currentUser->getId()) {
if (!$canAccessUnassignedSubmission && !in_array($currentUser->getId(), $params['assignedTo'])) {
return $response->withStatus(403)->withJsonError('api.submissions.403.requestedOthersUnpublishedSubmissions');
}

$submissionService = Services::get('submission');
$submissionsIterator = $submissionService->getMany($params);
$submissionsIterator = Services::get('submission')->getMany($params);
$items = array();
if (count($submissionsIterator)) {
$propertyArgs = array(
'request' => $request,
'slimRequest' => $slimRequest,
);
foreach ($submissionsIterator as $submission) {
$items[] = $submissionService->getBackendListProperties($submission, $propertyArgs);
$items[] = Services::get('submission')->getBackendListProperties($submission, $propertyArgs);
}
}
$data = array(
'items' => $items,
'itemsMax' => $submissionService->getMax($params),
'itemsMax' => Services::get('submission')->getMax($params),
);

return $response->withJson($data);
Expand All @@ -176,14 +175,10 @@ public function getMany($slimRequest, $response, $args) {
* @return Response
*/
public function delete($slimRequest, $response, $args) {

$request = $this->getRequest();
$currentUser = $request->getUser();
$context = $request->getContext();

$submissionId = (int) $args['submissionId'];

$submissionDao = Application::getSubmissionDAO();
$submissionDao = DAORegistry::getDAO('SubmissionDAO'); /* @var $submissionDao SubmissionDAO */
$submission = $submissionDao->getById($submissionId);

if (!$submission) {
Expand All @@ -195,13 +190,11 @@ public function delete($slimRequest, $response, $args) {
}

import('classes.core.Services');
$submissionService = Services::get('submission');

if (!$submissionService->canCurrentUserDelete($submission)) {
if (!Services::get('submission')->canCurrentUserDelete($submission)) {
return $response->withStatus(403)->withJsonError('api.submissions.403.unauthorizedDeleteSubmission');
}

$submissionService->delete($submission);
Services::get('submission')->delete($submission);

return $response->withJson(true);
}
Expand Down
Loading

0 comments on commit edb53e1

Please sign in to comment.