diff --git a/.env.test b/.env.test index 80137bf0..ea650f9f 100644 --- a/.env.test +++ b/.env.test @@ -26,11 +26,11 @@ REPLICAS_PORT_S7=4717 REPLICAS_PORT_S8=4718 # Credentials for CopyPatrol database -TOOLSDB_HOST=127.0.0.1 -TOOLSDB_PORT=4720 -TOOLSDB_USERNAME= -TOOLSDB_PASSWORD= -COPYPATROL_DB_NAME=s52615__copypatrol_migrate_test_02_p +TROVE_HOST=127.0.0.1 +TROVE_PORT=4721 +TROVE_USERNAME= +TROVE_PASSWORD= +COPYPATROL_DB_NAME= APP_ENABLED_LANGS=ar,en,es,fr,simple APP_NOTICE_TEXT= diff --git a/.gitignore b/.gitignore index 776a6de1..4cafc179 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,6 @@ /.env.local.php /.env.*.local /config/secrets/prod/prod.decrypt.private.php -/public/bundles/ /var/ /vendor/ ###< symfony/framework-bundle ### diff --git a/composer.json b/composer.json index 1540888c..9318312d 100644 --- a/composer.json +++ b/composer.json @@ -11,20 +11,23 @@ ], "require": { "php": ">=7.4", + "ext-apcu": "*", "ext-ctype": "*", "ext-iconv": "*", - "ext-json": "*", "ext-intl": "*", - "ext-apcu": "*", + "ext-json": "*", "doctrine/annotations": "^2.0", "doctrine/doctrine-bundle": "^2.2", + "nelmio/api-doc-bundle": "^4.20", + "nelmio/cors-bundle": "^2.4", "phpxmlrpc/phpxmlrpc": "^4.10", + "symfony/asset": "5.4.*", "symfony/dotenv": "^5.4", "symfony/expression-language": "^5.4", "symfony/flex": "^1.3.1", "symfony/framework-bundle": "^5.4", "symfony/monolog-bundle": "^3.7", - "symfony/twig-bundle": "^5.4", + "symfony/twig-bundle": "5.4.*", "symfony/webpack-encore-bundle": "^1.16", "symfony/yaml": "^5.4", "wikimedia/toolforge-bundle": "dev-trove" diff --git a/composer.lock b/composer.lock index c6b12616..878d8201 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3485a5954fe4ffdbb1f620fa1e993bf3", + "content-hash": "28856878dd2579e514651d829e6e0c7f", "packages": [ { "name": "doctrine/annotations", @@ -982,6 +982,393 @@ ], "time": "2023-10-27T15:25:26+00:00" }, + { + "name": "nelmio/api-doc-bundle", + "version": "v4.20.0", + "source": { + "type": "git", + "url": "https://github.com/nelmio/NelmioApiDocBundle.git", + "reference": "61c08f139e104db21b12832173b08fa37c22e619" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nelmio/NelmioApiDocBundle/zipball/61c08f139e104db21b12832173b08fa37c22e619", + "reference": "61c08f139e104db21b12832173b08fa37c22e619", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=7.2", + "phpdocumentor/reflection-docblock": "^3.1|^4.0|^5.0", + "psr/cache": "^1.0|^2.0|^3.0", + "psr/container": "^1.0|^2.0", + "psr/log": "^1.0|^2.0|^3.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/framework-bundle": "^5.4.24|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/options-resolver": "^5.4|^6.0|^7.0", + "symfony/property-info": "^5.4|^6.0|^7.0", + "symfony/routing": "^5.4|^6.0|^7.0", + "zircote/swagger-php": "^4.2.15" + }, + "require-dev": { + "api-platform/core": "^2.7.0|^3", + "composer/package-versions-deprecated": "1.11.99.1", + "doctrine/annotations": "^2.0", + "friendsofsymfony/rest-bundle": "^2.8|^3.0", + "jms/serializer": "^1.14|^3.0", + "jms/serializer-bundle": "^2.3|^3.0|^4.0|^5.0", + "phpunit/phpunit": "^8.5|^9.6", + "sensio/framework-extra-bundle": "^5.4|^6.0", + "symfony/asset": "^5.4|^6.0|^7.0", + "symfony/browser-kit": "^5.4|^6.0|^7.0", + "symfony/cache": "^5.4|^6.0|^7.0", + "symfony/dom-crawler": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/form": "^5.4|^6.0|^7.0", + "symfony/phpunit-bridge": "^6.4", + "symfony/property-access": "^5.4|^6.0|^7.0", + "symfony/security-csrf": "^5.4|^6.0|^7.0", + "symfony/serializer": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/templating": "^5.4|^6.0|^7.0", + "symfony/twig-bundle": "^5.4|^6.0|^7.0", + "symfony/validator": "^5.4|^6.0|^7.0", + "willdurand/hateoas-bundle": "^1.0|^2.0" + }, + "suggest": { + "api-platform/core": "For using an API oriented framework.", + "doctrine/annotations": "For using doctrine annotations", + "friendsofsymfony/rest-bundle": "For using the parameters annotations.", + "jms/serializer-bundle": "For describing your models.", + "symfony/asset": "For using the Swagger UI.", + "symfony/cache": "For using a PSR-6 compatible cache implementation with the API doc generator.", + "symfony/form": "For describing your form type models.", + "symfony/monolog-bundle": "For using a PSR-3 compatible logger implementation with the API PHP describer.", + "symfony/security-csrf": "For using csrf protection tokens in forms.", + "symfony/serializer": "For describing your models.", + "symfony/twig-bundle": "For using the Swagger UI.", + "symfony/validator": "For describing the validation constraints in your models.", + "willdurand/hateoas-bundle": "For extracting HATEOAS metadata." + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev" + } + }, + "autoload": { + "psr-4": { + "Nelmio\\ApiDocBundle\\": "" + }, + "exclude-from-classmap": [ + "Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://github.com/nelmio/NelmioApiDocBundle/contributors" + } + ], + "description": "Generates documentation for your REST API from annotations", + "keywords": [ + "api", + "doc", + "documentation", + "rest" + ], + "support": { + "issues": "https://github.com/nelmio/NelmioApiDocBundle/issues", + "source": "https://github.com/nelmio/NelmioApiDocBundle/tree/v4.20.0" + }, + "time": "2024-02-13T14:15:29+00:00" + }, + { + "name": "nelmio/cors-bundle", + "version": "2.4.0", + "source": { + "type": "git", + "url": "https://github.com/nelmio/NelmioCorsBundle.git", + "reference": "78fcdb91f76b080a1008133def9c7f613833933d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nelmio/NelmioCorsBundle/zipball/78fcdb91f76b080a1008133def9c7f613833933d", + "reference": "78fcdb91f76b080a1008133def9c7f613833933d", + "shasum": "" + }, + "require": { + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/framework-bundle": "^5.4 || ^6.0 || ^7.0" + }, + "require-dev": { + "mockery/mockery": "^1.3.6", + "symfony/phpunit-bridge": "^5.4 || ^6.0 || ^7.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Nelmio\\CorsBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nelmio", + "homepage": "http://nelm.io" + }, + { + "name": "Symfony Community", + "homepage": "https://github.com/nelmio/NelmioCorsBundle/contributors" + } + ], + "description": "Adds CORS (Cross-Origin Resource Sharing) headers support in your Symfony application", + "keywords": [ + "api", + "cors", + "crossdomain" + ], + "support": { + "issues": "https://github.com/nelmio/NelmioCorsBundle/issues", + "source": "https://github.com/nelmio/NelmioCorsBundle/tree/2.4.0" + }, + "time": "2023-11-30T16:41:19+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "5.3.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.3", + "webmozart/assert": "^1.9.1" + }, + "require-dev": { + "mockery/mockery": "~1.3.2", + "psalm/phar": "^4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" + }, + "time": "2021-10-19T17:43:47+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.8.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "fad452781b3d774e3337b0c0b245dd8e5a4455fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/fad452781b3d774e3337b0c0b245dd8e5a4455fc", + "reference": "fad452781b3d774e3337b0c0b245dd8e5a4455fc", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1.0", + "php": "^7.4 || ^8.0", + "phpdocumentor/reflection-common": "^2.0", + "phpstan/phpdoc-parser": "^1.13" + }, + "require-dev": { + "ext-tokenizer": "*", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.13.9", + "vimeo/psalm": "^4.25" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.8.0" + }, + "time": "2024-01-11T11:49:22+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.25.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/bd84b629c8de41aa2ae82c067c955e06f1b00240", + "reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^4.15", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.25.0" + }, + "time": "2024-01-04T17:06:16+00:00" + }, { "name": "phpxmlrpc/phpxmlrpc", "version": "4.10.1", @@ -3172,6 +3559,75 @@ ], "time": "2023-11-06T17:08:13+00:00" }, + { + "name": "symfony/options-resolver", + "version": "v5.4.21", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9", + "reference": "4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php73": "~1.0", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\OptionsResolver\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an improved replacement for the array_replace PHP function", + "homepage": "https://symfony.com", + "keywords": [ + "config", + "configuration", + "options" + ], + "support": { + "source": "https://github.com/symfony/options-resolver/tree/v5.4.21" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-14T08:03:56+00:00" + }, { "name": "symfony/polyfill-ctype", "version": "v1.29.0", @@ -3784,6 +4240,97 @@ ], "time": "2024-01-23T13:51:25+00:00" }, + { + "name": "symfony/property-info", + "version": "v5.4.35", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-info.git", + "reference": "d30d48f366ad2bfbf521256be85eb1c182c29198" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-info/zipball/d30d48f366ad2bfbf521256be85eb1c182c29198", + "reference": "d30d48f366ad2bfbf521256be85eb1c182c29198", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php80": "^1.16", + "symfony/string": "^5.1|^6.0" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/dependency-injection": "<4.4" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4|^2", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "phpstan/phpdoc-parser": "^1.0", + "symfony/cache": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/serializer": "^4.4|^5.0|^6.0" + }, + "suggest": { + "phpdocumentor/reflection-docblock": "To use the PHPDoc", + "psr/cache-implementation": "To cache results", + "symfony/doctrine-bridge": "To use Doctrine metadata", + "symfony/serializer": "To use Serializer metadata" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyInfo\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "dunglas@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Extracts information about PHP class' properties using metadata of popular sources", + "homepage": "https://symfony.com", + "keywords": [ + "doctrine", + "phpdoc", + "property", + "symfony", + "type", + "validator" + ], + "support": { + "source": "https://github.com/symfony/property-info/tree/v5.4.35" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-01-23T15:43:50+00:00" + }, { "name": "symfony/routing", "version": "v5.4.35", @@ -4714,6 +5261,64 @@ ], "time": "2023-11-21T18:54:41+00:00" }, + { + "name": "webmozart/assert", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": "^7.2 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.11.0" + }, + "time": "2022-06-03T18:03:27+00:00" + }, { "name": "wikimedia/toolforge-bundle", "version": "dev-trove", @@ -4774,6 +5379,87 @@ "source": "https://github.com/wikimedia/toolforgebundle" }, "time": "2024-02-13T14:59:13+00:00" + }, + { + "name": "zircote/swagger-php", + "version": "4.8.4", + "source": { + "type": "git", + "url": "https://github.com/zircote/swagger-php.git", + "reference": "bdee7f5a9216ce103ba2c953c1c43c4a3e139e4c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zircote/swagger-php/zipball/bdee7f5a9216ce103ba2c953c1c43c4a3e139e4c", + "reference": "bdee7f5a9216ce103ba2c953c1c43c4a3e139e4c", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=7.2", + "psr/log": "^1.1 || ^2.0 || ^3.0", + "symfony/deprecation-contracts": "^2 || ^3", + "symfony/finder": ">=2.2", + "symfony/yaml": ">=3.3" + }, + "require-dev": { + "composer/package-versions-deprecated": "^1.11", + "doctrine/annotations": "^1.7 || ^2.0", + "friendsofphp/php-cs-fixer": "^2.17 || ^3.47.1", + "phpstan/phpstan": "^1.6", + "phpunit/phpunit": ">=8", + "vimeo/psalm": "^4.23" + }, + "suggest": { + "doctrine/annotations": "^1.7 || ^2.0" + }, + "bin": [ + "bin/openapi" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev" + } + }, + "autoload": { + "psr-4": { + "OpenApi\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Robert Allen", + "email": "zircote@gmail.com" + }, + { + "name": "Bob Fanger", + "email": "bfanger@gmail.com", + "homepage": "https://bfanger.nl" + }, + { + "name": "Martin Rademacher", + "email": "mano@radebatz.net", + "homepage": "https://radebatz.net" + } + ], + "description": "swagger-php - Generate interactive documentation for your RESTful API using phpdoc annotations", + "homepage": "https://github.com/zircote/swagger-php/", + "keywords": [ + "api", + "json", + "rest", + "service discovery" + ], + "support": { + "issues": "https://github.com/zircote/swagger-php/issues", + "source": "https://github.com/zircote/swagger-php/tree/4.8.4" + }, + "time": "2024-02-04T21:16:47+00:00" } ], "packages-dev": [ @@ -7407,11 +8093,11 @@ "prefer-lowest": false, "platform": { "php": ">=7.4", + "ext-apcu": "*", "ext-ctype": "*", "ext-iconv": "*", - "ext-json": "*", "ext-intl": "*", - "ext-apcu": "*" + "ext-json": "*" }, "platform-dev": [], "platform-overrides": { diff --git a/config/bundles.php b/config/bundles.php index 0b4f2452..20db83d2 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -9,4 +9,6 @@ Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => [ 'all' => true ], Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => [ 'all' => true ], Symfony\Bundle\MonologBundle\MonologBundle::class => [ 'all' => true ], + Nelmio\CorsBundle\NelmioCorsBundle::class => [ 'all' => true ], + Nelmio\ApiDocBundle\NelmioApiDocBundle::class => [ 'all' => true ], ]; diff --git a/config/packages/nelmio_api_doc.yaml b/config/packages/nelmio_api_doc.yaml new file mode 100644 index 00000000..8bd78511 --- /dev/null +++ b/config/packages/nelmio_api_doc.yaml @@ -0,0 +1,100 @@ +nelmio_api_doc: + documentation: + info: + title: CopyPatrol + description: A tool that allows you to see recent Wikipedia edits that are flagged as possible copyright violations. + version: 1.0.0 + components: + parameters: + lang: + name: lang + in: path + required: true + description: The language of the project + schema: + type: string + example: en + schemas: + Case: + type: object + description: A case of a possible copyright violation + properties: + diff_id: + type: integer + description: The ID of the record in the CopyPatrol database + example: 123456 + project: + type: string + description: The name of the project + example: Wikipedia + lang: + type: string + description: The language of the project + example: en + page_namespace: + type: integer + description: The namespace ID of the page + example: 0 + page_title: + type: string + description: The title of the page + example: Foo_bar + rev_id: + type: integer + description: The revision ID of the edit + example: 123456789 + rev_parent_id: + type: integer + description: The parent revision ID of the edit. `0` for new pages + example: 0 + rev_user_text: + type: string + description: The username of the editor + example: Example User + submission_id: + type: integer + description: The UUID of the submission in the iThenticate database + example: 123e4567-e89b-12d3-a456-426614174000 + status: + type: integer + description: + The status of the case. + - `0` for unreviewed + - `1` for fixed + - `2` for no action needed + status_timestamp: + type: string + format: date-time + description: The timestamp of the last status change + example: 20210123125959 + status_user_text: + type: string|null + description: The username of the user who last changed the status + example: Example User + source_id: + type: integer + description: The ID of the source in the CopyPatrol database + example: 123456 + description: + type: string + description: The description of the URL (FIXME) + # example: "This is a possible copyright violation" + url: + type: string + description: The URL of the source + example: https://example.org + percent: + type: number + format: float + description: The similarity percentage of the diff against the source + example: 99.99 + + responses: + 404: + description: Not found + 500: + description: Internal server error + + areas: # to filter documented areas + path_patterns: + - ^/api(\.json$|\/) diff --git a/config/packages/nelmio_cors.yaml b/config/packages/nelmio_cors.yaml new file mode 100644 index 00000000..efc7454d --- /dev/null +++ b/config/packages/nelmio_cors.yaml @@ -0,0 +1,6 @@ +nelmio_cors: + paths: + '^/api/': + allow_origin: ['*'] + allow_methods: ['GET', 'PUT'] + max_age: 3600 diff --git a/config/routes/nelmio_api_doc.yaml b/config/routes/nelmio_api_doc.yaml new file mode 100644 index 00000000..7cdda2bf --- /dev/null +++ b/config/routes/nelmio_api_doc.yaml @@ -0,0 +1,10 @@ +# Expose your documentation as JSON swagger compliant +app.swagger: + path: /api.json + methods: GET + defaults: { _controller: nelmio_api_doc.controller.swagger } + +app.swagger_ui: + path: /api + methods: GET + defaults: { _controller: nelmio_api_doc.controller.swagger_ui } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 9aca671f..3598d0ca 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,22 +1,16 @@ - - - - ./tests - - - - - ./src - - - - - + + + + ./src + + + + + ./tests + + + + + diff --git a/src/Controller/ApiController.php b/src/Controller/ApiController.php new file mode 100644 index 00000000..04f34adc --- /dev/null +++ b/src/Controller/ApiController.php @@ -0,0 +1,108 @@ +getFeedActionOptions( $request, $lang ); + return new JsonResponse( $copyPatrolRepo->getPlagiarismRecords( $options ) ); + } + + /** + * Get information about a specific plagiarism case. + * @Route( + * "/api/case/{submissionId}", + * methods={"GET"}, + * name="api_case", + * requirements={"lang"="simple|\w{2}", "submissionId"="\d+|[a-z\d+\-]+"} + * ) + * @OA\Tag(name="API") + * @OA\Parameter( + * name="submissionId", + * in="path", + * description="The submission UUID of the case. For very old cases, this may an integer ID.", + * required=true, + * schema=@OA\Schema(type="uuid") + * ) + * @OA\Response( + * response=200, + * description="Returns information about a specific plagiarism case", + * @OA\JsonContent(ref="#/components/schemas/Case") + * ) + * @param CopyPatrolRepository $copyPatrolRepo + * @param string $submissionId + * @return JsonResponse + */ + public function caseApiAction( CopyPatrolRepository $copyPatrolRepo, string $submissionId ): JsonResponse { + // FIXME: make this work with the older integer submission IDs + return new JsonResponse( $copyPatrolRepo->getRecordBySubmissionId( $submissionId ) ); + } +} diff --git a/src/Controller/AppController.php b/src/Controller/AppController.php index cc1877e0..4f4a0558 100644 --- a/src/Controller/AppController.php +++ b/src/Controller/AppController.php @@ -73,22 +73,7 @@ public function feedAction( } // Filtering options that we pass to the repository. - $options = [ - 'lang' => $lang, - 'filter' => $request->query->get( 'filter', CopyPatrolRepository::FILTER_OPEN ), - 'filter_user' => $request->query->get( 'filter' ) === CopyPatrolRepository::FILTER_REVIEWED - // You can only filter by user for 'reviewed' cases. - ? $request->query->get( 'filterUser' ) - : null, - 'filter_page' => $request->query->get( 'filterPage' ) ?: null, - 'drafts' => $request->query->get( 'drafts' ) ?: false, - // This refers to the revision ID. - 'revision' => $request->query->get( 'revision' ) ?: null, - // This refers to the submission ID (aka iThenticate ID). - 'id' => $request->query->get( 'id' ) ?: null, - // Refers to submission ID, used for OFFSET. - 'last_id' => $request->get( 'lastid', 0 ), - ]; + $options = $this->getFeedActionOptions( $request, $lang ); // Everything we need for the view, including the filtering options. $ret = array_merge( $options, [ @@ -124,6 +109,30 @@ public function feedAction( return $this->render( 'feed.html.twig', $ret ); } + /** + * @param Request $request + * @param string $lang + * @return array + */ + protected function getFeedActionOptions( Request $request, string $lang ): array { + return [ + 'lang' => $lang, + 'filter' => $request->query->get( 'filter', CopyPatrolRepository::FILTER_OPEN ), + 'filter_user' => $request->query->get( 'filter' ) === CopyPatrolRepository::FILTER_REVIEWED + // You can only filter by user for 'reviewed' cases. + ? $request->query->get( 'filterUser' ) + : null, + 'filter_page' => $request->query->get( 'filterPage' ) ?: null, + 'drafts' => $request->query->get( 'drafts' ) ?: false, + // This refers to the revision ID. + 'revision' => $request->query->get( 'revision' ) ?: null, + // This refers to the submission ID (aka iThenticate ID). + 'id' => $request->query->get( 'id' ) ?: null, + // Refers to diff ID, used for OFFSET. + 'last_id' => $request->get( 'lastid', 0 ), + ]; + } + /** * Returns a Record object, with additional data such as user edit counts, and which pages are dead. * @@ -204,7 +213,7 @@ public function leaderboardAction( CopyPatrolRepository $repository, string $lan /** * @Route("/{lang}/review_add/{submissionId}/{status}", * name="add_review", - * requirements={"lang"="simple|\w{2}", "id"="\d+", "status"="\d"}, + * requirements={"lang"="simple|\w{2}", "submissionId"="\d+|[a-z\d+\-]+", "status"="\d"}, * methods={"PUT"} * ) * @param RequestStack $requestStack diff --git a/symfony.lock b/symfony.lock index 7fc611ed..133b6087 100644 --- a/symfony.lock +++ b/symfony.lock @@ -71,6 +71,31 @@ "monolog/monolog": { "version": "2.4.0" }, + "nelmio/api-doc-bundle": { + "version": "4.20", + "recipe": { + "repo": "github.com/symfony/recipes-contrib", + "branch": "main", + "version": "3.0", + "ref": "c8e0c38e1a280ab9e37587a8fa32b251d5bc1c94" + }, + "files": [ + "config/packages/nelmio_api_doc.yaml", + "config/routes/nelmio_api_doc.yaml" + ] + }, + "nelmio/cors-bundle": { + "version": "2.4", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "1.5", + "ref": "6bea22e6c564fba3a1391615cada1437d0bde39c" + }, + "files": [ + "config/packages/nelmio_cors.yaml" + ] + }, "nikic/php-parser": { "version": "v4.10.4" }, diff --git a/templates/bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig b/templates/bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig new file mode 100644 index 00000000..a55d5253 --- /dev/null +++ b/templates/bundles/NelmioApiDocBundle/SwaggerUi/index.html.twig @@ -0,0 +1,12 @@ +{% extends '@!NelmioApiDoc/SwaggerUi/index.html.twig' %} + +{% block swagger_initialization %} + +{% endblock %} + +{% block header %} +{% endblock %} diff --git a/tests/Controller/ApiControllerTest.php b/tests/Controller/ApiControllerTest.php new file mode 100644 index 00000000..d91e603d --- /dev/null +++ b/tests/Controller/ApiControllerTest.php @@ -0,0 +1,52 @@ +client = static::createClient(); + $this->controller = new ApiController(); + $this->controller->setContainer( static::getContainer() ); + $this->copyPatrolRepo = new CopyPatrolRepository( + static::getContainer()->get( 'cache.app' ), + static::getContainer()->get( 'doctrine' ) + ); + $this->request = new Request( [] ); + } + + public function testFeedApiAction(): void { + $response = $this->controller->feedApiAction( $this->request, $this->copyPatrolRepo, 'fr' ); + static::assertSame( JsonResponse::class, get_class( $response ) ); + static::assertSame( 200, $response->getStatusCode() ); + } + + public function testCaseApiAction(): void { + $response = $this->controller->caseApiAction( $this->copyPatrolRepo, '9f1acf0a-808a-457d-bf4b-800ba86d1309' ); + static::assertSame( JsonResponse::class, get_class( $response ) ); + static::assertSame( 200, $response->getStatusCode() ); + } + +}