diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000000000000000000000000000000000..880f0cb6f602f2b3023ef86392a23ae3d4d60a83 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +root = true + +# General +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true + +[*.{js,php,vue,scss}] +indent_style = tab +insert_final_newline = true + +[Makefile] +indent_style = tab + +[*.yml] +indent_style = space +indent_size = 2 diff --git a/.eslintrc.js b/.eslintrc.js index 937b64f687ca4ce5a7c9b33eb71fd6c0a5156789..72c27b6ed2b1f77add13bb4620aa29c41de708d4 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,5 +1,7 @@ +// SPDX-FileCopyrightText: {{ app.author_name }} <{{ app.author_mail }}> +// SPDX-License-Identifier: {{ app.license }} module.exports = { - extends: [ - '@nextcloud' - ] -}; + extends: [ + '@nextcloud', + ], +} diff --git a/.gitignore b/.gitignore index 39efdaed9788fef88ed3edc2e3ffc53aa11cf928..25851242fda3ea71887611907a5fa39836c782bd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,9 @@ .DS_Store node_modules/ +js/ npm-debug.log* yarn-debug.log* yarn-error.log* - # Editor directories and files .idea .vscode @@ -11,16 +11,11 @@ yarn-error.log* *.ntvs* *.njsproj *.sln - .marginalia - build/ coverage/ vendor/ -js/ - translationtool.phar .php-cs-fixer.cache .phpunit.result.cache junit.xml -.php-cs-fixer.dist.php diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c39c8e9944954f2cede5c61ad25c55adf1e5f6ba..bf60e189b5d8e6e014e262805ba431ac734d8b2e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,3 +1,5 @@ +variables: + TO_PACKAGE: 'appinfo l10n img lib templates js' include: - project: "e/infra/ecloud/nextcloud-apps/ci-templates" ref: main diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 0000000000000000000000000000000000000000..f7bbdd81232d70f67d284ad4822a40fa550ecf56 --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,18 @@ +getFinder() + ->ignoreVCSIgnored(true) + ->notPath('build') + ->notPath('l10n') + ->notPath('src') + ->notPath('vendor') + ->in(__DIR__); +return $config; diff --git a/appinfo/routes.php b/appinfo/routes.php index aa39f72a61b332638b6b36366653524fc5024983..2daf9af7d6af8eab7fe3e7f0c8d4ae4d07f152f3 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -1,16 +1,16 @@ [ - ['name' => 'user#set_account_data', 'url' => '/api/set_account_data', 'verb' => 'POST'], - ['name' => 'user#user_exists', 'url' => '/api/user_exists', 'verb' => 'POST'], - ['name' => 'user#set_mail_quota_usage', 'url' => '/api/set_mail_quota_usage', 'verb' => 'POST'], - ['name' => 'shop_account#set_shop_email_post_delete', 'url' => '/shop-accounts/set_shop_email_post_delete', 'verb' => 'POST' ], - ['name' => 'shop_account#set_shop_delete_preference', 'url' => '/shop-accounts/set_shop_delete_preference', 'verb' => 'POST' ], - ['name' => 'shop_account#get_order_info', 'url' => '/shop-accounts/order_info', 'verb' => 'GET'], - ['name' => 'shop_account#get_shop_user', 'url' => '/shop-accounts/user', 'verb' => 'GET'], - ['name' => 'shop_account#check_shop_email_post_delete', 'url' => '/shop-accounts/check_shop_email_post_delete', 'verb' => 'GET'], - [ - 'name' => 'user#preflighted_cors', 'url' => '/api/{path}', - 'verb' => 'OPTIONS', 'requirements' => array('path' => '.+') - ], + ['name' => 'user#set_account_data', 'url' => '/api/set_account_data', 'verb' => 'POST'], + ['name' => 'user#user_exists', 'url' => '/api/user_exists', 'verb' => 'POST'], + ['name' => 'user#set_mail_quota_usage', 'url' => '/api/set_mail_quota_usage', 'verb' => 'POST'], + ['name' => 'shop_account#set_shop_email_post_delete', 'url' => '/shop-accounts/set_shop_email_post_delete', 'verb' => 'POST' ], + ['name' => 'shop_account#set_shop_delete_preference', 'url' => '/shop-accounts/set_shop_delete_preference', 'verb' => 'POST' ], + ['name' => 'shop_account#get_order_info', 'url' => '/shop-accounts/order_info', 'verb' => 'GET'], + ['name' => 'shop_account#get_shop_user', 'url' => '/shop-accounts/user', 'verb' => 'GET'], + ['name' => 'shop_account#check_shop_email_post_delete', 'url' => '/shop-accounts/check_shop_email_post_delete', 'verb' => 'GET'], + [ + 'name' => 'user#preflighted_cors', 'url' => '/api/{path}', + 'verb' => 'OPTIONS', 'requirements' => array('path' => '.+') + ], ]]; diff --git a/babel.config.js b/babel.config.js index 7a5d71ef597c4738a0d718bb4f28290a693b8244..330f0f5695095eafa3e7e0d8631a111cb307fdc9 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,11 +1,5 @@ -module.exports = { - plugins: ['@babel/plugin-syntax-dynamic-import'], - presets: [ - [ - '@babel/preset-env', - { - modules: false - } - ] - ] -} +// SPDX-FileCopyrightText: {{ app.author_name }} <{{ app.author_mail }}> +// SPDX-License-Identifier: {{ app.license }} +const babelConfig = require('@nextcloud/babel-config') + +module.exports = babelConfig diff --git a/composer.json b/composer.json new file mode 100644 index 0000000000000000000000000000000000000000..01f45f582c344c159ab35ab4d2f0fb0825e33afa --- /dev/null +++ b/composer.json @@ -0,0 +1,10 @@ +{ + "require-dev": { + "nextcloud/coding-standard": "^1.0", + "friendsofphp/php-cs-fixer": "^3.13" + }, + "scripts": { + "cs:check": "php-cs-fixer fix --dry-run --diff", + "cs:fix": "php-cs-fixer fix" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000000000000000000000000000000000000..1e955cd4d085a6245ed9ede03f8cd1656d943644 --- /dev/null +++ b/composer.lock @@ -0,0 +1,2088 @@ +{ + "_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": "5c8676ef88653f041796c086ecdf00db", + "packages": [], + "packages-dev": [ + { + "name": "composer/pcre", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "4482b6409ca6bfc2af043a5711cd21ac3e7a8dfb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/4482b6409ca6bfc2af043a5711cd21ac3e7a8dfb", + "reference": "4482b6409ca6bfc2af043a5711cd21ac3e7a8dfb", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.3", + "phpstan/phpstan-strict-rules": "^1.1", + "symfony/phpunit-bridge": "^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/3.0.2" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-11-03T20:24:16+00:00" + }, + { + "name": "composer/semver", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9", + "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.4", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.3.2" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-04-01T19:23:25+00:00" + }, + { + "name": "composer/xdebug-handler", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "ced299686f41dce890debac69273b47ffe98a40c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ced299686f41dce890debac69273b47ffe98a40c", + "reference": "ced299686f41dce890debac69273b47ffe98a40c", + "shasum": "" + }, + "require": { + "composer/pcre": "^1 || ^2 || ^3", + "php": "^7.2.5 || ^8.0", + "psr/log": "^1 || ^2 || ^3" + }, + "require-dev": { + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-strict-rules": "^1.1", + "symfony/phpunit-bridge": "^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Composer\\XdebugHandler\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "Restarts a process without Xdebug.", + "keywords": [ + "Xdebug", + "performance" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/xdebug-handler/issues", + "source": "https://github.com/composer/xdebug-handler/tree/3.0.3" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-02-25T21:32:43+00:00" + }, + { + "name": "doctrine/annotations", + "version": "1.13.3", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "648b0343343565c4a056bfc8392201385e8d89f0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/648b0343343565c4a056bfc8392201385e8d89f0", + "reference": "648b0343343565c4a056bfc8392201385e8d89f0", + "shasum": "" + }, + "require": { + "doctrine/lexer": "1.*", + "ext-tokenizer": "*", + "php": "^7.1 || ^8.0", + "psr/cache": "^1 || ^2 || ^3" + }, + "require-dev": { + "doctrine/cache": "^1.11 || ^2.0", + "doctrine/coding-standard": "^6.0 || ^8.1", + "phpstan/phpstan": "^1.4.10 || ^1.8.0", + "phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5", + "symfony/cache": "^4.4 || ^5.2", + "vimeo/psalm": "^4.10" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "https://www.doctrine-project.org/projects/annotations.html", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "support": { + "issues": "https://github.com/doctrine/annotations/issues", + "source": "https://github.com/doctrine/annotations/tree/1.13.3" + }, + "time": "2022-07-02T10:48:51+00:00" + }, + { + "name": "doctrine/lexer", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/c268e882d4dbdd85e36e4ad69e02dc284f89d229", + "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9.0", + "phpstan/phpstan": "^1.3", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.11" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/1.2.3" + }, + "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%2Flexer", + "type": "tidelift" + } + ], + "time": "2022-02-28T11:07:21+00:00" + }, + { + "name": "friendsofphp/php-cs-fixer", + "version": "v3.13.0", + "source": { + "type": "git", + "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", + "reference": "a6232229a8309e8811dc751c28b91cb34b2943e1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/a6232229a8309e8811dc751c28b91cb34b2943e1", + "reference": "a6232229a8309e8811dc751c28b91cb34b2943e1", + "shasum": "" + }, + "require": { + "composer/semver": "^3.2", + "composer/xdebug-handler": "^3.0.3", + "doctrine/annotations": "^1.13", + "ext-json": "*", + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0", + "sebastian/diff": "^4.0", + "symfony/console": "^5.4 || ^6.0", + "symfony/event-dispatcher": "^5.4 || ^6.0", + "symfony/filesystem": "^5.4 || ^6.0", + "symfony/finder": "^5.4 || ^6.0", + "symfony/options-resolver": "^5.4 || ^6.0", + "symfony/polyfill-mbstring": "^1.23", + "symfony/polyfill-php80": "^1.25", + "symfony/polyfill-php81": "^1.25", + "symfony/process": "^5.4 || ^6.0", + "symfony/stopwatch": "^5.4 || ^6.0" + }, + "require-dev": { + "justinrainbow/json-schema": "^5.2", + "keradus/cli-executor": "^2.0", + "mikey179/vfsstream": "^1.6.10", + "php-coveralls/php-coveralls": "^2.5.2", + "php-cs-fixer/accessible-object": "^1.1", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.2.1", + "phpspec/prophecy": "^1.15", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "phpunitgoodpractices/polyfill": "^1.6", + "phpunitgoodpractices/traits": "^1.9.2", + "symfony/phpunit-bridge": "^6.0", + "symfony/yaml": "^5.4 || ^6.0" + }, + "suggest": { + "ext-dom": "For handling output formats in XML", + "ext-mbstring": "For handling non-UTF8 characters." + }, + "bin": [ + "php-cs-fixer" + ], + "type": "application", + "autoload": { + "psr-4": { + "PhpCsFixer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Dariusz RumiƄski", + "email": "dariusz.ruminski@gmail.com" + } + ], + "description": "A tool to automatically fix PHP code style", + "support": { + "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.13.0" + }, + "funding": [ + { + "url": "https://github.com/keradus", + "type": "github" + } + ], + "time": "2022-10-31T19:28:50+00:00" + }, + { + "name": "nextcloud/coding-standard", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/nextcloud/coding-standard.git", + "reference": "f3d1f9375e89c605deb1734f59a9f51ecbe80578" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nextcloud/coding-standard/zipball/f3d1f9375e89c605deb1734f59a9f51ecbe80578", + "reference": "f3d1f9375e89c605deb1734f59a9f51ecbe80578", + "shasum": "" + }, + "require": { + "friendsofphp/php-cs-fixer": "^3.2", + "php": "^7.3|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Nextcloud\\CodingStandard\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christoph Wurst", + "email": "christoph@winzerhof-wurst.at" + } + ], + "description": "Nextcloud coding standards for the php cs fixer", + "support": { + "issues": "https://github.com/nextcloud/coding-standard/issues", + "source": "https://github.com/nextcloud/coding-standard/tree/v1.0.0" + }, + "time": "2021-11-10T08:44:10+00:00" + }, + { + "name": "psr/cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/3.0.0" + }, + "time": "2021-02-03T23:26:27+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "psr/log", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.0" + }, + "time": "2021-07-14T16:46:02+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:10:38+00:00" + }, + { + "name": "symfony/console", + "version": "v6.1.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "a1282bd0c096e0bdb8800b104177e2ce404d8815" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/a1282bd0c096e0bdb8800b104177e2ce404d8815", + "reference": "a1282bd0c096e0bdb8800b104177e2ce404d8815", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/string": "^5.4|^6.0" + }, + "conflict": { + "symfony/dependency-injection": "<5.4", + "symfony/dotenv": "<5.4", + "symfony/event-dispatcher": "<5.4", + "symfony/lock": "<5.4", + "symfony/process": "<5.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/event-dispatcher": "^5.4|^6.0", + "symfony/lock": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0", + "symfony/var-dumper": "^5.4|^6.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "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": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v6.1.7" + }, + "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": "2022-10-26T21:42:49+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918", + "reference": "07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.1.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": "2022-02-25T11:15:52+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v6.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "a0449a7ad7daa0f7c0acd508259f80544ab5a347" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/a0449a7ad7daa0f7c0acd508259f80544ab5a347", + "reference": "a0449a7ad7daa0f7c0acd508259f80544ab5a347", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/event-dispatcher-contracts": "^2|^3" + }, + "conflict": { + "symfony/dependency-injection": "<5.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/error-handler": "^5.4|^6.0", + "symfony/expression-language": "^5.4|^6.0", + "symfony/http-foundation": "^5.4|^6.0", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/stopwatch": "^5.4|^6.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "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 tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v6.1.0" + }, + "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": "2022-05-05T16:51:07+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v3.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "02ff5eea2f453731cfbc6bc215e456b781480448" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/02ff5eea2f453731cfbc6bc215e456b781480448", + "reference": "02ff5eea2f453731cfbc6bc215e456b781480448", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/event-dispatcher": "^1" + }, + "suggest": { + "symfony/event-dispatcher-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.1.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": "2022-02-25T11:15:52+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v6.1.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "4d216a2beef096edf040a070117c39ca2abce307" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/4d216a2beef096edf040a070117c39ca2abce307", + "reference": "4d216a2beef096edf040a070117c39ca2abce307", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "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 basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v6.1.5" + }, + "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": "2022-09-21T20:29:40+00:00" + }, + { + "name": "symfony/finder", + "version": "v6.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "39696bff2c2970b3779a5cac7bf9f0b88fc2b709" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/39696bff2c2970b3779a5cac7bf9f0b88fc2b709", + "reference": "39696bff2c2970b3779a5cac7bf9f0b88fc2b709", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "symfony/filesystem": "^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "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": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v6.1.3" + }, + "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": "2022-07-29T07:42:06+00:00" + }, + { + "name": "symfony/options-resolver", + "version": "v6.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "a3016f5442e28386ded73c43a32a5b68586dd1c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/a3016f5442e28386ded73c43a32a5b68586dd1c4", + "reference": "a3016f5442e28386ded73c43a32a5b68586dd1c4", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "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/v6.1.0" + }, + "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": "2022-02-25T11:15:52+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", + "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "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.26.0" + }, + "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": "2022-05-24T11:49:31+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "433d05519ce6990bf3530fba6957499d327395c2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/433d05519ce6990bf3530fba6957499d327395c2", + "reference": "433d05519ce6990bf3530fba6957499d327395c2", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.26.0" + }, + "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": "2022-05-24T11:49:31+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "219aa369ceff116e673852dce47c3a41794c14bd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd", + "reference": "219aa369ceff116e673852dce47c3a41794c14bd", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0" + }, + "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": "2022-05-24T11:49:31+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0" + }, + "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": "2022-05-24T11:49:31+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace", + "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0" + }, + "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": "2022-05-10T07:21:04+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/13f6d1271c663dc5ae9fb843a8f16521db7687a1", + "reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.26.0" + }, + "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": "2022-05-24T11:49:31+00:00" + }, + { + "name": "symfony/process", + "version": "v6.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "a6506e99cfad7059b1ab5cab395854a0a0c21292" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/a6506e99cfad7059b1ab5cab395854a0a0c21292", + "reference": "a6506e99cfad7059b1ab5cab395854a0a0c21292", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "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": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v6.1.3" + }, + "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": "2022-06-27T17:24:16+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "925e713fe8fcacf6bc05e936edd8dd5441a21239" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/925e713fe8fcacf6bc05e936edd8dd5441a21239", + "reference": "925e713fe8fcacf6bc05e936edd8dd5441a21239", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^2.0" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.1.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": "2022-05-30T19:18:58+00:00" + }, + { + "name": "symfony/stopwatch", + "version": "v6.1.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/stopwatch.git", + "reference": "266636bb8f3fbdccc302491df7b3a1b9a8c238a7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/266636bb8f3fbdccc302491df7b3a1b9a8c238a7", + "reference": "266636bb8f3fbdccc302491df7b3a1b9a8c238a7", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/service-contracts": "^1|^2|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + }, + "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 a way to profile code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/stopwatch/tree/v6.1.5" + }, + "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": "2022-09-28T16:00:52+00:00" + }, + { + "name": "symfony/string", + "version": "v6.1.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "823f143370880efcbdfa2dbca946b3358c4707e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/823f143370880efcbdfa2dbca946b3358c4707e5", + "reference": "823f143370880efcbdfa2dbca946b3358c4707e5", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.0" + }, + "require-dev": { + "symfony/error-handler": "^5.4|^6.0", + "symfony/http-client": "^5.4|^6.0", + "symfony/translation-contracts": "^2.0|^3.0", + "symfony/var-exporter": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v6.1.7" + }, + "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": "2022-10-10T09:34:31+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.3.0" +} diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 7a48af8f9aa328d2d0f588f764a588783051f9ee..7b718d8bc3a49aa0b025db22302cb25e8b6dcc4a 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -26,7 +26,6 @@ declare(strict_types=1); namespace OCA\EcloudAccounts\AppInfo; - use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IRegistrationContext; @@ -37,28 +36,22 @@ use OCP\User\Events\BeforeUserDeletedEvent; use OCP\User\Events\UserChangedEvent; use OCA\EcloudAccounts\Listeners\UserChangedListener; +class Application extends App implements IBootstrap { + public const APP_ID = 'ecloud-accounts'; -class Application extends App implements IBootstrap -{ - - const APP_ID = 'ecloud-accounts'; - - public function __construct(array $urlParams = []) - { - parent::__construct(self::APP_ID, $urlParams); - } + public function __construct(array $urlParams = []) { + parent::__construct(self::APP_ID, $urlParams); + } - public function register(IRegistrationContext $context): void - { - $context->registerEventListener(BeforeUserDeletedEvent::class, BeforeUserDeletedListener::class); - $context->registerEventListener(UserChangedEvent::class, UserChangedListener::class); - } + public function register(IRegistrationContext $context): void { + $context->registerEventListener(BeforeUserDeletedEvent::class, BeforeUserDeletedListener::class); + $context->registerEventListener(UserChangedEvent::class, UserChangedListener::class); + } - public function boot(IBootContext $context): void - { - $serverContainer = $context->getServerContainer(); - $serverContainer->registerService('LDAPConnectionService', function($c) { - return new LDAPConnectionService(); - }); - } + public function boot(IBootContext $context): void { + $serverContainer = $context->getServerContainer(); + $serverContainer->registerService('LDAPConnectionService', function ($c) { + return new LDAPConnectionService(); + }); + } } diff --git a/lib/Controller/ShopAccountController.php b/lib/Controller/ShopAccountController.php index c62b56c56964118f182e4e8f4eb918409b21eaa1..78779a4baa34671b783f843d94c026d2d0d9c96b 100644 --- a/lib/Controller/ShopAccountController.php +++ b/lib/Controller/ShopAccountController.php @@ -1,4 +1,5 @@ shopAccountService = $shopAccountService; - $this->userSession = $userSession; - } - - /** - * @NoAdminRequired - */ - public function checkShopEmailPostDelete(string $shopEmailPostDelete) { - $user = $this->userSession->getUser(); - $email = $user->getEMailAddress(); - $response = new DataResponse(); - - try { - $this->shopAccountService->validateShopEmailPostDelete($shopEmailPostDelete, $email); - } - catch(Exception $e) { - $response->setStatus(400); - $response->setData(['message' => $e->getMessage()]); - return $response; - } - } - /** - * @NoAdminRequired - */ - - public function setShopEmailPostDelete(string $shopEmailPostDelete) { - $user = $this->userSession->getUser(); - $userId = $user->getUID(); - $email = $user->getEMailAddress(); - $response = new DataResponse(); - - try { - $this->shopAccountService->validateShopEmailPostDelete($shopEmailPostDelete, $email); - } - catch(Exception $e) { - $response->setStatus(400); - $response->setData(['message' => $e->getMessage()]); - return $response; - } - - $this->shopAccountService->setShopEmailPostDeletePreference($userId, $shopEmailPostDelete); - - } - - /** - * @NoAdminRequired - */ - public function setShopDeletePreference(bool $deleteShopAccount) { - $user = $this->userSession->getUser(); - $userId = $user->getUID(); - - $this->shopAccountService->setShopDeletePreference($userId, $deleteShopAccount); - } - - /** - * @NoAdminRequired - */ - public function getOrderInfo(int $userId) { - $response = new DataResponse(); - $data = ['count' => 0, 'my_orders_url' => $this->shopAccountService->getShopUrl() . '/my-account/orders']; - $orders = $this->shopAccountService->getOrders($userId); - - if($orders) { - $data['count'] = count($orders); - } - - $response->setData($data); - return $response; - } - - /** - * @NoAdminRequired - */ - public function getShopUser() { - $response = new DataResponse(); - $user = $this->userSession->getUser(); - $email = $user->getEMailAddress(); - - $shopUser = $this->shopAccountService->getUser($email); - - if(!$shopUser || !$this->shopAccountService->isUserOIDC($shopUser)) { - $response->setStatus(404); - return $response; - } - $response->setData($shopUser); - return $response; - } -} \ No newline at end of file + private $shopAccountService; + private $userSession; + + public function __construct($appName, IRequest $request, IUserSession $userSession, ShopAccountService $shopAccountService) { + parent::__construct($appName, $request); + $this->shopAccountService = $shopAccountService; + $this->userSession = $userSession; + } + + /** + * @NoAdminRequired + */ + public function checkShopEmailPostDelete(string $shopEmailPostDelete) { + $user = $this->userSession->getUser(); + $email = $user->getEMailAddress(); + $response = new DataResponse(); + + try { + $this->shopAccountService->validateShopEmailPostDelete($shopEmailPostDelete, $email); + } catch (Exception $e) { + $response->setStatus(400); + $response->setData(['message' => $e->getMessage()]); + return $response; + } + } + /** + * @NoAdminRequired + */ + + public function setShopEmailPostDelete(string $shopEmailPostDelete) { + $user = $this->userSession->getUser(); + $userId = $user->getUID(); + $email = $user->getEMailAddress(); + $response = new DataResponse(); + + try { + $this->shopAccountService->validateShopEmailPostDelete($shopEmailPostDelete, $email); + } catch (Exception $e) { + $response->setStatus(400); + $response->setData(['message' => $e->getMessage()]); + return $response; + } + + $this->shopAccountService->setShopEmailPostDeletePreference($userId, $shopEmailPostDelete); + } + + /** + * @NoAdminRequired + */ + public function setShopDeletePreference(bool $deleteShopAccount) { + $user = $this->userSession->getUser(); + $userId = $user->getUID(); + + $this->shopAccountService->setShopDeletePreference($userId, $deleteShopAccount); + } + + /** + * @NoAdminRequired + */ + public function getOrderInfo(int $userId) { + $response = new DataResponse(); + $data = ['count' => 0, 'my_orders_url' => $this->shopAccountService->getShopUrl() . '/my-account/orders']; + $orders = $this->shopAccountService->getOrders($userId); + + if ($orders) { + $data['count'] = count($orders); + } + + $response->setData($data); + return $response; + } + + /** + * @NoAdminRequired + */ + public function getShopUser() { + $response = new DataResponse(); + $user = $this->userSession->getUser(); + $email = $user->getEMailAddress(); + + $shopUser = $this->shopAccountService->getUser($email); + + if (!$shopUser || !$this->shopAccountService->isUserOIDC($shopUser)) { + $response->setStatus(404); + return $response; + } + $response->setData($shopUser); + return $response; + } +} diff --git a/lib/Controller/UserController.php b/lib/Controller/UserController.php index 8544f6bc010da13a4e7c4d63af221848db6120d2..e6bef59985dfcf5a86f4a1ec7c4f3f6df5047bf2 100644 --- a/lib/Controller/UserController.php +++ b/lib/Controller/UserController.php @@ -13,138 +13,129 @@ use OCP\AppFramework\Http\DataResponse; use OCA\EcloudAccounts\Service\UserService; use OCA\EcloudAccounts\Db\MailUsageMapper; -class UserController extends ApiController -{ - - /** @var UserService */ - private $userService; - - private $mailUsageMapper; - - private $logger; - - private $config; - - public function __construct($appName, IRequest $request, ILogger $logger, IConfig $config, UserService $userService, MailUsageMapper $mailUsageMapper) - { - parent::__construct($appName, $request); - $this->userService = $userService; - $this->mailUsageMapper = $mailUsageMapper; - $this->logger = $logger; - $this->config = $config; - } - - /** - * @CORS - * @PublicPage - * @NoCSRFRequired - */ - public function userExists(string $token, string $uid): DataResponse - { - $response = new DataResponse(); - if (!$this->checkAppCredentials($token)) { - $response->setStatus(401); - return $response; - } - - $exists = false; - - if ($this->userService->userExists($uid)) { - $exists = true; - } - - // To check for old accounts - $mailDomain = $this->config->getSystemValue('mail_domain'); - $mailDomainSuffix = !empty($mailDomain) ? '@' . $mailDomain : ''; - if (!$exists && stristr($uid, $mailDomainSuffix) === false) { - $exists = $this->userService->userExists($uid . $mailDomainSuffix); - } - - $response->setData($exists); - return $response; - } - - /** - * @CORS - * @PublicPage - * @NoCSRFRequired - */ - public function setAccountData(string $token, string $uid, string $email, string $recoveryEmail, string $hmeAlias, string $quota = '1024 MB'): DataResponse - { - $response = new DataResponse(); - - if (!$this->checkAppCredentials($token)) { - $response->setStatus(401); - return $response; - } - - if (!$this->userService->userExists($uid)) { - $response->setStatus(404); - return $response; - } - - $user = $this->userService->getUser($uid); - - if (is_null($user)) { - $response->setStatus(404); - return $response; - } - - $user->setEMailAddress($email); - $user->setQuota($quota); - - $recoveryEmailUpdated = $this->userService->setRecoveryEmail($uid, $recoveryEmail); - if (!$recoveryEmailUpdated) { - return $this->getErrorResponse($response, 'error_setting_recovery', 400); - } - $hmeAliasAdded = $this->userService->addHMEAliasInConfig($uid, $hmeAlias); - if (!$hmeAliasAdded) { - return $this->getErrorResponse($response, 'error_adding_hme_alias', 400); - } - return $response; - } - - /** - * @CORS - * @PublicPage - * @NoCSRFRequired - */ - public function setMailQuotaUsage(array $usage, string $token): DataResponse - { - $response = new DataResponse(); - if (!$this->checkAppCredentials($token)) { - $response->setStatus(401); - return $response; - } - try { - // Explicitly cast input values to integer - $usage = array_map(fn ($value) => (int) $value, $usage); - $this->updateMailQuotaUsageInPreferences($usage); - } catch (Exception $e) { - $statusCode = 500; - $errorMessage = 'error_setting_mail_quota_usage'; - $response = $this->getErrorResponse($response, $errorMessage, $statusCode); - - $this->logger->error($errorMessage . ': ' . $e->getMessage()); - } - return $response; - } - - private function updateMailQuotaUsageInPreferences(array $usage) - { - $this->mailUsageMapper->updateUsageInPreferences($usage); - } - - private function getErrorResponse(DataResponse $response, string $error, int $code) - { - $response->setStatus($code); - $response->setData(['error' => $error]); - return $response; - } - - private function checkAppCredentials(string $token): bool - { - $ecloud_accounts_secret = $this->userService->getConfigValue('secret'); - return strcmp($token, $ecloud_accounts_secret) === 0; - } +class UserController extends ApiController { + /** @var UserService */ + private $userService; + + private $mailUsageMapper; + + private $logger; + + private $config; + + public function __construct($appName, IRequest $request, ILogger $logger, IConfig $config, UserService $userService, MailUsageMapper $mailUsageMapper) { + parent::__construct($appName, $request); + $this->userService = $userService; + $this->mailUsageMapper = $mailUsageMapper; + $this->logger = $logger; + $this->config = $config; + } + + /** + * @CORS + * @PublicPage + * @NoCSRFRequired + */ + public function userExists(string $token, string $uid): DataResponse { + $response = new DataResponse(); + if (!$this->checkAppCredentials($token)) { + $response->setStatus(401); + return $response; + } + + $exists = false; + + if ($this->userService->userExists($uid)) { + $exists = true; + } + + // To check for old accounts + $mailDomain = $this->config->getSystemValue('mail_domain'); + $mailDomainSuffix = !empty($mailDomain) ? '@' . $mailDomain : ''; + if (!$exists && stristr($uid, $mailDomainSuffix) === false) { + $exists = $this->userService->userExists($uid . $mailDomainSuffix); + } + + $response->setData($exists); + return $response; + } + + /** + * @CORS + * @PublicPage + * @NoCSRFRequired + */ + public function setAccountData(string $token, string $uid, string $email, string $recoveryEmail, string $hmeAlias, string $quota = '1024 MB'): DataResponse { + $response = new DataResponse(); + + if (!$this->checkAppCredentials($token)) { + $response->setStatus(401); + return $response; + } + + if (!$this->userService->userExists($uid)) { + $response->setStatus(404); + return $response; + } + + $user = $this->userService->getUser($uid); + + if (is_null($user)) { + $response->setStatus(404); + return $response; + } + + $user->setEMailAddress($email); + $user->setQuota($quota); + + $recoveryEmailUpdated = $this->userService->setRecoveryEmail($uid, $recoveryEmail); + if (!$recoveryEmailUpdated) { + return $this->getErrorResponse($response, 'error_setting_recovery', 400); + } + $hmeAliasAdded = $this->userService->addHMEAliasInConfig($uid, $hmeAlias); + if (!$hmeAliasAdded) { + return $this->getErrorResponse($response, 'error_adding_hme_alias', 400); + } + return $response; + } + + /** + * @CORS + * @PublicPage + * @NoCSRFRequired + */ + public function setMailQuotaUsage(array $usage, string $token): DataResponse { + $response = new DataResponse(); + if (!$this->checkAppCredentials($token)) { + $response->setStatus(401); + return $response; + } + try { + // Explicitly cast input values to integer + $usage = array_map(fn ($value) => (int) $value, $usage); + $this->updateMailQuotaUsageInPreferences($usage); + } catch (Exception $e) { + $statusCode = 500; + $errorMessage = 'error_setting_mail_quota_usage'; + $response = $this->getErrorResponse($response, $errorMessage, $statusCode); + + $this->logger->error($errorMessage . ': ' . $e->getMessage()); + } + return $response; + } + + private function updateMailQuotaUsageInPreferences(array $usage) { + $this->mailUsageMapper->updateUsageInPreferences($usage); + } + + private function getErrorResponse(DataResponse $response, string $error, int $code) { + $response->setStatus($code); + $response->setData(['error' => $error]); + return $response; + } + + private function checkAppCredentials(string $token): bool { + $ecloud_accounts_secret = $this->userService->getConfigValue('secret'); + return strcmp($token, $ecloud_accounts_secret) === 0; + } } diff --git a/lib/Db/MailUsageMapper.php b/lib/Db/MailUsageMapper.php index abc5a991e1ea2672d5db711abd0e79ba0e39cc89..649cda5ef5a52fefe71660a1583765555088f2ea 100644 --- a/lib/Db/MailUsageMapper.php +++ b/lib/Db/MailUsageMapper.php @@ -7,46 +7,42 @@ use OCP\IDBConnection; use OCP\IConfig; use OCP\ILogger; -class MailUsageMapper -{ - private $db; - private $config; - private $logger; - - public function __construct(IDBConnection $db, IConfig $config, ILogger $logger) - { - $this->db = $db; - $this->config = $config; - $this->logger = $logger; - } - - public function updateUsageInPreferences(array $usage = []) - { - try { - if (empty($usage)) { - return; - } - - $dbTablePrefix = $this->config->getSystemValue('dbtableprefix', ''); - $params = []; - $preferencesTable = $dbTablePrefix . 'preferences'; - $query = 'INSERT INTO ' . $preferencesTable . ' (userid, appid, configkey, configvalue) VALUES '; - - // Add values to the insert query and params array - foreach ($usage as $username => $usedSpace) { - $query .= ' (?, "ecloud-accounts", "mailQuotaUsage", ?),'; - $params[] = $username; - $params[] = $usedSpace; - } - - // Remove the dangling comma at the end - $query = rtrim($query, ','); - // Update only configvalue in case entry already exists - $query .= ' ON DUPLICATE KEY UPDATE configvalue = VALUES(configvalue);'; - $this->db->executeQuery($query, $params); - - } catch (Exception $e) { - $this->logger->error('Error updating mailbox usage! ' . $e->getMessage()); - } - } +class MailUsageMapper { + private $db; + private $config; + private $logger; + + public function __construct(IDBConnection $db, IConfig $config, ILogger $logger) { + $this->db = $db; + $this->config = $config; + $this->logger = $logger; + } + + public function updateUsageInPreferences(array $usage = []) { + try { + if (empty($usage)) { + return; + } + + $dbTablePrefix = $this->config->getSystemValue('dbtableprefix', ''); + $params = []; + $preferencesTable = $dbTablePrefix . 'preferences'; + $query = 'INSERT INTO ' . $preferencesTable . ' (userid, appid, configkey, configvalue) VALUES '; + + // Add values to the insert query and params array + foreach ($usage as $username => $usedSpace) { + $query .= ' (?, "ecloud-accounts", "mailQuotaUsage", ?),'; + $params[] = $username; + $params[] = $usedSpace; + } + + // Remove the dangling comma at the end + $query = rtrim($query, ','); + // Update only configvalue in case entry already exists + $query .= ' ON DUPLICATE KEY UPDATE configvalue = VALUES(configvalue);'; + $this->db->executeQuery($query, $params); + } catch (Exception $e) { + $this->logger->error('Error updating mailbox usage! ' . $e->getMessage()); + } + } } diff --git a/lib/Db/MailboxMapper.php b/lib/Db/MailboxMapper.php index b1d188872fc212e0942d1db11cd59201c0414353..9d1104e18a3dec2b70bf46cf8a400d4c89195438 100644 --- a/lib/Db/MailboxMapper.php +++ b/lib/Db/MailboxMapper.php @@ -8,74 +8,68 @@ use OCA\EcloudAccounts\Exception\DbConnectionParamsException; use Doctrine\DBAL\DriverManager; use Throwable; -class MailboxMapper -{ - private $config; - private $conn; - private $logger; +class MailboxMapper { + private $config; + private $conn; + private $logger; - public function __construct(IConfig $config, ILogger $logger) - { - $this->config = $config; - $this->logger = $logger; - $this->initConnection(); - } + public function __construct(IConfig $config, ILogger $logger) { + $this->config = $config; + $this->logger = $logger; + $this->initConnection(); + } - private function initConnection() - { - try { - $params = $this->getConnectionParams(); - $this->conn = DriverManager::getConnection($params); - } catch (Throwable $e) { - $this->logger->info('Error connecting to SQL raw backend: ' . $e->getMessage()); - } - } + private function initConnection() { + try { + $params = $this->getConnectionParams(); + $this->conn = DriverManager::getConnection($params); + } catch (Throwable $e) { + $this->logger->info('Error connecting to SQL raw backend: ' . $e->getMessage()); + } + } - private function isDbConfigValid($config) : bool - { - if (!$config || !is_array($config)) { - return false; - } - return isset($config['db_name']) - && isset($config['mariadb_charset']) - && isset($config['db_user']) - && isset($config['db_password']) - && isset($config['db_host']) - && isset($config['db_port']) ; - } + private function isDbConfigValid($config) : bool { + if (!$config || !is_array($config)) { + return false; + } + return isset($config['db_name']) + && isset($config['mariadb_charset']) + && isset($config['db_user']) + && isset($config['db_password']) + && isset($config['db_host']) + && isset($config['db_port']) ; + } - private function getConnectionParams() - { - $config = $this->config->getSystemValue('user_backend_sql_raw'); - - if (!$this->isDbConfigValid($config)) { - throw new DbConnectionParamsException('Invalid SQL raw configuration!'); - } + private function getConnectionParams() { + $config = $this->config->getSystemValue('user_backend_sql_raw'); + + if (!$this->isDbConfigValid($config)) { + throw new DbConnectionParamsException('Invalid SQL raw configuration!'); + } - $params = [ - 'dbname' => $config['db_name'], - 'charset' => $config['mariadb_charset'], - 'user' => $config['db_user'], - 'password' => $config['db_password'], - 'host' => $config['db_host'], - 'port' => $config['db_port'], - 'driver' => 'pdo_mysql' - ]; - return $params; - } + $params = [ + 'dbname' => $config['db_name'], + 'charset' => $config['mariadb_charset'], + 'user' => $config['db_user'], + 'password' => $config['db_password'], + 'host' => $config['db_host'], + 'port' => $config['db_port'], + 'driver' => 'pdo_mysql' + ]; + return $params; + } - public function updateMailboxQuota(string $username, int $quotaInMb) - { - try { - $qb = $this->conn->createQueryBuilder(); - $qb->update('mailbox', 'm') - ->set('m.quota', $quotaInMb) - ->where('m.username = :username') - ->setParameter('username', $username); + public function updateMailboxQuota(string $username, int $quotaInMb) { + try { + $qb = $this->conn->createQueryBuilder(); + $qb->update('mailbox', 'm') + ->set('m.quota', $quotaInMb) + ->where('m.username = :username') + ->setParameter('username', $username); - $qb->execute(); - } catch (Exception $e) { - $this->logger->error('Error setting mailbox quota of user ' . $username . ' to ' . strval($quotaInMb) . ': ' . $e->getMessage()); - } - } + $qb->execute(); + } catch (Exception $e) { + $this->logger->error('Error setting mailbox quota of user ' . $username . ' to ' . strval($quotaInMb) . ': ' . $e->getMessage()); + } + } } diff --git a/lib/Exception/DbConnectionParamsException.php b/lib/Exception/DbConnectionParamsException.php index 059f8c101fde259447680a445eda445d1b5dab2b..705b27ba04133f4c3c2a6f338e9eb13754547d4b 100644 --- a/lib/Exception/DbConnectionParamsException.php +++ b/lib/Exception/DbConnectionParamsException.php @@ -2,10 +2,8 @@ namespace OCA\EcloudAccounts\Exception; -class DbConnectionParamsException extends \Exception -{ - public function __construct($message = NULL, $code = 0) - { - parent::__construct($message, $code); - } +class DbConnectionParamsException extends \Exception { + public function __construct($message = null, $code = 0) { + parent::__construct($message, $code); + } } diff --git a/lib/Listeners/BeforeUserDeletedListener.php b/lib/Listeners/BeforeUserDeletedListener.php index e383b52fbb4d4a3de85d42efd9a70340b517c795..9b87f22a45dd35f97556194d84da2f66885696dc 100644 --- a/lib/Listeners/BeforeUserDeletedListener.php +++ b/lib/Listeners/BeforeUserDeletedListener.php @@ -5,8 +5,6 @@ declare(strict_types=1); namespace OCA\EcloudAccounts\Listeners; use Exception; -use Curl; -use OCA\EcloudAccounts\AppInfo\Application; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; use OCP\ILogger; @@ -16,97 +14,89 @@ use OCA\EcloudAccounts\Service\LDAPConnectionService; use OCA\EcloudAccounts\Service\ShopAccountService; use OCA\EcloudAccounts\Service\UserService; - -class BeforeUserDeletedListener implements IEventListener -{ - private $logger; - private $config; - private $LDAPConnectionService; - private $shopAccountService; - private $userService; - - public function __construct(ILogger $logger, IConfig $config, LDAPConnectionService $LDAPConnectionService, UserService $userService, ShopAccountService $shopAccountService) - { - $this->logger = $logger; - $this->config = $config; - $this->LDAPConnectionService = $LDAPConnectionService; - $this->shopAccountService = $shopAccountService; - $this->userService = $userService; - } - - - public function handle(Event $event): void - { - if (!($event instanceof BeforeUserDeletedEvent)) { - return; - } - - $user = $event->getUser(); - $email = $user->getEMailAddress(); - $uid = $user->getUID(); - $isUserOnLDAP = $this->LDAPConnectionService->isUserOnLDAPBackend($user); - - $this->logger->info("PostDelete user {user}", array('user' => $uid)); - $this->userService->ecloudDelete( - $uid, - $this->config->getSystemValue('e_welcome_domain'), - $this->config->getSystemValue('e_welcome_secret'), - $email, - $isUserOnLDAP - ); - - try { - if ($this->LDAPConnectionService->isLDAPEnabled() && $isUserOnLDAP) { - $conn = $this->LDAPConnectionService->getLDAPConnection(); - $this->deleteAliasEntries($conn, $email); - $this->LDAPConnectionService->closeLDAPConnection($conn); - } - } catch (Exception $e) { - $this->logger->error('Error deleting aliases for user '. $uid . ' :' . $e->getMessage()); - } - - $deleteShopAccount = $this->shopAccountService->getShopDeletePreference($uid); - $shopUser = $this->shopAccountService->getUser($email); - - if($shopUser && $this->shopAccountService->isUserOIDC($shopUser)) { - if($deleteShopAccount) { - $this->shopAccountService->deleteUser($shopUser['id']); - } - else { - $newEmail = $this->shopAccountService->getShopEmailPostDeletePreference($uid); - $newEmail = $this->shopAccountService->updateUserEmailAndEmptyOIDC($shopUser['id'], $newEmail); - } - } - } - - private function deleteAliasEntries($conn, string $email) - { - $aliasBaseDn = getenv('LDAP_ALIASES_BASE_DN'); - $aliasDns = $this->getAliasEntries($conn, $aliasBaseDn, $email); - foreach ($aliasDns as $aliasDn) { - $deleted = ldap_delete($conn, $aliasDn); - if (!$deleted) { - $this->logger->error('Deleting alias ' . $aliasDn . ' for email ' . $email . ' failed'); - } - } - } - - private function getAliasEntries($conn, string $aliasBaseDn, string $email) : array - { - $filter = "(mailAddress=$email)"; - $aliasEntries = ldap_search($conn, $aliasBaseDn, $filter); - if (!$aliasEntries) { - return []; - } - - $aliasEntries = ldap_get_entries($conn, $aliasEntries); - $aliasEntries = array_filter($aliasEntries, fn ($entry) => is_array($entry)); - $aliasEntries = array_map( - fn ($entry) => $entry['dn'], - $aliasEntries - ); - - return $aliasEntries; - } - +class BeforeUserDeletedListener implements IEventListener { + private $logger; + private $config; + private $LDAPConnectionService; + private $shopAccountService; + private $userService; + + public function __construct(ILogger $logger, IConfig $config, LDAPConnectionService $LDAPConnectionService, UserService $userService, ShopAccountService $shopAccountService) { + $this->logger = $logger; + $this->config = $config; + $this->LDAPConnectionService = $LDAPConnectionService; + $this->shopAccountService = $shopAccountService; + $this->userService = $userService; + } + + + public function handle(Event $event): void { + if (!($event instanceof BeforeUserDeletedEvent)) { + return; + } + + $user = $event->getUser(); + $email = $user->getEMailAddress(); + $uid = $user->getUID(); + $isUserOnLDAP = $this->LDAPConnectionService->isUserOnLDAPBackend($user); + + $this->logger->info("PostDelete user {user}", array('user' => $uid)); + $this->userService->ecloudDelete( + $uid, + $this->config->getSystemValue('e_welcome_domain'), + $this->config->getSystemValue('e_welcome_secret'), + $email, + $isUserOnLDAP + ); + + try { + if ($this->LDAPConnectionService->isLDAPEnabled() && $isUserOnLDAP) { + $conn = $this->LDAPConnectionService->getLDAPConnection(); + $this->deleteAliasEntries($conn, $email); + $this->LDAPConnectionService->closeLDAPConnection($conn); + } + } catch (Exception $e) { + $this->logger->error('Error deleting aliases for user '. $uid . ' :' . $e->getMessage()); + } + + $deleteShopAccount = $this->shopAccountService->getShopDeletePreference($uid); + $shopUser = $this->shopAccountService->getUser($email); + + if ($shopUser && $this->shopAccountService->isUserOIDC($shopUser)) { + if ($deleteShopAccount) { + $this->shopAccountService->deleteUser($shopUser['id']); + } else { + $newEmail = $this->shopAccountService->getShopEmailPostDeletePreference($uid); + $newEmail = $this->shopAccountService->updateUserEmailAndEmptyOIDC($shopUser['id'], $newEmail); + } + } + } + + private function deleteAliasEntries($conn, string $email) { + $aliasBaseDn = getenv('LDAP_ALIASES_BASE_DN'); + $aliasDns = $this->getAliasEntries($conn, $aliasBaseDn, $email); + foreach ($aliasDns as $aliasDn) { + $deleted = ldap_delete($conn, $aliasDn); + if (!$deleted) { + $this->logger->error('Deleting alias ' . $aliasDn . ' for email ' . $email . ' failed'); + } + } + } + + private function getAliasEntries($conn, string $aliasBaseDn, string $email) : array { + $filter = "(mailAddress=$email)"; + $aliasEntries = ldap_search($conn, $aliasBaseDn, $filter); + if (!$aliasEntries) { + return []; + } + + $aliasEntries = ldap_get_entries($conn, $aliasEntries); + $aliasEntries = array_filter($aliasEntries, fn ($entry) => is_array($entry)); + $aliasEntries = array_map( + fn ($entry) => $entry['dn'], + $aliasEntries + ); + + return $aliasEntries; + } } diff --git a/lib/Listeners/UserChangedListener.php b/lib/Listeners/UserChangedListener.php index d6942f61c778fbaa9ec488ff4e5c5230d4943115..a9eeb81cc3eeb8c55fd07a00f31e352d476003d1 100644 --- a/lib/Listeners/UserChangedListener.php +++ b/lib/Listeners/UserChangedListener.php @@ -13,83 +13,78 @@ use OCP\User\Events\UserChangedEvent; use OCA\EcloudAccounts\Db\MailboxMapper; use OCA\EcloudAccounts\Service\LDAPConnectionService; -class UserChangedListener implements IEventListener -{ - private const QUOTA_FEATURE = 'quota'; - - private const RECOVERY_EMAIL_FEATURE = 'recovery-email'; - - private $util; - - private $logger; - - private $ldapConnectionService; - - private $mailboxMapper; - - public function __construct(Util $util, LDAPConnectionService $LDAPConnectionService, ILogger $logger, MailboxMapper $mailboxMapper) - { - $this->util = $util; - $this->ldapConnectionService = $LDAPConnectionService; - $this->mailboxMapper = $mailboxMapper; - $this->logger = $logger; - } - - public function handle(Event $event): void - { - if (!($event instanceof UserChangedEvent)) { - return; - } - - $feature = $event->getFeature(); - $user = $event->getUser(); - $username = $user->getUID(); - - if ($feature === self::QUOTA_FEATURE) { - $updatedQuota = $event->getValue(); - $quotaInBytes = (int) $this->util->computerFileSize($updatedQuota); - $backend = $user->getBackend()->getBackendName(); - - $this->updateQuota($username, $backend, $quotaInBytes); - } - - if ($feature === self::RECOVERY_EMAIL_FEATURE) { - $recoveryEmail = $event->getValue(); - $recoveryEmailAttribute = [ - 'recoveryMailAddress' => $recoveryEmail - ]; - - $this->updateAttributesInLDAP($username, $recoveryEmailAttribute); - } - } - - private function updateQuota(string $username, string $backend, int $quotaInBytes) - { - try { - if ($backend === 'SQL raw') { - $this->mailboxMapper->updateMailboxQuota($username, $quotaInBytes); - } - if ($backend === 'LDAP') { - $quotaAttribute = [ - 'quota' => $quotaInBytes - ]; - $this->updateAttributesInLDAP($username, $quotaAttribute); - } - } catch (Exception $e) { - $this->logger->error("Error setting quota for user $username " . $e->getMessage()); - } - } - - private function updateAttributesInLDAP(string $username, array $attributes) - { - if ($this->ldapConnectionService->isLDAPEnabled()) { - $conn = $this->ldapConnectionService->getLDAPConnection(); - $userDn = $this->ldapConnectionService->username2dn($username); - - if (!ldap_modify($conn, $userDn, $attributes)) { - throw new Exception('Could not modify user entry at LDAP server!'); - } - $this->ldapConnectionService->closeLDAPConnection($conn); - } - } +class UserChangedListener implements IEventListener { + private const QUOTA_FEATURE = 'quota'; + + private const RECOVERY_EMAIL_FEATURE = 'recovery-email'; + + private $util; + + private $logger; + + private $ldapConnectionService; + + private $mailboxMapper; + + public function __construct(Util $util, LDAPConnectionService $LDAPConnectionService, ILogger $logger, MailboxMapper $mailboxMapper) { + $this->util = $util; + $this->ldapConnectionService = $LDAPConnectionService; + $this->mailboxMapper = $mailboxMapper; + $this->logger = $logger; + } + + public function handle(Event $event): void { + if (!($event instanceof UserChangedEvent)) { + return; + } + + $feature = $event->getFeature(); + $user = $event->getUser(); + $username = $user->getUID(); + + if ($feature === self::QUOTA_FEATURE) { + $updatedQuota = $event->getValue(); + $quotaInBytes = (int) $this->util->computerFileSize($updatedQuota); + $backend = $user->getBackend()->getBackendName(); + + $this->updateQuota($username, $backend, $quotaInBytes); + } + + if ($feature === self::RECOVERY_EMAIL_FEATURE) { + $recoveryEmail = $event->getValue(); + $recoveryEmailAttribute = [ + 'recoveryMailAddress' => $recoveryEmail + ]; + + $this->updateAttributesInLDAP($username, $recoveryEmailAttribute); + } + } + + private function updateQuota(string $username, string $backend, int $quotaInBytes) { + try { + if ($backend === 'SQL raw') { + $this->mailboxMapper->updateMailboxQuota($username, $quotaInBytes); + } + if ($backend === 'LDAP') { + $quotaAttribute = [ + 'quota' => $quotaInBytes + ]; + $this->updateAttributesInLDAP($username, $quotaAttribute); + } + } catch (Exception $e) { + $this->logger->error("Error setting quota for user $username " . $e->getMessage()); + } + } + + private function updateAttributesInLDAP(string $username, array $attributes) { + if ($this->ldapConnectionService->isLDAPEnabled()) { + $conn = $this->ldapConnectionService->getLDAPConnection(); + $userDn = $this->ldapConnectionService->username2dn($username); + + if (!ldap_modify($conn, $userDn, $attributes)) { + throw new Exception('Could not modify user entry at LDAP server!'); + } + $this->ldapConnectionService->closeLDAPConnection($conn); + } + } } diff --git a/lib/Service/CurlService.php b/lib/Service/CurlService.php index 1faebc0db75ab8cbe281bb34ee7e2de13ede701d..d7a477fc51e251c3ff991f4f090f324963c7c812 100644 --- a/lib/Service/CurlService.php +++ b/lib/Service/CurlService.php @@ -10,97 +10,94 @@ declare(strict_types=1); namespace OCA\EcloudAccounts\Service; + use Exception; -class CurlService -{ - /** - * GET alias for request method - * - * @param $url - * @param array $params - * @param array $headers - * @param array $userOptions - * @return mixed - */ - public function get($url, $params = array(), $headers = array(), $userOptions = array()) - { - return $this->request('GET', $url, $params, $headers, $userOptions); - } +class CurlService { + /** + * GET alias for request method + * + * @param $url + * @param array $params + * @param array $headers + * @param array $userOptions + * @return mixed + */ + public function get($url, $params = array(), $headers = array(), $userOptions = array()) { + return $this->request('GET', $url, $params, $headers, $userOptions); + } - /** - * POST alis for request method - * - * @param $url - * @param array $params - * @param array $headers - * @param array $userOptions - * @return mixed - */ - public function post($url, $params = array(), $headers = array(), $userOptions = array()) - { - return $this->request('POST', $url, $params, $headers, $userOptions); - } + /** + * POST alis for request method + * + * @param $url + * @param array $params + * @param array $headers + * @param array $userOptions + * @return mixed + */ + public function post($url, $params = array(), $headers = array(), $userOptions = array()) { + return $this->request('POST', $url, $params, $headers, $userOptions); + } - public function delete($url, $params = [], $headers = [], $userOptions = []) { - return $this->request('DELETE', $url, $params, $headers, $userOptions); - } + public function delete($url, $params = [], $headers = [], $userOptions = []) { + return $this->request('DELETE', $url, $params, $headers, $userOptions); + } - /** - * Curl run request - * - * @param $method - * @param string $url - * @param array $params - * @param array $headers - * @param array $userOptions - * @return mixed - * @throws Exception - */ - private function request($method, $url, $params = array(), $headers = array(), $userOptions = array()) - { - $ch = curl_init(); - $method = strtoupper($method); - $options = array( - CURLOPT_RETURNTRANSFER => true, - CURLOPT_HTTPHEADER => $headers - ); - array_merge($options, $userOptions); - switch ($method) { - case 'GET': - if ($params) { - $url = $url . '?' . http_build_query($params); - } - break; - case 'POST': - $options[CURLOPT_POST] = true; - $options[CURLOPT_POSTFIELDS] = $params; - break; - case 'DELETE': - $options[CURLOPT_CUSTOMREQUEST] = "DELETE"; - if ($params) { - $url = $url . '?' . http_build_query($params); - } - break; - default: - throw new Exception('Unsuported method.'); - break; - } - $options[CURLOPT_URL] = $url; + /** + * Curl run request + * + * @param $method + * @param string $url + * @param array $params + * @param array $headers + * @param array $userOptions + * @return mixed + * @throws Exception + */ + private function request($method, $url, $params = array(), $headers = array(), $userOptions = array()) { + $ch = curl_init(); + $method = strtoupper($method); + $options = array( + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => $headers + ); + array_merge($options, $userOptions); + switch ($method) { + case 'GET': + if ($params) { + $url = $url . '?' . http_build_query($params); + } + break; + case 'POST': + $options[CURLOPT_POST] = true; + $options[CURLOPT_POSTFIELDS] = $params; + break; + case 'DELETE': + $options[CURLOPT_CUSTOMREQUEST] = "DELETE"; + if ($params) { + $url = $url . '?' . http_build_query($params); + } + break; + default: + throw new Exception('Unsuported method.'); + break; + } + $options[CURLOPT_URL] = $url; - curl_setopt_array($ch, $options); + curl_setopt_array($ch, $options); - $response = curl_exec($ch); + $response = curl_exec($ch); - if ($errno = curl_errno($ch)) { - var_dump($errno); - $errorMessage = curl_strerror($errno); - throw new Exception("Curl error $errno - $errorMessage"); - } + if ($errno = curl_errno($ch)) { + var_dump($errno); + $errorMessage = curl_strerror($errno); + throw new Exception("Curl error $errno - $errorMessage"); + } - curl_close($ch); + curl_close($ch); - return $response; - } + return $response; + } } diff --git a/lib/Service/LDAPConnectionService.php b/lib/Service/LDAPConnectionService.php index 650313bc52bc2a2d6039a75447754636a76fa995..a45024e6dc9591868f7e7691c85b18cda4f14f0e 100644 --- a/lib/Service/LDAPConnectionService.php +++ b/lib/Service/LDAPConnectionService.php @@ -7,98 +7,90 @@ namespace OCA\EcloudAccounts\Service; use Exception; use OCP\IUserManager; -class LDAPConnectionService -{ - - /** @var IUserManager */ - private $userManager; - - private $configuration; - - private $ldapEnabled; - - private $access; - - public function __construct(IUserManager $userManager) - { - $this->userManager = $userManager; - $this->getConfigurationFromBackend(); - } - - - private function getConfigurationFromBackend() - { - // We don't actually need user id to get access from backend - $uid = ''; - $backends = $this->userManager->getBackends(); - foreach ($backends as $backend) { - if ($backend->getBackendName() === 'LDAP') { - $this->access = $backend->getLDAPAccess($uid); - $connection = $this->access->getConnection(); - $configuration = $connection->getConfiguration(); - - if ($configuration['ldap_configuration_active']) { - $this->ldapEnabled = true; - $this->configuration = $configuration; - break; - } - } - } - } - - public function isUserOnLDAPBackend($user) { - $backend = $user->getBackend(); - return $backend->getBackendName() === 'LDAP'; - } - - public function isLDAPEnabled() : bool { - return $this->ldapEnabled; - } - - public function username2dn(string $username) { - return $this->access->username2dn($username); - } - - - public function getUserBaseDn() : string - { - if (isset($this->configuration['ldap_base_users'])) { - return $this->configuration['ldap_base_users']; - } - throw new Exception('User Base Dn not set!'); - } - - public function getLDAPConnection() - { - if(!$this->ldapEnabled) { - throw new Exception('LDAP backend is not enabled'); - } - - $adminDn = $this->configuration['ldap_dn']; - $adminPassword = $this->configuration['ldap_agent_password']; - $host = $this->configuration['ldap_host']; - $port = intval($this->configuration['ldap_port']); - - $conn = ldap_connect($host, $port); - ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION, 3); - ldap_bind($conn, $adminDn, $adminPassword); - - if (!$conn) { - throw new Exception('Could not connect to LDAP server!'); - } - return $conn; - } - - public function closeLDAPConnection($conn) : void - { - ldap_close($conn); - } - - public function getLDAPAccess() - { - if (!$this->access) { - throw new Exception('Access not defined!'); - } - return $this->access; - } +class LDAPConnectionService { + /** @var IUserManager */ + private $userManager; + + private $configuration; + + private $ldapEnabled; + + private $access; + + public function __construct(IUserManager $userManager) { + $this->userManager = $userManager; + $this->getConfigurationFromBackend(); + } + + + private function getConfigurationFromBackend() { + // We don't actually need user id to get access from backend + $uid = ''; + $backends = $this->userManager->getBackends(); + foreach ($backends as $backend) { + if ($backend->getBackendName() === 'LDAP') { + $this->access = $backend->getLDAPAccess($uid); + $connection = $this->access->getConnection(); + $configuration = $connection->getConfiguration(); + + if ($configuration['ldap_configuration_active']) { + $this->ldapEnabled = true; + $this->configuration = $configuration; + break; + } + } + } + } + + public function isUserOnLDAPBackend($user) { + $backend = $user->getBackend(); + return $backend->getBackendName() === 'LDAP'; + } + + public function isLDAPEnabled() : bool { + return $this->ldapEnabled; + } + + public function username2dn(string $username) { + return $this->access->username2dn($username); + } + + + public function getUserBaseDn() : string { + if (isset($this->configuration['ldap_base_users'])) { + return $this->configuration['ldap_base_users']; + } + throw new Exception('User Base Dn not set!'); + } + + public function getLDAPConnection() { + if (!$this->ldapEnabled) { + throw new Exception('LDAP backend is not enabled'); + } + + $adminDn = $this->configuration['ldap_dn']; + $adminPassword = $this->configuration['ldap_agent_password']; + $host = $this->configuration['ldap_host']; + $port = intval($this->configuration['ldap_port']); + + $conn = ldap_connect($host, $port); + ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION, 3); + ldap_bind($conn, $adminDn, $adminPassword); + + if (!$conn) { + throw new Exception('Could not connect to LDAP server!'); + } + return $conn; + } + + public function closeLDAPConnection($conn) : void { + ldap_close($conn); + } + + public function getLDAPAccess() { + if (!$this->access) { + throw new Exception('Access not defined!'); + } + return $this->access; + } } diff --git a/lib/Service/ShopAccountService.php b/lib/Service/ShopAccountService.php index c3145c65d0bbe22980281507978afe4e554de657..cb2984a28c843f0e17916f31d778e8ed95fc4306 100644 --- a/lib/Service/ShopAccountService.php +++ b/lib/Service/ShopAccountService.php @@ -7,174 +7,166 @@ use Exception; use OCP\IConfig; use OCP\ILogger; use OCA\EcloudAccounts\AppInfo\Application; -use OCA\EcloudAccounts\Service\CurlService; class ShopAccountService { - - private $config; - private $appName; - private $curl; - private $logger; - - public function __construct($appName, IConfig $config, CurlService $curlService, ILogger $logger) - { - - $this->config = $config; - $this->appName = $appName; - - $shopUsername = $this->config->getSystemValue('murena_shop_username'); - $shopPassword = $this->config->getSystemValue('murena_shop_password'); - $this->shopUrl = $this->config->getSystemValue('murena_shop_url'); - $this->shopReassignUserId = $this->config->getSystemValue('murena_shop_reassign_user_id'); - - - $this->shopUserUrl = $this->shopUrl . "/wp-json/wp/v2/users"; - $this->shopOrdersUrl = $this->shopUrl . "/wp-json/wc/v3/orders"; - $this->shopCredentials = base64_encode($shopUsername . ":" . $shopPassword); - $this->curl = $curlService; - $this->logger = $logger; - } - - public function getShopUrl() { - return $this->shopUrl; - } - - public function setShopDeletePreference($userId, bool $delete) { - $this->config->setUserValue($userId, $this->appName, 'delete_shop_account', intval($delete)); - } - - public function shopEmailExists(string $shopEmail) : bool { - return !empty($this->getUser($shopEmail)); - } - - public function validateShopEmailPostDelete(string $shopEmailPostDelete, string $cloudEmail) : void { - if(!filter_var($shopEmailPostDelete, FILTER_VALIDATE_EMAIL)) { - throw new Exception('Invalid Email Format.'); - } - if($shopEmailPostDelete === $cloudEmail) { - throw new Exception('Murena.com email cannot be same as this account\'s email.'); - } - if($this->shopEmailExists($shopEmailPostDelete)) { - throw new Exception('A Murena.com account already uses this e-mail address.'); - } - } - - public function setShopEmailPostDeletePreference($userId, string $shopEmailPostDelete) { - $this->config->setUserValue($userId, $this->appName, 'shop_email_post_delete', $shopEmailPostDelete); - } - - public function getShopDeletePreference($userId) { - return boolval($this->config->getUserValue($userId, $this->appName, 'delete_shop_account', false)); - } - - public function getShopEmailPostDeletePreference($userId) { - $recoveryEmail = $this->config->getUserValue($userId, 'email-recovery', 'recovery-email'); - - return $this->config->getUserValue($userId, $this->appName, 'shop_email_post_delete', $recoveryEmail); - } - - public function getOrders(int $userId): ?array { - try { - return $this->callShopAPI($this->shopOrdersUrl, 'GET', ['customer' => $userId]); - } - catch(Exception $e) { - $this->logger->error('There was an issue querying shop for orders for user ' . strval($userId)); - $this->logger->logException($e, ['app' => Application::APP_ID]); - } - return null; - } - - public function getUsers(string $searchTerm): ?array - { - try { - return $this->callShopAPI($this->shopUserUrl, 'GET', ['search' => $searchTerm]); - } - catch(Exception $e) { - $this->logger->error('There was an issue querying shop for users'); - $this->logger->logException($e, ['app' => Application::APP_ID]); - } - return null; - } - - public function getUser(string $email) : ?array { - $users = $this->getUsers($email); - if(empty($users)) { - return null; - } - return $users[0]; - } - - public function deleteUser(int $userId) : void { - $params = [ - 'force' => true, - 'reassign' => $this->shopReassignUserId - ]; - $deleteUrl = $this->shopUserUrl . '/' . strval($userId); - - try { - $answer = $this->callShopAPI($deleteUrl, 'DELETE', $params); - - if(!$answer['deleted']) { - throw new Exception('Unknown error while deleting!'); - } - } - catch(Exception $e) { - $this->logger->error('Error deleting user at WP with ID ' . $userId); - $this->logger->logException($e, ['app' => Application::APP_ID]); - } - - } - - public function updateUserEmailAndEmptyOIDC(int $userId, string $email) : void { - $updateUrl = $this->shopUserUrl . '/' . strval($userId); - - $params = [ - 'email' => $email, - 'openid-connect-generic-last-user-claim' => [] - ]; - - try { - $answer = $this->callShopAPI($updateUrl, 'POST', $params); - - if($answer['email'] !== $email) { - throw new Exception('Unknown error while updating!'); - } - } - catch(Exception $e) { - $this->logger->error('Error updating user email at WP with ID ' . $userId . ' and new email ' . $email); - $this->logger->logException($e, ['app' => Application::APP_ID]); - } - } - - private function callShopAPI(string $url, string $method, array $data = []) { - - $headers = [ - "cache-control: no-cache", - "content-type: application/json", - "Authorization: Basic " . $this->shopCredentials - ]; - - if($method === 'GET') { - $answer = $this->curl->get($url, $data, $headers); - } - - if($method === 'DELETE') { - $answer = $this->curl->delete($url, $data, $headers); - } - - if ($method === 'POST') { - $answer = $this->curl->post($url, json_encode($data), $headers); - } - - $answer = json_decode($answer, true); - if(isset($answer['code']) && isset($answer['message'])) { - throw new Exception($answer['message']); - } - - return $answer; - } - - public function isUserOIDC(array $user) { - return !empty($user['openid-connect-generic-last-user-claim']); - } -} \ No newline at end of file + private $config; + private $appName; + private $curl; + private $logger; + + public function __construct($appName, IConfig $config, CurlService $curlService, ILogger $logger) { + $this->config = $config; + $this->appName = $appName; + + $shopUsername = $this->config->getSystemValue('murena_shop_username'); + $shopPassword = $this->config->getSystemValue('murena_shop_password'); + $this->shopUrl = $this->config->getSystemValue('murena_shop_url', ''); + $this->shopReassignUserId = $this->config->getSystemValue('murena_shop_reassign_user_id'); + + + $this->shopUserUrl = $this->shopUrl . "/wp-json/wp/v2/users"; + $this->shopOrdersUrl = $this->shopUrl . "/wp-json/wc/v3/orders"; + $this->shopCredentials = base64_encode($shopUsername . ":" . $shopPassword); + $this->curl = $curlService; + $this->logger = $logger; + } + + public function getShopUrl() { + return $this->shopUrl; + } + + public function setShopDeletePreference($userId, bool $delete) { + $this->config->setUserValue($userId, $this->appName, 'delete_shop_account', intval($delete)); + } + + public function shopEmailExists(string $shopEmail) : bool { + return !empty($this->getUser($shopEmail)); + } + + public function validateShopEmailPostDelete(string $shopEmailPostDelete, string $cloudEmail) : void { + if (!filter_var($shopEmailPostDelete, FILTER_VALIDATE_EMAIL)) { + throw new Exception('Invalid Email Format.'); + } + if ($shopEmailPostDelete === $cloudEmail) { + throw new Exception('Murena.com email cannot be same as this account\'s email.'); + } + if ($this->shopEmailExists($shopEmailPostDelete)) { + throw new Exception('A Murena.com account already uses this e-mail address.'); + } + } + + public function setShopEmailPostDeletePreference($userId, string $shopEmailPostDelete) { + $this->config->setUserValue($userId, $this->appName, 'shop_email_post_delete', $shopEmailPostDelete); + } + + public function getShopDeletePreference($userId) { + return boolval($this->config->getUserValue($userId, $this->appName, 'delete_shop_account', false)); + } + + public function getShopEmailPostDeletePreference($userId) { + $recoveryEmail = $this->config->getUserValue($userId, 'email-recovery', 'recovery-email'); + + return $this->config->getUserValue($userId, $this->appName, 'shop_email_post_delete', $recoveryEmail); + } + + public function getOrders(int $userId): ?array { + try { + return $this->callShopAPI($this->shopOrdersUrl, 'GET', ['customer' => $userId]); + } catch (Exception $e) { + $this->logger->error('There was an issue querying shop for orders for user ' . strval($userId)); + $this->logger->logException($e, ['app' => Application::APP_ID]); + } + return null; + } + + public function getUsers(string $searchTerm): ?array { + try { + return $this->callShopAPI($this->shopUserUrl, 'GET', ['search' => $searchTerm]); + } catch (Exception $e) { + $this->logger->error('There was an issue querying shop for users'); + $this->logger->logException($e, ['app' => Application::APP_ID]); + } + return null; + } + + public function getUser(string $email) : ?array { + $users = $this->getUsers($email); + if (empty($users)) { + return null; + } + return $users[0]; + } + + public function deleteUser(int $userId) : void { + $params = [ + 'force' => true, + 'reassign' => $this->shopReassignUserId + ]; + $deleteUrl = $this->shopUserUrl . '/' . strval($userId); + + try { + $answer = $this->callShopAPI($deleteUrl, 'DELETE', $params); + + if (!$answer['deleted']) { + throw new Exception('Unknown error while deleting!'); + } + } catch (Exception $e) { + $this->logger->error('Error deleting user at WP with ID ' . $userId); + $this->logger->logException($e, ['app' => Application::APP_ID]); + } + } + + public function updateUserEmailAndEmptyOIDC(int $userId, string $email) : void { + $updateUrl = $this->shopUserUrl . '/' . strval($userId); + + $params = [ + 'email' => $email, + 'openid-connect-generic-last-user-claim' => [] + ]; + + try { + $answer = $this->callShopAPI($updateUrl, 'POST', $params); + + if ($answer['email'] !== $email) { + throw new Exception('Unknown error while updating!'); + } + } catch (Exception $e) { + $this->logger->error('Error updating user email at WP with ID ' . $userId . ' and new email ' . $email); + $this->logger->logException($e, ['app' => Application::APP_ID]); + } + } + + private function callShopAPI(string $url, string $method, array $data = []) { + if (empty($this->shopUrl)) { + return []; + } + $headers = [ + "cache-control: no-cache", + "content-type: application/json", + "Authorization: Basic " . $this->shopCredentials + ]; + + if ($method === 'GET') { + $answer = $this->curl->get($url, $data, $headers); + } + + if ($method === 'DELETE') { + $answer = $this->curl->delete($url, $data, $headers); + } + + if ($method === 'POST') { + $answer = $this->curl->post($url, json_encode($data), $headers); + } + + $answer = json_decode($answer, true); + if (isset($answer['code']) && isset($answer['message'])) { + throw new Exception($answer['message']); + } + + return $answer; + } + + public function isUserOIDC(array $user) { + return !empty($user['openid-connect-generic-last-user-claim']); + } +} diff --git a/lib/Service/UserService.php b/lib/Service/UserService.php index 70b991f86aee50c0e5d4e154a27533efaa1db3a7..11c649019e06b1e204fdb6fc7685cdcb148b4081 100644 --- a/lib/Service/UserService.php +++ b/lib/Service/UserService.php @@ -8,139 +8,127 @@ use OCP\IUserManager; use OCP\IUser; use OCP\IConfig; use OCP\ILogger; -use OCA\EcloudAccounts\Service\CurlService; use OCA\EcloudAccounts\AppInfo\Application; use UnexpectedValueException; -class UserService -{ - - /** @var IUserManager */ - private $userManager; - - /** @var array */ - private $appConfig; - - /** @var IConfig */ - private $config; - - private $curl; - - - public function __construct($appName, IUserManager $userManager, IConfig $config, CurlService $curlService, ILogger $logger) - { - $this->userManager = $userManager; - $this->config = $config; - $this->appConfig = $this->config->getSystemValue($appName); - $this->curl = $curlService; - $this->logger = $logger; - } - - - public function getConfigValue(string $key, mixed $default = false) - { - if (!empty($this->appConfig[$key])) { - return $this->appConfig[$key]; - } - return $default; - } - - - public function userExists(string $uid): bool - { - $exists = $this->userManager->userExists($uid); - if ($exists) { - return $exists; - } - - $backends = $this->userManager->getBackends(); - foreach ($backends as $backend) { - if ($backend->getBackendName() === 'LDAP') { - $access = $backend->getLDAPAccess($uid); - $users = $access->fetchUsersByLoginName($uid) ; - if (count($users) > 0) { - $exists = true; - } - } - } - return $exists; - } - - public function getUser(string $uid): ?IUser - { - return $this->userManager->get($uid); - } - - public function setRecoveryEmail(string $uid, string $recoveryEmail): bool - { - try { - $this->config->setUserValue($uid, 'email-recovery', 'recovery-email', $recoveryEmail); - return true; - } catch (UnexpectedValueException $e) { - return false; - } - } - - public function getHMEAliasesFromConfig($uid) : array - { - $aliases = $this->config->getUserValue($uid, 'hide-my-email', 'email-aliases', []); - if (!empty($aliases)) { - $aliases = json_decode($aliases, true); - } - return $aliases; - } - - public function addHMEAliasInConfig($uid, $alias) : bool - { - $aliases = $this->getHMEAliasesFromConfig($uid); - $aliases[] = $alias; - $aliases = json_encode($aliases); - try { - $this->config->setUserValue($uid, 'hide-my-email', 'email-aliases', $aliases); - return true; - } catch (UnexpectedValueException $e) { - return false; - } - } - - /** - * Once NC deleted the account, - * perform specific ecloud selfhosting actions - * post delete action is delegated to the welcome container - * - * @param $userID string - * @param $welcomeDomain string main NC domain (welcome container) - * @param $welcomeSecret string generated at ecloud selfhosting install and added as a custom var in NC's config - * @return mixed response of the external endpoint - */ - public function ecloudDelete(string $userID, string $welcomeDomain, string $welcomeSecret, string $email, bool $isUserOnLDAP = false) - { - $endpoint = '/postDelete.php'; - if ($isUserOnLDAP) { - $endpoint = '/postDeleteLDAP.php'; - } - $postDeleteUrl = "https://" . $welcomeDomain . $endpoint; - /** - * send action to docker_welcome - * Handling the non NC part of deletion process - */ - try { - $params = [ - 'sec' => $welcomeSecret, - 'uid' => $userID, - 'email' => $email - ]; - - $answer = $this->curl->post($postDeleteUrl, $params); - - return json_decode($answer, true); - } catch (\Exception $e) { - $this->logger->error('There has been an issue while contacting the external deletion script'); - $this->logger->logException($e, ['app' => Application::APP_ID]); - } - - return null; - } - +class UserService { + /** @var IUserManager */ + private $userManager; + + /** @var array */ + private $appConfig; + + /** @var IConfig */ + private $config; + + private $curl; + + + public function __construct($appName, IUserManager $userManager, IConfig $config, CurlService $curlService, ILogger $logger) { + $this->userManager = $userManager; + $this->config = $config; + $this->appConfig = $this->config->getSystemValue($appName); + $this->curl = $curlService; + $this->logger = $logger; + } + + + public function getConfigValue(string $key, mixed $default = false) { + if (!empty($this->appConfig[$key])) { + return $this->appConfig[$key]; + } + return $default; + } + + + public function userExists(string $uid): bool { + $exists = $this->userManager->userExists($uid); + if ($exists) { + return $exists; + } + + $backends = $this->userManager->getBackends(); + foreach ($backends as $backend) { + if ($backend->getBackendName() === 'LDAP') { + $access = $backend->getLDAPAccess($uid); + $users = $access->fetchUsersByLoginName($uid) ; + if (count($users) > 0) { + $exists = true; + } + } + } + return $exists; + } + + public function getUser(string $uid): ?IUser { + return $this->userManager->get($uid); + } + + public function setRecoveryEmail(string $uid, string $recoveryEmail): bool { + try { + $this->config->setUserValue($uid, 'email-recovery', 'recovery-email', $recoveryEmail); + return true; + } catch (UnexpectedValueException $e) { + return false; + } + } + + public function getHMEAliasesFromConfig($uid) : array { + $aliases = $this->config->getUserValue($uid, 'hide-my-email', 'email-aliases', []); + if (!empty($aliases)) { + $aliases = json_decode($aliases, true); + } + return $aliases; + } + + public function addHMEAliasInConfig($uid, $alias) : bool { + $aliases = $this->getHMEAliasesFromConfig($uid); + $aliases[] = $alias; + $aliases = json_encode($aliases); + try { + $this->config->setUserValue($uid, 'hide-my-email', 'email-aliases', $aliases); + return true; + } catch (UnexpectedValueException $e) { + return false; + } + } + + /** + * Once NC deleted the account, + * perform specific ecloud selfhosting actions + * post delete action is delegated to the welcome container + * + * @param $userID string + * @param $welcomeDomain string main NC domain (welcome container) + * @param $welcomeSecret string generated at ecloud selfhosting install and added as a custom var in NC's config + * @return mixed response of the external endpoint + */ + public function ecloudDelete(string $userID, string $welcomeDomain, string $welcomeSecret, string $email, bool $isUserOnLDAP = false) { + $endpoint = '/postDelete.php'; + if ($isUserOnLDAP) { + $endpoint = '/postDeleteLDAP.php'; + } + $postDeleteUrl = "https://" . $welcomeDomain . $endpoint; + /** + * send action to docker_welcome + * Handling the non NC part of deletion process + */ + try { + $params = [ + 'sec' => $welcomeSecret, + 'uid' => $userID, + 'email' => $email + ]; + + $answer = $this->curl->post($postDeleteUrl, $params); + + return json_decode($answer, true); + } catch (\Exception $e) { + $this->logger->error('There has been an issue while contacting the external deletion script'); + $this->logger->logException($e, ['app' => Application::APP_ID]); + } + + return null; + } } diff --git a/lib/Settings/Personal.php b/lib/Settings/Personal.php index f981db6895912a90dd225fa5184afbb794fda940..96e764c29a68b8903c93d938bdacd30503a2f951 100644 --- a/lib/Settings/Personal.php +++ b/lib/Settings/Personal.php @@ -13,7 +13,6 @@ use OCP\App\IAppManager; use OCP\IUserManager; class Personal implements ISettings { - private const DROP_ACCOUNT_APP_ID = 'drop_account'; /** @var IUserSession */ private $userSession; @@ -47,7 +46,6 @@ class Personal implements ISettings { * @since 9.1 */ public function getForm(): TemplateResponse { - $user = $this->userSession->getUser(); if ($user) { $onlyUser = $this->userManager->countUsers() < 2; @@ -75,7 +73,7 @@ class Personal implements ISettings { */ public function getSection(): ?string { $dropAccountEnabled = $this->appManager->isEnabledForUser(self::DROP_ACCOUNT_APP_ID); - if($dropAccountEnabled) { + if ($dropAccountEnabled) { return self::DROP_ACCOUNT_APP_ID; } return null; diff --git a/package-lock.json b/package-lock.json index c5df651bdf7c27a2dda842cae965785ced291221..19a1b4b854801c868cf2276639830c15a9f5620c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,26 +8,24 @@ "name": "ecloud-accounts", "version": "2.2.0", "dependencies": { - "@nextcloud/axios": "^2.0.0", + "@nextcloud/axios": "^2.1.0", "@nextcloud/dialogs": "^3.2.0", - "@nextcloud/initial-state": "^1.2.1", - "@nextcloud/l10n": "^1.4.1", - "@nextcloud/password-confirmation": "^1.0.1", + "@nextcloud/initial-state": "^2.0.0", + "@nextcloud/l10n": "^1.6.0", "@nextcloud/router": "^2.0.0", "@nextcloud/vue": "^5.4.0", - "vue": "^2.7.8" + "vue": "^2.7.0" }, "devDependencies": { - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/preset-env": "^7.18.10", + "@nextcloud/babel-config": "^1.0.0", "@nextcloud/browserslist-config": "^2.2.0", - "@nextcloud/eslint-config": "^8.1.2", - "@nextcloud/stylelint-config": "^2.0.1", - "@nextcloud/webpack-vue-config": "^5.3.0", - "@vue/test-utils": "^1.3.0" + "@nextcloud/eslint-config": "^8.0.0", + "@nextcloud/stylelint-config": "^2.1.2", + "@nextcloud/webpack-vue-config": "^5.2.1" }, "engines": { - "node": ">=14.0.0" + "node": "^16.0.0", + "npm": "^7.0.0 || ^8.0.0" } }, "node_modules/@ampproject/remapping": { @@ -1916,11 +1914,12 @@ } }, "node_modules/@nextcloud/axios": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@nextcloud/axios/-/axios-2.0.0.tgz", - "integrity": "sha512-Pgg0QtA+phxYbe3kMWwhN03ltMZU3x2SfPLRbOPJGP29DgULKBS6YH3U4ev2M8T0drrwCcRnB7esb+FSrW+D5g==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@nextcloud/axios/-/axios-2.1.0.tgz", + "integrity": "sha512-fUwRQeYfdX0sP+DJnQiqlJfB7ngNHWu6Gbi0nYapkB7IFiLECeL2SWzDOFj+M04j4ApsblEMBqGOJ38WEgdeyA==", "dependencies": { "@nextcloud/auth": "^2.0.0", + "@nextcloud/router": "^2.0.0", "axios": "^0.27.2", "tslib": "^2.4.0" }, @@ -1929,6 +1928,20 @@ "npm": "^7.0.0 || ^8.0.0" } }, + "node_modules/@nextcloud/babel-config": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@nextcloud/babel-config/-/babel-config-1.0.0.tgz", + "integrity": "sha512-olz7sqPD7xMDP2KcYwODtitH37faR/C5jKX1oxXzdDf+s1FRy6OQTC5ZqZR2LHZA6jTUvmwM/xWBPoEB/HPFRw==", + "dev": true, + "peerDependencies": { + "@babel/core": "^7.13.10", + "@babel/plugin-proposal-class-properties": "^7.13.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-modules-commonjs": "^7.13.8", + "@babel/plugin-transform-shorthand-properties": "^7.12.13", + "@babel/preset-env": "^7.13.12" + } + }, "node_modules/@nextcloud/browser-storage": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@nextcloud/browser-storage/-/browser-storage-0.1.1.tgz", @@ -1980,6 +1993,14 @@ "core-js": "^3.6.4" } }, + "node_modules/@nextcloud/capabilities/node_modules/@nextcloud/initial-state": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@nextcloud/initial-state/-/initial-state-1.2.1.tgz", + "integrity": "sha512-2TH2DzJBolYHWfbSovTWkByAIg0gdsyuVfZpf5APnJu/9PixXKbnrVFnaEdxjeP262Gok7ARMFFQeSiuzKRQeQ==", + "dependencies": { + "core-js": "^3.6.4" + } + }, "node_modules/@nextcloud/dialogs": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/@nextcloud/dialogs/-/dialogs-3.2.0.tgz", @@ -2077,12 +2098,9 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/@nextcloud/initial-state": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@nextcloud/initial-state/-/initial-state-1.2.1.tgz", - "integrity": "sha512-2TH2DzJBolYHWfbSovTWkByAIg0gdsyuVfZpf5APnJu/9PixXKbnrVFnaEdxjeP262Gok7ARMFFQeSiuzKRQeQ==", - "dependencies": { - "core-js": "^3.6.4" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@nextcloud/initial-state/-/initial-state-2.0.0.tgz", + "integrity": "sha512-xmNP30v/RnkJ2z1HcuEo7YfcLJJa+FdWTwgNldXHOlMeMbl/ESpsGkWL2sULrhYurz64L0JpfwEdi/cHcmyuZQ==" }, "node_modules/@nextcloud/l10n": { "version": "1.6.0", @@ -2169,11 +2187,6 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, - "node_modules/@nextcloud/password-confirmation": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@nextcloud/password-confirmation/-/password-confirmation-1.0.1.tgz", - "integrity": "sha512-qsyzc8uKcMqssBkm5O1qdV7pL4EJWOMnj036w0UmhLozaoPlla5nUvC51uC1N9ONREEtN0Q/xEEOskNn1qD1hQ==" - }, "node_modules/@nextcloud/router": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@nextcloud/router/-/router-2.0.0.tgz", @@ -2699,21 +2712,6 @@ "url": "https://opencollective.com/postcss/" } }, - "node_modules/@vue/test-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-1.3.0.tgz", - "integrity": "sha512-Xk2Xiyj2k5dFb8eYUKkcN9PzqZSppTlx7LaQWBbdA8tqh3jHr/KHX2/YLhNFc/xwDrgeLybqd+4ZCPJSGPIqeA==", - "dev": true, - "dependencies": { - "dom-event-types": "^1.0.0", - "lodash": "^4.17.15", - "pretty": "^2.0.0" - }, - "peerDependencies": { - "vue": "2.x", - "vue-template-compiler": "^2.x" - } - }, "node_modules/@webassemblyjs/ast": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", @@ -2911,12 +2909,6 @@ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "peer": true }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -3942,7 +3934,8 @@ "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "peer": true }, "node_modules/comment-parser": { "version": "1.3.1", @@ -4015,30 +4008,6 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, - "node_modules/condense-newlines": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/condense-newlines/-/condense-newlines-0.2.1.tgz", - "integrity": "sha512-P7X+QL9Hb9B/c8HI5BFFKmjgBu2XpQuF98WZ9XkO+dBGgk5XgwiQz7o1SmpglNWId3581UcS0SFAWfoIhMHPfg==", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-whitespace": "^0.3.0", - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/config-chain": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", - "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", - "dev": true, - "dependencies": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, "node_modules/connect-history-api-fallback": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", @@ -4599,12 +4568,6 @@ "node": ">=6.0.0" } }, - "node_modules/dom-event-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/dom-event-types/-/dom-event-types-1.1.0.tgz", - "integrity": "sha512-jNCX+uNJ3v38BKvPbpki6j5ItVlnSqVV6vDWGS6rExzCMjsc39frLjm1n91o6YaKK6AZl0wLloItW6C6mr61BQ==", - "dev": true - }, "node_modules/dom-serializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", @@ -4677,30 +4640,6 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "node_modules/editorconfig": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", - "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", - "dev": true, - "dependencies": { - "commander": "^2.19.0", - "lru-cache": "^4.1.5", - "semver": "^5.6.0", - "sigmund": "^1.0.1" - }, - "bin": { - "editorconfig": "bin/editorconfig" - } - }, - "node_modules/editorconfig/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -5808,18 +5747,6 @@ ], "peer": true }, - "node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -6216,25 +6143,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -6254,27 +6162,6 @@ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "peer": true }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/global-modules": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", @@ -6926,7 +6813,8 @@ "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true + "dev": true, + "peer": true }, "node_modules/internal-slot": { "version": "1.0.3", @@ -7090,15 +6978,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -7329,15 +7208,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-whitespace": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-whitespace/-/is-whitespace-0.3.0.tgz", - "integrity": "sha512-RydPhl4S6JwAyj0JJjshWJEFG6hNye3pZFBRZaTUfZFwGHxzppNaNOVgQuS/E/SlhrApuMXrpnK1EEIXfdo3Dg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -7413,26 +7283,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/js-beautify": { - "version": "1.14.6", - "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.6.tgz", - "integrity": "sha512-GfofQY5zDp+cuHc+gsEXKPpNw2KbPddreEo35O6jT6i0RVK6LhsoYBhq5TvK4/n74wnA0QbK8gGd+jUZwTMKJw==", - "dev": true, - "dependencies": { - "config-chain": "^1.1.13", - "editorconfig": "^0.15.3", - "glob": "^8.0.3", - "nopt": "^6.0.0" - }, - "bin": { - "css-beautify": "js/bin/css-beautify.js", - "html-beautify": "js/bin/html-beautify.js", - "js-beautify": "js/bin/js-beautify.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/js-sdsl": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", @@ -7509,18 +7359,6 @@ "node": ">=6" } }, - "node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/klona": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", @@ -7652,6 +7490,7 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "dev": true, + "peer": true, "dependencies": { "pseudomap": "^1.0.2", "yallist": "^2.1.2" @@ -8090,21 +7929,6 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" }, - "node_modules/nopt": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", - "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", - "dev": true, - "dependencies": { - "abbrev": "^1.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/normalize-package-data": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", @@ -8867,20 +8691,6 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/pretty": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pretty/-/pretty-2.0.0.tgz", - "integrity": "sha512-G9xUchgTEiNpormdYBl+Pha50gOUovT18IvAe7EYMZ1/f9W/WWMPRn+xI68yXNMUk3QXHDwo/1wV/4NejVNe1w==", - "dev": true, - "dependencies": { - "condense-newlines": "^0.2.1", - "extend-shallow": "^2.0.1", - "js-beautify": "^1.6.12" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -8898,12 +8708,6 @@ "dev": true, "peer": true }, - "node_modules/proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", - "dev": true - }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -8932,7 +8736,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", - "dev": true + "dev": true, + "peer": true }, "node_modules/public-encrypt": { "version": "4.0.3", @@ -9920,12 +9725,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==", - "dev": true - }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -11962,7 +11761,8 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", - "dev": true + "dev": true, + "peer": true }, "node_modules/yaml": { "version": "1.10.2", @@ -13287,15 +13087,23 @@ } }, "@nextcloud/axios": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@nextcloud/axios/-/axios-2.0.0.tgz", - "integrity": "sha512-Pgg0QtA+phxYbe3kMWwhN03ltMZU3x2SfPLRbOPJGP29DgULKBS6YH3U4ev2M8T0drrwCcRnB7esb+FSrW+D5g==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@nextcloud/axios/-/axios-2.1.0.tgz", + "integrity": "sha512-fUwRQeYfdX0sP+DJnQiqlJfB7ngNHWu6Gbi0nYapkB7IFiLECeL2SWzDOFj+M04j4ApsblEMBqGOJ38WEgdeyA==", "requires": { "@nextcloud/auth": "^2.0.0", + "@nextcloud/router": "^2.0.0", "axios": "^0.27.2", "tslib": "^2.4.0" } }, + "@nextcloud/babel-config": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@nextcloud/babel-config/-/babel-config-1.0.0.tgz", + "integrity": "sha512-olz7sqPD7xMDP2KcYwODtitH37faR/C5jKX1oxXzdDf+s1FRy6OQTC5ZqZR2LHZA6jTUvmwM/xWBPoEB/HPFRw==", + "dev": true, + "requires": {} + }, "@nextcloud/browser-storage": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@nextcloud/browser-storage/-/browser-storage-0.1.1.tgz", @@ -13330,6 +13138,16 @@ "requires": { "@nextcloud/initial-state": "^1.1.2", "core-js": "^3.6.4" + }, + "dependencies": { + "@nextcloud/initial-state": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@nextcloud/initial-state/-/initial-state-1.2.1.tgz", + "integrity": "sha512-2TH2DzJBolYHWfbSovTWkByAIg0gdsyuVfZpf5APnJu/9PixXKbnrVFnaEdxjeP262Gok7ARMFFQeSiuzKRQeQ==", + "requires": { + "core-js": "^3.6.4" + } + } } }, "@nextcloud/dialogs": { @@ -13392,12 +13210,9 @@ } }, "@nextcloud/initial-state": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@nextcloud/initial-state/-/initial-state-1.2.1.tgz", - "integrity": "sha512-2TH2DzJBolYHWfbSovTWkByAIg0gdsyuVfZpf5APnJu/9PixXKbnrVFnaEdxjeP262Gok7ARMFFQeSiuzKRQeQ==", - "requires": { - "core-js": "^3.6.4" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@nextcloud/initial-state/-/initial-state-2.0.0.tgz", + "integrity": "sha512-xmNP30v/RnkJ2z1HcuEo7YfcLJJa+FdWTwgNldXHOlMeMbl/ESpsGkWL2sULrhYurz64L0JpfwEdi/cHcmyuZQ==" }, "@nextcloud/l10n": { "version": "1.6.0", @@ -13473,11 +13288,6 @@ } } }, - "@nextcloud/password-confirmation": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@nextcloud/password-confirmation/-/password-confirmation-1.0.1.tgz", - "integrity": "sha512-qsyzc8uKcMqssBkm5O1qdV7pL4EJWOMnj036w0UmhLozaoPlla5nUvC51uC1N9ONREEtN0Q/xEEOskNn1qD1hQ==" - }, "@nextcloud/router": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@nextcloud/router/-/router-2.0.0.tgz", @@ -13949,17 +13759,6 @@ } } }, - "@vue/test-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-1.3.0.tgz", - "integrity": "sha512-Xk2Xiyj2k5dFb8eYUKkcN9PzqZSppTlx7LaQWBbdA8tqh3jHr/KHX2/YLhNFc/xwDrgeLybqd+4ZCPJSGPIqeA==", - "dev": true, - "requires": { - "dom-event-types": "^1.0.0", - "lodash": "^4.17.15", - "pretty": "^2.0.0" - } - }, "@webassemblyjs/ast": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", @@ -14144,12 +13943,6 @@ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "peer": true }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, "abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -14945,7 +14738,8 @@ "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "peer": true }, "comment-parser": { "version": "1.3.1", @@ -15011,27 +14805,6 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, - "condense-newlines": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/condense-newlines/-/condense-newlines-0.2.1.tgz", - "integrity": "sha512-P7X+QL9Hb9B/c8HI5BFFKmjgBu2XpQuF98WZ9XkO+dBGgk5XgwiQz7o1SmpglNWId3581UcS0SFAWfoIhMHPfg==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-whitespace": "^0.3.0", - "kind-of": "^3.0.2" - } - }, - "config-chain": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", - "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", - "dev": true, - "requires": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, "connect-history-api-fallback": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", @@ -15476,12 +15249,6 @@ "esutils": "^2.0.2" } }, - "dom-event-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/dom-event-types/-/dom-event-types-1.1.0.tgz", - "integrity": "sha512-jNCX+uNJ3v38BKvPbpki6j5ItVlnSqVV6vDWGS6rExzCMjsc39frLjm1n91o6YaKK6AZl0wLloItW6C6mr61BQ==", - "dev": true - }, "dom-serializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", @@ -15530,26 +15297,6 @@ "domhandler": "^5.0.1" } }, - "editorconfig": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", - "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", - "dev": true, - "requires": { - "commander": "^2.19.0", - "lru-cache": "^4.1.5", - "semver": "^5.6.0", - "sigmund": "^1.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -16397,15 +16144,6 @@ } } }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -16710,39 +16448,6 @@ "get-intrinsic": "^1.1.1" } }, - "glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, "glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -17252,7 +16957,8 @@ "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true + "dev": true, + "peer": true }, "internal-slot": { "version": "1.0.3", @@ -17365,12 +17071,6 @@ "dev": true, "peer": true }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "dev": true - }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -17523,12 +17223,6 @@ "call-bind": "^1.0.2" } }, - "is-whitespace": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-whitespace/-/is-whitespace-0.3.0.tgz", - "integrity": "sha512-RydPhl4S6JwAyj0JJjshWJEFG6hNye3pZFBRZaTUfZFwGHxzppNaNOVgQuS/E/SlhrApuMXrpnK1EEIXfdo3Dg==", - "dev": true - }, "is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -17588,18 +17282,6 @@ } } }, - "js-beautify": { - "version": "1.14.6", - "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.6.tgz", - "integrity": "sha512-GfofQY5zDp+cuHc+gsEXKPpNw2KbPddreEo35O6jT6i0RVK6LhsoYBhq5TvK4/n74wnA0QbK8gGd+jUZwTMKJw==", - "dev": true, - "requires": { - "config-chain": "^1.1.13", - "editorconfig": "^0.15.3", - "glob": "^8.0.3", - "nopt": "^6.0.0" - } - }, "js-sdsl": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", @@ -17658,15 +17340,6 @@ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - }, "klona": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", @@ -17778,6 +17451,7 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "dev": true, + "peer": true, "requires": { "pseudomap": "^1.0.2", "yallist": "^2.1.2" @@ -18128,15 +17802,6 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" }, - "nopt": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", - "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", - "dev": true, - "requires": { - "abbrev": "^1.0.0" - } - }, "normalize-package-data": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", @@ -18684,17 +18349,6 @@ "optional": true, "peer": true }, - "pretty": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pretty/-/pretty-2.0.0.tgz", - "integrity": "sha512-G9xUchgTEiNpormdYBl+Pha50gOUovT18IvAe7EYMZ1/f9W/WWMPRn+xI68yXNMUk3QXHDwo/1wV/4NejVNe1w==", - "dev": true, - "requires": { - "condense-newlines": "^0.2.1", - "extend-shallow": "^2.0.1", - "js-beautify": "^1.6.12" - } - }, "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -18709,12 +18363,6 @@ "dev": true, "peer": true }, - "proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", - "dev": true - }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -18739,7 +18387,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", - "dev": true + "dev": true, + "peer": true }, "public-encrypt": { "version": "4.0.3", @@ -19501,12 +19150,6 @@ "object-inspect": "^1.9.0" } }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==", - "dev": true - }, "signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -21058,7 +20701,8 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", - "dev": true + "dev": true, + "peer": true }, "yaml": { "version": "1.10.2", diff --git a/package.json b/package.json index a5515beb7239ebfd95e32d539226b717412884ff..8d9a0b4ca5501a83cff962fe066304a9e518e3a0 100644 --- a/package.json +++ b/package.json @@ -1,45 +1,42 @@ { "name": "ecloud-accounts", "version": "2.2.0", - "description": "An app to allow users to delete their accounts.", + "description": "App for ecloud account management.", "repository": { "type": "git", "url": "https://gitlab.e.foundation/e/infra/ecloud/nextcloud-apps/ecloud-accounts" }, "private": true, "scripts": { - "build": "NODE_ENV=production webpack --progress --config webpack.js", - "dev": "NODE_ENV=development webpack --progress --config webpack.js", - "watch": "NODE_ENV=development webpack --progress --watch --config webpack.js", - "serve": "NODE_ENV=development webpack serve --progress --config webpack.js", + "build": "NODE_ENV=production webpack --progress", + "dev": "NODE_ENV=development webpack --progress", + "watch": "NODE_ENV=development webpack --progress --watch", "lint": "eslint --ext .js,.vue src", "lint:fix": "eslint --ext .js,.vue src --fix", - "stylelint": "stylelint src", - "stylelint:fix": "stylelint src --fix" + "stylelint": "stylelint {src,css}/**/{*.scss,*.css} --allow-empty-input", + "stylelint:fix": "stylelint {src,css}/**/{*.scss,*.css} --fix --allow-empty-input" }, "dependencies": { - "@nextcloud/axios": "^2.0.0", + "@nextcloud/axios": "^2.1.0", "@nextcloud/dialogs": "^3.2.0", - "@nextcloud/initial-state": "^1.2.1", - "@nextcloud/l10n": "^1.4.1", - "@nextcloud/password-confirmation": "^1.0.1", + "@nextcloud/initial-state": "^2.0.0", + "@nextcloud/l10n": "^1.6.0", "@nextcloud/router": "^2.0.0", "@nextcloud/vue": "^5.4.0", - "vue": "^2.7.8" + "vue": "^2.7.0" }, "browserslist": [ "extends @nextcloud/browserslist-config" ], "engines": { - "node": ">=14.0.0" + "node": "^16.0.0", + "npm": "^7.0.0 || ^8.0.0" }, "devDependencies": { - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/preset-env": "^7.18.10", + "@nextcloud/babel-config": "^1.0.0", "@nextcloud/browserslist-config": "^2.2.0", - "@nextcloud/eslint-config": "^8.1.2", - "@nextcloud/stylelint-config": "^2.0.1", - "@nextcloud/webpack-vue-config": "^5.3.0", - "@vue/test-utils": "^1.3.0" + "@nextcloud/eslint-config": "^8.0.0", + "@nextcloud/stylelint-config": "^2.1.2", + "@nextcloud/webpack-vue-config": "^5.2.1" } } diff --git a/stylelint.config.js b/stylelint.config.js new file mode 100644 index 0000000000000000000000000000000000000000..fbe1e6e359b8c56a350574000f85f3d3c3feb829 --- /dev/null +++ b/stylelint.config.js @@ -0,0 +1,5 @@ +// SPDX-FileCopyrightText: {{ app.author_name }} <{{ app.author_mail }}> +// SPDX-License-Identifier: {{ app.license }} +const stylelintConfig = require('@nextcloud/stylelint-config') + +module.exports = stylelintConfig diff --git a/webpack.js b/webpack.config.js similarity index 65% rename from webpack.js rename to webpack.config.js index 2a9f55b4d50e0cf8be14504a60969cf652a5f62f..eb7e4bfd4e123207fc04a751ca617a3820a48943 100644 --- a/webpack.js +++ b/webpack.config.js @@ -1,3 +1,5 @@ +// SPDX-FileCopyrightText: {{ app.author_name }} <{{ app.author_mail }}> +// SPDX-License-Identifier: {{ app.license }} const webpackConfig = require('@nextcloud/webpack-vue-config') const path = require('path') @@ -5,6 +7,6 @@ module.exports = { ...webpackConfig, entry: { 'personal-settings': path.join(__dirname, 'src/personal.js'), - 'delete-account-listeners': path.join(__dirname, 'src/delete-account-listeners.js') + 'delete-account-listeners': path.join(__dirname, 'src/delete-account-listeners.js'), }, }