diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml
new file mode 100644
index 00000000..49539c60
--- /dev/null
+++ b/.github/workflows/phpunit.yml
@@ -0,0 +1,89 @@
+name: PHPUnit
+
+on:
+ pull_request:
+ push:
+ branches:
+ - master
+ - stable*
+
+env:
+ APP_NAME: files_lock
+
+
+jobs:
+ integration:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ php-versions: ['7.4', '8.0', '8.1']
+ databases: ['sqlite', 'mysql', 'pgsql']
+ server-versions: ['master']
+
+ name: php${{ matrix.php-versions }}-${{ matrix.databases }}-${{ matrix.server-versions }}
+
+ services:
+ postgres:
+ image: postgres
+ ports:
+ - 4445:5432/tcp
+ env:
+ POSTGRES_USER: root
+ POSTGRES_PASSWORD: rootpassword
+ POSTGRES_DB: nextcloud
+ options: --health-cmd pg_isready --health-interval 5s --health-timeout 2s --health-retries 5
+ mysql:
+ image: mariadb:10.5
+ ports:
+ - 4444:3306/tcp
+ env:
+ MYSQL_ROOT_PASSWORD: rootpassword
+ options: --health-cmd="mysqladmin ping" --health-interval 5s --health-timeout 2s --health-retries 5
+
+ steps:
+ - name: Checkout server
+ uses: actions/checkout@v3
+ with:
+ repository: nextcloud/server
+ ref: ${{ matrix.server-versions }}
+
+ - name: Checkout submodules
+ shell: bash
+ run: |
+ auth_header="$(git config --local --get http.https://github.com/.extraheader)"
+ git submodule sync --recursive
+ git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1
+
+ - name: Checkout app
+ uses: actions/checkout@v3
+ with:
+ path: apps/${{ env.APP_NAME }}
+
+ - name: Set up php ${{ matrix.php-versions }}
+ uses: shivammathur/setup-php@2.17.1
+ with:
+ php-version: ${{ matrix.php-versions }}
+ tools: phpunit
+ extensions: zip, gd, mbstring, iconv, fileinfo, intl, sqlite, pdo_sqlite, mysql, pdo_mysql, pgsql, pdo_pgsql
+ coverage: none
+
+ - name: Set up PHPUnit
+ working-directory: apps/${{ env.APP_NAME }}
+ run: composer i
+
+ - name: Set up Nextcloud
+ run: |
+ if [ "${{ matrix.databases }}" = "mysql" ]; then
+ export DB_PORT=4444
+ elif [ "${{ matrix.databases }}" = "pgsql" ]; then
+ export DB_PORT=4445
+ fi
+ mkdir data
+ ./occ maintenance:install --verbose --database=${{ matrix.databases }} --database-name=nextcloud --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
+ ./occ app:enable --force ${{ env.APP_NAME }}
+ php -S localhost:8080 &
+
+ - name: PHPUnit
+ working-directory: ./apps/${{ env.APP_NAME }}
+ run: ./vendor/phpunit/phpunit/phpunit -c tests/phpunit.xml
diff --git a/appinfo/info.xml b/appinfo/info.xml
index 33221228..935110f5 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -10,12 +10,13 @@ Allow your users to temporary lock their files to avoid conflicts while working
]]>
- 20.1.0
+ 20.1.0-1
agpl
Maxence Lange
FilesLock
+
https://github.com/nextcloud/files_lock/blob/master/README.md
@@ -36,6 +37,12 @@ Allow your users to temporary lock their files to avoid conflicts while working
OCA\FilesLock\Command\Lock
+
+
+ OCA\FilesLock\DAV\LockPlugin
+
+
+
diff --git a/composer.json b/composer.json
new file mode 100644
index 00000000..cb6308a2
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,8 @@
+{
+ "name": "nextcloud/files_lock",
+ "require-dev": {
+ "phpunit/phpunit": "^9.5"
+ },
+ "license": "AGPL",
+ "require": {}
+}
diff --git a/composer.lock b/composer.lock
new file mode 100644
index 00000000..caca9f58
--- /dev/null
+++ b/composer.lock
@@ -0,0 +1,2117 @@
+{
+ "_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": "3a897f7b6a8eacd50025013b51f9b792",
+ "packages": [],
+ "packages-dev": [
+ {
+ "name": "doctrine/instantiator",
+ "version": "1.4.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/instantiator.git",
+ "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc",
+ "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1 || ^8.0"
+ },
+ "require-dev": {
+ "doctrine/coding-standard": "^9",
+ "ext-pdo": "*",
+ "ext-phar": "*",
+ "phpbench/phpbench": "^0.16 || ^1",
+ "phpstan/phpstan": "^1.4",
+ "phpstan/phpstan-phpunit": "^1",
+ "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
+ "vimeo/psalm": "^4.22"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Marco Pivetta",
+ "email": "ocramius@gmail.com",
+ "homepage": "https://ocramius.github.io/"
+ }
+ ],
+ "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
+ "homepage": "https://www.doctrine-project.org/projects/instantiator.html",
+ "keywords": [
+ "constructor",
+ "instantiate"
+ ],
+ "support": {
+ "issues": "https://github.com/doctrine/instantiator/issues",
+ "source": "https://github.com/doctrine/instantiator/tree/1.4.1"
+ },
+ "funding": [
+ {
+ "url": "https://www.doctrine-project.org/sponsorship.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://www.patreon.com/phpdoctrine",
+ "type": "patreon"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-03-03T08:28:38+00:00"
+ },
+ {
+ "name": "myclabs/deep-copy",
+ "version": "1.11.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/myclabs/DeepCopy.git",
+ "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614",
+ "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1 || ^8.0"
+ },
+ "conflict": {
+ "doctrine/collections": "<1.6.8",
+ "doctrine/common": "<2.13.3 || >=3,<3.2.2"
+ },
+ "require-dev": {
+ "doctrine/collections": "^1.6.8",
+ "doctrine/common": "^2.13.3 || ^3.2.2",
+ "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/DeepCopy/deep_copy.php"
+ ],
+ "psr-4": {
+ "DeepCopy\\": "src/DeepCopy/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Create deep copies (clones) of your objects",
+ "keywords": [
+ "clone",
+ "copy",
+ "duplicate",
+ "object",
+ "object graph"
+ ],
+ "support": {
+ "issues": "https://github.com/myclabs/DeepCopy/issues",
+ "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0"
+ },
+ "funding": [
+ {
+ "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-03-03T13:19:32+00:00"
+ },
+ {
+ "name": "nikic/php-parser",
+ "version": "v4.13.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nikic/PHP-Parser.git",
+ "reference": "210577fe3cf7badcc5814d99455df46564f3c077"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077",
+ "reference": "210577fe3cf7badcc5814d99455df46564f3c077",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "php": ">=7.0"
+ },
+ "require-dev": {
+ "ircmaxell/php-yacc": "^0.0.7",
+ "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
+ },
+ "bin": [
+ "bin/php-parse"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.9-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PhpParser\\": "lib/PhpParser"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Nikita Popov"
+ }
+ ],
+ "description": "A PHP parser written in PHP",
+ "keywords": [
+ "parser",
+ "php"
+ ],
+ "support": {
+ "issues": "https://github.com/nikic/PHP-Parser/issues",
+ "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2"
+ },
+ "time": "2021-11-30T19:35:32+00:00"
+ },
+ {
+ "name": "phar-io/manifest",
+ "version": "2.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/manifest.git",
+ "reference": "97803eca37d319dfa7826cc2437fc020857acb53"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53",
+ "reference": "97803eca37d319dfa7826cc2437fc020857acb53",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-phar": "*",
+ "ext-xmlwriter": "*",
+ "phar-io/version": "^3.0.1",
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
+ "support": {
+ "issues": "https://github.com/phar-io/manifest/issues",
+ "source": "https://github.com/phar-io/manifest/tree/2.0.3"
+ },
+ "time": "2021-07-20T11:28:43+00:00"
+ },
+ {
+ "name": "phar-io/version",
+ "version": "3.2.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/version.git",
+ "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
+ "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Library for handling version information and constraints",
+ "support": {
+ "issues": "https://github.com/phar-io/version/issues",
+ "source": "https://github.com/phar-io/version/tree/3.2.1"
+ },
+ "time": "2022-02-21T01:04:05+00:00"
+ },
+ {
+ "name": "phpdocumentor/reflection-common",
+ "version": "2.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
+ "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b",
+ "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-2.x": "2.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jaap van Otterdijk",
+ "email": "opensource@ijaap.nl"
+ }
+ ],
+ "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
+ "homepage": "http://www.phpdoc.org",
+ "keywords": [
+ "FQSEN",
+ "phpDocumentor",
+ "phpdoc",
+ "reflection",
+ "static analysis"
+ ],
+ "support": {
+ "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues",
+ "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x"
+ },
+ "time": "2020-06-27T09:03:43+00:00"
+ },
+ {
+ "name": "phpdocumentor/reflection-docblock",
+ "version": "5.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
+ "reference": "622548b623e81ca6d78b721c5e029f4ce664f170"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170",
+ "reference": "622548b623e81ca6d78b721c5e029f4ce664f170",
+ "shasum": ""
+ },
+ "require": {
+ "ext-filter": "*",
+ "php": "^7.2 || ^8.0",
+ "phpdocumentor/reflection-common": "^2.2",
+ "phpdocumentor/type-resolver": "^1.3",
+ "webmozart/assert": "^1.9.1"
+ },
+ "require-dev": {
+ "mockery/mockery": "~1.3.2",
+ "psalm/phar": "^4.8"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Mike van Riel",
+ "email": "me@mikevanriel.com"
+ },
+ {
+ "name": "Jaap van Otterdijk",
+ "email": "account@ijaap.nl"
+ }
+ ],
+ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
+ "support": {
+ "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
+ "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0"
+ },
+ "time": "2021-10-19T17:43:47+00:00"
+ },
+ {
+ "name": "phpdocumentor/type-resolver",
+ "version": "1.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/TypeResolver.git",
+ "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/93ebd0014cab80c4ea9f5e297ea48672f1b87706",
+ "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0",
+ "phpdocumentor/reflection-common": "^2.0"
+ },
+ "require-dev": {
+ "ext-tokenizer": "*",
+ "psalm/phar": "^4.8"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-1.x": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Mike van Riel",
+ "email": "me@mikevanriel.com"
+ }
+ ],
+ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
+ "support": {
+ "issues": "https://github.com/phpDocumentor/TypeResolver/issues",
+ "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.0"
+ },
+ "time": "2022-01-04T19:58:01+00:00"
+ },
+ {
+ "name": "phpspec/prophecy",
+ "version": "v1.15.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpspec/prophecy.git",
+ "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/bbcd7380b0ebf3961ee21409db7b38bc31d69a13",
+ "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/instantiator": "^1.2",
+ "php": "^7.2 || ~8.0, <8.2",
+ "phpdocumentor/reflection-docblock": "^5.2",
+ "sebastian/comparator": "^3.0 || ^4.0",
+ "sebastian/recursion-context": "^3.0 || ^4.0"
+ },
+ "require-dev": {
+ "phpspec/phpspec": "^6.0 || ^7.0",
+ "phpunit/phpunit": "^8.0 || ^9.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Prophecy\\": "src/Prophecy"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Konstantin Kudryashov",
+ "email": "ever.zet@gmail.com",
+ "homepage": "http://everzet.com"
+ },
+ {
+ "name": "Marcello Duarte",
+ "email": "marcello.duarte@gmail.com"
+ }
+ ],
+ "description": "Highly opinionated mocking framework for PHP 5.3+",
+ "homepage": "https://github.com/phpspec/prophecy",
+ "keywords": [
+ "Double",
+ "Dummy",
+ "fake",
+ "mock",
+ "spy",
+ "stub"
+ ],
+ "support": {
+ "issues": "https://github.com/phpspec/prophecy/issues",
+ "source": "https://github.com/phpspec/prophecy/tree/v1.15.0"
+ },
+ "time": "2021-12-08T12:19:24+00:00"
+ },
+ {
+ "name": "phpunit/php-code-coverage",
+ "version": "9.2.15",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
+ "reference": "2e9da11878c4202f97915c1cb4bb1ca318a63f5f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2e9da11878c4202f97915c1cb4bb1ca318a63f5f",
+ "reference": "2e9da11878c4202f97915c1cb4bb1ca318a63f5f",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-libxml": "*",
+ "ext-xmlwriter": "*",
+ "nikic/php-parser": "^4.13.0",
+ "php": ">=7.3",
+ "phpunit/php-file-iterator": "^3.0.3",
+ "phpunit/php-text-template": "^2.0.2",
+ "sebastian/code-unit-reverse-lookup": "^2.0.2",
+ "sebastian/complexity": "^2.0",
+ "sebastian/environment": "^5.1.2",
+ "sebastian/lines-of-code": "^1.0.3",
+ "sebastian/version": "^3.0.1",
+ "theseer/tokenizer": "^1.2.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "suggest": {
+ "ext-pcov": "*",
+ "ext-xdebug": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "9.2-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
+ "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
+ "keywords": [
+ "coverage",
+ "testing",
+ "xunit"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.15"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2022-03-07T09:28:20+00:00"
+ },
+ {
+ "name": "phpunit/php-file-iterator",
+ "version": "3.0.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
+ "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
+ "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "FilterIterator implementation that filters files based on a list of suffixes.",
+ "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
+ "keywords": [
+ "filesystem",
+ "iterator"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
+ "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2021-12-02T12:48:52+00:00"
+ },
+ {
+ "name": "phpunit/php-invoker",
+ "version": "3.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-invoker.git",
+ "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
+ "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "ext-pcntl": "*",
+ "phpunit/phpunit": "^9.3"
+ },
+ "suggest": {
+ "ext-pcntl": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Invoke callables with a timeout",
+ "homepage": "https://github.com/sebastianbergmann/php-invoker/",
+ "keywords": [
+ "process"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-invoker/issues",
+ "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-09-28T05:58:55+00:00"
+ },
+ {
+ "name": "phpunit/php-text-template",
+ "version": "2.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-text-template.git",
+ "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
+ "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Simple template engine.",
+ "homepage": "https://github.com/sebastianbergmann/php-text-template/",
+ "keywords": [
+ "template"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
+ "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-10-26T05:33:50+00:00"
+ },
+ {
+ "name": "phpunit/php-timer",
+ "version": "5.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-timer.git",
+ "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
+ "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Utility class for timing",
+ "homepage": "https://github.com/sebastianbergmann/php-timer/",
+ "keywords": [
+ "timer"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-timer/issues",
+ "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-10-26T13:16:10+00:00"
+ },
+ {
+ "name": "phpunit/phpunit",
+ "version": "9.5.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
+ "reference": "35ea4b7f3acabb26f4bb640f8c30866c401da807"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/35ea4b7f3acabb26f4bb640f8c30866c401da807",
+ "reference": "35ea4b7f3acabb26f4bb640f8c30866c401da807",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/instantiator": "^1.3.1",
+ "ext-dom": "*",
+ "ext-json": "*",
+ "ext-libxml": "*",
+ "ext-mbstring": "*",
+ "ext-xml": "*",
+ "ext-xmlwriter": "*",
+ "myclabs/deep-copy": "^1.10.1",
+ "phar-io/manifest": "^2.0.3",
+ "phar-io/version": "^3.0.2",
+ "php": ">=7.3",
+ "phpspec/prophecy": "^1.12.1",
+ "phpunit/php-code-coverage": "^9.2.13",
+ "phpunit/php-file-iterator": "^3.0.5",
+ "phpunit/php-invoker": "^3.1.1",
+ "phpunit/php-text-template": "^2.0.3",
+ "phpunit/php-timer": "^5.0.2",
+ "sebastian/cli-parser": "^1.0.1",
+ "sebastian/code-unit": "^1.0.6",
+ "sebastian/comparator": "^4.0.5",
+ "sebastian/diff": "^4.0.3",
+ "sebastian/environment": "^5.1.3",
+ "sebastian/exporter": "^4.0.3",
+ "sebastian/global-state": "^5.0.1",
+ "sebastian/object-enumerator": "^4.0.3",
+ "sebastian/resource-operations": "^3.0.3",
+ "sebastian/type": "^3.0",
+ "sebastian/version": "^3.0.2"
+ },
+ "require-dev": {
+ "ext-pdo": "*",
+ "phpspec/prophecy-phpunit": "^2.0.1"
+ },
+ "suggest": {
+ "ext-soap": "*",
+ "ext-xdebug": "*"
+ },
+ "bin": [
+ "phpunit"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "9.5-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/Framework/Assert/Functions.php"
+ ],
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "The PHP Unit Testing framework.",
+ "homepage": "https://phpunit.de/",
+ "keywords": [
+ "phpunit",
+ "testing",
+ "xunit"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/phpunit/issues",
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.19"
+ },
+ "funding": [
+ {
+ "url": "https://phpunit.de/sponsors.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2022-03-15T09:57:31+00:00"
+ },
+ {
+ "name": "sebastian/cli-parser",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/cli-parser.git",
+ "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2",
+ "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for parsing CLI options",
+ "homepage": "https://github.com/sebastianbergmann/cli-parser",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
+ "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-09-28T06:08:49+00:00"
+ },
+ {
+ "name": "sebastian/code-unit",
+ "version": "1.0.8",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/code-unit.git",
+ "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120",
+ "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Collection of value objects that represent the PHP code units",
+ "homepage": "https://github.com/sebastianbergmann/code-unit",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/code-unit/issues",
+ "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-10-26T13:08:54+00:00"
+ },
+ {
+ "name": "sebastian/code-unit-reverse-lookup",
+ "version": "2.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
+ "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
+ "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Looks up which function or method a line of code belongs to",
+ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
+ "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-09-28T05:30:19+00:00"
+ },
+ {
+ "name": "sebastian/comparator",
+ "version": "4.0.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/comparator.git",
+ "reference": "55f4261989e546dc112258c7a75935a81a7ce382"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55f4261989e546dc112258c7a75935a81a7ce382",
+ "reference": "55f4261989e546dc112258c7a75935a81a7ce382",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3",
+ "sebastian/diff": "^4.0",
+ "sebastian/exporter": "^4.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "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": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@2bepublished.at"
+ }
+ ],
+ "description": "Provides the functionality to compare PHP values for equality",
+ "homepage": "https://github.com/sebastianbergmann/comparator",
+ "keywords": [
+ "comparator",
+ "compare",
+ "equality"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/comparator/issues",
+ "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.6"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-10-26T15:49:45+00:00"
+ },
+ {
+ "name": "sebastian/complexity",
+ "version": "2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/complexity.git",
+ "reference": "739b35e53379900cc9ac327b2147867b8b6efd88"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88",
+ "reference": "739b35e53379900cc9ac327b2147867b8b6efd88",
+ "shasum": ""
+ },
+ "require": {
+ "nikic/php-parser": "^4.7",
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for calculating the complexity of PHP code units",
+ "homepage": "https://github.com/sebastianbergmann/complexity",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/complexity/issues",
+ "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-10-26T15:52:27+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": "sebastian/environment",
+ "version": "5.1.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/environment.git",
+ "reference": "388b6ced16caa751030f6a69e588299fa09200ac"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/388b6ced16caa751030f6a69e588299fa09200ac",
+ "reference": "388b6ced16caa751030f6a69e588299fa09200ac",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "suggest": {
+ "ext-posix": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides functionality to handle HHVM/PHP environments",
+ "homepage": "http://www.github.com/sebastianbergmann/environment",
+ "keywords": [
+ "Xdebug",
+ "environment",
+ "hhvm"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/environment/issues",
+ "source": "https://github.com/sebastianbergmann/environment/tree/5.1.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-09-28T05:52:38+00:00"
+ },
+ {
+ "name": "sebastian/exporter",
+ "version": "4.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/exporter.git",
+ "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/65e8b7db476c5dd267e65eea9cab77584d3cfff9",
+ "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3",
+ "sebastian/recursion-context": "^4.0"
+ },
+ "require-dev": {
+ "ext-mbstring": "*",
+ "phpunit/phpunit": "^9.3"
+ },
+ "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": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
+ }
+ ],
+ "description": "Provides the functionality to export PHP variables for visualization",
+ "homepage": "https://www.github.com/sebastianbergmann/exporter",
+ "keywords": [
+ "export",
+ "exporter"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/exporter/issues",
+ "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2021-11-11T14:18:36+00:00"
+ },
+ {
+ "name": "sebastian/global-state",
+ "version": "5.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/global-state.git",
+ "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2",
+ "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3",
+ "sebastian/object-reflector": "^2.0",
+ "sebastian/recursion-context": "^4.0"
+ },
+ "require-dev": {
+ "ext-dom": "*",
+ "phpunit/phpunit": "^9.3"
+ },
+ "suggest": {
+ "ext-uopz": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Snapshotting of global state",
+ "homepage": "http://www.github.com/sebastianbergmann/global-state",
+ "keywords": [
+ "global state"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/global-state/issues",
+ "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2022-02-14T08:28:10+00:00"
+ },
+ {
+ "name": "sebastian/lines-of-code",
+ "version": "1.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/lines-of-code.git",
+ "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc",
+ "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc",
+ "shasum": ""
+ },
+ "require": {
+ "nikic/php-parser": "^4.6",
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for counting the lines of code in PHP source code",
+ "homepage": "https://github.com/sebastianbergmann/lines-of-code",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
+ "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-11-28T06:42:11+00:00"
+ },
+ {
+ "name": "sebastian/object-enumerator",
+ "version": "4.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-enumerator.git",
+ "reference": "5c9eeac41b290a3712d88851518825ad78f45c71"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71",
+ "reference": "5c9eeac41b290a3712d88851518825ad78f45c71",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3",
+ "sebastian/object-reflector": "^2.0",
+ "sebastian/recursion-context": "^4.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "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"
+ }
+ ],
+ "description": "Traverses array structures and object graphs to enumerate all referenced objects",
+ "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
+ "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-10-26T13:12:34+00:00"
+ },
+ {
+ "name": "sebastian/object-reflector",
+ "version": "2.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-reflector.git",
+ "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
+ "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Allows reflection of object attributes, including inherited and non-public ones",
+ "homepage": "https://github.com/sebastianbergmann/object-reflector/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
+ "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-10-26T13:14:26+00:00"
+ },
+ {
+ "name": "sebastian/recursion-context",
+ "version": "4.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/recursion-context.git",
+ "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cd9d8cf3c5804de4341c283ed787f099f5506172",
+ "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "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": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ }
+ ],
+ "description": "Provides functionality to recursively process PHP variables",
+ "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
+ "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-10-26T13:17:30+00:00"
+ },
+ {
+ "name": "sebastian/resource-operations",
+ "version": "3.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/resource-operations.git",
+ "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
+ "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides a list of PHP built-in functions that operate on resources",
+ "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/resource-operations/issues",
+ "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-09-28T06:45:17+00:00"
+ },
+ {
+ "name": "sebastian/type",
+ "version": "3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/type.git",
+ "reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b233b84bc4465aff7b57cf1c4bc75c86d00d6dad",
+ "reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Collection of value objects that represent the types of the PHP type system",
+ "homepage": "https://github.com/sebastianbergmann/type",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/type/issues",
+ "source": "https://github.com/sebastianbergmann/type/tree/3.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2022-03-15T09:54:48+00:00"
+ },
+ {
+ "name": "sebastian/version",
+ "version": "3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/version.git",
+ "reference": "c6c1022351a901512170118436c764e473f6de8c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c",
+ "reference": "c6c1022351a901512170118436c764e473f6de8c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that helps with managing the version number of Git-hosted PHP projects",
+ "homepage": "https://github.com/sebastianbergmann/version",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/version/issues",
+ "source": "https://github.com/sebastianbergmann/version/tree/3.0.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-09-28T06:39:44+00:00"
+ },
+ {
+ "name": "symfony/polyfill-ctype",
+ "version": "v1.25.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-ctype.git",
+ "reference": "30885182c981ab175d4d034db0f6f469898070ab"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab",
+ "reference": "30885182c981ab175d4d034db0f6f469898070ab",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "provide": {
+ "ext-ctype": "*"
+ },
+ "suggest": {
+ "ext-ctype": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.23-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.25.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": "2021-10-20T20:35:02+00:00"
+ },
+ {
+ "name": "theseer/tokenizer",
+ "version": "1.2.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/theseer/tokenizer.git",
+ "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e",
+ "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-tokenizer": "*",
+ "ext-xmlwriter": "*",
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
+ "support": {
+ "issues": "https://github.com/theseer/tokenizer/issues",
+ "source": "https://github.com/theseer/tokenizer/tree/1.2.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/theseer",
+ "type": "github"
+ }
+ ],
+ "time": "2021-07-28T10:34:58+00:00"
+ },
+ {
+ "name": "webmozart/assert",
+ "version": "1.10.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/webmozarts/assert.git",
+ "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25",
+ "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0",
+ "symfony/polyfill-ctype": "^1.8"
+ },
+ "conflict": {
+ "phpstan/phpstan": "<0.12.20",
+ "vimeo/psalm": "<4.6.1 || 4.6.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^8.5.13"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.10-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Webmozart\\Assert\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
+ }
+ ],
+ "description": "Assertions to validate method input/output with nice error messages.",
+ "keywords": [
+ "assert",
+ "check",
+ "validate"
+ ],
+ "support": {
+ "issues": "https://github.com/webmozarts/assert/issues",
+ "source": "https://github.com/webmozarts/assert/tree/1.10.0"
+ },
+ "time": "2021-03-09T10:59:23+00:00"
+ }
+ ],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": [],
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": [],
+ "platform-dev": [],
+ "plugin-api-version": "2.2.0"
+}
diff --git a/js/files.js b/js/files.js
index 947993ff..90c90964 100644
--- a/js/files.js
+++ b/js/files.js
@@ -1,9 +1,14 @@
(function() {
+ var LOCK_TYPE_USER = 0;
+ var LOCK_TYPE_APP = 1;
+
_.extend(OC.Files.Client, {
PROPERTY_FILES_LOCK: '{' + OC.Files.Client.NS_NEXTCLOUD + '}lock',
PROPERTY_FILES_LOCK_OWNER: '{' + OC.Files.Client.NS_NEXTCLOUD + '}lock-owner',
PROPERTY_FILES_LOCK_OWNER_DISPLAYNAME: '{' + OC.Files.Client.NS_NEXTCLOUD + '}lock-owner-displayname',
+ PROPERTY_FILES_LOCK_OWNER_TYPE: '{' + OC.Files.Client.NS_NEXTCLOUD + '}lock-owner-type',
+ PROPERTY_FILES_LOCK_OWNER_EDITOR: '{' + OC.Files.Client.NS_NEXTCLOUD + '}lock-owner-editor',
PROPERTY_FILES_LOCK_TIME: '{' + OC.Files.Client.NS_NEXTCLOUD + '}lock-time'
})
@@ -18,6 +23,8 @@
props.push(OC.Files.Client.PROPERTY_FILES_LOCK_OWNER)
props.push(OC.Files.Client.PROPERTY_FILES_LOCK_OWNER_DISPLAYNAME)
props.push(OC.Files.Client.PROPERTY_FILES_LOCK_TIME)
+ props.push(OC.Files.Client.PROPERTY_FILES_LOCK_OWNER_TYPE)
+ props.push(OC.Files.Client.PROPERTY_FILES_LOCK_OWNER_EDITOR)
return props
}
@@ -27,6 +34,8 @@
var isLocked = props[OC.Files.Client.PROPERTY_FILES_LOCK]
if (!_.isUndefined(isLocked) && isLocked !== '') {
data.locked = isLocked === '1'
+ data.lockOwnerType = props[OC.Files.Client.PROPERTY_FILES_LOCK_OWNER_TYPE]
+ data.lockOwnerEditor = props[OC.Files.Client.PROPERTY_FILES_LOCK_OWNER_EDITOR]
data.lockOwner = props[OC.Files.Client.PROPERTY_FILES_LOCK_OWNER]
data.lockOwnerDisplayname = props[OC.Files.Client.PROPERTY_FILES_LOCK_OWNER_DISPLAYNAME]
data.lockTime = props[OC.Files.Client.PROPERTY_FILES_LOCK_TIME]
@@ -39,6 +48,8 @@
var $tr = oldCreateRow.apply(this, arguments)
if (fileData.locked) {
$tr.attr('data-locked', fileData.locked)
+ $tr.attr('data-lock-owner-type', fileData.lockOwnerType)
+ $tr.attr('data-lock-owner-editor', fileData.lockOwnerEditor)
$tr.attr('data-lock-owner', fileData.lockOwner)
$tr.attr('data-lock-owner-displayname', fileData.lockOwnerDisplayname)
$tr.attr('data-lock-time', fileData.lockTime)
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index 7feadf6e..fabe9249 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -37,7 +37,8 @@
use OCA\Files\Event\LoadAdditionalScriptsEvent;
use OCA\FilesLock\Capability;
use OCA\FilesLock\Listeners\LoadAdditionalScripts;
-use OCA\FilesLock\Plugins\FilesLockPlugin;
+use OCA\FilesLock\Plugins\FilesLockBackend;
+use OCA\FilesLock\Plugins\LockPlugin;
use OCA\FilesLock\Service\FileService;
use OCA\FilesLock\Service\LockService;
use OCA\FilesLock\Storage\LockWrapper;
@@ -65,8 +66,10 @@ class Application extends App implements IBootstrap {
const DAV_PROPERTY_LOCK = '{http://nextcloud.org/ns}lock';
+ const DAV_PROPERTY_LOCK_OWNER_TYPE = '{http://nextcloud.org/ns}lock-owner-type';
const DAV_PROPERTY_LOCK_OWNER = '{http://nextcloud.org/ns}lock-owner';
const DAV_PROPERTY_LOCK_OWNER_DISPLAYNAME = '{http://nextcloud.org/ns}lock-owner-displayname';
+ const DAV_PROPERTY_LOCK_EDITOR = '{http://nextcloud.org/ns}lock-owner-editor';
const DAV_PROPERTY_LOCK_TIME = '{http://nextcloud.org/ns}lock-time';
@@ -120,29 +123,6 @@ public function registerHooks(IServerContainer $container) {
$this->fileService = $container->get(FileService::class);
$this->lockService = $container->get(LockService::class);
- $eventDispatcher->addListener(
- 'OCA\DAV\Connector\Sabre::addPlugin', function (SabrePluginEvent $e) {
- $server = $e->getServer();
- $absolute = false;
- switch (get_class($server->tree)) {
- case ObjectTree::class:
- $absolute = false;
- break;
-
- case CachingTree::class:
- $absolute = true;
- break;
- }
-
- $server->on('propFind', [$this->lockService, 'propFind']);
- $server->addPlugin(
- new Plugin(
- new FilesLockPlugin($this->userSession, $this->fileService, $this->lockService, $absolute)
- )
- );
- }
- );
-
Util::connectHook('OC_Filesystem', 'preSetup', $this, 'addStorageWrapper');
}
diff --git a/lib/Command/Lock.php b/lib/Command/Lock.php
index 7b6efd51..e658ac3a 100644
--- a/lib/Command/Lock.php
+++ b/lib/Command/Lock.php
@@ -204,7 +204,7 @@ private function lockFile(InputInterface $input, OutputInterface $output, int $f
$file = $this->fileService->getFileFromId($user->getUID(), $fileId);
$output->writeln('locking ' . $file->getName() . ' to ' . $userId . '');
- $this->lockService->lockFile($file, $user);
+ $this->lockService->lockFileAsUser($file, $user);
}
diff --git a/lib/Controller/LockController.php b/lib/Controller/LockController.php
index 6f039dea..44b6717c 100644
--- a/lib/Controller/LockController.php
+++ b/lib/Controller/LockController.php
@@ -94,7 +94,7 @@ public function locking(string $fileId): DataResponse {
$user = $this->userSession->getUser();
$file = $this->fileService->getFileFromId($user->getUID(), (int)$fileId);
- $lock = $this->lockService->lockFile($file, $user);
+ $lock = $this->lockService->lockFileAsUser($file, $user);
return new DataResponse($lock, Http::STATUS_OK);
} catch (Exception $e) {
diff --git a/lib/Plugins/FilesLockPlugin.php b/lib/DAV/LockBackend.php
similarity index 78%
rename from lib/Plugins/FilesLockPlugin.php
rename to lib/DAV/LockBackend.php
index 3c3a5862..633b0d5a 100644
--- a/lib/Plugins/FilesLockPlugin.php
+++ b/lib/DAV/LockBackend.php
@@ -25,7 +25,7 @@
*/
-namespace OCA\FilesLock\Plugins;
+namespace OCA\FilesLock\DAV;
use Exception;
@@ -34,18 +34,10 @@
use OCP\IUserSession;
use Sabre\DAV\Locks\Backend\BackendInterface;
use Sabre\DAV\Locks\LockInfo;
+use Sabre\DAV\Server;
-/**
- * Class AppLockPlugin
- *
- * @package OCA\DAV\Files
- */
-class FilesLockPlugin implements BackendInterface {
-
-
- /** @var IUserSession */
- private $userSession;
+class LockBackend implements BackendInterface {
/** @var FileService */
private $fileService;
@@ -56,19 +48,10 @@ class FilesLockPlugin implements BackendInterface {
/** @var bool */
private $absolute = false;
-
- /**
- * FilesLockPlugin constructor.
- *
- * @param IUserSession $userSession
- * @param FileService $fileService
- * @param LockService $lockService
- * @param bool $absolute
- */
public function __construct(
- IUserSession $userSession, FileService $fileService, LockService $lockService, bool $absolute
+ Server $server, FileService $fileService, LockService $lockService, bool $absolute
) {
- $this->userSession = $userSession;
+ $this->server = $server;
$this->fileService = $fileService;
$this->lockService = $lockService;
$this->absolute = $absolute;
@@ -93,11 +76,6 @@ function getLocks($uri, $returnChildLocks): array {
$lock = $this->lockService->getLockFromFileId($file->getId());
- $user = $this->userSession->getUser();
- if ($user !== null && $lock->getUserId() === $user->getUID()) {
- return [];
- }
-
return [$lock->toLockInfo()];
} catch (Exception $e) {
return $locks;
diff --git a/lib/DAV/LockPlugin.php b/lib/DAV/LockPlugin.php
new file mode 100644
index 00000000..cbaf7059
--- /dev/null
+++ b/lib/DAV/LockPlugin.php
@@ -0,0 +1,159 @@
+lockService = $lockService;
+ $this->fileService = $fileService;
+ $this->userManager = $userManager;
+ $this->userSession = $userSession;
+ }
+
+ public function initialize(Server $server) {
+ $absolute = false;
+ switch (get_class($server->tree)) {
+ case ObjectTree::class:
+ $absolute = false;
+ break;
+
+ case CachingTree::class:
+ $absolute = true;
+ break;
+ }
+ $this->locksBackend = new LockBackend($server, $this->fileService, $this->lockService, $absolute);
+ $server->on('propFind', [$this, 'customProperties']);
+ parent::initialize($server);
+ }
+
+ /**
+ * @param PropFind $propFind
+ * @param INode $node
+ *
+ * @return void
+ */
+ public function customProperties(PropFind $propFind, INode $node) {
+ if (!$node instanceof SabreNode) {
+ return;
+ }
+
+ $nodeId = $node->getId();
+
+ $propFind->handle(Application::DAV_PROPERTY_LOCK, function () use ($nodeId) {
+ $lock = $this->lockService->getLockForNodeId($nodeId);
+ return $lock instanceof FileLock;
+ });
+
+ $propFind->handle(Application::DAV_PROPERTY_LOCK_OWNER, function () use ($nodeId) {
+ $lock = $this->lockService->getLockForNodeId($nodeId);
+
+ if ($lock !== false && $lock->getLockType() === FileLock::LOCK_TYPE_USER) {
+ return $lock->getUserId();
+ }
+
+ return null;
+ });
+
+ $propFind->handle(Application::DAV_PROPERTY_LOCK_TIME, function () use ($nodeId) {
+ $lock = $this->lockService->getLockForNodeId($nodeId);
+
+ if ($lock !== false) {
+ return $lock->getCreation();
+ }
+
+ return null;
+ });
+
+ $propFind->handle(Application::DAV_PROPERTY_LOCK_OWNER_DISPLAYNAME, function () use ($nodeId) {
+ $lock = $this->lockService->getLockForNodeId($nodeId);
+
+ if ($lock === false) {
+ return null;
+ }
+
+ if ($lock->getLockType() === FileLock::LOCK_TYPE_APP) {
+ return \OC::$server->get(AppLockService::class)->getAppName($lock->getUserId());
+ }
+
+ $user = $this->userManager->get($lock->getUserId());
+ if ($user !== null) {
+ return $user->getDisplayName();
+ }
+
+ return null;
+ });
+
+ $propFind->handle(Application::DAV_PROPERTY_LOCK_OWNER_TYPE, function () use ($nodeId) {
+ $lock = $this->lockService->getLockForNodeId($nodeId);
+
+ if ($lock !== false) {
+ return $lock->getLockType();
+ }
+
+ return null;
+ });
+
+ $propFind->handle(Application::DAV_PROPERTY_LOCK_EDITOR, function () use ($nodeId) {
+ $lock = $this->lockService->getLockForNodeId($nodeId);
+ if ($lock === false || $lock->getLockType() !== FileLock::LOCK_TYPE_APP) {
+ return null;
+ }
+
+ return $lock->getUserId();
+ });
+ }
+
+ public function httpLock(RequestInterface $request, ResponseInterface $response) {
+ if ($request->getHeader('X-User-Lock')) {
+ $file = $this->fileService->getFileFromAbsoluteUri($this->server->getRequestUri());
+ $this->lockService->lockFileAsUser($file, $this->userSession->getUser());
+ $response->setHeader('Content-Type', 'application/xml; charset=utf-8');
+ //$response->setHeader('Lock-Token', 'token.'>');
+ //$response->setStatus($newFile ? 201 : 200);
+ //$response->setBody($this->generateLockResponse($lockInfo));
+ $response->setStatus(200);
+ return false;
+ }
+ return parent::httpLock($request, $response);
+ }
+
+ public function httpUnlock(RequestInterface $request, ResponseInterface $response) {
+ if ($request->getHeader('X-User-Lock')) {
+ $file = $this->fileService->getFileFromAbsoluteUri($this->server->getRequestUri());
+ $this->lockService->unlockFile($file->getId(), $this->userSession->getUser()->getUID());
+ $response->setHeader('Content-Type', 'application/xml; charset=utf-8');
+ //$response->setHeader('Lock-Token', 'token.'>');
+ //$response->setStatus($newFile ? 201 : 200);
+ //$response->setBody($this->generateLockResponse($lockInfo));
+ $response->setStatus(200);
+ return false;
+ }
+ return parent::httpLock($request, $response);
+ }
+}
diff --git a/lib/Db/LocksRequest.php b/lib/Db/LocksRequest.php
index fdb5d5bc..18227173 100644
--- a/lib/Db/LocksRequest.php
+++ b/lib/Db/LocksRequest.php
@@ -52,7 +52,8 @@ public function save(FileLock $lock) {
$qb->setValue('user_id', $qb->createNamedParameter($lock->getUserId()))
->setValue('file_id', $qb->createNamedParameter($lock->getFileId()))
->setValue('token', $qb->createNamedParameter($lock->getToken()))
- ->setValue('creation', $qb->createNamedParameter($lock->getCreation()));
+ ->setValue('creation', $qb->createNamedParameter($lock->getCreation()))
+ ->setValue('type', $qb->createNamedParameter($lock->getLockType()));
try {
$qb->execute();
diff --git a/lib/Db/LocksRequestBuilder.php b/lib/Db/LocksRequestBuilder.php
index 57a3fd6d..a5818d7f 100644
--- a/lib/Db/LocksRequestBuilder.php
+++ b/lib/Db/LocksRequestBuilder.php
@@ -90,7 +90,7 @@ protected function getLocksUpdateSql(): CoreQueryBuilder {
protected function getLocksSelectSql(): CoreQueryBuilder {
$qb = $this->getQueryBuilder();
- $qb->select('l.id', 'l.user_id', 'l.file_id', 'l.token', 'l.creation')
+ $qb->select('l.id', 'l.user_id', 'l.file_id', 'l.token', 'l.creation', 'l.type')
->from(self::TABLE_LOCKS, 'l');
$qb->setDefaultSelectAlias('l');
diff --git a/lib/Migration/Version1000Date20220201111525.php b/lib/Migration/Version1000Date20220201111525.php
new file mode 100644
index 00000000..0eec3655
--- /dev/null
+++ b/lib/Migration/Version1000Date20220201111525.php
@@ -0,0 +1,57 @@
+getTable('files_lock');
+
+ $hasSchemaChanges = false;
+ if (!$table->hasColumn('type')) {
+ $table->addColumn(
+ 'type', Types::SMALLINT,
+ [
+ 'default' => 0,
+ 'unsigned' => true,
+ ]
+ );
+ $hasSchemaChanges = true;
+ }
+
+ if (!$table->hasColumn('scope')) {
+ $table->addColumn(
+ 'scope', Types::SMALLINT,
+ [
+ 'default' => 0,
+ 'unsigned' => true,
+ ]
+ );
+ $hasSchemaChanges = true;
+ }
+
+ if (!$table->hasColumn('ttl')) {
+ $table->addColumn(
+ 'ttl', Types::INTEGER,
+ [
+ 'default' => 0,
+ ]
+ );
+ $hasSchemaChanges = true;
+ }
+ return $hasSchemaChanges ? $schema : null;
+ }
+}
diff --git a/lib/Model/FileLock.php b/lib/Model/FileLock.php
index 232f5646..9eb7171f 100644
--- a/lib/Model/FileLock.php
+++ b/lib/Model/FileLock.php
@@ -33,6 +33,7 @@
use OCA\FilesLock\Tools\Db\IQueryRow;
use OCA\FilesLock\Tools\Traits\TArrayTools;
use JsonSerializable;
+use OCP\AppFramework\Utility\ITimeFactory;
use Sabre\DAV\Locks\LockInfo;
/**
@@ -47,6 +48,14 @@ class FileLock implements IQueryRow, JsonSerializable {
public const ETA_INFINITE = -1;
+ public const LOCK_TYPE_USER = 0;
+ public const LOCK_TYPE_APP = 1;
+ private const LOCK_TYPE_DAV = 2; // Not in use but reserved for WebDAV implementation
+
+
+ public const LOCK_SCOPE_EXCLUSIVE = 0;
+ private const LOCK_SCOPE_SHARED = 1; // Not in use but reserved for WebDAV implementation
+
/** @var int */
private $id = 0;
@@ -69,6 +78,9 @@ class FileLock implements IQueryRow, JsonSerializable {
/** @var int */
private $creation = 0;
+ /** @var int */
+ private $lockType = self::LOCK_TYPE_USER;
+
/**
* FileLock constructor.
@@ -77,7 +89,7 @@ class FileLock implements IQueryRow, JsonSerializable {
*/
public function __construct(int $timeout = 1800) {
$this->timeout = $timeout;
- $this->creation = time();
+ $this->creation = \OC::$server->get(ITimeFactory::class)->getTime();
}
@@ -202,8 +214,7 @@ public function getETA(): int {
return self::ETA_INFINITE;
}
$end = $this->getCreation() + $this->getTimeout();
- $eta = $end - time();
-
+ $eta = $end - \OC::$server->get(ITimeFactory::class)->getTime();
return ($eta < 1) ? 0 : $eta;
}
@@ -225,6 +236,15 @@ public function setCreation(int $creation): self {
return $this;
}
+ public function getLockType(): int {
+ return $this->lockType;
+ }
+
+ public function setLockType(int $lockType): self {
+ $this->lockType = $lockType;
+ return $this;
+ }
+
/**
* @return LockInfo
@@ -254,6 +274,7 @@ public function importFromDatabase(array $data):IQueryRow {
$this->setFileId($this->getInt('file_id', $data));
$this->setToken($this->get('token', $data));
$this->setCreation($this->getInt('creation', $data));
+ $this->setLockType($this->getInt('type', $data));
return $this;
}
@@ -269,6 +290,7 @@ public function import(array $data) {
$this->setFileId($this->getInt('fileId', $data));
$this->setToken($this->get('token', $data));
$this->setCreation($this->getInt('creation', $data));
+ $this->setLockType($this->getInt('type', $data));
}
@@ -283,7 +305,8 @@ public function jsonSerialize(): array {
'fileId' => $this->getFileId(),
'token' => $this->getToken(),
'eta' => $this->getETA(),
- 'creation' => $this->getCreation()
+ 'creation' => $this->getCreation(),
+ 'type' => $this->getLockType(),
];
}
diff --git a/lib/Service/AppLockService.php b/lib/Service/AppLockService.php
new file mode 100644
index 00000000..fd23452c
--- /dev/null
+++ b/lib/Service/AppLockService.php
@@ -0,0 +1,104 @@
+lockService = $lockService;
+ $this->appManager = $appManager;
+ $this->configService = $configService;
+ $this->directEditingManager = $directEditingManager;
+ $this->eventDispatcher = $eventDispatcher;
+ }
+
+ public function lockFileAsApp(Node $file, string $appId): FileLock {
+ if (!$this->appManager->isEnabledForUser($appId)) {
+ throw new PreConditionNotMetException('App is not enabled for the user');
+ }
+
+ if ($file->getType() !== Node::TYPE_FILE) {
+ throw new NotFileException('Must be a file, seems to be a folder.');
+ }
+
+ $lock = new FileLock($this->configService->getTimeoutSeconds());
+ $lock->setLockType(FileLock::LOCK_TYPE_APP);
+ $lock->setUserId($appId);
+ $lock->setFileId($file->getId());
+
+ $this->lockService->lock($lock);
+
+ return $lock;
+ }
+
+ public function unlockFileAsApp(Node $file, string $appId): FileLock {
+ if (!$this->appManager->isEnabledForUser($appId)) {
+ throw new PreConditionNotMetException('App is not enabled for the user');
+ }
+
+ if ($file->getType() !== Node::TYPE_FILE) {
+ throw new NotFileException('Must be a file, seems to be a folder.');
+ }
+
+ $lock = new FileLock($this->configService->getTimeoutSeconds());
+ $lock->setLockType(FileLock::LOCK_TYPE_APP);
+ $lock->setUserId($appId);
+ $lock->setFileId($file->getId());
+
+ $this->lockService->unlock($lock);
+
+ return $lock;
+ }
+
+ public function executeInAppScope(string $appId, callable $callback): void {
+ if ($this->appInScope) {
+ throw new PreConditionNotMetException('Could not obtain app scope as already in use by ' . $this->appInScope);
+ }
+
+ try {
+ $this->appInScope = $appId;
+ $callback();
+ } finally {
+ $this->appInScope = null;
+ }
+ }
+
+ public function getAppInScope(): ?string {
+ return $this->appInScope;
+ }
+
+ public function getAppName(string $appId): ?string {
+ $appInfo = $this->appManager->getAppInfo($appId);
+ return $appInfo['name'] ?? null;
+ }
+
+ public function getDirectEditorForAppId(string $appId): ?string {
+ if (!$this->directEditors) {
+ $this->eventDispatcher->dispatchTyped(new RegisterDirectEditorEvent($this->directEditingManager));
+ $this->directEditors = $this->directEditingManager->getEditors();
+ }
+ $editor = current(array_filter($this->directEditors, function ($editor) use ($appId) {
+ return $editor->getId() === $appId;
+ }));
+ return $editor ? $editor->getId() : null;
+ }
+
+}
diff --git a/lib/Service/LockService.php b/lib/Service/LockService.php
index 8217c66e..ffd770a6 100644
--- a/lib/Service/LockService.php
+++ b/lib/Service/LockService.php
@@ -41,12 +41,18 @@
use OCA\FilesLock\Model\FileLock;
use OCA\FilesLock\Tools\Traits\TLogger;
use OCA\FilesLock\Tools\Traits\TStringTools;
+use OCP\App\IAppManager;
+use OCP\DirectEditing\IManager;
+use OCP\DirectEditing\RegisterDirectEditorEvent;
+use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\InvalidPathException;
use OCP\Files\Node;
use OCP\Files\NotFoundException;
use OCP\IL10N;
use OCP\IUser;
use OCP\IUserManager;
+use OCP\Notification\IApp;
+use OCP\PreConditionNotMetException;
use Sabre\DAV\INode;
use Sabre\DAV\PropFind;
@@ -66,50 +72,28 @@ class LockService {
use TLogger;
- /** @var string */
- private $userId;
+ private ?string $userId;
+ private IUserManager $userManager;
+ private IL10N $l10n;
+ private LocksRequest $locksRequest;
+ private FileService $fileService;
+ private ConfigService $configService;
+ private IAppManager $appManager;
- /** @var IUserManager */
- private $userManager;
+ private array $locks = [];
+ private bool $lockRetrieved = false;
+ private array $lockCache = [];
+ private ?string $appInScope;
- /** @var IL10N */
- private $l10n;
- /** @var LocksRequest */
- private $locksRequest;
-
- /** @var FileService */
- private $fileService;
-
- /** @var ConfigService */
- private $configService;
-
-
- /** @var array */
- private $locks = [];
-
- /** @var bool */
- private $lockRetrieved = false;
-
- /** @var array */
- private $lockCache = [];
-
-
- /**
- * @param $userId
- * @param IL10N $l10n
- * @param IUserManager $userManager
- * @param LocksRequest $locksRequest
- * @param FileService $fileService
- * @param ConfigService $configService
- */
public function __construct(
$userId,
IL10N $l10n,
IUserManager $userManager,
LocksRequest $locksRequest,
FileService $fileService,
- ConfigService $configService
+ ConfigService $configService,
+ IAppManager $appManager
) {
$this->userId = $userId;
$this->l10n = $l10n;
@@ -117,6 +101,7 @@ public function __construct(
$this->locksRequest = $locksRequest;
$this->fileService = $fileService;
$this->configService = $configService;
+ $this->appManager = $appManager;
$this->setup('app', 'files_lock');
}
@@ -126,7 +111,7 @@ public function __construct(
*
* @return FileLock|bool
*/
- private function getLockForNodeId(int $nodeId) {
+ public function getLockForNodeId(int $nodeId) {
if (array_key_exists($nodeId, $this->lockCache) && $this->lockCache[$nodeId] !== null) {
return $this->lockCache[$nodeId];
}
@@ -140,70 +125,6 @@ private function getLockForNodeId(int $nodeId) {
return $this->lockCache[$nodeId];
}
- /**
- * @param PropFind $propFind
- * @param INode $node
- *
- * @return void
- */
- public function propFind(PropFind $propFind, INode $node) {
- if (!$node instanceof SabreNode) {
- return;
- }
- $nodeId = $node->getId();
-
- $propFind->handle(
- Application::DAV_PROPERTY_LOCK, function () use ($nodeId) {
- $lock = $this->getLockForNodeId($nodeId);
-
- if ($lock === false) {
- return false;
- }
-
- return true;
- }
- );
-
- $propFind->handle(
- Application::DAV_PROPERTY_LOCK_OWNER, function () use ($nodeId) {
- $lock = $this->getLockForNodeId($nodeId);
-
- if ($lock !== false) {
- return $lock->getUserId();
- }
-
- return null;
- }
- );
-
- $propFind->handle(
- Application::DAV_PROPERTY_LOCK_TIME, function () use ($nodeId) {
- $lock = $this->getLockForNodeId($nodeId);
-
- if ($lock !== false) {
- return $lock->getCreation();
- }
-
- return 0;
- }
- );
-
- $propFind->handle(
- Application::DAV_PROPERTY_LOCK_OWNER_DISPLAYNAME, function () use ($nodeId) {
- $lock = $this->getLockForNodeId($nodeId);
-
- if ($lock !== false) {
- $user = $this->userManager->get($lock->getUserId());
- if ($user !== null) {
- return $user->getDisplayName();
- }
- }
-
- return null;
- }
- );
- }
-
/**
* @param FileLock $lock
@@ -234,7 +155,7 @@ public function lock(FileLock $lock) {
* @throws NotFileException
* @throws NotFoundException
*/
- public function lockFile(Node $file, IUser $user): FileLock {
+ public function lockFileAsUser(Node $file, IUser $user): FileLock {
if ($file->getType() !== Node::TYPE_FILE) {
throw new NotFileException('Must be a file, seems to be a folder.');
}
@@ -248,7 +169,6 @@ public function lockFile(Node $file, IUser $user): FileLock {
return $lock;
}
-
/**
* @param FileLock $lock
* @param bool $force
@@ -260,7 +180,7 @@ public function unlock(FileLock $lock, bool $force = false) {
$this->notice('unlocking file', false, ['fileLock' => $lock]);
$known = $this->getLockFromFileId($lock->getFileId());
- if (!$force && $lock->getUserId() !== $known->getUserId()) {
+ if (!$force && ($lock->getUserId() !== $known->getUserId() || $lock->getLockType() !== $known->getLockType())) {
throw new UnauthorizedUnlockException(
$this->l10n->t('File can only be unlocked by the owner of the lock')
);
diff --git a/lib/Storage/LockWrapper.php b/lib/Storage/LockWrapper.php
index eda2faaa..13669ede 100644
--- a/lib/Storage/LockWrapper.php
+++ b/lib/Storage/LockWrapper.php
@@ -24,6 +24,7 @@
use OC\Files\Storage\Wrapper\Wrapper;
use OCA\FilesLock\Exceptions\LockNotFoundException;
use OCA\FilesLock\Model\FileLock;
+use OCA\FilesLock\Service\AppLockService;
use OCA\FilesLock\Service\FileService;
use OCA\FilesLock\Service\LockService;
use OCP\Constants;
@@ -121,7 +122,14 @@ protected function isLocked(string $ownerId, string $path, string $viewerId, &$l
}
$lock = $this->lockService->getLockFromFileId($file->getId());
- if ($viewerId === '' || $lock->getUserId() !== $viewerId) {
+ // TODO: double check empty viewer id condition
+ if ($viewerId === '') {
+ return true;
+ }
+ if ($lock->getLockType() === FileLock::LOCK_TYPE_USER && $lock->getUserId() !== $viewerId) {
+ return true;
+ }
+ if ($lock->getLockType() === FileLock::LOCK_TYPE_APP && $lock->getUserId() !== \OC::$server->get(AppLockService::class)->getAppInScope()) {
return true;
}
} catch (LockNotFoundException | InvalidPathException | NotFoundException $e) {
diff --git a/tests/Feature/LockFeatureTest.php b/tests/Feature/LockFeatureTest.php
new file mode 100644
index 00000000..67635870
--- /dev/null
+++ b/tests/Feature/LockFeatureTest.php
@@ -0,0 +1,204 @@
+
+ *
+ * @author Julius Härtl
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+use OCA\FilesLock\Service\LockService;
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\Files\IRootFolder;
+use OCP\Lock\ManuallyLockedException;
+use OCP\Share\IShare;
+use Test\TestCase;
+use Test\Util\User\Dummy;
+
+/**
+ * @group DB
+ */
+class LockFeatureTest extends TestCase {
+
+ public const TEST_USER1 = "test-user1";
+ public const TEST_USER2 = "test-user2";
+
+ private LockService $lockService;
+ private IRootFolder $rootFolder;
+ private ?int $time = null;
+
+ public static function setUpBeforeClass(): void {
+ parent::setUpBeforeClass();
+
+ $backend = new Dummy();
+ OC_User::useBackend($backend);
+ $backend->createUser(self::TEST_USER1, self::TEST_USER1);
+ $backend->createUser(self::TEST_USER2, self::TEST_USER2);
+ }
+
+ public function setUp(): void {
+ parent::setUp();
+ $this->time = null;
+ $this->lockService = \OC::$server->get(LockService::class);
+ $this->rootFolder = \OC::$server->get(IRootFolder::class);
+ $this->timeFactory = $this->createMock(ITimeFactory::class);
+ $this->timeFactory->expects(self::any())
+ ->method('getTime')
+ ->willReturnCallback(function () {
+ if ($this->time) {
+ return $this->time;
+ }
+ return time();
+ });
+ $folder = $this->loginAndGetUserFolder(self::TEST_USER1);
+ $folder->delete('testfile');
+ $folder->delete('testfile2');
+ $folder->delete('testfile3');
+ $this->overwriteService(ITimeFactory::class, $this->timeFactory);
+ }
+
+ public function testLockUser() {
+ $file = $this->loginAndGetUserFolder(self::TEST_USER1)
+ ->newFile('testfile', 'AAA');
+ $this->shareFileWithUser($file, self::TEST_USER1, self::TEST_USER2);
+ $this->lockService->lockFileAsUser($file, \OC::$server->getUserManager()->get(self::TEST_USER1));
+ $file->putContent('BBB');
+
+ $file = $this->loginAndGetUserFolder(self::TEST_USER2)
+ ->get('testfile');
+ try {
+ $file->putContent('CCC');
+ $this->fail('Expected to throw a ManuallyLockedException');
+ } catch (ManuallyLockedException $e) {
+ self::assertInstanceOf(ManuallyLockedException::class, $e);
+ self::assertEquals('BBB', $file->getContent());
+ }
+
+ $file = $this->loginAndGetUserFolder(self::TEST_USER1)
+ ->get('testfile');
+ $file->putContent('DDD');
+ self::assertEquals('DDD', $file->getContent());
+
+ $this->lockService->unlockFile($file->getId(), self::TEST_USER1);
+
+ $file = $this->loginAndGetUserFolder(self::TEST_USER2)
+ ->get('testfile');
+ $file->putContent('EEE');
+ self::assertEquals('EEE', $file->getContent());
+ }
+ public function testLockUserExpire() {
+ $file = $this->loginAndGetUserFolder(self::TEST_USER1)
+ ->newFile('testfile', 'AAA');
+ $this->shareFileWithUser($file, self::TEST_USER1, self::TEST_USER2);
+ $this->lockService->lockFileAsUser($file, \OC::$server->getUserManager()->get(self::TEST_USER1));
+ $file->putContent('BBB');
+
+ $file = $this->loginAndGetUserFolder(self::TEST_USER2)
+ ->get('testfile');
+ try {
+ $file->putContent('CCC');
+ $this->fail('Expected to throw a ManuallyLockedException');
+ } catch (ManuallyLockedException $e) {
+ self::assertInstanceOf(ManuallyLockedException::class, $e);
+ self::assertEquals('BBB', $file->getContent());
+ }
+
+ $this->toTheFuture(3600);
+ $file->putContent('CCC');
+ self::assertEquals('CCC', $file->getContent());
+
+ }
+
+ public function testLockApp() {
+ $file = $this->loginAndGetUserFolder(self::TEST_USER1)
+ ->newFile('testfile2', 'AAA');
+ $this->shareFileWithUser($file, self::TEST_USER1, self::TEST_USER2);
+ $this->lockService->lockFileAsApp($file, 'collaborative_app');
+ try {
+ $file->putContent('BBB');
+ $this->fail('Expected to throw a ManuallyLockedException');
+ } catch (ManuallyLockedException $e) {
+ self::assertInstanceOf(ManuallyLockedException::class, $e);
+ self::assertEquals('AAA', $file->getContent());
+ }
+
+ $this->lockService->executeInAppScope('collaborative_app', function () use ($file) {
+ self::assertEquals('collaborative_app', $this->lockService->getAppInScope());
+ $file->putContent('EEE');
+ self::assertEquals('EEE', $file->getContent());
+ });
+
+ $this->loginAndGetUserFolder(self::TEST_USER2);
+ $this->lockService->executeInAppScope('collaborative_app', function () use ($file) {
+ self::assertEquals('collaborative_app', $this->lockService->getAppInScope());
+ $file->putContent('FFF');
+ self::assertEquals('FFF', $file->getContent());
+ });
+ }
+
+ public function testLockDifferentApps() {
+ $file = $this->loginAndGetUserFolder(self::TEST_USER1)
+ ->newFile('testfile3', 'AAA');
+ $this->lockService->lockFileAsApp($file, 'collaborative_app');
+
+ $this->lockService->executeInAppScope('collaborative_app', function () use ($file) {
+ self::assertEquals('collaborative_app', $this->lockService->getAppInScope());
+ $file->putContent('EEE');
+ self::assertEquals('EEE', $file->getContent());
+ });
+
+ $this->lockService->executeInAppScope('other_app', function () use ($file) {
+ self::assertEquals('other_app', $this->lockService->getAppInScope());
+ try {
+ $file->putContent('BBB');
+ $this->fail('Expected to throw a ManuallyLockedException');
+ } catch (ManuallyLockedException $e) {
+ self::assertInstanceOf(ManuallyLockedException::class, $e);
+ self::assertEquals('EEE', $file->getContent());
+ }
+ });
+ }
+
+ private function loginAndGetUserFolder(string $userId) {
+ $this->loginAsUser($userId);
+ return $this->rootFolder->getUserFolder($userId);
+ }
+
+ private function shareFileWithUser(\OCP\Files\File $file, $owner, $user) {
+ $this->shareManager = \OC::$server->getShareManager();
+ $share1 = $this->shareManager->newShare();
+ $share1->setNode($file)
+ ->setSharedBy($owner)
+ ->setSharedWith($user)
+ ->setShareType(IShare::TYPE_USER)
+ ->setPermissions(19);
+ $share1 = $this->shareManager->createShare($share1);
+ $share1->setStatus(IShare::STATUS_ACCEPTED);
+ $this->shareManager->updateShare($share1);
+ }
+
+ private function toTheFuture(int $seconds): void {
+ $this->time = time() + $seconds;
+ }
+
+ public function tearDown(): void {
+ parent::tearDown();
+ $folder = $this->rootFolder->getUserFolder(self::TEST_USER1);
+ $folder->delete('testfile');
+ $folder->delete('testfile2');
+ }
+}
diff --git a/tests/Unit/.gitkeep b/tests/Unit/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
new file mode 100644
index 00000000..c4eae8ce
--- /dev/null
+++ b/tests/bootstrap.php
@@ -0,0 +1,39 @@
+
+ *
+ * @author Julius Härtl
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+define('PHPUNIT_RUN', 1);
+
+$configDir = getenv('CONFIG_DIR');
+if ($configDir) {
+ define('PHPUNIT_CONFIG_DIR', $configDir);
+}
+
+require_once __DIR__ . '/../../../lib/base.php';
+
+\OC::$composerAutoloader->addPsr4('Test\\', OC::$SERVERROOT . '/tests/lib/', true);
+\OC::$composerAutoloader->addPsr4('Tests\\', OC::$SERVERROOT . '/tests/', true);
+
+// load all enabled apps
+\OC_App::loadApps();
+
+set_include_path(get_include_path() . PATH_SEPARATOR . '/usr/share/php');
diff --git a/tests/phpunit.xml b/tests/phpunit.xml
new file mode 100644
index 00000000..afcdfac5
--- /dev/null
+++ b/tests/phpunit.xml
@@ -0,0 +1,16 @@
+
+
+
+
+ ./../lib
+
+
+
+
+ Unit
+
+
+ Feature
+
+
+