first commit
This commit is contained in:
@@ -0,0 +1,935 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file classes/plugins/PubObjectsExportPlugin.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 PubObjectsExportPlugin
|
||||
*
|
||||
* @ingroup plugins
|
||||
*
|
||||
* @brief Basis class for XML metadata export plugins
|
||||
*/
|
||||
|
||||
namespace APP\plugins;
|
||||
|
||||
use APP\core\Application;
|
||||
use APP\core\Request;
|
||||
use APP\facades\Repo;
|
||||
use APP\issue\Issue;
|
||||
use APP\journal\Journal;
|
||||
use APP\journal\JournalDAO;
|
||||
use APP\notification\NotificationManager;
|
||||
use APP\submission\Submission;
|
||||
use APP\template\TemplateManager;
|
||||
use PKP\core\EntityDAO;
|
||||
use PKP\core\JSONMessage;
|
||||
use PKP\db\DAO;
|
||||
use PKP\db\DAORegistry;
|
||||
use PKP\db\SchemaDAO;
|
||||
use PKP\file\FileManager;
|
||||
use PKP\filter\FilterDAO;
|
||||
use PKP\galley\Galley;
|
||||
use PKP\linkAction\LinkAction;
|
||||
use PKP\linkAction\request\NullAction;
|
||||
use PKP\notification\PKPNotification;
|
||||
use PKP\plugins\Hook;
|
||||
use PKP\plugins\importexport\PKPImportExportDeployment;
|
||||
use PKP\plugins\ImportExportPlugin;
|
||||
use PKP\plugins\PluginRegistry;
|
||||
use PKP\submission\PKPSubmission;
|
||||
use PKP\user\User;
|
||||
|
||||
// The statuses.
|
||||
define('EXPORT_STATUS_ANY', '');
|
||||
define('EXPORT_STATUS_NOT_DEPOSITED', 'notDeposited');
|
||||
define('EXPORT_STATUS_MARKEDREGISTERED', 'markedRegistered');
|
||||
define('EXPORT_STATUS_REGISTERED', 'registered');
|
||||
|
||||
// The actions.
|
||||
define('EXPORT_ACTION_EXPORT', 'export');
|
||||
define('EXPORT_ACTION_MARKREGISTERED', 'markRegistered');
|
||||
define('EXPORT_ACTION_DEPOSIT', 'deposit');
|
||||
|
||||
// Configuration errors.
|
||||
define('EXPORT_CONFIG_ERROR_SETTINGS', 0x02);
|
||||
|
||||
abstract class PubObjectsExportPlugin extends ImportExportPlugin
|
||||
{
|
||||
public const EXPORT_ACTION_EXPORT = 'export';
|
||||
public const EXPORT_ACTION_MARKREGISTERED = 'markRegistered';
|
||||
public const EXPORT_ACTION_DEPOSIT = 'deposit';
|
||||
|
||||
/** @var PubObjectCache */
|
||||
public $_cache;
|
||||
|
||||
/**
|
||||
* Get the plugin cache
|
||||
*
|
||||
* @return PubObjectCache
|
||||
*/
|
||||
public function getCache()
|
||||
{
|
||||
if (!$this->_cache instanceof PubObjectCache) {
|
||||
// Instantiate the cache.
|
||||
$this->_cache = new PubObjectCache();
|
||||
}
|
||||
return $this->_cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc Plugin::register()
|
||||
*
|
||||
* @param null|mixed $mainContextId
|
||||
*/
|
||||
public function register($category, $path, $mainContextId = null)
|
||||
{
|
||||
if (!parent::register($category, $path, $mainContextId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Application::isUnderMaintenance()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->addLocaleData();
|
||||
|
||||
Hook::add('AcronPlugin::parseCronTab', [$this, 'callbackParseCronTab']);
|
||||
foreach ($this->_getDAOs() as $dao) {
|
||||
if ($dao instanceof SchemaDAO) {
|
||||
Hook::add('Schema::get::' . $dao->schemaName, [$this, 'addToSchema']);
|
||||
} elseif ($dao instanceof EntityDAO) {
|
||||
Hook::add('Schema::get::' . $dao->schema, [$this, 'addToSchema']);
|
||||
} else {
|
||||
Hook::add(strtolower_codesafe(get_class($dao)) . '::getAdditionalFieldNames', [&$this, 'getAdditionalFieldNames']);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc Plugin::manage()
|
||||
*/
|
||||
public function manage($args, $request)
|
||||
{
|
||||
$user = $request->getUser();
|
||||
$router = $request->getRouter();
|
||||
$context = $router->getContext($request);
|
||||
|
||||
$form = $this->_instantiateSettingsForm($context);
|
||||
$notificationManager = new NotificationManager();
|
||||
switch ($request->getUserVar('verb')) {
|
||||
case 'save':
|
||||
$form->readInputData();
|
||||
if ($form->validate()) {
|
||||
$form->execute();
|
||||
$notificationManager->createTrivialNotification($user->getId(), PKPNotification::NOTIFICATION_TYPE_SUCCESS);
|
||||
return new JSONMessage(true);
|
||||
} else {
|
||||
return new JSONMessage(true, $form->fetch($request));
|
||||
}
|
||||
// no break
|
||||
case 'index':
|
||||
$form->initData();
|
||||
return new JSONMessage(true, $form->fetch($request));
|
||||
case 'statusMessage':
|
||||
$statusMessage = $this->getStatusMessage($request);
|
||||
if ($statusMessage) {
|
||||
$templateMgr = TemplateManager::getManager($request);
|
||||
$templateMgr->assign([
|
||||
'statusMessage' => htmlentities($statusMessage),
|
||||
]);
|
||||
return new JSONMessage(true, $templateMgr->fetch($this->getTemplateResource('statusMessage.tpl')));
|
||||
}
|
||||
}
|
||||
return parent::manage($args, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc ImportExportPlugin::display()
|
||||
*/
|
||||
public function display($args, $request)
|
||||
{
|
||||
parent::display($args, $request);
|
||||
|
||||
$context = $request->getContext();
|
||||
switch (array_shift($args)) {
|
||||
case 'index':
|
||||
case '':
|
||||
// Check for configuration errors:
|
||||
$configurationErrors = [];
|
||||
// missing plugin settings
|
||||
$form = $this->_instantiateSettingsForm($context);
|
||||
foreach ($form->getFormFields() as $fieldName => $fieldType) {
|
||||
if ($form->isOptional($fieldName)) {
|
||||
continue;
|
||||
}
|
||||
$pluginSetting = $this->getSetting($context->getId(), $fieldName);
|
||||
if (empty($pluginSetting)) {
|
||||
$configurationErrors[] = EXPORT_CONFIG_ERROR_SETTINGS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Add link actions
|
||||
$actions = $this->getExportActions($context);
|
||||
$actionNames = array_intersect_key($this->getExportActionNames(), array_flip($actions));
|
||||
$linkActions = [];
|
||||
foreach ($actionNames as $action => $actionName) {
|
||||
$linkActions[] = new LinkAction($action, new NullAction(), $actionName);
|
||||
}
|
||||
$templateMgr = TemplateManager::getManager($request);
|
||||
$templateMgr->assign([
|
||||
'plugin' => $this,
|
||||
'actionNames' => $actionNames,
|
||||
'configurationErrors' => $configurationErrors,
|
||||
]);
|
||||
break;
|
||||
case 'exportSubmissions':
|
||||
case 'exportIssues':
|
||||
case 'exportRepresentations':
|
||||
$this->prepareAndExportPubObjects($request, $context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gathers relevant pub objects and runs export action
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Journal $context
|
||||
* @param array $args Optional args for passing in submissionIds from external API calls
|
||||
*/
|
||||
public function prepareAndExportPubObjects($request, $context, $args = [])
|
||||
{
|
||||
$selectedSubmissions = (array) $request->getUserVar('selectedSubmissions');
|
||||
$selectedIssues = (array) $request->getUserVar('selectedIssues');
|
||||
$selectedRepresentations = (array) $request->getUserVar('selectedRepresentations');
|
||||
$tab = (string) $request->getUserVar('tab');
|
||||
$noValidation = $request->getUserVar('validation') ? false : true;
|
||||
|
||||
if (!empty($args['submissionIds'])) {
|
||||
$selectedSubmissions = (array) $args['submissionIds'];
|
||||
}
|
||||
if (!empty($args['issueIds'])) {
|
||||
$selectedIssues = (array) $args['issueIds'];
|
||||
}
|
||||
if (empty($selectedSubmissions) && empty($selectedIssues) && empty($selectedRepresentations)) {
|
||||
fatalError(__('plugins.importexport.common.error.noObjectsSelected'));
|
||||
}
|
||||
if (!empty($selectedSubmissions)) {
|
||||
$objects = $this->getPublishedSubmissions($selectedSubmissions, $context);
|
||||
$filter = $this->getSubmissionFilter();
|
||||
$objectsFileNamePart = 'articles';
|
||||
} elseif (!empty($selectedIssues)) {
|
||||
$objects = $this->getPublishedIssues($selectedIssues, $context);
|
||||
$filter = $this->getIssueFilter();
|
||||
$objectsFileNamePart = 'issues';
|
||||
} elseif (!empty($selectedRepresentations)) {
|
||||
$objects = $this->getArticleGalleys($selectedRepresentations, $context);
|
||||
$filter = $this->getRepresentationFilter();
|
||||
$objectsFileNamePart = 'galleys';
|
||||
}
|
||||
|
||||
// Execute export action
|
||||
$this->executeExportAction($request, $objects, $filter, $tab, $objectsFileNamePart, $noValidation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute export action.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param array $objects Array of objects to be exported
|
||||
* @param string $filter Filter to use
|
||||
* @param string $tab Tab to return to
|
||||
* @param string $objectsFileNamePart Export file name part for this kind of objects
|
||||
* @param bool $noValidation If set to true no XML validation will be done
|
||||
* @param bool $shouldRedirect If set to true, will redirect to `$tab`. Should be true if executed within an ImportExportPlugin.
|
||||
*/
|
||||
public function executeExportAction($request, $objects, $filter, $tab, $objectsFileNamePart, $noValidation = null, $shouldRedirect = true)
|
||||
{
|
||||
$context = $request->getContext();
|
||||
$path = ['plugin', $this->getName()];
|
||||
if ($this->_checkForExportAction(EXPORT_ACTION_EXPORT)) {
|
||||
assert($filter != null);
|
||||
|
||||
$onlyValidateExport = ($request->getUserVar('onlyValidateExport')) ? true : false;
|
||||
if ($onlyValidateExport) {
|
||||
$noValidation = false;
|
||||
}
|
||||
|
||||
// Get the XML
|
||||
$exportXml = $this->exportXML($objects, $filter, $context, $noValidation);
|
||||
|
||||
if ($onlyValidateExport) {
|
||||
if (isset($exportXml)) {
|
||||
$this->_sendNotification(
|
||||
$request->getUser(),
|
||||
'plugins.importexport.common.validation.success',
|
||||
PKPNotification::NOTIFICATION_TYPE_SUCCESS
|
||||
);
|
||||
} else {
|
||||
$this->_sendNotification(
|
||||
$request->getUser(),
|
||||
'plugins.importexport.common.validation.fail',
|
||||
PKPNotification::NOTIFICATION_TYPE_ERROR
|
||||
);
|
||||
}
|
||||
|
||||
if ($shouldRedirect) {
|
||||
$request->redirect(null, null, null, $path, null, $tab);
|
||||
}
|
||||
} else {
|
||||
$fileManager = new FileManager();
|
||||
$exportFileName = $this->getExportFileName($this->getExportPath(), $objectsFileNamePart, $context, '.xml');
|
||||
$fileManager->writeFile($exportFileName, $exportXml);
|
||||
$fileManager->downloadByPath($exportFileName);
|
||||
$fileManager->deleteByPath($exportFileName);
|
||||
}
|
||||
} elseif ($this->_checkForExportAction(EXPORT_ACTION_DEPOSIT)) {
|
||||
assert($filter != null);
|
||||
// Get the XML
|
||||
$exportXml = $this->exportXML($objects, $filter, $context, $noValidation);
|
||||
// Write the XML to a file.
|
||||
// export file name example: crossref-20160723-160036-articles-1.xml
|
||||
$fileManager = new FileManager();
|
||||
$exportFileName = $this->getExportFileName($this->getExportPath(), $objectsFileNamePart, $context, '.xml');
|
||||
$fileManager->writeFile($exportFileName, $exportXml);
|
||||
// Deposit the XML file.
|
||||
$result = $this->depositXML($objects, $context, $exportFileName);
|
||||
// send notifications
|
||||
if ($result === true) {
|
||||
$this->_sendNotification(
|
||||
$request->getUser(),
|
||||
$this->getDepositSuccessNotificationMessageKey(),
|
||||
PKPNotification::NOTIFICATION_TYPE_SUCCESS
|
||||
);
|
||||
} else {
|
||||
if (is_array($result)) {
|
||||
foreach ($result as $error) {
|
||||
assert(is_array($error) && count($error) >= 1);
|
||||
$this->_sendNotification(
|
||||
$request->getUser(),
|
||||
$error[0],
|
||||
PKPNotification::NOTIFICATION_TYPE_ERROR,
|
||||
($error[1] ?? null)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove all temporary files.
|
||||
$fileManager->deleteByPath($exportFileName);
|
||||
if ($shouldRedirect) {
|
||||
// redirect back to the right tab
|
||||
$request->redirect(null, null, null, $path, null, $tab);
|
||||
}
|
||||
} elseif ($this->_checkForExportAction(EXPORT_ACTION_MARKREGISTERED)) {
|
||||
$this->markRegistered($context, $objects);
|
||||
if ($shouldRedirect) {
|
||||
// redirect back to the right tab
|
||||
$request->redirect(null, null, null, $path, null, $tab);
|
||||
}
|
||||
} else {
|
||||
$dispatcher = $request->getDispatcher();
|
||||
$dispatcher->handle404();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the locale key used in the notification for
|
||||
* the successful deposit.
|
||||
*/
|
||||
public function getDepositSuccessNotificationMessageKey()
|
||||
{
|
||||
return 'plugins.importexport.common.register.success';
|
||||
}
|
||||
|
||||
/**
|
||||
* Deposit XML document.
|
||||
* This must be implemented in the subclasses, if the action is supported.
|
||||
*
|
||||
* @param mixed $objects Array of or single published submission, issue or galley
|
||||
* @param Journal $context
|
||||
* @param string $filename Export XML filename
|
||||
*
|
||||
* @return bool|array Whether the XML document has been registered
|
||||
*/
|
||||
abstract public function depositXML($objects, $context, $filename);
|
||||
|
||||
/**
|
||||
* Get detailed message of the object status i.e. failure messages.
|
||||
* Parameters needed have to be in the request object.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return string Preformatted text that will be displayed in a div element in the modal
|
||||
*/
|
||||
public function getStatusMessage($request)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the submission filter.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getSubmissionFilter()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the issue filter.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getIssueFilter()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the representation filter.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getRepresentationFilter()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status names for the filter search option.
|
||||
*
|
||||
* @return array (string status => string text)
|
||||
*/
|
||||
public function getStatusNames()
|
||||
{
|
||||
return [
|
||||
EXPORT_STATUS_ANY => __('plugins.importexport.common.status.any'),
|
||||
EXPORT_STATUS_NOT_DEPOSITED => __('plugins.importexport.common.status.notDeposited'),
|
||||
EXPORT_STATUS_MARKEDREGISTERED => __('plugins.importexport.common.status.markedRegistered'),
|
||||
EXPORT_STATUS_REGISTERED => __('plugins.importexport.common.status.registered'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status actions for the display to the user,
|
||||
* i.e. links to a web site with more information about the status.
|
||||
*
|
||||
* @param object $pubObject
|
||||
*
|
||||
* @return array (string status => link)
|
||||
*/
|
||||
public function getStatusActions($pubObject)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get actions.
|
||||
*
|
||||
* @param Journal $context
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getExportActions($context)
|
||||
{
|
||||
$actions = [EXPORT_ACTION_EXPORT, EXPORT_ACTION_MARKREGISTERED];
|
||||
if ($this->getSetting($context->getId(), 'username') && $this->getSetting($context->getId(), 'password')) {
|
||||
array_unshift($actions, EXPORT_ACTION_DEPOSIT);
|
||||
}
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get action names.
|
||||
*
|
||||
* @return array (string action => string text)
|
||||
*/
|
||||
public function getExportActionNames()
|
||||
{
|
||||
return [
|
||||
EXPORT_ACTION_DEPOSIT => __('plugins.importexport.common.action.register'),
|
||||
EXPORT_ACTION_EXPORT => __('plugins.importexport.common.action.export'),
|
||||
EXPORT_ACTION_MARKREGISTERED => __('plugins.importexport.common.action.markRegistered'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the plugin's deployment class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getExportDeploymentClassName();
|
||||
|
||||
/**
|
||||
* Get the XML for selected objects.
|
||||
*
|
||||
* @param mixed $objects Array of or single published submission, issue or galley
|
||||
* @param string $filter
|
||||
* @param Journal $context
|
||||
* @param bool $noValidation If set to true no XML validation will be done
|
||||
* @param null|mixed $outputErrors
|
||||
*
|
||||
* @return string XML document.
|
||||
*/
|
||||
public function exportXML($objects, $filter, $context, $noValidation = null, &$outputErrors = null)
|
||||
{
|
||||
$filterDao = DAORegistry::getDAO('FilterDAO'); /** @var FilterDAO $filterDao */
|
||||
$exportFilters = $filterDao->getObjectsByGroup($filter);
|
||||
assert(count($exportFilters) == 1); // Assert only a single serialization filter
|
||||
$exportFilter = array_shift($exportFilters);
|
||||
$exportDeployment = $this->_instantiateExportDeployment($context);
|
||||
$exportFilter->setDeployment($exportDeployment);
|
||||
if ($noValidation) {
|
||||
$exportFilter->setNoValidation($noValidation);
|
||||
}
|
||||
libxml_use_internal_errors(true);
|
||||
$exportXml = $exportFilter->execute($objects, true);
|
||||
$xml = $exportXml->saveXml();
|
||||
$errors = array_filter(libxml_get_errors(), function ($a) {
|
||||
return $a->level == LIBXML_ERR_ERROR || $a->level == LIBXML_ERR_FATAL;
|
||||
});
|
||||
if (!empty($errors)) {
|
||||
if ($outputErrors === null) {
|
||||
$this->displayXMLValidationErrors($errors, $xml);
|
||||
} else {
|
||||
$outputErrors = $errors;
|
||||
}
|
||||
}
|
||||
return $xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark selected submissions or issues as registered.
|
||||
*
|
||||
* @param Journal $context
|
||||
* @param array $objects Array of published submissions, issues or galleys
|
||||
*/
|
||||
public function markRegistered($context, $objects)
|
||||
{
|
||||
foreach ($objects as $object) {
|
||||
$object->setData($this->getDepositStatusSettingName(), EXPORT_STATUS_MARKEDREGISTERED);
|
||||
$this->updateObject($object);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the given object.
|
||||
*
|
||||
* @param Issue|Submission|Galley $object
|
||||
*/
|
||||
protected function updateObject($object)
|
||||
{
|
||||
// Register a hook for the required additional
|
||||
// object fields. We do this on a temporary
|
||||
// basis as the hook adds a performance overhead
|
||||
// and the field will "stealthily" survive even
|
||||
// when the DAO does not know about it.
|
||||
$dao = $object->getDAO();
|
||||
$dao->update($object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add properties for this type of public identifier to the entity's list for
|
||||
* storage in the database.
|
||||
* This is used for non-SchemaDAO-backed entities only.
|
||||
*
|
||||
* @see PubObjectsExportPlugin::addToSchema()
|
||||
*
|
||||
* @param string $hookName
|
||||
* @param DAO $dao
|
||||
* @param array $additionalFields
|
||||
*
|
||||
* @return false
|
||||
*/
|
||||
public function getAdditionalFieldNames($hookName, $dao, &$additionalFields)
|
||||
{
|
||||
foreach ($this->_getObjectAdditionalSettings() as $fieldName) {
|
||||
$additionalFields[] = $fieldName;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add properties for this type of public identifier to the entity's list for
|
||||
* storage in the database.
|
||||
* This is used for SchemaDAO-backed entities only.
|
||||
*
|
||||
* @see PKPPubIdPlugin::getAdditionalFieldNames()
|
||||
*
|
||||
* @param string $hookName `Schema::get::publication`
|
||||
* @param array $params
|
||||
*/
|
||||
public function addToSchema($hookName, $params)
|
||||
{
|
||||
$schema = & $params[0];
|
||||
foreach ($this->_getObjectAdditionalSettings() as $fieldName) {
|
||||
$schema->properties->{$fieldName} = (object) [
|
||||
'type' => 'string',
|
||||
'apiSummary' => true,
|
||||
'validation' => ['nullable'],
|
||||
];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of additional setting names that should be stored with the objects.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function _getObjectAdditionalSettings()
|
||||
{
|
||||
return [$this->getDepositStatusSettingName()];
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc AcronPlugin::parseCronTab()
|
||||
*/
|
||||
public function callbackParseCronTab($hookName, $args)
|
||||
{
|
||||
$taskFilesPath = & $args[0];
|
||||
|
||||
$scheduledTasksPath = "{$this->getPluginPath()}/scheduledTasks.xml";
|
||||
|
||||
if (!file_exists($scheduledTasksPath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$taskFilesPath[] = $scheduledTasksPath;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all unregistered articles.
|
||||
*
|
||||
* @param Journal $context
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getUnregisteredArticles($context)
|
||||
{
|
||||
// Retrieve all published submissions that have not yet been registered.
|
||||
$articles = Repo::submission()->dao->getExportable(
|
||||
$context->getId(),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
$this->getDepositStatusSettingName(),
|
||||
EXPORT_STATUS_NOT_DEPOSITED,
|
||||
null
|
||||
);
|
||||
return $articles->toArray();
|
||||
}
|
||||
/**
|
||||
* Check whether we are in test mode.
|
||||
*
|
||||
* @param Journal $context
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isTestMode($context)
|
||||
{
|
||||
return ($this->getSetting($context->getId(), 'testMode') == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get deposit status setting name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDepositStatusSettingName()
|
||||
{
|
||||
return $this->getPluginSettingsPrefix() . '::status';
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @copydoc PKPImportExportPlugin::usage
|
||||
*/
|
||||
public function usage($scriptName)
|
||||
{
|
||||
echo __(
|
||||
'plugins.importexport.' . $this->getPluginSettingsPrefix() . '.cliUsage',
|
||||
[
|
||||
'scriptName' => $scriptName,
|
||||
'pluginName' => $this->getName()
|
||||
]
|
||||
) . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc PKPImportExportPlugin::executeCLI()
|
||||
*/
|
||||
public function executeCLI($scriptName, &$args)
|
||||
{
|
||||
$command = array_shift($args);
|
||||
if (!in_array($command, ['export', 'register'])) {
|
||||
$this->usage($scriptName);
|
||||
return;
|
||||
}
|
||||
|
||||
$outputFile = $command == 'export' ? array_shift($args) : null;
|
||||
$contextPath = array_shift($args);
|
||||
$objectType = array_shift($args);
|
||||
|
||||
$contextDao = DAORegistry::getDAO('JournalDAO'); /** @var JournalDAO $contextDao */
|
||||
$context = $contextDao->getByPath($contextPath);
|
||||
if (!$context) {
|
||||
if ($contextPath != '') {
|
||||
echo __('plugins.importexport.common.cliError') . "\n";
|
||||
echo __('plugins.importexport.common.error.unknownContext', ['contextPath' => $contextPath]) . "\n\n";
|
||||
}
|
||||
$this->usage($scriptName);
|
||||
return;
|
||||
}
|
||||
|
||||
PluginRegistry::loadCategory('pubIds', true, $context->getId());
|
||||
|
||||
if ($outputFile) {
|
||||
if ($this->isRelativePath($outputFile)) {
|
||||
$outputFile = PWD . '/' . $outputFile;
|
||||
}
|
||||
$outputDir = dirname($outputFile);
|
||||
if (!is_writable($outputDir) || (file_exists($outputFile) && !is_writable($outputFile))) {
|
||||
echo __('plugins.importexport.common.cliError') . "\n";
|
||||
echo __('plugins.importexport.common.export.error.outputFileNotWritable', ['param' => $outputFile]) . "\n\n";
|
||||
$this->usage($scriptName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch ($objectType) {
|
||||
case 'articles':
|
||||
$objects = $this->getPublishedSubmissions($args, $context);
|
||||
$filter = $this->getSubmissionFilter();
|
||||
$objectsFileNamePart = 'articles';
|
||||
break;
|
||||
case 'issues':
|
||||
$objects = $this->getPublishedIssues($args, $context);
|
||||
$filter = $this->getIssueFilter();
|
||||
$objectsFileNamePart = 'issues';
|
||||
break;
|
||||
case 'galleys':
|
||||
$objects = $this->getArticleGalleys($args, $context);
|
||||
$filter = $this->getRepresentationFilter();
|
||||
$objectsFileNamePart = 'galleys';
|
||||
break;
|
||||
default:
|
||||
$this->usage($scriptName);
|
||||
return;
|
||||
}
|
||||
if (empty($objects)) {
|
||||
echo __('plugins.importexport.common.cliError') . "\n";
|
||||
echo __('plugins.importexport.common.error.unknownObjects') . "\n\n";
|
||||
$this->usage($scriptName);
|
||||
return;
|
||||
}
|
||||
if (!$filter) {
|
||||
$this->usage($scriptName);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->executeCLICommand($scriptName, $command, $context, $outputFile, $objects, $filter, $objectsFileNamePart);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the CLI command
|
||||
*
|
||||
* @param string $scriptName The name of the command-line script (displayed as usage info)
|
||||
* @param string $command (export or register)
|
||||
* @param Journal $context
|
||||
* @param string $outputFile Path to the file where the exported XML should be saved
|
||||
* @param array $objects Objects to be exported or registered
|
||||
* @param string $filter Filter to use
|
||||
* @param string $objectsFileNamePart Export file name part for this kind of objects
|
||||
*/
|
||||
public function executeCLICommand($scriptName, $command, $context, $outputFile, $objects, $filter, $objectsFileNamePart)
|
||||
{
|
||||
$exportXml = $this->exportXML($objects, $filter, $context);
|
||||
if ($command == 'export' && $outputFile) {
|
||||
file_put_contents($outputFile, $exportXml);
|
||||
}
|
||||
|
||||
if ($command == 'register') {
|
||||
$fileManager = new FileManager();
|
||||
$exportFileName = $this->getExportFileName($this->getExportPath(), $objectsFileNamePart, $context, '.xml');
|
||||
$fileManager->writeFile($exportFileName, $exportXml);
|
||||
$result = $this->depositXML($objects, $context, $exportFileName);
|
||||
if ($result === true) {
|
||||
echo __('plugins.importexport.common.register.success') . "\n";
|
||||
} else {
|
||||
echo __('plugins.importexport.common.cliError') . "\n";
|
||||
if (is_array($result)) {
|
||||
foreach ($result as $error) {
|
||||
assert(is_array($error) && count($error) >= 1);
|
||||
$errorMessage = __($error[0], ['param' => ($error[1] ?? null)]);
|
||||
echo "*** {$errorMessage}\n";
|
||||
}
|
||||
echo "\n";
|
||||
} else {
|
||||
echo __('plugins.importexport.common.register.error.mdsError', ['param' => ' - ']) . "\n\n";
|
||||
}
|
||||
$this->usage($scriptName);
|
||||
}
|
||||
$fileManager->deleteByPath($exportFileName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get published submissions from submission IDs.
|
||||
*
|
||||
* @param array $submissionIds
|
||||
* @param Journal $context
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getPublishedSubmissions($submissionIds, $context)
|
||||
{
|
||||
$allSubmissionIds = Repo::submission()
|
||||
->getCollector()
|
||||
->filterByContextIds([$context->getId()])
|
||||
->filterByStatus([PKPSubmission::STATUS_PUBLISHED])
|
||||
->getIds()
|
||||
->toArray();
|
||||
$validSubmissionIds = array_intersect($allSubmissionIds, $submissionIds);
|
||||
return array_map(function ($submissionId) {
|
||||
return Repo::submission()->get($submissionId);
|
||||
}, $validSubmissionIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get published issues from issue IDs.
|
||||
*
|
||||
* @param array $issueIds
|
||||
* @param Journal $context
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getPublishedIssues($issueIds, $context)
|
||||
{
|
||||
return Repo::issue()
|
||||
->getCollector()
|
||||
->filterByContextIds([$context->getId()])
|
||||
->filterByIssueIds($issueIds)
|
||||
->filterByPublished(true)
|
||||
->getMany()
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get article galleys from gallley IDs.
|
||||
*
|
||||
* @param array $galleyIds
|
||||
* @param Journal $context
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getArticleGalleys($galleyIds, $context)
|
||||
{
|
||||
$allGalleyIds = Repo::galley()
|
||||
->getCollector()
|
||||
->filterByContextIds([$context->getId()])
|
||||
->getIds()
|
||||
->toArray();
|
||||
$validGalleyIds = array_intersect($allGalleyIds, $galleyIds);
|
||||
return array_map(function ($galleyId) {
|
||||
return Repo::submission()->get($galleyId);
|
||||
}, $validGalleyIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a notification.
|
||||
*
|
||||
* @param User $user
|
||||
* @param string $message An i18n key.
|
||||
* @param int $notificationType One of the NOTIFICATION_TYPE_* constants.
|
||||
* @param string $param An additional parameter for the message.
|
||||
*/
|
||||
public function _sendNotification($user, $message, $notificationType, $param = null)
|
||||
{
|
||||
static $notificationManager = null;
|
||||
$notificationManager ??= new NotificationManager();
|
||||
$params = is_null($param) ? [] : ['param' => $param];
|
||||
$notificationManager->createTrivialNotification(
|
||||
$user->getId(),
|
||||
$notificationType,
|
||||
['contents' => __($message, $params)]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate the export deployment.
|
||||
*
|
||||
* @param Journal $context
|
||||
*
|
||||
* @return PKPImportExportDeployment
|
||||
*/
|
||||
public function _instantiateExportDeployment($context)
|
||||
{
|
||||
$exportDeploymentClassName = $this->getExportDeploymentClassName();
|
||||
$exportDeployment = new $exportDeploymentClassName($context, $this);
|
||||
return $exportDeployment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate the settings form.
|
||||
*
|
||||
* @param Journal $context
|
||||
*
|
||||
* @return \PKP\form\Form
|
||||
*/
|
||||
public function _instantiateSettingsForm($context)
|
||||
{
|
||||
$settingsFormClassName = $this->getSettingsFormClassName();
|
||||
return new $settingsFormClassName($this, $context->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DAOs for objects that need to be augmented with additional settings.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function _getDAOs()
|
||||
{
|
||||
return [
|
||||
Repo::publication()->dao,
|
||||
Repo::submission()->dao,
|
||||
Application::getRepresentationDAO(),
|
||||
Repo::issue()->dao,
|
||||
Repo::submissionFile()->dao
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for export action type as set user var and as action passed from API call
|
||||
*
|
||||
* @param string $exportAction Action to check for
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function _checkForExportAction($exportAction)
|
||||
{
|
||||
$request = $this->getRequest();
|
||||
if ($request->getUserVar($exportAction)) {
|
||||
return true;
|
||||
} elseif ($request->getUserVar('action') == $exportAction) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!PKP_STRICT_MODE) {
|
||||
class_alias('\APP\plugins\PubObjectsExportPlugin', '\PubObjectsExportPlugin');
|
||||
}
|
||||
Reference in New Issue
Block a user