[ Mini Kiebo ]
Server: Windows NT DESKTOP-5B8S0D4 6.2 build 9200 (Windows 8 Professional Edition) i586
Path:
D:
/
Backup
/
05122024
/
htdocs
/
jurnal-kesmas
/
v1
/
lib
/
pkp
/
tools
/
[
Home
]
File: buildSwagger.php
<?php /** * @file tools/buildSwagger.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 buildSwagger * * @ingroup tools * * @brief CLI tool to compile a complete swagger.json file for hosting API * documentation. */ use APP\core\Services; use PKP\decision\DecisionType; use PKP\file\FileManager; define('APP_ROOT', dirname(__FILE__, 4)); require(APP_ROOT . '/tools/bootstrap.php'); class buildSwagger extends \PKP\cliTool\CommandLineTool { public $outputFile; public $parameters; /** * Constructor. * * @param array $argv command-line arguments (see usage) */ public function __construct($argv = []) { parent::__construct($argv); $this->outputFile = array_shift($this->argv); } /** * Print command usage information. */ public function usage() { echo "Command-line tool to compile swagger.json API definitions\n" . "Usage:\n" . "\t{$this->scriptName} [outputFile]: Compile swagger file and save to [outputFile]\n" . "\t{$this->scriptName} usage: Display usage information this tool\n"; } /** * Parse and execute the import/export task. */ public function execute() { if (empty($this->outputFile)) { $this->usage(); exit; } elseif ((file_exists($this->outputFile) && !is_writable($this->outputFile)) || (!is_writeable(dirname($this->outputFile)))) { echo "You do not have permission to write to this file.\n"; exit; } else { $source = file_get_contents(APP_ROOT . '/docs/dev/swagger-source.json'); $decisions = file_get_contents(APP_ROOT . '/docs/dev/swagger-source-decision-examples.json'); if (!$source || !$decisions) { echo 'Unable to find source files at ' . APP_ROOT . '/docs/dev/'; exit; } $locales = ['en', 'fr_CA']; $apiSchema = json_decode($source); foreach ($apiSchema->definitions as $definitionName => $definition) { // We assume a definition that is not a string does not need to be compiled // from the schema files. It has already been defined. if (!is_string($definition)) { continue; } $editDefinition = $summaryDefinition = $readDefinition = ['type' => 'object', 'properties' => []]; $entitySchema = Services::get('schema')->get($definition, true); foreach ($entitySchema->properties as $propName => $propSchema) { $editPropSchema = clone $propSchema; $readPropSchema = clone $propSchema; $summaryPropSchema = clone $propSchema; // Special handling to catch readOnly, writeOnly and apiSummary props in objects if (!empty($propSchema->{'$ref'})) { if (empty($propSchema->readOnly) || empty($propSchema->writeDisabledInApi)) { $editPropSchema->properties = $propSchema; } if (empty($propSchema->writeOnly)) { $readPropSchema->properties = $propSchema; } if (!empty($propSchema->apiSummary)) { $summaryPropSchema->properties = $propSchema; } } elseif ($propSchema->type === 'object') { $subPropsEdit = $subPropsRead = $subPropsSummary = []; foreach ($propSchema->properties as $subPropName => $subPropSchema) { if (empty($subPropSchema->readOnly) && empty($propSchema->writeDisabledInApi)) { $subPropsEdit[$subPropName] = $subPropSchema; } if (empty($subPropSchema->writeOnly)) { $subPropsRead[$subPropName] = $subPropSchema; } if (!empty($subPropSchema->apiSummary)) { $subPropsSummary[$subPropName] = $subPropSchema; } } if (!empty($propSchema->multilingual)) { $subPropsSchemaEdit = $subPropsSchemaRead = $subPropsSchemaSummary = [ 'type' => 'object', 'properties' => [], ]; foreach ($locales as $localeKey) { $subPropsSchemaEdit[$localeKey]['properties'] = $subPropsEdit; $subPropsSchemaRead[$localeKey]['properties'] = $subPropsRead; $subPropsSchemaSummary[$localeKey]['properties'] = $subPropsSummary; } } else { $subPropsSchemaEdit = $subPropsEdit; $subPropsSchemaRead = $subPropsRead; $subPropsSchemaSummary = $subPropsSummary; } if (empty($propSchema->readOnly) && empty($propSchema->writeDisabledInApi)) { $editPropSchema->properties = $subPropsSchemaEdit; } if (empty($propSchema->writeOnly)) { $readPropSchema->properties = $subPropsSchemaRead; } if (!empty($propSchema->apiSummary)) { $summaryPropSchema->properties = $subPropsSchemaSummary; } // All non-object props } else { if (!empty($propSchema->multilingual)) { if ($propSchema->type === 'array') { $subProperties = []; foreach ($locales as $localeKey) { $subProperties[$localeKey] = $propSchema->items; } if (empty($propSchema->readOnly) && empty($propSchema->writeDisabledInApi)) { $editPropSchema->properties = $subProperties; } if (empty($propSchema->writeOnly)) { $readPropSchema->properties = $subProperties; } if (!empty($propSchema->apiSummary)) { $summaryPropSchema->properties = $subProperties; } } else { if (empty($propSchema->readOnly) && empty($propSchema->writeDisabledInApi)) { $editPropSchema = ['$ref' => '#/definitions/LocaleObject']; } if (empty($propSchema->writeOnly)) { $readPropSchema = ['$ref' => '#/definitions/LocaleObject']; } if (!empty($propSchema->apiSummary)) { $summaryPropSchema = ['$ref' => '#/definitions/LocaleObject']; } } } } if (empty($propSchema->readOnly) && empty($propSchema->writeDisabledInApi)) { $editDefinition['properties'][$propName] = $editPropSchema; } if (empty($propSchema->writeOnly)) { $readDefinition['properties'][$propName] = $readPropSchema; } if (!empty($propSchema->apiSummary)) { $summaryDefinition['properties'][$propName] = $summaryPropSchema; } } if (!empty($editDefinition['properties'])) { $definitionEditableName = $definitionName . 'Editable'; ksort($editDefinition['properties']); $apiSchema->definitions->{$definitionEditableName} = $this->setEnum($editDefinition); } if (!empty($readDefinition['properties'])) { ksort($readDefinition['properties']); $apiSchema->definitions->{$definitionName} = $this->setEnum($readDefinition); } if (!empty($summaryDefinition['properties'])) { $definitionSummaryName = $definitionName . 'Summary'; ksort($summaryDefinition['properties']); $apiSchema->definitions->{$definitionSummaryName} = $this->setEnum($summaryDefinition); } } $this->addDecisionExamples($apiSchema, json_decode($decisions)); file_put_contents($this->outputFile, json_encode($apiSchema, JSON_PRETTY_PRINT)); echo "Done\n"; } } /** * Convert the `in:` validation rules to swagger's * `enum` specification */ protected function setEnum(array $definition): array { foreach ($definition['properties'] as $propName => $schema) { if (isset($schema->validation) && is_array($schema->validation)) { foreach ($schema->validation as $rule) { if (substr($rule, 0, 3) === 'in:') { $enum = explode(',', substr($rule, 3)); if ($schema->type === 'integer') { $enum = array_map('intval', $enum); } $definition['properties'][$propName]->enum = $enum; } } } } return $definition; } /** * Add the example request bodies for each decision */ protected function addDecisionExamples(stdClass $schema, stdClass $decisions): void { $examples = []; foreach ($decisions as $class => $decision) { /** @var DecisionType $object */ $object = new $class(); $value = [ 'decision' => $object->getDecision(), ]; if ($this->isDecisionInReview($object)) { $value['reviewRound'] = 123; $value['round'] = 1; } if (!empty($decision->actions)) { $value['actions'] = array_map( function (stdClass $action) { if ($action->type === 'form') { return array_merge((array) $action->data, ['id' => $action->id]); } elseif ($action->type === 'email') { return [ 'attachments' => [ [ 'name' => 'example-upload.pdf', 'temporaryFileId' => 1, 'documentType' => FileManager::DOCUMENT_TYPE_PDF ], [ 'name' => 'example-submission-file.pdf', 'submissionFileId' => 1, 'documentType' => FileManager::DOCUMENT_TYPE_PDF ], [ 'name' => 'example-library-file.pdf', 'libraryFileId' => 1, 'documentType' => FileManager::DOCUMENT_TYPE_PDF ] ], 'bcc' => 'example@pkp.sfu.ca', 'cc' => 'example@pkp.sfu.ca', 'id' => $action->id, 'locale' => 'en', 'recipients' => $action->canChangeRecipients ? [1,2] : [], 'subject' => 'Example email subject', 'body' => '<p>Example email body.</p>', ]; } throw new Exception('Unrecognized decision action type. Can not compile example request body for decision ' . $class); }, $decision->actions ?? [] ); } $examples[$class] = [ 'summary' => $object->getLabel(), 'value' => $value, ]; } $schema ->paths ->{'/submissions/{submissionId}/decisions'} ->post ->requestBody ->content ->{'application/json'} ->examples = $examples; } /** * Is the decision type in a review stage? */ protected function isDecisionInReview(DecisionType $decision): bool { return in_array($decision->getStageId(), [WORKFLOW_STAGE_ID_INTERNAL_REVIEW, WORKFLOW_STAGE_ID_EXTERNAL_REVIEW]); } } $tool = new buildSwagger($argv ?? []); $tool->execute();