Open Preprint Systems  3.3.0
PreprintHandler.inc.php
1 <?php
2 
17 import('classes.handler.Handler');
18 
19 use \Firebase\JWT\JWT;
20 
21 class PreprintHandler extends Handler {
23  var $context;
24 
26  var $preprint;
27 
30 
32  var $galley;
33 
35  var $fileId;
36 
37 
41  function authorize($request, &$args, $roleAssignments) {
42  // Permit the use of the Authorization header and an API key for access to unpublished/subscription content
43  if ($header = array_search('Authorization', array_flip(getallheaders()))) {
44  list($bearer, $jwt) = explode(' ', $header);
45  if (strcasecmp($bearer, 'Bearer') == 0) {
46  $apiToken = json_decode(JWT::decode($jwt, Config::getVar('security', 'api_key_secret', ''), array('HS256')));
47  $this->setApiToken($apiToken);
48  }
49  }
50 
51  import('lib.pkp.classes.security.authorization.ContextRequiredPolicy');
52  $this->addPolicy(new ContextRequiredPolicy($request));
53 
54  import('classes.security.authorization.OpsServerMustPublishPolicy');
55  $this->addPolicy(new OpsServerMustPublishPolicy($request));
56 
57  return parent::authorize($request, $args, $roleAssignments);
58  }
59 
64  function initialize($request, $args = array()) {
65  $urlPath = empty($args) ? 0 : array_shift($args);
66 
67  // Get the submission that matches the requested urlPath
68  $submission = Services::get('submission')->getByUrlPath($urlPath, $request->getContext()->getId());
69 
70  if (!$submission && ctype_digit((string) $urlPath)) {
71  $submission = Services::get('submission')->get($urlPath);
72  if ($submission && $request->getContext()->getId() != $submission->getContextId()) $submission = null;
73  }
74 
75  if (!$submission || $submission->getData('status') !== STATUS_PUBLISHED) {
76  $request->getDispatcher()->handle404();
77  }
78 
79  // If the urlPath does not match the urlPath of the current
80  // publication, redirect to the current URL
81  $currentUrlPath = $submission->getBestId();
82  if ($currentUrlPath && $currentUrlPath != $urlPath) {
83  $newArgs = $args;
84  $newArgs[0] = $currentUrlPath;
85  $request->redirect(null, $request->getRequestedPage(), $request->getRequestedOp(), $newArgs);
86  }
87 
88  $this->preprint = $submission;
89 
90  // Get the requested publication or if none requested get the current publication
91  $subPath = empty($args) ? 0 : array_shift($args);
92  if ($subPath === 'version') {
93  $publicationId = (int) array_shift($args);
94  $galleyId = empty($args) ? 0 : array_shift($args);
95  foreach ((array) $this->preprint->getData('publications') as $publication) {
96  if ($publication->getId() === $publicationId) {
97  $this->publication = $publication;
98  }
99  }
100  if (!$this->publication) {
101  $request->getDispatcher()->handle404();
102  }
103  } else {
104  $this->publication = $this->preprint->getCurrentPublication();
105  $galleyId = $subPath;
106  }
107 
108  if ($this->publication->getData('status') !== STATUS_PUBLISHED) {
109  $request->getDispatcher()->handle404();
110  }
111 
112  if ($galleyId && in_array($request->getRequestedOp(), ['view', 'download'])) {
113  $galleys = (array) $this->publication->getData('galleys');
114  foreach ($galleys as $galley) {
115  if ($galley->getBestGalleyId() == $galleyId) {
116  $this->galley = $galley;
117  break;
118  }
119  }
120  // Redirect to the most recent version of the submission if the request
121  // points to an outdated galley but doesn't use the specific versioned
122  // URL. This can happen when a galley's urlPath is changed between versions.
123  if (!$this->galley) {
124  $publications = $submission->getPublishedPublications();
125  foreach ($publications as $publication) {
126  foreach ((array) $publication->getData('galleys') as $galley) {
127  if ($galley->getBestGalleyId() == $galleyId) {
128  $request->redirect(null, $request->getRequestedPage(), $request->getRequestedOp(), [$submission->getBestId()]);
129  }
130  }
131  }
132  $request->getDispatcher()->handle404();
133  }
134 
135  // Store the file id if it exists
136  if (!empty($args)) {
137  $this->fileId = array_shift($args);
138  }
139  }
140  }
141 
147  function view($args, $request) {
148  $context = $request->getContext();
149  $user = $request->getUser();
152 
153  $templateMgr = TemplateManager::getManager($request);
154  $templateMgr->assign(array(
155  'preprint' => $preprint,
156  'publication' => $publication,
157  'firstPublication' => reset($preprint->getData('publications')),
158  'currentPublication' => $preprint->getCurrentPublication(),
159  'galley' => $this->galley,
160  'fileId' => $this->fileId,
161  ));
162  $this->setupTemplate($request);
163 
164  $sectionDao = DAORegistry::getDAO('SectionDAO'); /* @var $sectionDao SectionDAO */
165  $categoryDao = DAORegistry::getDAO('CategoryDAO'); /* @var $categoryDao CategoryDAO */
166  $publicationCategories = $categoryDao->getByPublicationId($publication->getId())->toArray();
167  foreach ($publicationCategories as $category) {
168  $title = $category->getLocalizedTitle();
169  if ($category->getParentId()) {
170  $title = $categoryDao->getById($category->getParentId())->getLocalizedTitle() . ' > ' . $title;
171  }
172  $categories[] = [
173  'path' => $category->getPath(),
174  'title' => $title,
175  ];
176  }
177 
178  $templateMgr->assign([
179  'ccLicenseBadge' => Application::get()->getCCLicenseBadge($publication->getData('licenseUrl')),
180  'publication' => $publication,
181  'section' => $sectionDao->getById($publication->getData('sectionId')),
182  'categories' => $categories,
183  ]);
184 
185 
186 
187  if ($this->galley && !$this->userCanViewGalley($request, $preprint->getId(), $this->galley->getId())) {
188  fatalError('Cannot view galley.');
189  }
190 
191  // Get galleys sorted into primary and supplementary groups
192  $galleys = $publication->getData('galleys');
193  $primaryGalleys = array();
194  $supplementaryGalleys = array();
195  if ($galleys) {
196  $genreDao = DAORegistry::getDAO('GenreDAO');
197  $primaryGenres = $genreDao->getPrimaryByContextId($context->getId())->toArray();
198  $primaryGenreIds = array_map(function($genre) {
199  return $genre->getId();
200  }, $primaryGenres);
201  $supplementaryGenres = $genreDao->getBySupplementaryAndContextId(true, $context->getId())->toArray();
202  $supplementaryGenreIds = array_map(function($genre) {
203  return $genre->getId();
204  }, $supplementaryGenres);
205 
206  foreach ($galleys as $galley) {
207  $remoteUrl = $galley->getRemoteURL();
208  $file = $galley->getFile();
209  if (!$remoteUrl && !$file) {
210  continue;
211  }
212  if ($remoteUrl || in_array($file->getGenreId(), $primaryGenreIds)) {
213  $primaryGalleys[] = $galley;
214  } elseif (in_array($file->getGenreId(), $supplementaryGenreIds)) {
215  $supplementaryGalleys[] = $galley;
216  }
217  }
218  }
219  $templateMgr->assign(array(
220  'primaryGalleys' => $primaryGalleys,
221  'supplementaryGalleys' => $supplementaryGalleys,
222  ));
223 
224  // Citations
225  if ($publication->getData('citationsRaw')) {
226  $citationDao = DAORegistry::getDAO('CitationDAO'); /* @var $citationDao CitationDAO */
227  $parsedCitations = $citationDao->getByPublicationId($publication->getId());
228  $templateMgr->assign([
229  'parsedCitations' => $parsedCitations->toArray(),
230  ]);
231  }
232 
233  // Assign deprecated values to the template manager for
234  // compatibility with older themes
235  $templateMgr->assign([
236  'licenseTerms' => $context->getLocalizedData('licenseTerms'),
237  'licenseUrl' => $publication->getData('licenseUrl'),
238  'copyrightHolder' => $publication->getData('copyrightHolder'),
239  'copyrightYear' => $publication->getData('copyrightYear'),
240  'pubIdPlugins' => PluginRegistry::loadCategory('pubIds', true),
241  'keywords' => $publication->getData('keywords'),
242  ]);
243 
244  // Fetch and assign the galley to the template
245  if ($this->galley && $this->galley->getRemoteURL()) $request->redirectUrl($this->galley->getRemoteURL());
246 
247  if (empty($this->galley)) {
248  // No galley: Prepare the preprint landing page.
249 
250  // Ask robots not to index outdated versions and point to the canonical url for the latest version
251  if ($publication->getId() !== $preprint->getCurrentPublication()->getId()) {
252  $templateMgr->addHeader('noindex', '<meta name="robots" content="noindex">');
253  $url = $request->getDispatcher()->url($request, ROUTE_PAGE, null, 'preprint', 'view', $preprint->getBestId());
254  $templateMgr->addHeader('canonical', '<link rel="canonical" href="' . $url . '">');
255  }
256 
257  if (!HookRegistry::call('PreprintHandler::view', array(&$request, &$preprint, $publication))) {
258  return $templateMgr->display('frontend/pages/preprint.tpl');
259  }
260 
261  } else {
262 
263  // Ask robots not to index outdated versions
264  if ($publication->getId() !== $preprint->getCurrentPublication()->getId()) {
265  $templateMgr->addHeader('noindex', '<meta name="robots" content="noindex">');
266  }
267 
268  // Galley: Prepare the galley file download.
269  if (!HookRegistry::call('PreprintHandler::view::galley', array(&$request, &$this->galley, &$preprint, $publication))) {
270  if ($this->publication->getId() !== $this->preprint->getCurrentPublication()->getId()) {
271  $redirectArgs = [
272  $preprint->getBestId(),
273  'version',
274  $publication->getId(),
275  $this->galley->getBestGalleyId()
276  ];
277  } else {
278  $redirectArgs = [
279  $preprint->getId(),
280  $this->galley->getBestGalleyId()
281  ];
282  }
283  $request->redirect(null, null, 'download', $redirectArgs);
284  }
285  }
286  }
287 
294  function viewFile($args, $request) {
295  $preprintId = isset($args[0]) ? $args[0] : 0;
296  $galleyId = isset($args[1]) ? $args[1] : 0;
297  $fileId = isset($args[2]) ? (int) $args[2] : 0;
298  header('HTTP/1.1 301 Moved Permanently');
299  $request->redirect(null, null, 'download', array($preprintId, $galleyId, $fileId));
300  }
301 
307  function download($args, $request) {
308  if (!isset($this->galley)) $request->getDispatcher()->handle404();
309  if ($this->galley->getRemoteURL()) $request->redirectUrl($this->galley->getRemoteURL());
310  else if ($this->userCanViewGalley($request, $this->preprint->getId(), $this->galley->getId())) {
311  if (!$this->fileId) {
312  $submissionFile = $this->galley->getFile();
313  if ($submissionFile) {
314  $this->fileId = $submissionFile->getFileId();
315  // The file manager expects the real article id. Extract it from the submission file.
316  }
317  }
318 
319  // If no file ID could be determined, treat it as a 404.
320  if (!$this->fileId) $request->getDispatcher()->handle404();
321 
322  // If the file ID is not the galley's file ID, ensure it is a dependent file, or else 404.
323  if ($this->fileId != $this->galley->getFileId()) {
324  $submissionFileDao = DAORegistry::getDAO('SubmissionFileDAO'); /* @var $submissionFileDao SubmissionFileDAO */
325  $dependentFileIds = array_map(
326  function($f) {return $f->getFileId();},
327  $submissionFileDao->getLatestRevisionsByAssocId(ASSOC_TYPE_SUBMISSION_FILE, $this->galley->getFileId(), $this->preprint->getId(), SUBMISSION_FILE_DEPENDENT)
328  );
329  if (!in_array($this->fileId, $dependentFileIds))
330  $request->getDispatcher()->handle404();
331  }
332 
333  if (!HookRegistry::call('PreprintHandler::download', array($this->preprint, &$this->galley, &$this->fileId))) {
334  import('lib.pkp.classes.file.SubmissionFileManager');
335  $submissionFileManager = new SubmissionFileManager($this->preprint->getContextId(), $this->preprint->getId());
336  $submissionFileManager->downloadById($this->fileId, null, $request->getUserVar('inline')?true:false);
337  }
338  } else {
339  header('HTTP/1.0 403 Forbidden');
340  echo '403 Forbidden<br>';
341  }
342  }
343 
350  function userCanViewGalley($request, $preprintId, $galleyId = null) {
351  $submission = $this->preprint;
352  if ($submission->getStatus() == STATUS_PUBLISHED) {
353  return true;
354  } else {
355  $request->redirect(null, 'search');
356  }
357  return true;
358  }
359 
364  function setupTemplate($request) {
365  parent::setupTemplate($request);
366  AppLocale::requireComponents(LOCALE_COMPONENT_PKP_READER, LOCALE_COMPONENT_PKP_SUBMISSION, LOCALE_COMPONENT_APP_SUBMISSION);
367  }
368 }
OpsServerMustPublishPolicy
Access policy to limit access to servers that do not publish online.
Definition: OpsServerMustPublishPolicy.inc.php:18
PreprintHandler\setupTemplate
setupTemplate($request)
Definition: PreprintHandler.inc.php:364
SubmissionFileManager
Helper class for database-backed submission file management tasks.
Definition: SubmissionFileManager.inc.php:30
AppLocale\requireComponents
static requireComponents()
Definition: env1/MockAppLocale.inc.php:56
PKPHandler\setApiToken
setApiToken($apiToken)
Definition: PKPHandler.inc.php:568
PreprintHandler\viewFile
viewFile($args, $request)
Definition: PreprintHandler.inc.php:294
PreprintHandler\$fileId
$fileId
Definition: PreprintHandler.inc.php:35
PreprintHandler\authorize
authorize($request, &$args, $roleAssignments)
Definition: PreprintHandler.inc.php:41
DAORegistry\getDAO
static & getDAO($name, $dbconn=null)
Definition: DAORegistry.inc.php:57
PreprintHandler\view
view($args, $request)
Definition: PreprintHandler.inc.php:147
PreprintHandler\$galley
$galley
Definition: PreprintHandler.inc.php:32
PreprintHandler\download
download($args, $request)
Definition: PreprintHandler.inc.php:307
PreprintHandler\$preprint
$preprint
Definition: PreprintHandler.inc.php:26
PluginRegistry\loadCategory
static loadCategory($category, $enabledOnly=false, $mainContextId=null)
Definition: PluginRegistry.inc.php:103
PreprintHandler\$context
$context
Definition: PreprintHandler.inc.php:23
Config\getVar
static getVar($section, $key, $default=null)
Definition: Config.inc.php:35
PKPTemplateManager\getManager
static & getManager($request=null)
Definition: PKPTemplateManager.inc.php:1226
PreprintHandler\$publication
$publication
Definition: PreprintHandler.inc.php:29
PreprintHandler\userCanViewGalley
userCanViewGalley($request, $preprintId, $galleyId=null)
Definition: PreprintHandler.inc.php:350
PKPApplication\get
static get()
Definition: PKPApplication.inc.php:235
PKPHandler\addPolicy
addPolicy($authorizationPolicy, $addToTop=false)
Definition: PKPHandler.inc.php:157
fatalError
if(!function_exists('import')) fatalError($reason)
Definition: functions.inc.php:32
HookRegistry\call
static call($hookName, $args=null)
Definition: HookRegistry.inc.php:86
Handler
Base request handler application class.
Definition: Handler.inc.php:18
ContextRequiredPolicy
Policy to deny access if a context cannot be found in the request.
Definition: ContextRequiredPolicy.inc.php:17
PreprintHandler
Handle requests for preprint functions.
Definition: PreprintHandler.inc.php:21
PreprintHandler\initialize
initialize($request, $args=array())
Definition: PreprintHandler.inc.php:64
PKPServices\get
static get($service)
Definition: PKPServices.inc.php:49