231 lines
7.7 KiB
PHP
231 lines
7.7 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @file WebFeedGatewayPlugin.php
|
|
*
|
|
* Copyright (c) 2014-2023 Simon Fraser University
|
|
* Copyright (c) 2003-2023 John Willinsky
|
|
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
|
*
|
|
* @class WebFeedGatewayPlugin
|
|
*
|
|
* @brief Gateway component of web feed plugin
|
|
*
|
|
*/
|
|
|
|
namespace APP\plugins\generic\webFeed;
|
|
|
|
use APP\core\Application;
|
|
use APP\core\Request;
|
|
use APP\facades\Repo;
|
|
use APP\section\Section;
|
|
use APP\submission\Collector;
|
|
use APP\submission\Submission;
|
|
use APP\template\TemplateManager;
|
|
use Exception;
|
|
use PKP\category\Category;
|
|
use PKP\core\Registry;
|
|
use PKP\plugins\GatewayPlugin;
|
|
|
|
class WebFeedGatewayPlugin extends GatewayPlugin
|
|
{
|
|
public const ATOM = 'atom';
|
|
public const RSS = 'rss';
|
|
public const RSS2 = 'rss2';
|
|
|
|
public const FEED_MIME_TYPE = [
|
|
self::ATOM => 'application/atom+xml',
|
|
self::RSS => 'application/rdf+xml',
|
|
self::RSS2 => 'application/rss+xml'
|
|
];
|
|
|
|
public const DEFAULT_RECENT_ITEMS = 30;
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
public function __construct(protected WebFeedPlugin $parentPlugin)
|
|
{
|
|
parent::__construct();
|
|
}
|
|
|
|
/**
|
|
* Handle fetch requests for this plugin.
|
|
*
|
|
* @param array $args Arguments.
|
|
* @param Request $request Request object.
|
|
*/
|
|
public function fetch($args, $request): bool
|
|
{
|
|
$context = $request->getContext();
|
|
if (!$context || !$this->parentPlugin->getEnabled($context->getId())) {
|
|
return false;
|
|
}
|
|
|
|
// Make sure the feed type is specified and valid
|
|
$feedType = array_shift($args);
|
|
if (!in_array($feedType, array_keys(static::FEED_MIME_TYPE))) {
|
|
throw new Exception('Invalid feed format');
|
|
}
|
|
|
|
// Get limit setting from web feeds plugin
|
|
$displayItems = $this->parentPlugin->getSetting($context->getId(), 'displayItems');
|
|
$recentItems = abs((int) $this->parentPlugin->getSetting($context->getId(), 'recentItems')) ?: static::DEFAULT_RECENT_ITEMS;
|
|
|
|
$includeIdentifiers = (bool) $this->parentPlugin->getSetting($context->getId(), 'includeIdentifiers');
|
|
$latestDate = null;
|
|
$submissions = Repo::submission()->getCollector()
|
|
->filterByContextIds([$context->getId()])
|
|
->filterByStatus([Submission::STATUS_PUBLISHED])
|
|
->limit($recentItems)
|
|
->orderBy(Collector::ORDERBY_LAST_MODIFIED, Collector::ORDER_DIR_DESC);
|
|
|
|
// OJS only feature
|
|
// If the plugin is configured to display only the latest issue, so we filter by it and apply the needed changes to the query
|
|
if (WebFeedPlugin::hasIssues() && $displayItems === 'issue') {
|
|
$issue = Repo::issue()->getCurrent($context->getId(), true);
|
|
$submissions->filterByIssueIds([$issue?->getId() ?? 0])
|
|
->limit(null)
|
|
->orderBy(Collector::ORDERBY_SEQUENCE, Collector::ORDER_DIR_ASC);
|
|
$latestDate = $issue?->getData('datePublished');
|
|
}
|
|
|
|
$submissions = $submissions->getMany();
|
|
$latestDate ??= $submissions->first()?->getData('lastModified');
|
|
$submissions = $submissions->map(fn (Submission $submission) => ['submission' => $submission, 'identifiers' => $this->getIdentifiers($submission)]);
|
|
$userGroups = Repo::userGroup()->getCollector()->filterByContextIds([$context->getId()])->getMany();
|
|
|
|
$applicationIdentifier = strtolower(preg_replace('/[^a-z]/i', '', Application::getName()));
|
|
TemplateManager::getManager($request)
|
|
->assign(
|
|
[
|
|
'applicationName' => match ($applicationIdentifier) {
|
|
'ojs' => 'Open Journal Systems',
|
|
'omp' => 'Open Monograph Press',
|
|
'ops' => 'Open Preprint Systems'
|
|
},
|
|
'applicationVersion' => Registry::get('appVersion'),
|
|
'applicationIdentifier' => $applicationIdentifier,
|
|
'publicationPage' => match ($applicationIdentifier) {
|
|
'ojs' => 'article',
|
|
'omp' => 'catalog',
|
|
'ops' => 'preprint'
|
|
},
|
|
'publicationOp' => match ($applicationIdentifier) {
|
|
'ojs' => 'view',
|
|
'omp' => 'book',
|
|
'ops' => 'view'
|
|
},
|
|
'openAccess' => match ($applicationIdentifier) {
|
|
'ojs' => Submission::ARTICLE_ACCESS_OPEN,
|
|
'omp' => null,
|
|
'ops' => Submission::PREPRINT_ACCESS_OPEN
|
|
},
|
|
'submissions' => $submissions,
|
|
'context' => $context,
|
|
'latestDate' => $latestDate,
|
|
'feedUrl' => $request->getRequestUrl(),
|
|
'userGroups' => $userGroups,
|
|
'includeIdentifiers' => $includeIdentifiers
|
|
]
|
|
)
|
|
->setHeaders(['content-type: ' . static::FEED_MIME_TYPE[$feedType] . '; charset=utf-8'])
|
|
->display($this->parentPlugin->getTemplateResource("{$feedType}.tpl"));
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the identifiers assigned to a submission
|
|
*
|
|
* @return array<array{'type':string,'label':string,'values':string[]}>
|
|
*/
|
|
private function getIdentifiers(Submission $submission): array
|
|
{
|
|
$identifiers = [];
|
|
if ($section = $this->getSection($submission->getSectionId())) {
|
|
$identifiers[] = ['type' => 'section', 'label' => __('section.section'), 'values' => [$section->getLocalizedTitle()]];
|
|
}
|
|
|
|
$publication = $submission->getCurrentPublication();
|
|
$categories = Repo::category()->getCollector()
|
|
->filterByPublicationIds([$publication->getId()])
|
|
->getMany()
|
|
->map(fn (Category $category) => $category->getLocalizedTitle())
|
|
->toArray();
|
|
if (count($categories)) {
|
|
$identifiers[] = ['type' => 'category', 'label' => __('category.category'), 'values' => $categories];
|
|
}
|
|
|
|
foreach (['keywords' => 'common.keywords', 'subjects' => 'common.subjects', 'disciplines' => 'search.discipline'] as $field => $label) {
|
|
$values = $publication->getLocalizedData($field) ?? [];
|
|
if (count($values)) {
|
|
$identifiers[] = ['type' => $field, 'label' => __($label), 'values' => $values];
|
|
}
|
|
}
|
|
|
|
return $identifiers;
|
|
}
|
|
|
|
/**
|
|
* Retrieves a section
|
|
*/
|
|
private function getSection(?int $sectionId): ?Section
|
|
{
|
|
static $sections = [];
|
|
return $sectionId
|
|
? $sections[$sectionId] ??= Repo::section()->get($sectionId)
|
|
: null;
|
|
}
|
|
|
|
/**
|
|
* @copydoc Plugin::getHideManagement()
|
|
*/
|
|
public function getHideManagement(): bool
|
|
{
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @copydoc Plugin::getName()
|
|
*/
|
|
public function getName(): string
|
|
{
|
|
return substr(static::class, strlen(__NAMESPACE__) + 1);
|
|
}
|
|
|
|
/**
|
|
* @copydoc Plugin::getDisplayName()
|
|
*/
|
|
public function getDisplayName(): string
|
|
{
|
|
return __('plugins.generic.webfeed.displayName');
|
|
}
|
|
|
|
/**
|
|
* @copydoc Plugin::getDescription()
|
|
*/
|
|
public function getDescription(): string
|
|
{
|
|
return __('plugins.generic.webfeed.description');
|
|
}
|
|
|
|
/**
|
|
* @copydoc Plugin::getPluginPath()
|
|
*/
|
|
public function getPluginPath(): string
|
|
{
|
|
return $this->parentPlugin->getPluginPath();
|
|
}
|
|
|
|
/**
|
|
* @copydoc Plugin::getEnabled()
|
|
*
|
|
* @param null|mixed $contextId
|
|
*/
|
|
public function getEnabled($contextId = null): bool
|
|
{
|
|
return $this->parentPlugin->getEnabled($contextId);
|
|
}
|
|
}
|