commit 72bf365285866bb0631edb1ccd7af88d54c74395 Author: thrillfall Date: Sun Jun 27 13:19:26 2021 +0200 parse EpisodeAction message from AntennaPod persist and list with database create episodeAction list reponse (with mocked timestamp, started and total) create episodeActions with received values update existing episodeActions by unique episode link receive and store subscription changes deal with multiple subscription changes in single request split database into subdirectories only return subscription changes younger then passed parameter since parse passed timestamp parse passed timestamp for episode_actions listing only return list of urls for subscription changes align list endpoint naming schema store userId with episode actions and subscriptions return json object on application root route diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..140fada --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +vendor/* diff --git a/appinfo/info.xml b/appinfo/info.xml new file mode 100644 index 0000000..f9543c5 --- /dev/null +++ b/appinfo/info.xml @@ -0,0 +1,23 @@ + + + gpoddersync + G Podder Sync + replicate GPodder API + + 0.0.1 + agpl + Thrillfall + GPodderSync + integration + https://github.com/thrillfall + + + + + + G Podder Sync + gpoddersync.page.index + + + diff --git a/appinfo/routes.php b/appinfo/routes.php new file mode 100644 index 0000000..0178bff --- /dev/null +++ b/appinfo/routes.php @@ -0,0 +1,23 @@ + OCA\GPodderSync\Controller\PageController->index() + * + * The controller class has to be registered in the application.php file since + * it's instantiated in there + */ +return [ + 'routes' => [ + ['name' => 'episode_action#create', 'url' => '/episode_action/create', 'verb' => 'POST'], + ['name' => 'episode_action#list', 'url' => '/episode_action', 'verb' => 'GET'], + + ['name' => 'subscription_change#list', 'url' => '/subscriptions', 'verb' => 'GET'], + ['name' => 'subscription_change#create', 'url' => '/subscription_change/create', 'verb' => 'POST'], + + ['name' => 'version#index', 'url' => '/', 'verb' => 'GET'], + + + + ] +]; diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..3210e6b --- /dev/null +++ b/composer.lock @@ -0,0 +1,1561 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "2de41ce448d3f890e8d99fb0f518269c", + "packages": [], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/d56bf6102915de5702778fe20f2de3b2fe570b5b", + "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^8.0", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^0.13 || 1.0.0-alpha2", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/1.4.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2020-11-10T18:47:58+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.10.2", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/776f831124e9c62e1a2c601ecc52e776d8bb7220", + "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "replace": { + "myclabs/deep-copy": "self.version" + }, + "require-dev": { + "doctrine/collections": "^1.0", + "doctrine/common": "^2.6", + "phpunit/phpunit": "^7.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + }, + "files": [ + "src/DeepCopy/deep_copy.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.10.2" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2020-11-13T09:40:50+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.2.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/069a785b2141f5bcf49f3e353548dc1cce6df556", + "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556", + "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" + }, + "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/master" + }, + "time": "2020-09-03T19:13:55+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", + "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.0" + }, + "require-dev": { + "ext-tokenizer": "*" + }, + "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.4.0" + }, + "time": "2020-09-17T18:55:26+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.10.3", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "451c3cd1418cf640de218914901e51b064abb093" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/451c3cd1418cf640de218914901e51b064abb093", + "reference": "451c3cd1418cf640de218914901e51b064abb093", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", + "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.5 || ^3.2", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10.x-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\": "src/Prophecy" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "support": { + "issues": "https://github.com/phpspec/prophecy/issues", + "source": "https://github.com/phpspec/prophecy/tree/v1.10.3" + }, + "time": "2020-03-05T15:02:03+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "4.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef7b2f56815df854e66ceaee8ebe9393ae36a40d", + "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": "^5.6 || ^7.0", + "phpunit/php-file-iterator": "^1.3", + "phpunit/php-text-template": "^1.2", + "phpunit/php-token-stream": "^1.4.2 || ^2.0", + "sebastian/code-unit-reverse-lookup": "^1.0", + "sebastian/environment": "^1.3.2 || ^2.0", + "sebastian/version": "^1.0 || ^2.0" + }, + "require-dev": { + "ext-xdebug": "^2.1.4", + "phpunit/phpunit": "^5.7" + }, + "suggest": { + "ext-xdebug": "^2.5.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "irc": "irc://irc.freenode.net/phpunit", + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/4.0" + }, + "time": "2017-04-02T07:44:40+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "irc": "irc://irc.freenode.net/phpunit", + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/1.4.5" + }, + "time": "2017-11-27T13:52:08+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1" + }, + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/master" + }, + "time": "2017-02-26T11:10:40+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "791198a2c6254db10131eecfe8c06670700904db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db", + "reference": "791198a2c6254db10131eecfe8c06670700904db", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.2.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", + "source": "https://github.com/sebastianbergmann/php-token-stream/tree/master" + }, + "abandoned": true, + "time": "2017-11-27T05:48:46+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "5.7.27", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c", + "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "~1.3", + "php": "^5.6 || ^7.0", + "phpspec/prophecy": "^1.6.2", + "phpunit/php-code-coverage": "^4.0.4", + "phpunit/php-file-iterator": "~1.4", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "^1.0.6", + "phpunit/phpunit-mock-objects": "^3.2", + "sebastian/comparator": "^1.2.4", + "sebastian/diff": "^1.4.3", + "sebastian/environment": "^1.3.4 || ^2.0", + "sebastian/exporter": "~2.0", + "sebastian/global-state": "^1.1", + "sebastian/object-enumerator": "~2.0", + "sebastian/resource-operations": "~1.0", + "sebastian/version": "^1.0.6|^2.0.1", + "symfony/yaml": "~2.1|~3.0|~4.0" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "3.0.2" + }, + "require-dev": { + "ext-pdo": "*" + }, + "suggest": { + "ext-xdebug": "*", + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.7.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "source": "https://github.com/sebastianbergmann/phpunit/tree/5.7.27" + }, + "time": "2018-02-01T05:50:59+00:00" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "3.4.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "a23b761686d50a560cc56233b9ecf49597cc9118" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/a23b761686d50a560cc56233b9ecf49597cc9118", + "reference": "a23b761686d50a560cc56233b9ecf49597cc9118", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.6 || ^7.0", + "phpunit/php-text-template": "^1.2", + "sebastian/exporter": "^1.2 || ^2.0" + }, + "conflict": { + "phpunit/phpunit": "<5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.4" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "support": { + "irc": "irc://irc.freenode.net/phpunit", + "issues": "https://github.com/sebastianbergmann/phpunit-mock-objects/issues", + "source": "https://github.com/sebastianbergmann/phpunit-mock-objects/tree/3.4" + }, + "abandoned": true, + "time": "2017-06-30T09:13:00+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/1de8cd5c010cb153fcd68b8d0f64606f523f7619", + "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T08:15:22+00:00" + }, + { + "name": "sebastian/comparator", + "version": "1.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2 || ~2.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/1.2" + }, + "time": "2017-01-29T09:50:25+00:00" + }, + { + "name": "sebastian/diff", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/1.4" + }, + "time": "2017-05-22T07:24:03+00:00" + }, + { + "name": "sebastian/environment", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac", + "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/master" + }, + "time": "2016-11-26T07:53:53+00:00" + }, + { + "name": "sebastian/exporter", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", + "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~2.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/master" + }, + "time": "2016-11-19T08:54:04+00:00" + }, + { + "name": "sebastian/global-state", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/1.1.1" + }, + "time": "2015-10-12T03:26:01+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1311872ac850040a79c3c058bea3e22d0f09cbb7", + "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7", + "shasum": "" + }, + "require": { + "php": ">=5.6", + "sebastian/recursion-context": "~2.0" + }, + "require-dev": { + "phpunit/phpunit": "~5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/master" + }, + "time": "2017-02-18T15:18:39+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a", + "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/master" + }, + "time": "2016-11-19T07:33:16+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "shasum": "" + }, + "require": { + "php": ">=5.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/master" + }, + "time": "2015-07-28T20:34:47+00:00" + }, + { + "name": "sebastian/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/master" + }, + "time": "2016-10-03T07:35:21+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.22.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "c6c942b1ac76c82448322025e084cadc56048b4e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e", + "reference": "c6c942b1ac76c82448322025e084cadc56048b4e", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.1" + }, + "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": "2021-01-07T16:49:33+00:00" + }, + { + "name": "symfony/yaml", + "version": "v4.4.22", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "1c2fd24147961525eaefb65b11987cab75adab59" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/1c2fd24147961525eaefb65b11987cab75adab59", + "reference": "1c2fd24147961525eaefb65b11987cab75adab59", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/console": "<3.4" + }, + "require-dev": { + "symfony/console": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "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": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v4.4.22" + }, + "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": "2021-04-23T12:09:37+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.10.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "symfony/polyfill-ctype": "^1.8" + }, + "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.10.0" + }, + "time": "2021-03-09T10:59:23+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.0.0" +} diff --git a/lib/Controller/EpisodeActionController.php b/lib/Controller/EpisodeActionController.php new file mode 100644 index 0000000..9167cb0 --- /dev/null +++ b/lib/Controller/EpisodeActionController.php @@ -0,0 +1,102 @@ +episodeActionRepository = $episodeActionRepository; + $this->episodeActionWriter = $episodeActionWriter; + $this->episodeActionReader = $episodeActionReader; + $this->userId = $UserId; + } + + /** + * + * @NoAdminRequired + * @NoCSRFRequired + * + * @return Response + */ + public function create($data) { + $episodeAction = $this->episodeActionReader->fromString($data); + $episodeActionEntity = new EpisodeActionEntity(); + $episodeActionEntity->setPodcast($episodeAction->getPodcast()); + $episodeActionEntity->setEpisode($episodeAction->getEpisode()); + $episodeActionEntity->setAction($episodeAction->getAction()); + $episodeActionEntity->setPosition($episodeAction->getPosition()); + $episodeActionEntity->setStarted($episodeAction->getStarted()); + $episodeActionEntity->setTotal($episodeAction->getTotal()); + $episodeActionEntity->setTimestamp($episodeAction->getTimestamp()); + $episodeActionEntity->setUserId($this->userId); + + try { + return $this->episodeActionWriter->save($episodeActionEntity); + } catch (UniqueConstraintViolationException $ex) { + $IdEpisodeActionEntityToUpdate = $this->episodeActionRepository->findByEpisode($episodeAction->getEpisode(), $this->userId)->getId(); + $episodeActionEntity->setId($IdEpisodeActionEntityToUpdate); + return $this->episodeActionWriter->update($episodeActionEntity); + } + } + + /** + * + * @NoAdminRequired + * @NoCSRFRequired + * + * @param int $since + * @return JSONResponse + */ + public function list(int $since): JSONResponse { + $sinceDatetime = $this->createDateTimeFromTimestamp($since); + return new JSONResponse([ + "actions" => $this->episodeActionRepository->findAll($sinceDatetime, $this->userId), + "timestamp" => time() + ]); + } + + /** + * @param int|null $since + * + * @return DateTime + */ + private function createDateTimeFromTimestamp(?int $since): DateTime { + return ($since) + ? (new \DateTime)->setTimestamp($since) + : (new \DateTime('-1 week')); + } +} diff --git a/lib/Controller/SubscriptionChangeController.php b/lib/Controller/SubscriptionChangeController.php new file mode 100644 index 0000000..6be166f --- /dev/null +++ b/lib/Controller/SubscriptionChangeController.php @@ -0,0 +1,91 @@ +subscriptionChangeSaver = $subscriptionChangeSaver; + $this->subscriptionChangeRepository = $subscriptionChangeRepository; + $this->userId = $UserId; + } + + /** + * + * @NoAdminRequired + * @NoCSRFRequired + * + * @return void + */ + public function create($add, $remove) { + return $this->subscriptionChangeSaver->saveSubscriptionChanges($add, $remove, $this->userId); + } + + /** + * + * @NoAdminRequired + * @NoCSRFRequired + * + * @param int $since + * @return JSONResponse + * @throws \Exception + */ + public function list(int $since = null): JSONResponse { + $sinceDatetime = $this->createDateTimeFromTimestamp($since); + return new JSONResponse([ + "add" => $this->extractUrlList($this->subscriptionChangeRepository->findAllSubscribed($sinceDatetime, $this->userId)), + "remove" => $this->extractUrlList($this->subscriptionChangeRepository->findAllUnSubscribed($sinceDatetime, $this->userId)), + "timestamp" => time() + ]); + } + + /** + * @param int|null $since + * + * @return DateTime + */ + private function createDateTimeFromTimestamp(?int $since): DateTime { + return ($since) + ? (new \DateTime)->setTimestamp($since) + : (new \DateTime('-1 week')); + } + + /** + * @param array $allSubscribed + * + * @return mixed + */ + private function extractUrlList(array $allSubscribed): array { + return array_map(function (SubscriptionChangeEntity $subscription) { + return $subscription->getUrl(); + }, $allSubscribed); + } +} diff --git a/lib/Controller/VersionController.php b/lib/Controller/VersionController.php new file mode 100644 index 0000000..8e3d472 --- /dev/null +++ b/lib/Controller/VersionController.php @@ -0,0 +1,40 @@ +userId = $UserId; + } + + /** + * + * @NoAdminRequired + * @NoCSRFRequired + * + * @return Response + */ + public function index() { + return new JSONResponse(["version" => "0.1"]); + } + + +} diff --git a/lib/Core/EpisodeAction/EpisodeAction.php b/lib/Core/EpisodeAction/EpisodeAction.php new file mode 100644 index 0000000..2410696 --- /dev/null +++ b/lib/Core/EpisodeAction/EpisodeAction.php @@ -0,0 +1,83 @@ +podcast = $podcast; + $this->episode = $episode; + $this->action = $action; + $this->timestamp = $timestamp; + $this->started = $started; + $this->position = $position; + $this->total = $total; + } + + /** + * @return string + */ + public function getPodcast(): string { + return $this->podcast; + } + + /** + * @return string + */ + public function getEpisode(): string { + return $this->episode; + } + + /** + * @return string + */ + public function getAction(): string { + return $this->action; + } + + /** + * @return string + */ + public function getTimestamp(): string { + return $this->timestamp; + } + + /** + * @return int + */ + public function getStarted(): int { + return $this->started; + } + + /** + * @return int + */ + public function getPosition(): int { + return $this->position; + } + + /** + * @return int + */ + public function getTotal(): int { + return $this->total; + } + + +} diff --git a/lib/Core/EpisodeAction/EpisodeActionReader.php b/lib/Core/EpisodeAction/EpisodeActionReader.php new file mode 100644 index 0000000..b5e3db0 --- /dev/null +++ b/lib/Core/EpisodeAction/EpisodeActionReader.php @@ -0,0 +1,28 @@ +.*?)(\', episode=\')(?.*?)(\', action=)(?.*?)(, timestamp=)(?.*?)(, started=)(?.*?)(, position=)(?.*?)(, total=)(?.*?)}]*/', + $episodeActionString, + $matches + ); + + file_put_contents('actionreader.log', var_export($matches, true), FILE_APPEND); + + return new EpisodeAction( + $matches["podcast"], + $matches["episode"], + $matches["action"], + $matches["timestamp"], + (int)$matches["started"], + (int)$matches["position"], + (int)$matches["total"], + ); + } + +} diff --git a/lib/Core/SubscriptionChange/SubscriptionChange.php b/lib/Core/SubscriptionChange/SubscriptionChange.php new file mode 100644 index 0000000..ce0388f --- /dev/null +++ b/lib/Core/SubscriptionChange/SubscriptionChange.php @@ -0,0 +1,35 @@ +url = $url; + $this->isSubscribed = $isSubscribed; + } + + /** + * @return bool + */ + public function isSubscribed(): bool { + return $this->isSubscribed; + } + + /** + * @return string + */ + public function getUrl(): string { + return $this->url; + } + + public function __toString() : String { + return $this->url; + } +} diff --git a/lib/Core/SubscriptionChange/SubscriptionChangeRequestParser.php b/lib/Core/SubscriptionChange/SubscriptionChangeRequestParser.php new file mode 100644 index 0000000..f9aee83 --- /dev/null +++ b/lib/Core/SubscriptionChange/SubscriptionChangeRequestParser.php @@ -0,0 +1,30 @@ +subscriptionChangeReader = $subscriptionChangeReader; + } + + /** + * @param string $urlsSubscribed + * @param string $urlsUnsubscribed + * + * @return SubscriptionChange[] + */ + public function createSubscriptionChangeList(string $urlsSubscribed, string $urlsUnsubscribed): array { + $urlsToSubscribe = $this->subscriptionChangeReader->fromString($urlsSubscribed, true); + $urlsToDelete = $this->subscriptionChangeReader->fromString($urlsUnsubscribed, false); + + /** @var \OCA\GPodderSync\Core\SubscriptionChange\SubscriptionChange[] $subscriptionChanges */ + return array_merge($urlsToSubscribe, $urlsToDelete); + } +} diff --git a/lib/Core/SubscriptionChange/SubscriptionChangeSaver.php b/lib/Core/SubscriptionChange/SubscriptionChangeSaver.php new file mode 100644 index 0000000..0ce1338 --- /dev/null +++ b/lib/Core/SubscriptionChange/SubscriptionChangeSaver.php @@ -0,0 +1,60 @@ +subscriptionChangeRepository = $subscriptionChangeRepository; + $this->subscriptionChangeWriter = $subscriptionChangeWriter; + $this->subscriptionChangeRequestParser = $subscriptionChangeRequestParser; + } + + public function saveSubscriptionChanges(string $urlsSubscribed, string $urlsUnsubscribed, string $userId) : void { + $subscriptionChanges = $this->subscriptionChangeRequestParser->createSubscriptionChangeList($urlsSubscribed, $urlsUnsubscribed); + foreach ($subscriptionChanges as $urlChangedSubscriptionStatus) { + $subscriptionChangeEntity = new SubscriptionChangeEntity(); + $subscriptionChangeEntity->setUrl($urlChangedSubscriptionStatus->getUrl()); + $subscriptionChangeEntity->setSubscribed($urlChangedSubscriptionStatus->isSubscribed()); + $subscriptionChangeEntity->setUpdated((new \DateTime())->format("Y-m-d\TH:i:s")); + $subscriptionChangeEntity->setUserId($userId); + + try { + $this->subscriptionChangeWriter->create($subscriptionChangeEntity); + } catch (UniqueConstraintViolationException $ex) { + $idEpisodeActionEntityToUpdate = $this->subscriptionChangeRepository->findByUrl($subscriptionChangeEntity->getUrl(), $userId)->getId(); + $subscriptionChangeEntity->setId($idEpisodeActionEntityToUpdate); + $this->subscriptionChangeWriter->update($subscriptionChangeEntity); + } + } + } + + +} diff --git a/lib/Core/SubscriptionChange/SubscriptionChangesReader.php b/lib/Core/SubscriptionChange/SubscriptionChangesReader.php new file mode 100644 index 0000000..a6603b0 --- /dev/null +++ b/lib/Core/SubscriptionChange/SubscriptionChangesReader.php @@ -0,0 +1,28 @@ +addType('id','integer'); + } + + public function jsonSerialize() { + return [ + 'id' => $this->id, + 'podcast' => $this->podcast, + 'episode' => $this->episode, + 'action' => $this->action, + 'position' => $this->position, + 'started' => $this->started, + 'total' => $this->total, + 'timestamp' => (new \DateTime($this->timestamp))->format("Y-m-d\TH:i:s"), + ]; + } +} diff --git a/lib/Db/EpisodeAction/EpisodeActionMapper.php b/lib/Db/EpisodeAction/EpisodeActionMapper.php new file mode 100644 index 0000000..783ada6 --- /dev/null +++ b/lib/Db/EpisodeAction/EpisodeActionMapper.php @@ -0,0 +1,50 @@ +db->getQueryBuilder(); + + $qb->select('*') + ->from($this->getTableName()) + ->where( + $qb->expr()->gt('timestamp', $qb->createNamedParameter($sinceTimestamp, IQueryBuilder::PARAM_DATE)) + ) + ->andWhere( + $qb->expr()->eq('user_id', $qb->createNamedParameter($userId)) + + ); + + return $this->findEntities($qb); + } + + public function findByEpisode(string $episode, string $userId) { + $qb = $this->db->getQueryBuilder(); + + $qb->select('*') + ->from($this->getTableName()) + ->where( + $qb->expr()->eq('episode', $qb->createNamedParameter($episode)) + ) + ->andWhere( + $qb->expr()->eq('user_id', $qb->createNamedParameter($userId)) + ); + + try { + return $this->findEntity($qb); + } catch (DoesNotExistException $e) { + } catch (MultipleObjectsReturnedException $e) { + } + } +} diff --git a/lib/Db/EpisodeAction/EpisodeActionRepository.php b/lib/Db/EpisodeAction/EpisodeActionRepository.php new file mode 100644 index 0000000..2d4c247 --- /dev/null +++ b/lib/Db/EpisodeAction/EpisodeActionRepository.php @@ -0,0 +1,23 @@ +episodeActionMapper = $episodeActionMapper; + } + + public function findAll(\DateTime $sinceTimestamp, string $userId) : array { + return $this->episodeActionMapper->findAll($sinceTimestamp, $userId); + } + + public function findByEpisode(string $episode, string $userId): EpisodeActionEntity { + return $this->episodeActionMapper->findByEpisode($episode, $userId); + } +} diff --git a/lib/Db/EpisodeAction/EpisodeActionWriter.php b/lib/Db/EpisodeAction/EpisodeActionWriter.php new file mode 100644 index 0000000..6624a4c --- /dev/null +++ b/lib/Db/EpisodeAction/EpisodeActionWriter.php @@ -0,0 +1,33 @@ +episodeActionMapper = $episodeActionMapper; + } + + public function save(EpisodeActionEntity $episodeActionEntity): EpisodeActionEntity { + return $this->episodeActionMapper->insert($episodeActionEntity); + } + + public function update(EpisodeActionEntity $episodeActionEntity) { + return $this->episodeActionMapper->update($episodeActionEntity); + + } + + public function purge() { + foreach ($this->episodeActionMapper->findAll() as $entity) { + $this->episodeActionMapper->delete($entity); + } + } +} diff --git a/lib/Db/SubscriptionChange/SubscriptionChangeEntity.php b/lib/Db/SubscriptionChange/SubscriptionChangeEntity.php new file mode 100644 index 0000000..3e6d5f7 --- /dev/null +++ b/lib/Db/SubscriptionChange/SubscriptionChangeEntity.php @@ -0,0 +1,29 @@ +addType('id','integer'); + $this->addType('subscribed','boolean'); + } + + public function jsonSerialize() { + return [ + 'id' => $this->id, + 'url' => $this->url, + 'subscribed' => $this->subscribed, + 'updated' => $this->updated, + ]; + } +} diff --git a/lib/Db/SubscriptionChange/SubscriptionChangeMapper.php b/lib/Db/SubscriptionChange/SubscriptionChangeMapper.php new file mode 100644 index 0000000..bde232b --- /dev/null +++ b/lib/Db/SubscriptionChange/SubscriptionChangeMapper.php @@ -0,0 +1,69 @@ +db->getQueryBuilder(); + + $qb->select('*') + ->from($this->getTableName()) + ->where( + $qb->expr()->eq('user_id', $qb->createNamedParameter($userId)) + ); + + return $this->findEntities($qb); + } + + public function findByUrl(string $url, string $userId): SubscriptionChangeEntity { + $qb = $this->db->getQueryBuilder(); + + $qb->select('*') + ->from($this->getTableName()) + ->where( + $qb->expr()->eq('url', $qb->createNamedParameter($url)) + ) + ->andWhere( + $qb->expr()->eq('user_id', $qb->createNamedParameter($userId)) + ); + + try { + return $this->findEntity($qb); + } catch (DoesNotExistException $e) { + } catch (MultipleObjectsReturnedException $e) { + } + } + + public function remove(SubscriptionChangeEntity $subscriptionChangeEntity) { + $this->delete($subscriptionChangeEntity); + } + + public function findAllSubscriptionState(bool $subscribed, \DateTime $sinceTimestamp, string $userId) { + $qb = $this->db->getQueryBuilder(); + + $qb->select('url') + ->from($this->getTableName()) + ->where( + $qb->expr()->eq('subscribed', $qb->createNamedParameter($subscribed, IQueryBuilder::PARAM_BOOL)) + )->andWhere( + $qb->expr()->gt('updated', $qb->createNamedParameter($sinceTimestamp, IQueryBuilder::PARAM_DATE)) + ) + ->andWhere( + $qb->expr()->eq('user_id', $qb->createNamedParameter($userId)) + ); + + return $this->findEntities($qb); + } + + +} diff --git a/lib/Db/SubscriptionChange/SubscriptionChangeRepository.php b/lib/Db/SubscriptionChange/SubscriptionChangeRepository.php new file mode 100644 index 0000000..f36a65f --- /dev/null +++ b/lib/Db/SubscriptionChange/SubscriptionChangeRepository.php @@ -0,0 +1,32 @@ +subscriptionChangeMapper = $subscriptionChangeMapper; + } + + public function findAll() : array { + return $this->subscriptionChangeMapper->findAll(); + } + + public function findByUrl(string $episode, string $userId): SubscriptionChangeEntity { + return $this->subscriptionChangeMapper->findByUrl($episode, $userId); + } + + public function findAllSubscribed(\DateTime $sinceTimestamp, string $userId) { + return $this->subscriptionChangeMapper->findAllSubscriptionState(true, $sinceTimestamp, $userId); + } + + public function findAllUnSubscribed(\DateTime $sinceTimestamp, string $userId) { + return $this->subscriptionChangeMapper->findAllSubscriptionState(false, $sinceTimestamp, $userId); + } +} diff --git a/lib/Db/SubscriptionChange/SubscriptionChangeWriter.php b/lib/Db/SubscriptionChange/SubscriptionChangeWriter.php new file mode 100644 index 0000000..4542ae2 --- /dev/null +++ b/lib/Db/SubscriptionChange/SubscriptionChangeWriter.php @@ -0,0 +1,32 @@ +subscriptionChangeMapper = $subscriptionChangeMapper; + } + + + public function purge() { + foreach ($this->subscriptionChangeMapper->findAll() as $entity) { + $this->subscriptionChangeMapper->delete($entity); + } + } + + public function create(SubscriptionChangeEntity $subscriptionChangeEntity): SubscriptionChangeEntity{ + return $this->subscriptionChangeMapper->insert($subscriptionChangeEntity); + } + + public function update(SubscriptionChangeEntity $subscriptionChangeEntity): SubscriptionChangeEntity{ + return $this->subscriptionChangeMapper->update($subscriptionChangeEntity); + } +} diff --git a/lib/Migration/Version0001Date20210520063113.php b/lib/Migration/Version0001Date20210520063113.php new file mode 100644 index 0000000..1904c08 --- /dev/null +++ b/lib/Migration/Version0001Date20210520063113.php @@ -0,0 +1,59 @@ +hasTable('gpoddersync_episode_action')) { + $table = $schema->createTable('gpoddersync_episode_action'); + $table->addColumn('id', 'integer', [ + 'autoincrement' => true, + 'notnull' => true, + ]); + $table->addColumn('podcast', 'string', [ + 'notnull' => true, + 'length' => 500 + ]); + $table->addColumn('episode', 'string', [ + 'notnull' => true, + 'length' => 500, + 'unique' => true, + ]); + $table->addColumn('action', 'string', [ + 'notnull' => true, + 'length' => 5 + ]); + $table->addColumn('position', 'integer', [ + 'notnull' => true, + ]); + + $table->addColumn('started', Types::INTEGER, [ + 'notnull' => true, + ]); + $table->addColumn('total', Types::INTEGER, [ + 'notnull' => true, + ]); + $table->addColumn('timestamp', Types::DATETIME_MUTABLE, [ + 'notnull' => true, + ]); + $table->addColumn('user_id', Types::STRING, [ + 'notnull' => true, + 'length' => 200, + ]); + + $table->setPrimaryKey(['id']); + $table->addUniqueIndex(['episode', 'user_id'], 'gpoddersync_episode_user_id'); + } + return $schema; + } +} diff --git a/lib/Migration/Version0002Date20210524131313.php b/lib/Migration/Version0002Date20210524131313.php new file mode 100644 index 0000000..e92b008 --- /dev/null +++ b/lib/Migration/Version0002Date20210524131313.php @@ -0,0 +1,45 @@ +hasTable('gpoddersync_subscriptions')) { + $table = $schema->createTable('gpoddersync_subscriptions'); + $table->addColumn('id', 'integer', [ + 'autoincrement' => true, + 'notnull' => true, + ]); + $table->addColumn('url', Types::STRING, [ + 'notnull' => true, + 'length' => 500 + ]); + + $table->addColumn('subscribed', Types::BOOLEAN, [ + 'notnull' => true, + ]); + + $table->addColumn('updated', Types::DATETIME_MUTABLE, [ + 'notnull' => true, + ]); + $table->addColumn('user_id', Types::STRING, [ + 'notnull' => true, + 'length' => 200, + ]); + + $table->setPrimaryKey(['id']); + $table->addUniqueIndex(['url', "user_id"], 'subscriptions_url_user'); + + } + return $schema; + } +} diff --git a/lib/Migration/Version0003Date20210524131313.php b/lib/Migration/Version0003Date20210524131313.php new file mode 100644 index 0000000..6c7419f --- /dev/null +++ b/lib/Migration/Version0003Date20210524131313.php @@ -0,0 +1,20 @@ +dropTable('gpoddersync_subscriptions'); + $schema->dropTable('gpoddersync_episode_action'); + return $schema; + } +} diff --git a/tests/Integration/AppTest.php b/tests/Integration/AppTest.php new file mode 100644 index 0000000..2477795 --- /dev/null +++ b/tests/Integration/AppTest.php @@ -0,0 +1,29 @@ +container = $app->getContainer(); + } + + public function testAppInstalled() { + $appManager = $this->container->query('OCP\App\IAppManager'); + $this->assertTrue($appManager->isInstalled('gpoddersync')); + } + +} diff --git a/tests/Unit/Core/EpisodeAction/EpisodeActionReaderTest.php b/tests/Unit/Core/EpisodeAction/EpisodeActionReaderTest.php new file mode 100644 index 0000000..685b2be --- /dev/null +++ b/tests/Unit/Core/EpisodeAction/EpisodeActionReaderTest.php @@ -0,0 +1,23 @@ +fromString('[EpisodeAction{podcast=\'https://feeds.simplecast.com/wEl4UUJZ\', episode=\'https://chrt.fm/track/47G541/injector.simplecastaudio.com/f16c3da7-cf46-4a42-99b7-8467255c6086/episodes/e8e24c01-6157-40e8-9b5a-45d539aeb7e6/audio/128/default.mp3?aid=rss_feed&awCollectionId=f16c3da7-cf46-4a42-99b7-8467255c6086&awEpisodeId=e8e24c01-6157-40e8-9b5a-45d539aeb7e6&feed=wEl4UUJZ\', action=PLAY, timestamp=Tue May 18 23:45:11 GMT+02:00 2021, started=31, position=36, total=2474}]'); + $this->assertSame("https://feeds.simplecast.com/wEl4UUJZ", $episodeAction->getPodcast()); + $this->assertSame("https://chrt.fm/track/47G541/injector.simplecastaudio.com/f16c3da7-cf46-4a42-99b7-8467255c6086/episodes/e8e24c01-6157-40e8-9b5a-45d539aeb7e6/audio/128/default.mp3?aid=rss_feed&awCollectionId=f16c3da7-cf46-4a42-99b7-8467255c6086&awEpisodeId=e8e24c01-6157-40e8-9b5a-45d539aeb7e6&feed=wEl4UUJZ", $episodeAction->getEpisode()); + $this->assertSame("PLAY", $episodeAction->getAction()); + $this->assertSame("Tue May 18 23:45:11 GMT+02:00 2021", $episodeAction->getTimestamp()); + $this->assertSame(31, $episodeAction->getStarted()); + $this->assertSame(36, $episodeAction->getPosition()); + $this->assertSame(2474, $episodeAction->getTotal()); + + } + +} diff --git a/tests/Unit/Core/SubscriptionChange/SubscriptionChangeReaderTest.php b/tests/Unit/Core/SubscriptionChange/SubscriptionChangeReaderTest.php new file mode 100644 index 0000000..05f2295 --- /dev/null +++ b/tests/Unit/Core/SubscriptionChange/SubscriptionChangeReaderTest.php @@ -0,0 +1,23 @@ +fromString('[https://feeds.megaphone.fm/HSW8286374095]', true); + $this->assertCount(1, $subscriptionChange); + $this->assertSame("https://feeds.megaphone.fm/HSW8286374095", $subscriptionChange[0]->getUrl()); + } + + public function testCreateFromEmptyString(): void { + $reader = new SubscriptionChangesReader(); + $subscriptionChange = $reader->fromString('[]', true); + $this->assertCount(0, $subscriptionChange); + } + +} diff --git a/tests/Unit/Core/SubscriptionChange/SubscriptionChangeRequestParserTest.php b/tests/Unit/Core/SubscriptionChange/SubscriptionChangeRequestParserTest.php new file mode 100644 index 0000000..44f67e9 --- /dev/null +++ b/tests/Unit/Core/SubscriptionChange/SubscriptionChangeRequestParserTest.php @@ -0,0 +1,32 @@ +createSubscriptionChangeList('[https://feeds.simplecast.com/54nAGcIl]','[]'); + $this->assertCount(1, $subscriptionChanges); + $this->assertSame('https://feeds.simplecast.com/54nAGcIl', $subscriptionChanges[0]->getUrl()); + $this->assertTrue($subscriptionChanges[0]->isSubscribed()); + } + + public function testSubscriptionRequestWithMultipleChangesConvertsToSubscriptionChangeList() { + $subscriptionChangesParser = new SubscriptionChangeRequestParser( + new SubscriptionChangesReader(), + ); + + $subscriptionChanges = $subscriptionChangesParser->createSubscriptionChangeList( + '[https://podcastfeeds.nbcnews.com/dateline-nbc,https://feeds.megaphone.fm/ADL9840290619]', + '[]'); + $this->assertCount(2, $subscriptionChanges); + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 0000000..4e70b91 --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,19 @@ +addValidRoot(OC::$SERVERROOT . '/tests'); + +// Fix for "Autoload path not allowed: .../gpoddersync/tests/testcase.php" +\OC_App::loadApp('gpoddersync'); + +if(!class_exists('PHPUnit_Framework_TestCase')) { + require_once('PHPUnit/Autoload.php'); +} + +OC_Hook::clear(); diff --git a/vendor/autoload.php b/vendor/autoload.php new file mode 100644 index 0000000..054e99f --- /dev/null +++ b/vendor/autoload.php @@ -0,0 +1,7 @@ +