├── .github └── workflows │ ├── appstore-build-publish.yml │ ├── lint-info-xml.yml │ ├── lint-php-cs.yml │ ├── lint-php.yml │ ├── phpunit-mysql.yml │ ├── phpunit-oci.yml │ ├── phpunit-pgsql.yml │ ├── phpunit-sqlite.yml │ ├── psalm-matrix.yml │ └── update-nextcloud-ocp.yml ├── .gitignore ├── .l10nignore ├── .nextcloudignore ├── .php-cs-fixer.dist.php ├── README.md ├── appinfo ├── info.xml └── routes.php ├── composer.json ├── composer.lock ├── css └── settings.css ├── img └── app.svg ├── js └── settings.js ├── krankerl.toml ├── l10n ├── .gitkeep ├── ar.js ├── ar.json ├── ast.js ├── ast.json ├── az.js ├── az.json ├── bg.js ├── bg.json ├── bg_BG.js ├── bg_BG.json ├── bn_BD.js ├── bn_BD.json ├── bn_IN.js ├── bn_IN.json ├── bs.js ├── bs.json ├── ca.js ├── ca.json ├── cs.js ├── cs.json ├── cs_CZ.js ├── cs_CZ.json ├── cy_GB.js ├── cy_GB.json ├── da.js ├── da.json ├── de.js ├── de.json ├── de_DE.js ├── de_DE.json ├── el.js ├── el.json ├── en_GB.js ├── en_GB.json ├── eo.js ├── eo.json ├── es.js ├── es.json ├── es_AR.js ├── es_AR.json ├── es_MX.js ├── es_MX.json ├── et_EE.js ├── et_EE.json ├── eu.js ├── eu.json ├── fa.js ├── fa.json ├── fi.js ├── fi.json ├── fi_FI.js ├── fi_FI.json ├── fr.js ├── fr.json ├── gl.js ├── gl.json ├── he.js ├── he.json ├── hr.js ├── hr.json ├── hu.js ├── hu.json ├── hu_HU.js ├── hu_HU.json ├── hy.js ├── hy.json ├── ia.js ├── ia.json ├── id.js ├── id.json ├── is.js ├── is.json ├── it.js ├── it.json ├── ja.js ├── ja.json ├── ka_GE.js ├── ka_GE.json ├── km.js ├── km.json ├── kn.js ├── kn.json ├── ko.js ├── ko.json ├── ku_IQ.js ├── ku_IQ.json ├── lb.js ├── lb.json ├── lt_LT.js ├── lt_LT.json ├── lv.js ├── lv.json ├── mk.js ├── mk.json ├── ms_MY.js ├── ms_MY.json ├── nb.js ├── nb.json ├── nb_NO.js ├── nb_NO.json ├── nl.js ├── nl.json ├── nn_NO.js ├── nn_NO.json ├── oc.js ├── oc.json ├── pl.js ├── pl.json ├── pt_BR.js ├── pt_BR.json ├── pt_PT.js ├── pt_PT.json ├── ro.js ├── ro.json ├── ru.js ├── ru.json ├── si_LK.js ├── si_LK.json ├── sk.js ├── sk.json ├── sk_SK.js ├── sk_SK.json ├── sl.js ├── sl.json ├── sq.js ├── sq.json ├── sr.js ├── sr.json ├── sr@latin.js ├── sr@latin.json ├── sv.js ├── sv.json ├── ta_LK.js ├── ta_LK.json ├── th.js ├── th.json ├── th_TH.js ├── th_TH.json ├── tr.js ├── tr.json ├── ug.js ├── ug.json ├── uk.js ├── uk.json ├── ur_PK.js ├── ur_PK.json ├── vi.js ├── vi.json ├── zh_CN.js ├── zh_CN.json ├── zh_HK.js ├── zh_HK.json ├── zh_TW.js └── zh_TW.json ├── lib ├── AppInfo │ └── Application.php ├── Controller │ └── AdminController.php ├── Settings │ ├── Admin.php │ └── Section.php ├── Snapshot.php ├── SnapshotManager.php └── Versions │ ├── SnapshotPreviewFile.php │ ├── SnapshotVersion.php │ └── SnapshotVersionBackend.php ├── psalm.xml ├── screenshots ├── settings.png └── versions.png ├── templates └── settings.php ├── tests ├── SnapshotManagerTest.php ├── bootstrap.php ├── phpunit.xml └── stubs │ └── psalm.phpstub └── vendor-bin ├── cs-fixer ├── composer.json └── composer.lock ├── phpunit ├── composer.json └── composer.lock └── psalm ├── composer.json └── composer.lock /.github/workflows/appstore-build-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow is provided via the organization template repository 2 | # 3 | # https://github.com/nextcloud/.github 4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization 5 | # 6 | # SPDX-FileCopyrightText: 2021-2024 Nextcloud GmbH and Nextcloud contributors 7 | # SPDX-License-Identifier: MIT 8 | 9 | name: Build and publish app release 10 | 11 | on: 12 | release: 13 | types: [published] 14 | 15 | permissions: 16 | contents: write 17 | 18 | jobs: 19 | build_and_publish: 20 | runs-on: ubuntu-latest 21 | 22 | if: ${{ github.repository_owner == 'icewind1991' }} 23 | 24 | steps: 25 | - name: Check actor permission 26 | uses: skjnldsv/check-actor-permission@69e92a3c4711150929bca9fcf34448c5bf5526e7 # v3.0 27 | with: 28 | require: write 29 | 30 | - name: Set app env 31 | run: | 32 | # Split and keep last 33 | echo "APP_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV 34 | echo "APP_VERSION=${GITHUB_REF##*/}" >> $GITHUB_ENV 35 | 36 | - name: Checkout 37 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 38 | with: 39 | persist-credentials: false 40 | path: ${{ env.APP_NAME }} 41 | 42 | - name: Get app version number 43 | id: app-version 44 | uses: skjnldsv/xpath-action@f5b036e9d973f42c86324833fd00be90665fbf77 # master 45 | with: 46 | filename: ${{ env.APP_NAME }}/appinfo/info.xml 47 | expression: "//info//version/text()" 48 | 49 | - name: Validate app version against tag 50 | run: | 51 | [ "${{ env.APP_VERSION }}" = "v${{ fromJSON(steps.app-version.outputs.result).version }}" ] 52 | 53 | - name: Get appinfo data 54 | id: appinfo 55 | uses: skjnldsv/xpath-action@f5b036e9d973f42c86324833fd00be90665fbf77 # master 56 | with: 57 | filename: ${{ env.APP_NAME }}/appinfo/info.xml 58 | expression: "//info//dependencies//nextcloud/@min-version" 59 | 60 | - name: Read package.json node and npm engines version 61 | uses: skjnldsv/read-package-engines-version-actions@06d6baf7d8f41934ab630e97d9e6c0bc9c9ac5e4 # v3 62 | id: versions 63 | # Continue if no package.json 64 | continue-on-error: true 65 | with: 66 | path: ${{ env.APP_NAME }} 67 | fallbackNode: '^20' 68 | fallbackNpm: '^10' 69 | 70 | - name: Set up node ${{ steps.versions.outputs.nodeVersion }} 71 | # Skip if no package.json 72 | if: ${{ steps.versions.outputs.nodeVersion }} 73 | uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 74 | with: 75 | node-version: ${{ steps.versions.outputs.nodeVersion }} 76 | 77 | - name: Set up npm ${{ steps.versions.outputs.npmVersion }} 78 | # Skip if no package.json 79 | if: ${{ steps.versions.outputs.npmVersion }} 80 | run: npm i -g 'npm@${{ steps.versions.outputs.npmVersion }}' 81 | 82 | - name: Get php version 83 | id: php-versions 84 | uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.3.1 85 | with: 86 | filename: ${{ env.APP_NAME }}/appinfo/info.xml 87 | 88 | - name: Set up php ${{ steps.php-versions.outputs.php-min }} 89 | uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2.32.0 90 | with: 91 | php-version: ${{ steps.php-versions.outputs.php-min }} 92 | coverage: none 93 | env: 94 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 95 | 96 | - name: Check composer.json 97 | id: check_composer 98 | uses: andstor/file-existence-action@076e0072799f4942c8bc574a82233e1e4d13e9d6 # v3.0.0 99 | with: 100 | files: "${{ env.APP_NAME }}/composer.json" 101 | 102 | - name: Install composer dependencies 103 | if: steps.check_composer.outputs.files_exists == 'true' 104 | run: | 105 | cd ${{ env.APP_NAME }} 106 | composer install --no-dev 107 | 108 | - name: Build ${{ env.APP_NAME }} 109 | # Skip if no package.json 110 | if: ${{ steps.versions.outputs.nodeVersion }} 111 | env: 112 | CYPRESS_INSTALL_BINARY: 0 113 | run: | 114 | cd ${{ env.APP_NAME }} 115 | npm ci 116 | npm run build --if-present 117 | 118 | - name: Check Krankerl config 119 | id: krankerl 120 | uses: andstor/file-existence-action@076e0072799f4942c8bc574a82233e1e4d13e9d6 # v3.0.0 121 | with: 122 | files: ${{ env.APP_NAME }}/krankerl.toml 123 | 124 | - name: Install Krankerl 125 | if: steps.krankerl.outputs.files_exists == 'true' 126 | run: | 127 | wget https://github.com/ChristophWurst/krankerl/releases/download/v0.14.0/krankerl_0.14.0_amd64.deb 128 | sudo dpkg -i krankerl_0.14.0_amd64.deb 129 | 130 | - name: Package ${{ env.APP_NAME }} ${{ env.APP_VERSION }} with krankerl 131 | if: steps.krankerl.outputs.files_exists == 'true' 132 | run: | 133 | cd ${{ env.APP_NAME }} 134 | krankerl package 135 | 136 | - name: Package ${{ env.APP_NAME }} ${{ env.APP_VERSION }} with makefile 137 | if: steps.krankerl.outputs.files_exists != 'true' 138 | run: | 139 | cd ${{ env.APP_NAME }} 140 | make appstore 141 | 142 | - name: Checkout server ${{ fromJSON(steps.appinfo.outputs.result).nextcloud.min-version }} 143 | continue-on-error: true 144 | id: server-checkout 145 | run: | 146 | NCVERSION='${{ fromJSON(steps.appinfo.outputs.result).nextcloud.min-version }}' 147 | wget --quiet https://download.nextcloud.com/server/releases/latest-$NCVERSION.zip 148 | unzip latest-$NCVERSION.zip 149 | 150 | - name: Checkout server master fallback 151 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 152 | if: ${{ steps.server-checkout.outcome != 'success' }} 153 | with: 154 | persist-credentials: false 155 | submodules: true 156 | repository: nextcloud/server 157 | path: nextcloud 158 | 159 | - name: Sign app 160 | run: | 161 | # Extracting release 162 | cd ${{ env.APP_NAME }}/build/artifacts 163 | tar -xvf ${{ env.APP_NAME }}.tar.gz 164 | cd ../../../ 165 | # Setting up keys 166 | echo '${{ secrets.APP_PRIVATE_KEY }}' > ${{ env.APP_NAME }}.key 167 | wget --quiet "https://github.com/nextcloud/app-certificate-requests/raw/master/${{ env.APP_NAME }}/${{ env.APP_NAME }}.crt" 168 | # Signing 169 | php nextcloud/occ integrity:sign-app --privateKey=../${{ env.APP_NAME }}.key --certificate=../${{ env.APP_NAME }}.crt --path=../${{ env.APP_NAME }}/build/artifacts/${{ env.APP_NAME }} 170 | # Rebuilding archive 171 | cd ${{ env.APP_NAME }}/build/artifacts 172 | tar -zcvf ${{ env.APP_NAME }}.tar.gz ${{ env.APP_NAME }} 173 | 174 | - name: Attach tarball to github release 175 | uses: svenstaro/upload-release-action@04733e069f2d7f7f0b4aebc4fbdbce8613b03ccd # v2 176 | id: attach_to_release 177 | with: 178 | repo_token: ${{ secrets.GITHUB_TOKEN }} 179 | file: ${{ env.APP_NAME }}/build/artifacts/${{ env.APP_NAME }}.tar.gz 180 | asset_name: ${{ env.APP_NAME }}-${{ env.APP_VERSION }}.tar.gz 181 | tag: ${{ github.ref }} 182 | overwrite: true 183 | 184 | - name: Upload app to Nextcloud appstore 185 | uses: nextcloud-releases/nextcloud-appstore-push-action@a011fe619bcf6e77ddebc96f9908e1af4071b9c1 # v1 186 | with: 187 | app_name: ${{ env.APP_NAME }} 188 | appstore_token: ${{ secrets.APPSTORE_TOKEN }} 189 | download_url: ${{ steps.attach_to_release.outputs.browser_download_url }} 190 | app_private_key: ${{ secrets.APP_PRIVATE_KEY }} 191 | -------------------------------------------------------------------------------- /.github/workflows/lint-info-xml.yml: -------------------------------------------------------------------------------- 1 | # This workflow is provided via the organization template repository 2 | # 3 | # https://github.com/nextcloud/.github 4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization 5 | # 6 | # SPDX-FileCopyrightText: 2021-2024 Nextcloud GmbH and Nextcloud contributors 7 | # SPDX-License-Identifier: MIT 8 | 9 | name: Lint info.xml 10 | 11 | on: pull_request 12 | 13 | permissions: 14 | contents: read 15 | 16 | concurrency: 17 | group: lint-info-xml-${{ github.head_ref || github.run_id }} 18 | cancel-in-progress: true 19 | 20 | jobs: 21 | xml-linters: 22 | runs-on: ubuntu-latest 23 | 24 | name: info.xml lint 25 | steps: 26 | - name: Checkout 27 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 28 | with: 29 | persist-credentials: false 30 | 31 | - name: Download schema 32 | run: wget https://raw.githubusercontent.com/nextcloud/appstore/master/nextcloudappstore/api/v1/release/info.xsd 33 | 34 | - name: Lint info.xml 35 | uses: ChristophWurst/xmllint-action@36f2a302f84f8c83fceea0b9c59e1eb4a616d3c1 # v1.2 36 | with: 37 | xml-file: ./appinfo/info.xml 38 | xml-schema-file: ./info.xsd 39 | -------------------------------------------------------------------------------- /.github/workflows/lint-php-cs.yml: -------------------------------------------------------------------------------- 1 | # This workflow is provided via the organization template repository 2 | # 3 | # https://github.com/nextcloud/.github 4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization 5 | # 6 | # SPDX-FileCopyrightText: 2021-2024 Nextcloud GmbH and Nextcloud contributors 7 | # SPDX-License-Identifier: MIT 8 | 9 | name: Lint php-cs 10 | 11 | on: pull_request 12 | 13 | permissions: 14 | contents: read 15 | 16 | concurrency: 17 | group: lint-php-cs-${{ github.head_ref || github.run_id }} 18 | cancel-in-progress: true 19 | 20 | jobs: 21 | lint: 22 | runs-on: ubuntu-latest 23 | 24 | name: php-cs 25 | 26 | steps: 27 | - name: Checkout 28 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 29 | with: 30 | persist-credentials: false 31 | 32 | - name: Get php version 33 | id: versions 34 | uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.3.1 35 | 36 | - name: Set up php${{ steps.versions.outputs.php-min }} 37 | uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2.32.0 38 | with: 39 | php-version: ${{ steps.versions.outputs.php-min }} 40 | extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite 41 | coverage: none 42 | ini-file: development 43 | env: 44 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 45 | 46 | - name: Install dependencies 47 | run: | 48 | composer remove nextcloud/ocp --dev 49 | composer i 50 | 51 | - name: Lint 52 | run: composer run cs:check || ( echo 'Please run `composer run cs:fix` to format your code' && exit 1 ) 53 | -------------------------------------------------------------------------------- /.github/workflows/lint-php.yml: -------------------------------------------------------------------------------- 1 | # This workflow is provided via the organization template repository 2 | # 3 | # https://github.com/nextcloud/.github 4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization 5 | # 6 | # SPDX-FileCopyrightText: 2021-2024 Nextcloud GmbH and Nextcloud contributors 7 | # SPDX-License-Identifier: MIT 8 | 9 | name: Lint php 10 | 11 | on: pull_request 12 | 13 | permissions: 14 | contents: read 15 | 16 | concurrency: 17 | group: lint-php-${{ github.head_ref || github.run_id }} 18 | cancel-in-progress: true 19 | 20 | jobs: 21 | matrix: 22 | runs-on: ubuntu-latest 23 | outputs: 24 | php-versions: ${{ steps.versions.outputs.php-versions }} 25 | steps: 26 | - name: Checkout app 27 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 28 | with: 29 | persist-credentials: false 30 | 31 | - name: Get version matrix 32 | id: versions 33 | uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.0.0 34 | 35 | php-lint: 36 | runs-on: ubuntu-latest 37 | needs: matrix 38 | strategy: 39 | matrix: 40 | php-versions: ${{fromJson(needs.matrix.outputs.php-versions)}} 41 | 42 | name: php-lint 43 | 44 | steps: 45 | - name: Checkout 46 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 47 | with: 48 | persist-credentials: false 49 | 50 | - name: Set up php ${{ matrix.php-versions }} 51 | uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2.32.0 52 | with: 53 | php-version: ${{ matrix.php-versions }} 54 | extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite 55 | coverage: none 56 | ini-file: development 57 | env: 58 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 59 | 60 | - name: Lint 61 | run: composer run lint 62 | 63 | summary: 64 | permissions: 65 | contents: none 66 | runs-on: ubuntu-latest 67 | needs: php-lint 68 | 69 | if: always() 70 | 71 | name: php-lint-summary 72 | 73 | steps: 74 | - name: Summary status 75 | run: if ${{ needs.php-lint.result != 'success' && needs.php-lint.result != 'skipped' }}; then exit 1; fi 76 | -------------------------------------------------------------------------------- /.github/workflows/phpunit-mysql.yml: -------------------------------------------------------------------------------- 1 | # This workflow is provided via the organization template repository 2 | # 3 | # https://github.com/nextcloud/.github 4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization 5 | # 6 | # SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors 7 | # SPDX-License-Identifier: MIT 8 | 9 | name: PHPUnit MySQL 10 | 11 | on: pull_request 12 | 13 | permissions: 14 | contents: read 15 | 16 | concurrency: 17 | group: phpunit-mysql-${{ github.head_ref || github.run_id }} 18 | cancel-in-progress: true 19 | 20 | jobs: 21 | matrix: 22 | runs-on: ubuntu-latest 23 | outputs: 24 | matrix: ${{ steps.versions.outputs.sparse-matrix }} 25 | steps: 26 | - name: Checkout app 27 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 28 | with: 29 | persist-credentials: false 30 | 31 | - name: Get version matrix 32 | id: versions 33 | uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.3.1 34 | with: 35 | matrix: '{"mysql-versions": ["8.4"]}' 36 | 37 | changes: 38 | runs-on: ubuntu-latest 39 | permissions: 40 | contents: read 41 | pull-requests: read 42 | 43 | outputs: 44 | src: ${{ steps.changes.outputs.src}} 45 | 46 | steps: 47 | - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 48 | id: changes 49 | continue-on-error: true 50 | with: 51 | filters: | 52 | src: 53 | - '.github/workflows/**' 54 | - 'appinfo/**' 55 | - 'lib/**' 56 | - 'templates/**' 57 | - 'tests/**' 58 | - 'vendor/**' 59 | - 'vendor-bin/**' 60 | - '.php-cs-fixer.dist.php' 61 | - 'composer.json' 62 | - 'composer.lock' 63 | 64 | phpunit-mysql: 65 | runs-on: ubuntu-latest 66 | 67 | needs: [changes, matrix] 68 | if: needs.changes.outputs.src != 'false' 69 | 70 | strategy: 71 | matrix: ${{ fromJson(needs.matrix.outputs.matrix) }} 72 | 73 | name: MySQL ${{ matrix.mysql-versions }} PHP ${{ matrix.php-versions }} Nextcloud ${{ matrix.server-versions }} 74 | 75 | services: 76 | mysql: 77 | image: ghcr.io/nextcloud/continuous-integration-mysql-${{ matrix.mysql-versions }}:latest 78 | ports: 79 | - 4444:3306/tcp 80 | env: 81 | MYSQL_ROOT_PASSWORD: rootpassword 82 | options: --health-cmd="mysqladmin ping" --health-interval 5s --health-timeout 2s --health-retries 10 83 | 84 | steps: 85 | - name: Set app env 86 | if: ${{ env.APP_NAME == '' }} 87 | run: | 88 | # Split and keep last 89 | echo "APP_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV 90 | 91 | - name: Checkout server 92 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 93 | with: 94 | persist-credentials: false 95 | submodules: true 96 | repository: nextcloud/server 97 | ref: ${{ matrix.server-versions }} 98 | 99 | - name: Checkout app 100 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 101 | with: 102 | persist-credentials: false 103 | path: apps/${{ env.APP_NAME }} 104 | 105 | - name: Set up php ${{ matrix.php-versions }} 106 | uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2.32.0 107 | with: 108 | php-version: ${{ matrix.php-versions }} 109 | # https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation 110 | extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, mysql, pdo_mysql 111 | coverage: none 112 | ini-file: development 113 | # Temporary workaround for missing pcntl_* in PHP 8.3 114 | ini-values: disable_functions= 115 | env: 116 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 117 | 118 | - name: Enable ONLY_FULL_GROUP_BY MySQL option 119 | run: | 120 | echo "SET GLOBAL sql_mode=(SELECT CONCAT(@@sql_mode,',ONLY_FULL_GROUP_BY'));" | mysql -h 127.0.0.1 -P 4444 -u root -prootpassword 121 | echo 'SELECT @@sql_mode;' | mysql -h 127.0.0.1 -P 4444 -u root -prootpassword 122 | 123 | - name: Check composer file existence 124 | id: check_composer 125 | uses: andstor/file-existence-action@076e0072799f4942c8bc574a82233e1e4d13e9d6 # v3.0.0 126 | with: 127 | files: apps/${{ env.APP_NAME }}/composer.json 128 | 129 | - name: Set up dependencies 130 | # Only run if phpunit config file exists 131 | if: steps.check_composer.outputs.files_exists == 'true' 132 | working-directory: apps/${{ env.APP_NAME }} 133 | run: | 134 | composer remove nextcloud/ocp --dev 135 | composer i 136 | 137 | - name: Set up Nextcloud 138 | env: 139 | DB_PORT: 4444 140 | run: | 141 | mkdir data 142 | ./occ maintenance:install --verbose --database=mysql --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 143 | ./occ app:enable --force ${{ env.APP_NAME }} 144 | 145 | - name: Check PHPUnit script is defined 146 | id: check_phpunit 147 | continue-on-error: true 148 | working-directory: apps/${{ env.APP_NAME }} 149 | run: | 150 | composer run --list | grep '^ test:unit ' | wc -l | grep 1 151 | 152 | - name: PHPUnit 153 | # Only run if phpunit config file exists 154 | if: steps.check_phpunit.outcome == 'success' 155 | working-directory: apps/${{ env.APP_NAME }} 156 | run: composer run test:unit 157 | 158 | - name: Check PHPUnit integration script is defined 159 | id: check_integration 160 | continue-on-error: true 161 | working-directory: apps/${{ env.APP_NAME }} 162 | run: | 163 | composer run --list | grep '^ test:integration ' | wc -l | grep 1 164 | 165 | - name: Run Nextcloud 166 | # Only run if phpunit integration config file exists 167 | if: steps.check_integration.outcome == 'success' 168 | run: php -S localhost:8080 & 169 | 170 | - name: PHPUnit integration 171 | # Only run if phpunit integration config file exists 172 | if: steps.check_integration.outcome == 'success' 173 | working-directory: apps/${{ env.APP_NAME }} 174 | run: composer run test:integration 175 | 176 | - name: Print logs 177 | if: always() 178 | run: | 179 | cat data/nextcloud.log 180 | 181 | - name: Skipped 182 | # Fail the action when neither unit nor integration tests ran 183 | if: steps.check_phpunit.outcome == 'failure' && steps.check_integration.outcome == 'failure' 184 | run: | 185 | echo 'Neither PHPUnit nor PHPUnit integration tests are specified in composer.json scripts' 186 | exit 1 187 | 188 | summary: 189 | permissions: 190 | contents: none 191 | runs-on: ubuntu-latest 192 | needs: [changes, phpunit-mysql] 193 | 194 | if: always() 195 | 196 | name: phpunit-mysql-summary 197 | 198 | steps: 199 | - name: Summary status 200 | run: if ${{ needs.changes.outputs.src != 'false' && needs.phpunit-mysql.result != 'success' }}; then exit 1; fi 201 | -------------------------------------------------------------------------------- /.github/workflows/phpunit-oci.yml: -------------------------------------------------------------------------------- 1 | # This workflow is provided via the organization template repository 2 | # 3 | # https://github.com/nextcloud/.github 4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization 5 | # 6 | # SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors 7 | # SPDX-License-Identifier: MIT 8 | 9 | name: PHPUnit OCI 10 | 11 | on: pull_request 12 | 13 | permissions: 14 | contents: read 15 | 16 | concurrency: 17 | group: phpunit-oci-${{ github.head_ref || github.run_id }} 18 | cancel-in-progress: true 19 | 20 | jobs: 21 | matrix: 22 | runs-on: ubuntu-latest 23 | outputs: 24 | php-version: ${{ steps.versions.outputs.php-available-list }} 25 | server-max: ${{ steps.versions.outputs.branches-max-list }} 26 | steps: 27 | - name: Checkout app 28 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 29 | with: 30 | persist-credentials: false 31 | 32 | - name: Get version matrix 33 | id: versions 34 | uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.3.1 35 | 36 | changes: 37 | runs-on: ubuntu-latest 38 | permissions: 39 | contents: read 40 | pull-requests: read 41 | 42 | outputs: 43 | src: ${{ steps.changes.outputs.src }} 44 | 45 | steps: 46 | - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 47 | id: changes 48 | continue-on-error: true 49 | with: 50 | filters: | 51 | src: 52 | - '.github/workflows/**' 53 | - 'appinfo/**' 54 | - 'lib/**' 55 | - 'templates/**' 56 | - 'tests/**' 57 | - 'vendor/**' 58 | - 'vendor-bin/**' 59 | - '.php-cs-fixer.dist.php' 60 | - 'composer.json' 61 | - 'composer.lock' 62 | 63 | phpunit-oci: 64 | runs-on: ubuntu-latest 65 | 66 | needs: [changes, matrix] 67 | if: needs.changes.outputs.src != 'false' 68 | 69 | strategy: 70 | matrix: 71 | php-versions: ${{ fromJson(needs.matrix.outputs.php-version) }} 72 | server-versions: ${{ fromJson(needs.matrix.outputs.server-max) }} 73 | 74 | name: OCI PHP ${{ matrix.php-versions }} Nextcloud ${{ matrix.server-versions }} 75 | 76 | services: 77 | oracle: 78 | image: ghcr.io/gvenzl/oracle-xe:11 79 | 80 | # Provide passwords and other environment variables to container 81 | env: 82 | ORACLE_RANDOM_PASSWORD: true 83 | APP_USER: autotest 84 | APP_USER_PASSWORD: owncloud 85 | 86 | # Forward Oracle port 87 | ports: 88 | - 1521:1521/tcp 89 | 90 | # Provide healthcheck script options for startup 91 | options: >- 92 | --health-cmd healthcheck.sh 93 | --health-interval 10s 94 | --health-timeout 5s 95 | --health-retries 10 96 | 97 | steps: 98 | - name: Set app env 99 | if: ${{ env.APP_NAME == '' }} 100 | run: | 101 | # Split and keep last 102 | echo "APP_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV 103 | 104 | - name: Checkout server 105 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 106 | with: 107 | persist-credentials: false 108 | submodules: true 109 | repository: nextcloud/server 110 | ref: ${{ matrix.server-versions }} 111 | 112 | - name: Checkout app 113 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 114 | with: 115 | persist-credentials: false 116 | path: apps/${{ env.APP_NAME }} 117 | 118 | - name: Set up php ${{ matrix.php-versions }} 119 | uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2.32.0 120 | with: 121 | php-version: ${{ matrix.php-versions }} 122 | # https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation 123 | extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, oci8 124 | coverage: none 125 | ini-file: development 126 | # Temporary workaround for missing pcntl_* in PHP 8.3 127 | ini-values: disable_functions= 128 | env: 129 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 130 | 131 | - name: Check composer file existence 132 | id: check_composer 133 | uses: andstor/file-existence-action@076e0072799f4942c8bc574a82233e1e4d13e9d6 # v3.0.0 134 | with: 135 | files: apps/${{ env.APP_NAME }}/composer.json 136 | 137 | - name: Set up dependencies 138 | # Only run if phpunit config file exists 139 | if: steps.check_composer.outputs.files_exists == 'true' 140 | working-directory: apps/${{ env.APP_NAME }} 141 | run: | 142 | composer remove nextcloud/ocp --dev 143 | composer i 144 | 145 | - name: Set up Nextcloud 146 | env: 147 | DB_PORT: 1521 148 | run: | 149 | mkdir data 150 | ./occ maintenance:install --verbose --database=oci --database-name=XE --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=autotest --database-pass=owncloud --admin-user admin --admin-pass admin 151 | ./occ app:enable --force ${{ env.APP_NAME }} 152 | 153 | - name: Check PHPUnit script is defined 154 | id: check_phpunit 155 | continue-on-error: true 156 | working-directory: apps/${{ env.APP_NAME }} 157 | run: | 158 | composer run --list | grep '^ test:unit ' | wc -l | grep 1 159 | 160 | - name: PHPUnit 161 | # Only run if phpunit config file exists 162 | if: steps.check_phpunit.outcome == 'success' 163 | working-directory: apps/${{ env.APP_NAME }} 164 | run: composer run test:unit 165 | 166 | - name: Check PHPUnit integration script is defined 167 | id: check_integration 168 | continue-on-error: true 169 | working-directory: apps/${{ env.APP_NAME }} 170 | run: | 171 | composer run --list | grep '^ test:integration ' | wc -l | grep 1 172 | 173 | - name: Run Nextcloud 174 | # Only run if phpunit integration config file exists 175 | if: steps.check_integration.outcome == 'success' 176 | run: php -S localhost:8080 & 177 | 178 | - name: PHPUnit integration 179 | # Only run if phpunit integration config file exists 180 | if: steps.check_integration.outcome == 'success' 181 | working-directory: apps/${{ env.APP_NAME }} 182 | run: composer run test:integration 183 | 184 | - name: Print logs 185 | if: always() 186 | run: | 187 | cat data/nextcloud.log 188 | 189 | - name: Skipped 190 | # Fail the action when neither unit nor integration tests ran 191 | if: steps.check_phpunit.outcome == 'failure' && steps.check_integration.outcome == 'failure' 192 | run: | 193 | echo 'Neither PHPUnit nor PHPUnit integration tests are specified in composer.json scripts' 194 | exit 1 195 | 196 | summary: 197 | permissions: 198 | contents: none 199 | runs-on: ubuntu-latest 200 | needs: [changes, phpunit-oci] 201 | 202 | if: always() 203 | 204 | name: phpunit-oci-summary 205 | 206 | steps: 207 | - name: Summary status 208 | run: if ${{ needs.changes.outputs.src != 'false' && needs.phpunit-oci.result != 'success' }}; then exit 1; fi 209 | -------------------------------------------------------------------------------- /.github/workflows/phpunit-pgsql.yml: -------------------------------------------------------------------------------- 1 | # This workflow is provided via the organization template repository 2 | # 3 | # https://github.com/nextcloud/.github 4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization 5 | # 6 | # SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors 7 | # SPDX-License-Identifier: MIT 8 | 9 | name: PHPUnit PostgreSQL 10 | 11 | on: pull_request 12 | 13 | permissions: 14 | contents: read 15 | 16 | concurrency: 17 | group: phpunit-pgsql-${{ github.head_ref || github.run_id }} 18 | cancel-in-progress: true 19 | 20 | jobs: 21 | matrix: 22 | runs-on: ubuntu-latest 23 | outputs: 24 | php-version: ${{ steps.versions.outputs.php-available-list }} 25 | server-max: ${{ steps.versions.outputs.branches-max-list }} 26 | steps: 27 | - name: Checkout app 28 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 29 | with: 30 | persist-credentials: false 31 | 32 | - name: Get version matrix 33 | id: versions 34 | uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.3.1 35 | 36 | changes: 37 | runs-on: ubuntu-latest 38 | permissions: 39 | contents: read 40 | pull-requests: read 41 | 42 | outputs: 43 | src: ${{ steps.changes.outputs.src }} 44 | 45 | steps: 46 | - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 47 | id: changes 48 | continue-on-error: true 49 | with: 50 | filters: | 51 | src: 52 | - '.github/workflows/**' 53 | - 'appinfo/**' 54 | - 'lib/**' 55 | - 'templates/**' 56 | - 'tests/**' 57 | - 'vendor/**' 58 | - 'vendor-bin/**' 59 | - '.php-cs-fixer.dist.php' 60 | - 'composer.json' 61 | - 'composer.lock' 62 | 63 | phpunit-pgsql: 64 | runs-on: ubuntu-latest 65 | 66 | needs: [changes, matrix] 67 | if: needs.changes.outputs.src != 'false' 68 | 69 | strategy: 70 | matrix: 71 | php-versions: ${{ fromJson(needs.matrix.outputs.php-version) }} 72 | server-versions: ${{ fromJson(needs.matrix.outputs.server-max) }} 73 | 74 | name: PostgreSQL PHP ${{ matrix.php-versions }} Nextcloud ${{ matrix.server-versions }} 75 | 76 | services: 77 | postgres: 78 | image: ghcr.io/nextcloud/continuous-integration-postgres-14:latest 79 | ports: 80 | - 4444:5432/tcp 81 | env: 82 | POSTGRES_USER: root 83 | POSTGRES_PASSWORD: rootpassword 84 | POSTGRES_DB: nextcloud 85 | options: --health-cmd pg_isready --health-interval 5s --health-timeout 2s --health-retries 5 86 | 87 | steps: 88 | - name: Set app env 89 | if: ${{ env.APP_NAME == '' }} 90 | run: | 91 | # Split and keep last 92 | echo "APP_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV 93 | 94 | - name: Checkout server 95 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 96 | with: 97 | persist-credentials: false 98 | submodules: true 99 | repository: nextcloud/server 100 | ref: ${{ matrix.server-versions }} 101 | 102 | - name: Checkout app 103 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 104 | with: 105 | persist-credentials: false 106 | path: apps/${{ env.APP_NAME }} 107 | 108 | - name: Set up php ${{ matrix.php-versions }} 109 | uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2.32.0 110 | with: 111 | php-version: ${{ matrix.php-versions }} 112 | # https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation 113 | extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, pgsql, pdo_pgsql 114 | coverage: none 115 | ini-file: development 116 | # Temporary workaround for missing pcntl_* in PHP 8.3 117 | ini-values: disable_functions= 118 | env: 119 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 120 | 121 | - name: Check composer file existence 122 | id: check_composer 123 | uses: andstor/file-existence-action@076e0072799f4942c8bc574a82233e1e4d13e9d6 # v3.0.0 124 | with: 125 | files: apps/${{ env.APP_NAME }}/composer.json 126 | 127 | - name: Set up dependencies 128 | # Only run if phpunit config file exists 129 | if: steps.check_composer.outputs.files_exists == 'true' 130 | working-directory: apps/${{ env.APP_NAME }} 131 | run: | 132 | composer remove nextcloud/ocp --dev 133 | composer i 134 | 135 | - name: Set up Nextcloud 136 | env: 137 | DB_PORT: 4444 138 | run: | 139 | mkdir data 140 | ./occ maintenance:install --verbose --database=pgsql --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 141 | ./occ app:enable --force ${{ env.APP_NAME }} 142 | 143 | - name: Check PHPUnit script is defined 144 | id: check_phpunit 145 | continue-on-error: true 146 | working-directory: apps/${{ env.APP_NAME }} 147 | run: | 148 | composer run --list | grep '^ test:unit ' | wc -l | grep 1 149 | 150 | - name: PHPUnit 151 | # Only run if phpunit config file exists 152 | if: steps.check_phpunit.outcome == 'success' 153 | working-directory: apps/${{ env.APP_NAME }} 154 | run: composer run test:unit 155 | 156 | - name: Check PHPUnit integration script is defined 157 | id: check_integration 158 | continue-on-error: true 159 | working-directory: apps/${{ env.APP_NAME }} 160 | run: | 161 | composer run --list | grep '^ test:integration ' | wc -l | grep 1 162 | 163 | - name: Run Nextcloud 164 | # Only run if phpunit integration config file exists 165 | if: steps.check_integration.outcome == 'success' 166 | run: php -S localhost:8080 & 167 | 168 | - name: PHPUnit integration 169 | # Only run if phpunit integration config file exists 170 | if: steps.check_integration.outcome == 'success' 171 | working-directory: apps/${{ env.APP_NAME }} 172 | run: composer run test:integration 173 | 174 | - name: Print logs 175 | if: always() 176 | run: | 177 | cat data/nextcloud.log 178 | 179 | - name: Skipped 180 | # Fail the action when neither unit nor integration tests ran 181 | if: steps.check_phpunit.outcome == 'failure' && steps.check_integration.outcome == 'failure' 182 | run: | 183 | echo 'Neither PHPUnit nor PHPUnit integration tests are specified in composer.json scripts' 184 | exit 1 185 | 186 | summary: 187 | permissions: 188 | contents: none 189 | runs-on: ubuntu-latest 190 | needs: [changes, phpunit-pgsql] 191 | 192 | if: always() 193 | 194 | name: phpunit-pgsql-summary 195 | 196 | steps: 197 | - name: Summary status 198 | run: if ${{ needs.changes.outputs.src != 'false' && needs.phpunit-pgsql.result != 'success' }}; then exit 1; fi 199 | -------------------------------------------------------------------------------- /.github/workflows/phpunit-sqlite.yml: -------------------------------------------------------------------------------- 1 | # This workflow is provided via the organization template repository 2 | # 3 | # https://github.com/nextcloud/.github 4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization 5 | # 6 | # SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors 7 | # SPDX-License-Identifier: MIT 8 | 9 | name: PHPUnit SQLite 10 | 11 | on: pull_request 12 | 13 | permissions: 14 | contents: read 15 | 16 | concurrency: 17 | group: phpunit-sqlite-${{ github.head_ref || github.run_id }} 18 | cancel-in-progress: true 19 | 20 | jobs: 21 | matrix: 22 | runs-on: ubuntu-latest 23 | outputs: 24 | php-version: ${{ steps.versions.outputs.php-available-list }} 25 | server-max: ${{ steps.versions.outputs.branches-max-list }} 26 | steps: 27 | - name: Checkout app 28 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 29 | with: 30 | persist-credentials: false 31 | 32 | - name: Get version matrix 33 | id: versions 34 | uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.3.1 35 | 36 | changes: 37 | runs-on: ubuntu-latest 38 | permissions: 39 | contents: read 40 | pull-requests: read 41 | 42 | outputs: 43 | src: ${{ steps.changes.outputs.src}} 44 | 45 | steps: 46 | - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 47 | id: changes 48 | continue-on-error: true 49 | with: 50 | filters: | 51 | src: 52 | - '.github/workflows/**' 53 | - 'appinfo/**' 54 | - 'lib/**' 55 | - 'templates/**' 56 | - 'tests/**' 57 | - 'vendor/**' 58 | - 'vendor-bin/**' 59 | - '.php-cs-fixer.dist.php' 60 | - 'composer.json' 61 | - 'composer.lock' 62 | 63 | phpunit-sqlite: 64 | runs-on: ubuntu-latest 65 | 66 | needs: [changes, matrix] 67 | if: needs.changes.outputs.src != 'false' 68 | 69 | strategy: 70 | matrix: 71 | php-versions: ${{ fromJson(needs.matrix.outputs.php-version) }} 72 | server-versions: ${{ fromJson(needs.matrix.outputs.server-max) }} 73 | 74 | name: SQLite PHP ${{ matrix.php-versions }} Nextcloud ${{ matrix.server-versions }} 75 | 76 | steps: 77 | - name: Set app env 78 | if: ${{ env.APP_NAME == '' }} 79 | run: | 80 | # Split and keep last 81 | echo "APP_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV 82 | 83 | - name: Checkout server 84 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 85 | with: 86 | persist-credentials: false 87 | submodules: true 88 | repository: nextcloud/server 89 | ref: ${{ matrix.server-versions }} 90 | 91 | - name: Checkout app 92 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 93 | with: 94 | persist-credentials: false 95 | path: apps/${{ env.APP_NAME }} 96 | 97 | - name: Set up php ${{ matrix.php-versions }} 98 | uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2.32.0 99 | with: 100 | php-version: ${{ matrix.php-versions }} 101 | # https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation 102 | extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite 103 | coverage: none 104 | ini-file: development 105 | # Temporary workaround for missing pcntl_* in PHP 8.3 106 | ini-values: disable_functions= 107 | env: 108 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 109 | 110 | - name: Check composer file existence 111 | id: check_composer 112 | uses: andstor/file-existence-action@076e0072799f4942c8bc574a82233e1e4d13e9d6 # v3.0.0 113 | with: 114 | files: apps/${{ env.APP_NAME }}/composer.json 115 | 116 | - name: Set up dependencies 117 | # Only run if phpunit config file exists 118 | if: steps.check_composer.outputs.files_exists == 'true' 119 | working-directory: apps/${{ env.APP_NAME }} 120 | run: | 121 | composer remove nextcloud/ocp --dev 122 | composer i 123 | 124 | - name: Set up Nextcloud 125 | env: 126 | DB_PORT: 4444 127 | run: | 128 | mkdir data 129 | ./occ maintenance:install --verbose --database=sqlite --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 130 | ./occ app:enable --force ${{ env.APP_NAME }} 131 | 132 | - name: Check PHPUnit script is defined 133 | id: check_phpunit 134 | continue-on-error: true 135 | working-directory: apps/${{ env.APP_NAME }} 136 | run: | 137 | composer run --list | grep '^ test:unit ' | wc -l | grep 1 138 | 139 | - name: PHPUnit 140 | # Only run if phpunit config file exists 141 | if: steps.check_phpunit.outcome == 'success' 142 | working-directory: apps/${{ env.APP_NAME }} 143 | run: composer run test:unit 144 | 145 | - name: Check PHPUnit integration script is defined 146 | id: check_integration 147 | continue-on-error: true 148 | working-directory: apps/${{ env.APP_NAME }} 149 | run: | 150 | composer run --list | grep '^ test:integration ' | wc -l | grep 1 151 | 152 | - name: Run Nextcloud 153 | # Only run if phpunit integration config file exists 154 | if: steps.check_integration.outcome == 'success' 155 | run: php -S localhost:8080 & 156 | 157 | - name: PHPUnit integration 158 | # Only run if phpunit integration config file exists 159 | if: steps.check_integration.outcome == 'success' 160 | working-directory: apps/${{ env.APP_NAME }} 161 | run: composer run test:integration 162 | 163 | - name: Print logs 164 | if: always() 165 | run: | 166 | cat data/nextcloud.log 167 | 168 | - name: Skipped 169 | # Fail the action when neither unit nor integration tests ran 170 | if: steps.check_phpunit.outcome == 'failure' && steps.check_integration.outcome == 'failure' 171 | run: | 172 | echo 'Neither PHPUnit nor PHPUnit integration tests are specified in composer.json scripts' 173 | exit 1 174 | 175 | summary: 176 | permissions: 177 | contents: none 178 | runs-on: ubuntu-latest 179 | needs: [changes, phpunit-sqlite] 180 | 181 | if: always() 182 | 183 | name: phpunit-sqlite-summary 184 | 185 | steps: 186 | - name: Summary status 187 | run: if ${{ needs.changes.outputs.src != 'false' && needs.phpunit-sqlite.result != 'success' }}; then exit 1; fi 188 | -------------------------------------------------------------------------------- /.github/workflows/psalm-matrix.yml: -------------------------------------------------------------------------------- 1 | # This workflow is provided via the organization template repository 2 | # 3 | # https://github.com/nextcloud/.github 4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization 5 | # 6 | # SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors 7 | # SPDX-License-Identifier: MIT 8 | 9 | name: Static analysis 10 | 11 | on: pull_request 12 | 13 | concurrency: 14 | group: psalm-${{ github.head_ref || github.run_id }} 15 | cancel-in-progress: true 16 | 17 | permissions: 18 | contents: read 19 | 20 | jobs: 21 | matrix: 22 | runs-on: ubuntu-latest 23 | outputs: 24 | ocp-matrix: ${{ steps.versions.outputs.ocp-matrix }} 25 | steps: 26 | - name: Checkout app 27 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 28 | with: 29 | persist-credentials: false 30 | 31 | - name: Get version matrix 32 | id: versions 33 | uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.3.1 34 | 35 | - name: Check enforcement of minimum PHP version ${{ steps.versions.outputs.php-min }} in psalm.xml 36 | run: grep 'phpVersion="${{ steps.versions.outputs.php-min }}' psalm.xml 37 | 38 | static-analysis: 39 | runs-on: ubuntu-latest 40 | needs: matrix 41 | strategy: 42 | # do not stop on another job's failure 43 | fail-fast: false 44 | matrix: ${{ fromJson(needs.matrix.outputs.ocp-matrix) }} 45 | 46 | name: static-psalm-analysis ${{ matrix.ocp-version }} 47 | steps: 48 | - name: Checkout 49 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 50 | with: 51 | persist-credentials: false 52 | 53 | - name: Set up php${{ matrix.php-min }} 54 | uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2.32.0 55 | with: 56 | php-version: ${{ matrix.php-min }} 57 | extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite 58 | coverage: none 59 | ini-file: development 60 | # Temporary workaround for missing pcntl_* in PHP 8.3 61 | ini-values: disable_functions= 62 | env: 63 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 64 | 65 | - name: Install dependencies 66 | run: | 67 | composer remove nextcloud/ocp --dev 68 | composer i 69 | 70 | 71 | - name: Install dependencies # zizmor: ignore[template-injection] 72 | run: composer require --dev 'nextcloud/ocp:${{ matrix.ocp-version }}' --ignore-platform-reqs --with-dependencies 73 | 74 | - name: Run coding standards check 75 | run: composer run psalm -- --threads=1 --monochrome --no-progress --output-format=github 76 | 77 | summary: 78 | runs-on: ubuntu-latest 79 | needs: static-analysis 80 | 81 | if: always() 82 | 83 | name: static-psalm-analysis-summary 84 | 85 | steps: 86 | - name: Summary status 87 | run: if ${{ needs.static-analysis.result != 'success' }}; then exit 1; fi 88 | -------------------------------------------------------------------------------- /.github/workflows/update-nextcloud-ocp.yml: -------------------------------------------------------------------------------- 1 | # This workflow is provided via the organization template repository 2 | # 3 | # https://github.com/nextcloud/.github 4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization 5 | # 6 | # SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors 7 | # SPDX-License-Identifier: MIT 8 | 9 | name: Update nextcloud/ocp 10 | 11 | on: 12 | workflow_dispatch: 13 | schedule: 14 | - cron: "5 2 * * 0" 15 | 16 | permissions: 17 | contents: read 18 | 19 | jobs: 20 | update-nextcloud-ocp: 21 | runs-on: ubuntu-latest 22 | 23 | strategy: 24 | fail-fast: false 25 | matrix: 26 | branches: ['main', 'master', 'stable31', 'stable30', 'stable29'] 27 | 28 | name: update-nextcloud-ocp-${{ matrix.branches }} 29 | 30 | steps: 31 | - id: checkout 32 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 33 | with: 34 | persist-credentials: false 35 | ref: ${{ matrix.branches }} 36 | submodules: true 37 | continue-on-error: true 38 | 39 | - name: Set up php8.2 40 | if: steps.checkout.outcome == 'success' 41 | uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2.32.0 42 | with: 43 | php-version: 8.2 44 | # https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation 45 | extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite 46 | coverage: none 47 | env: 48 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 49 | 50 | - name: Read codeowners 51 | if: steps.checkout.outcome == 'success' 52 | id: codeowners 53 | run: | 54 | grep '/appinfo/info.xml' .github/CODEOWNERS | cut -f 2- -d ' ' | xargs | awk '{ print "codeowners="$0 }' >> $GITHUB_OUTPUT 55 | continue-on-error: true 56 | 57 | - name: Composer install 58 | if: steps.checkout.outcome == 'success' 59 | run: composer install 60 | 61 | - name: Composer update nextcloud/ocp 62 | id: update_branch 63 | if: ${{ steps.checkout.outcome == 'success' && matrix.branches != 'main' }} 64 | run: composer require --dev 'nextcloud/ocp:dev-${{ matrix.branches }}' 65 | 66 | - name: Raise on issue on failure 67 | uses: dacbd/create-issue-action@cdb57ab6ff8862aa09fee2be6ba77a59581921c2 # v2.0.0 68 | if: ${{ steps.checkout.outcome == 'success' && failure() && steps.update_branch.conclusion == 'failure' }} 69 | with: 70 | token: ${{ secrets.GITHUB_TOKEN }} 71 | title: 'Failed to update nextcloud/ocp package on branch ${{ matrix.branches }}' 72 | body: 'Please check the output of the GitHub action and manually resolve the issues${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}${{ steps.codeowners.outputs.codeowners }}' 73 | 74 | - name: Composer update nextcloud/ocp 75 | id: update_main 76 | if: ${{ steps.checkout.outcome == 'success' && matrix.branches == 'main' }} 77 | run: composer require --dev nextcloud/ocp:dev-master 78 | 79 | - name: Raise on issue on failure 80 | uses: dacbd/create-issue-action@cdb57ab6ff8862aa09fee2be6ba77a59581921c2 # v2.0.0 81 | if: ${{ steps.checkout.outcome == 'success' && failure() && steps.update_main.conclusion == 'failure' }} 82 | with: 83 | token: ${{ secrets.GITHUB_TOKEN }} 84 | title: 'Failed to update nextcloud/ocp package on branch ${{ matrix.branches }}' 85 | body: 'Please check the output of the GitHub action and manually resolve the issues${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}${{ steps.codeowners.outputs.codeowners }}' 86 | 87 | - name: Reset checkout 3rdparty 88 | if: steps.checkout.outcome == 'success' 89 | run: | 90 | git clean -f 3rdparty 91 | git checkout 3rdparty 92 | continue-on-error: true 93 | 94 | - name: Reset checkout vendor 95 | if: steps.checkout.outcome == 'success' 96 | run: | 97 | git clean -f vendor 98 | git checkout vendor 99 | continue-on-error: true 100 | 101 | - name: Reset checkout vendor-bin 102 | if: steps.checkout.outcome == 'success' 103 | run: | 104 | git clean -f vendor-bin 105 | git checkout vendor-bin 106 | continue-on-error: true 107 | 108 | - name: Create Pull Request 109 | if: steps.checkout.outcome == 'success' 110 | uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 111 | with: 112 | token: ${{ secrets.COMMAND_BOT_PAT }} 113 | commit-message: 'chore(dev-deps): Bump nextcloud/ocp package' 114 | committer: GitHub 115 | author: nextcloud-command 116 | signoff: true 117 | branch: 'automated/noid/${{ matrix.branches }}-update-nextcloud-ocp' 118 | title: '[${{ matrix.branches }}] Update nextcloud/ocp dependency' 119 | body: | 120 | Auto-generated update of [nextcloud/ocp](https://github.com/nextcloud-deps/ocp/) dependency 121 | labels: | 122 | dependencies 123 | 3. to review 124 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | node_modules 3 | *.cache 4 | vendor 5 | -------------------------------------------------------------------------------- /.l10nignore: -------------------------------------------------------------------------------- 1 | # compiled vue templates 2 | js/files_versions.js 3 | src/templates.js 4 | -------------------------------------------------------------------------------- /.nextcloudignore: -------------------------------------------------------------------------------- 1 | .drone 2 | .git 3 | .github 4 | .gitignore 5 | .scrutinizer.yml 6 | .travis.yml 7 | .tx 8 | krankerl.toml 9 | screenshots 10 | .nextcloudignore 11 | tests 12 | composer.* 13 | psalm.xml 14 | -------------------------------------------------------------------------------- /.php-cs-fixer.dist.php: -------------------------------------------------------------------------------- 1 | getFinder() 15 | ->ignoreVCSIgnored(true) 16 | ->notPath('build') 17 | ->notPath('tests/stubs') 18 | ->notPath('l10n') 19 | ->notPath('src') 20 | ->notPath('vendor') 21 | ->in(__DIR__); 22 | return $config; 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # files_snapshots 2 | 3 | Access filesystem snapshots from Nextcloud. 4 | 5 |  6 | 7 | Allows using filesystem snapshots (such as provided by zfs and btrfs) instead of builtin Nextcloud versions. 8 | 9 | ## Limitations 10 | 11 | This app does not automatically create snapshots itself, because of this it might not have a snapshot 12 | for every change made to the file. 13 | 14 | Since no snapshots are created by the app, when reverting a file, any change made to a file since the last snapshot will be lost. 15 | 16 | ## Configuring 17 | 18 | In order to access snapshots, two things need to be configured under the admin settings. 19 | 20 | - snapshot format: where the snapshots of the Nextcloud data directory can be found 21 | 22 | example: `/srv/http/.zfs/snapshot/%snapshot%/nextcloud/data/` 23 | where `/srv/http/nextcloud/data` is the Nextcloud data directory 24 | and `/srv/http` is a folder which is being snapshoted to `/srv/http/.zfs/snapshot`. 25 | 26 | Additionally, if your snapshots are organized over multiple directories like 27 | 28 | ``` 29 | /.snapshots/hourly/2020-02-07_00:00/... 30 | /.snapshots/hourly/2020-02-07_01:00/... 31 | /.snapshots/daily/2020-02-06_00:00/... 32 | /.snapshots/daily/2020-02-07_00:00/... 33 | ``` 34 | 35 | you can use a glob such as `/.snapshots/*/%snapshot%/` to make the app search for snapshots in multiple directories. 36 | 37 | - snapshot folder date format: How the snapshot date is formatted in the snapshot name 38 | 39 | Specifications about the format: http://php.net/manual/de/datetime.createfromformat.php 40 | 41 | Example: `*Y-m-d_H:i:s*` will correctly match snapshots named `autosnap_2017-05-27_00:00:01_hourly` 42 | 43 | Hint: Each * will only match until the next separator or digit 44 | 45 | Example: `*-*-*-Y-m-d-Hi` will correctly match snapshots named `zfs-auto-snap_frequent-2017-06-23-1930` 46 | -------------------------------------------------------------------------------- /appinfo/info.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | files_snapshots 5 | Snapshots 6 | Access filesystem snapshots trough Nextcloud 7 | 8 | 1.0.12 9 | agpl 10 | Robin Appelman 11 | Files_Snapshots 12 | 13 | files 14 | 15 | https://github.com/icewind1991/files_snapshots 16 | https://github.com/icewind1991/files_snapshots/issues 17 | https://github.com/icewind1991/files_snapshots.git 18 | 19 | https://raw.githubusercontent.com/icewind1991/files_snapshots/master/screenshots/versions.png 20 | https://raw.githubusercontent.com/icewind1991/files_snapshots/master/screenshots/settings.png 21 | 22 | 23 | 24 | 25 | 26 | 27 | OCA\Files_Snapshots\Settings\Admin 28 | OCA\Files_Snapshots\Settings\Section 29 | 30 | 31 | 32 | OCA\Files_Snapshots\Versions\SnapshotVersionBackend 33 | 34 | 35 | -------------------------------------------------------------------------------- /appinfo/routes.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * @license GNU AGPL version 3 or any later version 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU Affero General Public License as 10 | * published by the Free Software Foundation, either version 3 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Affero General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Affero General Public License 19 | * along with this program. If not, see . 20 | * 21 | */ 22 | 23 | namespace OCA\Files_Snapshots\AppInfo; 24 | 25 | /** @var Application $application */ 26 | $application = \OC::$server->query(Application::class); 27 | $application->registerRoutes($this, [ 28 | 'routes' => [ 29 | [ 30 | 'name' => 'Admin#testSettings', 31 | 'url' => '/settings/test', 32 | 'verb' => 'POST', 33 | ], 34 | [ 35 | 'name' => 'Admin#save', 36 | 'url' => '/settings/save', 37 | 'verb' => 'POST', 38 | ], 39 | ], 40 | ]); 41 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "project", 3 | "require-dev": { 4 | "nextcloud/ocp": "dev-master" 5 | }, 6 | "require": { 7 | "bamarni/composer-bin-plugin": "^1.8" 8 | }, 9 | "license": "AGPLv3", 10 | "scripts": { 11 | "post-install-cmd": [ 12 | "@composer bin all install --ansi" 13 | ], 14 | "post-update-cmd": [ 15 | "@composer bin all update --ansi" 16 | ], 17 | "lint": "find . -name \\*.php -not -path './vendor/*' -not -path './vendor-bin/*' -not -path './build/*' -not -path './tests/integration/vendor/*' -print0 | xargs -0 -n1 php -l", 18 | "cs:check": "php-cs-fixer fix --dry-run --diff", 19 | "cs:fix": "php-cs-fixer fix", 20 | "test:unit": "phpunit -c tests/phpunit.xml", 21 | "psalm": "psalm --threads=1", 22 | "psalm:update-baseline": "psalm --threads=1 --update-baseline", 23 | "psalm:clear": "psalm --clear-cache && psalm --clear-global-cache", 24 | "psalm:fix": "psalm --alter --issues=InvalidReturnType,InvalidNullableReturnType,MissingParamType,InvalidFalsableReturnType" 25 | }, 26 | "config": { 27 | "allow-plugins": { 28 | "bamarni/composer-bin-plugin": true 29 | }, 30 | "platform": { 31 | "php": "8.1" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "79347efa5966aec068b8ece538e4c21b", 8 | "packages": [ 9 | { 10 | "name": "bamarni/composer-bin-plugin", 11 | "version": "1.8.2", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/bamarni/composer-bin-plugin.git", 15 | "reference": "92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/bamarni/composer-bin-plugin/zipball/92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880", 20 | "reference": "92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "composer-plugin-api": "^2.0", 25 | "php": "^7.2.5 || ^8.0" 26 | }, 27 | "require-dev": { 28 | "composer/composer": "^2.0", 29 | "ext-json": "*", 30 | "phpstan/extension-installer": "^1.1", 31 | "phpstan/phpstan": "^1.8", 32 | "phpstan/phpstan-phpunit": "^1.1", 33 | "phpunit/phpunit": "^8.5 || ^9.5", 34 | "symfony/console": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", 35 | "symfony/finder": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", 36 | "symfony/process": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0" 37 | }, 38 | "type": "composer-plugin", 39 | "extra": { 40 | "class": "Bamarni\\Composer\\Bin\\BamarniBinPlugin" 41 | }, 42 | "autoload": { 43 | "psr-4": { 44 | "Bamarni\\Composer\\Bin\\": "src" 45 | } 46 | }, 47 | "notification-url": "https://packagist.org/downloads/", 48 | "license": [ 49 | "MIT" 50 | ], 51 | "description": "No conflicts for your bin dependencies", 52 | "keywords": [ 53 | "composer", 54 | "conflict", 55 | "dependency", 56 | "executable", 57 | "isolation", 58 | "tool" 59 | ], 60 | "support": { 61 | "issues": "https://github.com/bamarni/composer-bin-plugin/issues", 62 | "source": "https://github.com/bamarni/composer-bin-plugin/tree/1.8.2" 63 | }, 64 | "time": "2022-10-31T08:38:03+00:00" 65 | } 66 | ], 67 | "packages-dev": [ 68 | { 69 | "name": "nextcloud/ocp", 70 | "version": "dev-master", 71 | "source": { 72 | "type": "git", 73 | "url": "https://github.com/nextcloud-deps/ocp.git", 74 | "reference": "e2304c4f0f5ecf7fe16a3d3745c63b5f019dc718" 75 | }, 76 | "dist": { 77 | "type": "zip", 78 | "url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/e2304c4f0f5ecf7fe16a3d3745c63b5f019dc718", 79 | "reference": "e2304c4f0f5ecf7fe16a3d3745c63b5f019dc718", 80 | "shasum": "" 81 | }, 82 | "require": { 83 | "php": "~8.1 || ~8.2 || ~8.3 || ~8.4", 84 | "psr/clock": "^1.0", 85 | "psr/container": "^2.0.2", 86 | "psr/event-dispatcher": "^1.0", 87 | "psr/log": "^3.0.2" 88 | }, 89 | "default-branch": true, 90 | "type": "library", 91 | "extra": { 92 | "branch-alias": { 93 | "dev-master": "32.0.0-dev" 94 | } 95 | }, 96 | "notification-url": "https://packagist.org/downloads/", 97 | "license": [ 98 | "AGPL-3.0-or-later" 99 | ], 100 | "authors": [ 101 | { 102 | "name": "Christoph Wurst", 103 | "email": "christoph@winzerhof-wurst.at" 104 | }, 105 | { 106 | "name": "Joas Schilling", 107 | "email": "coding@schilljs.com" 108 | } 109 | ], 110 | "description": "Composer package containing Nextcloud's public OCP API and the unstable NCU API", 111 | "support": { 112 | "issues": "https://github.com/nextcloud-deps/ocp/issues", 113 | "source": "https://github.com/nextcloud-deps/ocp/tree/master" 114 | }, 115 | "time": "2025-04-09T00:48:03+00:00" 116 | }, 117 | { 118 | "name": "psr/clock", 119 | "version": "1.0.0", 120 | "source": { 121 | "type": "git", 122 | "url": "https://github.com/php-fig/clock.git", 123 | "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" 124 | }, 125 | "dist": { 126 | "type": "zip", 127 | "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", 128 | "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", 129 | "shasum": "" 130 | }, 131 | "require": { 132 | "php": "^7.0 || ^8.0" 133 | }, 134 | "type": "library", 135 | "autoload": { 136 | "psr-4": { 137 | "Psr\\Clock\\": "src/" 138 | } 139 | }, 140 | "notification-url": "https://packagist.org/downloads/", 141 | "license": [ 142 | "MIT" 143 | ], 144 | "authors": [ 145 | { 146 | "name": "PHP-FIG", 147 | "homepage": "https://www.php-fig.org/" 148 | } 149 | ], 150 | "description": "Common interface for reading the clock.", 151 | "homepage": "https://github.com/php-fig/clock", 152 | "keywords": [ 153 | "clock", 154 | "now", 155 | "psr", 156 | "psr-20", 157 | "time" 158 | ], 159 | "support": { 160 | "issues": "https://github.com/php-fig/clock/issues", 161 | "source": "https://github.com/php-fig/clock/tree/1.0.0" 162 | }, 163 | "time": "2022-11-25T14:36:26+00:00" 164 | }, 165 | { 166 | "name": "psr/container", 167 | "version": "2.0.2", 168 | "source": { 169 | "type": "git", 170 | "url": "https://github.com/php-fig/container.git", 171 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" 172 | }, 173 | "dist": { 174 | "type": "zip", 175 | "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", 176 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", 177 | "shasum": "" 178 | }, 179 | "require": { 180 | "php": ">=7.4.0" 181 | }, 182 | "type": "library", 183 | "extra": { 184 | "branch-alias": { 185 | "dev-master": "2.0.x-dev" 186 | } 187 | }, 188 | "autoload": { 189 | "psr-4": { 190 | "Psr\\Container\\": "src/" 191 | } 192 | }, 193 | "notification-url": "https://packagist.org/downloads/", 194 | "license": [ 195 | "MIT" 196 | ], 197 | "authors": [ 198 | { 199 | "name": "PHP-FIG", 200 | "homepage": "https://www.php-fig.org/" 201 | } 202 | ], 203 | "description": "Common Container Interface (PHP FIG PSR-11)", 204 | "homepage": "https://github.com/php-fig/container", 205 | "keywords": [ 206 | "PSR-11", 207 | "container", 208 | "container-interface", 209 | "container-interop", 210 | "psr" 211 | ], 212 | "support": { 213 | "issues": "https://github.com/php-fig/container/issues", 214 | "source": "https://github.com/php-fig/container/tree/2.0.2" 215 | }, 216 | "time": "2021-11-05T16:47:00+00:00" 217 | }, 218 | { 219 | "name": "psr/event-dispatcher", 220 | "version": "1.0.0", 221 | "source": { 222 | "type": "git", 223 | "url": "https://github.com/php-fig/event-dispatcher.git", 224 | "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" 225 | }, 226 | "dist": { 227 | "type": "zip", 228 | "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", 229 | "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", 230 | "shasum": "" 231 | }, 232 | "require": { 233 | "php": ">=7.2.0" 234 | }, 235 | "type": "library", 236 | "extra": { 237 | "branch-alias": { 238 | "dev-master": "1.0.x-dev" 239 | } 240 | }, 241 | "autoload": { 242 | "psr-4": { 243 | "Psr\\EventDispatcher\\": "src/" 244 | } 245 | }, 246 | "notification-url": "https://packagist.org/downloads/", 247 | "license": [ 248 | "MIT" 249 | ], 250 | "authors": [ 251 | { 252 | "name": "PHP-FIG", 253 | "homepage": "http://www.php-fig.org/" 254 | } 255 | ], 256 | "description": "Standard interfaces for event handling.", 257 | "keywords": [ 258 | "events", 259 | "psr", 260 | "psr-14" 261 | ], 262 | "support": { 263 | "issues": "https://github.com/php-fig/event-dispatcher/issues", 264 | "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" 265 | }, 266 | "time": "2019-01-08T18:20:26+00:00" 267 | }, 268 | { 269 | "name": "psr/log", 270 | "version": "3.0.2", 271 | "source": { 272 | "type": "git", 273 | "url": "https://github.com/php-fig/log.git", 274 | "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" 275 | }, 276 | "dist": { 277 | "type": "zip", 278 | "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", 279 | "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", 280 | "shasum": "" 281 | }, 282 | "require": { 283 | "php": ">=8.0.0" 284 | }, 285 | "type": "library", 286 | "extra": { 287 | "branch-alias": { 288 | "dev-master": "3.x-dev" 289 | } 290 | }, 291 | "autoload": { 292 | "psr-4": { 293 | "Psr\\Log\\": "src" 294 | } 295 | }, 296 | "notification-url": "https://packagist.org/downloads/", 297 | "license": [ 298 | "MIT" 299 | ], 300 | "authors": [ 301 | { 302 | "name": "PHP-FIG", 303 | "homepage": "https://www.php-fig.org/" 304 | } 305 | ], 306 | "description": "Common interface for logging libraries", 307 | "homepage": "https://github.com/php-fig/log", 308 | "keywords": [ 309 | "log", 310 | "psr", 311 | "psr-3" 312 | ], 313 | "support": { 314 | "source": "https://github.com/php-fig/log/tree/3.0.2" 315 | }, 316 | "time": "2024-09-11T13:17:53+00:00" 317 | } 318 | ], 319 | "aliases": [], 320 | "minimum-stability": "stable", 321 | "stability-flags": { 322 | "nextcloud/ocp": 20 323 | }, 324 | "prefer-stable": false, 325 | "prefer-lowest": false, 326 | "platform": {}, 327 | "platform-dev": {}, 328 | "platform-overrides": { 329 | "php": "8.1" 330 | }, 331 | "plugin-api-version": "2.6.0" 332 | } 333 | -------------------------------------------------------------------------------- /css/settings.css: -------------------------------------------------------------------------------- 1 | #files_snapshots table.settings td:first-child { 2 | padding: 8px 2em 8px 0; 3 | } 4 | 5 | #files_snapshots input[type='text'] { 6 | width: 400px; 7 | max-width: calc(100% - 10px); 8 | } 9 | 10 | #files_snapshots div.settings { 11 | margin-bottom: 30px; 12 | } 13 | 14 | #files_snapshots table.result { 15 | margin-top: 1em; 16 | width: 100%; 17 | } 18 | 19 | #files_snapshots table.result td { 20 | padding: 5px; 21 | } 22 | 23 | #files_snapshots table.result tr.error td { 24 | border-bottom: none 0; 25 | } 26 | 27 | #files_snapshots div.loading { 28 | padding-top: 15em; 29 | } 30 | -------------------------------------------------------------------------------- /img/app.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /js/settings.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function () { 2 | var form = $('#files_snapshots'); 3 | var format = $('#format'); 4 | var dateFormat = $('#date_format'); 5 | var resultTable = $('table.result'); 6 | var resultBody = $('table.result tbody'); 7 | var loading = $('div.loading'); 8 | form.on('submit', function (event) { 9 | event.preventDefault(); 10 | $.post(OC.generateUrl('apps/files_snapshots/settings/save'), { 11 | snapshotFormat: format.val(), 12 | dateFormat: dateFormat.val() 13 | }); 14 | }); 15 | 16 | var testSettings = _.debounce(function () { 17 | resultTable.addClass('hidden'); 18 | loading.removeClass('hidden'); 19 | $.post(OC.generateUrl('apps/files_snapshots/settings/test'), { 20 | snapshotFormat: format.val(), 21 | dateFormat: dateFormat.val() 22 | }).then(function (snapshots) { 23 | resultBody.empty(); 24 | if (snapshots.length < 1) { 25 | resultBody.append($('').append($('').text(t('files_snapshots', 'No snapshots found')))); 26 | } else { 27 | for (var snap in snapshots) { 28 | if (snapshots.hasOwnProperty(snap)) { 29 | var row = $(''); 30 | row.append($('').text(snap)); 31 | row.append($('').text(snapshots[snap])); 32 | resultBody.append(row); 33 | } 34 | } 35 | } 36 | resultTable.removeClass('hidden'); 37 | loading.addClass('hidden'); 38 | }); 39 | }, 250); 40 | 41 | format.on('input', testSettings); 42 | dateFormat.on('input', testSettings); 43 | testSettings(); 44 | }); 45 | -------------------------------------------------------------------------------- /krankerl.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | before_cmds = [ 3 | "composer dump-autoload -a" 4 | ] 5 | -------------------------------------------------------------------------------- /l10n/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icewind1991/files_snapshots/d8ba3c3a5707e18a147c180421d1ff2283fde4ad/l10n/.gitkeep -------------------------------------------------------------------------------- /l10n/ar.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "غير قادر على الاستعادة : %s", 5 | "Versions" : "الإصدارات", 6 | "Failed to revert {file} to revision {timestamp}." : "فشل في استعادة {ملف} لنتقيح {الطابع الزمني}", 7 | "Restore" : "استعادة ", 8 | "More versions..." : "المزيد من الإصدارات", 9 | "No other versions available" : "لا توجد إصدارات أخرى متاحة" 10 | }, 11 | "nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;"); 12 | -------------------------------------------------------------------------------- /l10n/ar.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "غير قادر على الاستعادة : %s", 3 | "Versions" : "الإصدارات", 4 | "Failed to revert {file} to revision {timestamp}." : "فشل في استعادة {ملف} لنتقيح {الطابع الزمني}", 5 | "Restore" : "استعادة ", 6 | "More versions..." : "المزيد من الإصدارات", 7 | "No other versions available" : "لا توجد إصدارات أخرى متاحة" 8 | },"pluralForm" :"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;" 9 | } -------------------------------------------------------------------------------- /l10n/ast.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Nun pudo revertise: %s", 5 | "Versions" : "Versiones", 6 | "Failed to revert {file} to revision {timestamp}." : "Fallu al revertir {file} a la revisión {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"], 8 | "Restore" : "Restaurar", 9 | "No earlier versions available" : "Nun hai versiones más tempranes disponibles", 10 | "More versions …" : "Más versiones...", 11 | "No versions available" : "Nun hai versiones disponibles", 12 | "More versions..." : "Más versiones..." 13 | }, 14 | "nplurals=2; plural=(n != 1);"); 15 | -------------------------------------------------------------------------------- /l10n/ast.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Nun pudo revertise: %s", 3 | "Versions" : "Versiones", 4 | "Failed to revert {file} to revision {timestamp}." : "Fallu al revertir {file} a la revisión {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"], 6 | "Restore" : "Restaurar", 7 | "No earlier versions available" : "Nun hai versiones más tempranes disponibles", 8 | "More versions …" : "Más versiones...", 9 | "No versions available" : "Nun hai versiones disponibles", 10 | "More versions..." : "Más versiones..." 11 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 12 | } -------------------------------------------------------------------------------- /l10n/az.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Geri qaytarmaq olmur: %s", 5 | "Versions" : "Versiyaları", 6 | "Failed to revert {file} to revision {timestamp}." : "{timestamp} yenidən baxılması üçün {file} geri qaytarmaq mümkün olmadı.", 7 | "Restore" : "Geri qaytar", 8 | "More versions..." : "Əlavə versiyalar", 9 | "No other versions available" : "Başqa versiyalar mövcud deyil" 10 | }, 11 | "nplurals=2; plural=(n != 1);"); 12 | -------------------------------------------------------------------------------- /l10n/az.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Geri qaytarmaq olmur: %s", 3 | "Versions" : "Versiyaları", 4 | "Failed to revert {file} to revision {timestamp}." : "{timestamp} yenidən baxılması üçün {file} geri qaytarmaq mümkün olmadı.", 5 | "Restore" : "Geri qaytar", 6 | "More versions..." : "Əlavə versiyalar", 7 | "No other versions available" : "Başqa versiyalar mövcud deyil" 8 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 9 | } -------------------------------------------------------------------------------- /l10n/bg.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Грешка при връщане: %s", 5 | "Versions" : "Версии", 6 | "Failed to revert {file} to revision {timestamp}." : "Грешка при връщане на {file} към версия {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n байт","%n байта"], 8 | "Restore" : "Възтановяване", 9 | "No versions available" : "Няма налични версии", 10 | "More versions..." : "Още версии..." 11 | }, 12 | "nplurals=2; plural=(n != 1);"); 13 | -------------------------------------------------------------------------------- /l10n/bg.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Грешка при връщане: %s", 3 | "Versions" : "Версии", 4 | "Failed to revert {file} to revision {timestamp}." : "Грешка при връщане на {file} към версия {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n байт","%n байта"], 6 | "Restore" : "Възтановяване", 7 | "No versions available" : "Няма налични версии", 8 | "More versions..." : "Още версии..." 9 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 10 | } -------------------------------------------------------------------------------- /l10n/bg_BG.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Грешка при връщане: %s", 5 | "Versions" : "Версии", 6 | "Failed to revert {file} to revision {timestamp}." : "Грешка при връщане на {file} към версия {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n байт","%n байта"], 8 | "Restore" : "Възтановяване", 9 | "No versions available" : "Няма налични версии", 10 | "More versions..." : "Още версии...", 11 | "No other versions available" : "Няма други налични версии" 12 | }, 13 | "nplurals=2; plural=(n != 1);"); 14 | -------------------------------------------------------------------------------- /l10n/bg_BG.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Грешка при връщане: %s", 3 | "Versions" : "Версии", 4 | "Failed to revert {file} to revision {timestamp}." : "Грешка при връщане на {file} към версия {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n байт","%n байта"], 6 | "Restore" : "Възтановяване", 7 | "No versions available" : "Няма налични версии", 8 | "More versions..." : "Още версии...", 9 | "No other versions available" : "Няма други налични версии" 10 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 11 | } -------------------------------------------------------------------------------- /l10n/bn_BD.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "ফিরে যাওয়া গেলনা: %s", 5 | "Versions" : "সংষ্করন", 6 | "Failed to revert {file} to revision {timestamp}." : " {file} সংশোধিত {timestamp} এ ফিরে যেতে ব্যার্থ হলো।", 7 | "Restore" : "ফিরিয়ে দাও", 8 | "More versions..." : "আরো সংষ্করণ....", 9 | "No other versions available" : "আর কোন সংষ্করণ প্রাপ্তব্য নয়" 10 | }, 11 | "nplurals=2; plural=(n != 1);"); 12 | -------------------------------------------------------------------------------- /l10n/bn_BD.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "ফিরে যাওয়া গেলনা: %s", 3 | "Versions" : "সংষ্করন", 4 | "Failed to revert {file} to revision {timestamp}." : " {file} সংশোধিত {timestamp} এ ফিরে যেতে ব্যার্থ হলো।", 5 | "Restore" : "ফিরিয়ে দাও", 6 | "More versions..." : "আরো সংষ্করণ....", 7 | "No other versions available" : "আর কোন সংষ্করণ প্রাপ্তব্য নয়" 8 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 9 | } -------------------------------------------------------------------------------- /l10n/bn_IN.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "প্রত্যাবর্তন করা যায়নি: %s", 5 | "Versions" : "সংস্করণ", 6 | "Failed to revert {file} to revision {timestamp}." : "{ফাইল} প্রত্যাবর্তন থেকে পুনর্বিবেচনা {টাইমস্ট্যাম্প} করতে ব্যর্থ।", 7 | "Restore" : "পুনরুদ্ধার", 8 | "No other versions available" : "আর কোন সংস্করণ পাওয়া যাচ্ছে না", 9 | "More versions..." : "আরো সংস্করণ..." 10 | }, 11 | "nplurals=2; plural=(n != 1);"); 12 | -------------------------------------------------------------------------------- /l10n/bn_IN.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "প্রত্যাবর্তন করা যায়নি: %s", 3 | "Versions" : "সংস্করণ", 4 | "Failed to revert {file} to revision {timestamp}." : "{ফাইল} প্রত্যাবর্তন থেকে পুনর্বিবেচনা {টাইমস্ট্যাম্প} করতে ব্যর্থ।", 5 | "Restore" : "পুনরুদ্ধার", 6 | "No other versions available" : "আর কোন সংস্করণ পাওয়া যাচ্ছে না", 7 | "More versions..." : "আরো সংস্করণ..." 8 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 9 | } -------------------------------------------------------------------------------- /l10n/bs.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Nije moguće vratiti: %s", 5 | "Versions" : "Verzije", 6 | "Failed to revert {file} to revision {timestamp}." : "Nije uspelo vraćanje {file} na reviziju {timestamp}.", 7 | "Restore" : "Obnovi", 8 | "More versions..." : "Više verzija...", 9 | "No other versions available" : "Druge verzije su nedostupne" 10 | }, 11 | "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"); 12 | -------------------------------------------------------------------------------- /l10n/bs.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Nije moguće vratiti: %s", 3 | "Versions" : "Verzije", 4 | "Failed to revert {file} to revision {timestamp}." : "Nije uspelo vraćanje {file} na reviziju {timestamp}.", 5 | "Restore" : "Obnovi", 6 | "More versions..." : "Više verzija...", 7 | "No other versions available" : "Druge verzije su nedostupne" 8 | },"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" 9 | } -------------------------------------------------------------------------------- /l10n/ca.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "No s'ha pogut revertir: %s", 5 | "Versions" : "Versions", 6 | "Failed to revert {file} to revision {timestamp}." : "Ha fallat en retornar {file} a la revisió {timestamp}", 7 | "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"], 8 | "Restore" : "Recupera", 9 | "More versions …" : "Més versións ...", 10 | "No versions available" : "No hi ha versions disponibles", 11 | "More versions..." : "Més versions..." 12 | }, 13 | "nplurals=2; plural=(n != 1);"); 14 | -------------------------------------------------------------------------------- /l10n/ca.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "No s'ha pogut revertir: %s", 3 | "Versions" : "Versions", 4 | "Failed to revert {file} to revision {timestamp}." : "Ha fallat en retornar {file} a la revisió {timestamp}", 5 | "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"], 6 | "Restore" : "Recupera", 7 | "More versions …" : "Més versións ...", 8 | "No versions available" : "No hi ha versions disponibles", 9 | "More versions..." : "Més versions..." 10 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 11 | } -------------------------------------------------------------------------------- /l10n/cs.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Nelze vrátit: %s", 5 | "Versions" : "Verze", 6 | "Failed to revert {file} to revision {timestamp}." : "Selhalo vrácení souboru {file} na verzi {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n bajt","%n bajty","%n bajtů"], 8 | "Restore" : "Obnovit", 9 | "No earlier versions available" : "Nejsou dostupné dřívější verze", 10 | "More versions …" : "Víc verzí …", 11 | "No versions available" : "Nejsou dostupné žádné verze", 12 | "More versions..." : "Více verzí..." 13 | }, 14 | "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"); 15 | -------------------------------------------------------------------------------- /l10n/cs.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Nelze vrátit: %s", 3 | "Versions" : "Verze", 4 | "Failed to revert {file} to revision {timestamp}." : "Selhalo vrácení souboru {file} na verzi {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n bajt","%n bajty","%n bajtů"], 6 | "Restore" : "Obnovit", 7 | "No earlier versions available" : "Nejsou dostupné dřívější verze", 8 | "More versions …" : "Víc verzí …", 9 | "No versions available" : "Nejsou dostupné žádné verze", 10 | "More versions..." : "Více verzí..." 11 | },"pluralForm" :"nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;" 12 | } -------------------------------------------------------------------------------- /l10n/cs_CZ.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Nelze vrátit: %s", 5 | "Versions" : "Verze", 6 | "Failed to revert {file} to revision {timestamp}." : "Selhalo vrácení souboru {file} na verzi {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n bajt","%n bajty","%n bajtů"], 8 | "Restore" : "Obnovit", 9 | "No versions available" : "Nejsou dostupné žádné verze", 10 | "More versions..." : "Více verzí...", 11 | "No other versions available" : "Žádné další verze nejsou dostupné" 12 | }, 13 | "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"); 14 | -------------------------------------------------------------------------------- /l10n/cs_CZ.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Nelze vrátit: %s", 3 | "Versions" : "Verze", 4 | "Failed to revert {file} to revision {timestamp}." : "Selhalo vrácení souboru {file} na verzi {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n bajt","%n bajty","%n bajtů"], 6 | "Restore" : "Obnovit", 7 | "No versions available" : "Nejsou dostupné žádné verze", 8 | "More versions..." : "Více verzí...", 9 | "No other versions available" : "Žádné další verze nejsou dostupné" 10 | },"pluralForm" :"nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;" 11 | } -------------------------------------------------------------------------------- /l10n/cy_GB.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Restore" : "Adfer" 5 | }, 6 | "nplurals=4; plural=(n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3;"); 7 | -------------------------------------------------------------------------------- /l10n/cy_GB.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Restore" : "Adfer" 3 | },"pluralForm" :"nplurals=4; plural=(n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3;" 4 | } -------------------------------------------------------------------------------- /l10n/da.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Kunne ikke genskabe: %s", 5 | "Versions" : "Versioner", 6 | "Failed to revert {file} to revision {timestamp}." : "Kunne ikke tilbagerulle {file} til den tidligere udgave: {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"], 8 | "Restore" : "Gendan", 9 | "No earlier versions available" : "Ingen tidligere versioner tilgængelige", 10 | "More versions …" : "Flere versioner ...", 11 | "No versions available" : "Ingen tilgængelige versioner", 12 | "More versions..." : "Flere versioner..." 13 | }, 14 | "nplurals=2; plural=(n != 1);"); 15 | -------------------------------------------------------------------------------- /l10n/da.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Kunne ikke genskabe: %s", 3 | "Versions" : "Versioner", 4 | "Failed to revert {file} to revision {timestamp}." : "Kunne ikke tilbagerulle {file} til den tidligere udgave: {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"], 6 | "Restore" : "Gendan", 7 | "No earlier versions available" : "Ingen tidligere versioner tilgængelige", 8 | "More versions …" : "Flere versioner ...", 9 | "No versions available" : "Ingen tilgængelige versioner", 10 | "More versions..." : "Flere versioner..." 11 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 12 | } -------------------------------------------------------------------------------- /l10n/de.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "%s konnte nicht zurückgesetzt werden", 5 | "Versions" : "Versionen", 6 | "Failed to revert {file} to revision {timestamp}." : "Konnte {file} nicht auf Revision {timestamp} zurücksetzen.", 7 | "_%n byte_::_%n bytes_" : ["%n Byte","%n Bytes"], 8 | "Restore" : "Wiederherstellen", 9 | "No earlier versions available" : "Keine Vorgänger-Versionen vorhanden", 10 | "More versions …" : "Weitere Versionen...", 11 | "No versions available" : "Keine Versionen verfügbar", 12 | "More versions..." : "Weitere Versionen…" 13 | }, 14 | "nplurals=2; plural=(n != 1);"); 15 | -------------------------------------------------------------------------------- /l10n/de.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "%s konnte nicht zurückgesetzt werden", 3 | "Versions" : "Versionen", 4 | "Failed to revert {file} to revision {timestamp}." : "Konnte {file} nicht auf Revision {timestamp} zurücksetzen.", 5 | "_%n byte_::_%n bytes_" : ["%n Byte","%n Bytes"], 6 | "Restore" : "Wiederherstellen", 7 | "No earlier versions available" : "Keine Vorgänger-Versionen vorhanden", 8 | "More versions …" : "Weitere Versionen...", 9 | "No versions available" : "Keine Versionen verfügbar", 10 | "More versions..." : "Weitere Versionen…" 11 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 12 | } -------------------------------------------------------------------------------- /l10n/de_DE.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "%s konnte nicht zurückgesetzt werden", 5 | "Versions" : "Versionen", 6 | "Failed to revert {file} to revision {timestamp}." : "Konnte {file} nicht auf Revision {timestamp} zurücksetzen.", 7 | "_%n byte_::_%n bytes_" : ["%n Byte","%n Bytes"], 8 | "Restore" : "Wiederherstellen", 9 | "No earlier versions available" : "Keine Vorgänger-Versionen vorhanden", 10 | "More versions …" : "Weitere Versionen …", 11 | "No versions available" : "Keine Versionen verfügbar", 12 | "More versions..." : "Weitere Versionen…" 13 | }, 14 | "nplurals=2; plural=(n != 1);"); 15 | -------------------------------------------------------------------------------- /l10n/de_DE.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "%s konnte nicht zurückgesetzt werden", 3 | "Versions" : "Versionen", 4 | "Failed to revert {file} to revision {timestamp}." : "Konnte {file} nicht auf Revision {timestamp} zurücksetzen.", 5 | "_%n byte_::_%n bytes_" : ["%n Byte","%n Bytes"], 6 | "Restore" : "Wiederherstellen", 7 | "No earlier versions available" : "Keine Vorgänger-Versionen vorhanden", 8 | "More versions …" : "Weitere Versionen …", 9 | "No versions available" : "Keine Versionen verfügbar", 10 | "More versions..." : "Weitere Versionen…" 11 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 12 | } -------------------------------------------------------------------------------- /l10n/el.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Αδυναμία επαναφοράς: %s", 5 | "Versions" : "Εκδόσεις", 6 | "Failed to revert {file} to revision {timestamp}." : "Αποτυχία επαναφοράς του {file} στην αναθεώρηση {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n bytes","%n bytes"], 8 | "Restore" : "Επαναφορά", 9 | "No earlier versions available" : "Δεν είναι διαθέριμες νεότερες εκδόσεις", 10 | "More versions …" : "Περισσότερες εκδόσεις ...", 11 | "No versions available" : "Δεν υπάρχουν εκδόσεις διαθέσιμες", 12 | "More versions..." : "Περισσότερες εκδόσεις..." 13 | }, 14 | "nplurals=2; plural=(n != 1);"); 15 | -------------------------------------------------------------------------------- /l10n/el.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Αδυναμία επαναφοράς: %s", 3 | "Versions" : "Εκδόσεις", 4 | "Failed to revert {file} to revision {timestamp}." : "Αποτυχία επαναφοράς του {file} στην αναθεώρηση {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n bytes","%n bytes"], 6 | "Restore" : "Επαναφορά", 7 | "No earlier versions available" : "Δεν είναι διαθέριμες νεότερες εκδόσεις", 8 | "More versions …" : "Περισσότερες εκδόσεις ...", 9 | "No versions available" : "Δεν υπάρχουν εκδόσεις διαθέσιμες", 10 | "More versions..." : "Περισσότερες εκδόσεις..." 11 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 12 | } -------------------------------------------------------------------------------- /l10n/en_GB.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Could not revert: %s", 5 | "Versions" : "Versions", 6 | "Failed to revert {file} to revision {timestamp}." : "Failed to revert {file} to revision {timestamp}.", 7 | "Restore" : "Restore", 8 | "More versions..." : "More versions...", 9 | "No other versions available" : "No other versions available" 10 | }, 11 | "nplurals=2; plural=(n != 1);"); 12 | -------------------------------------------------------------------------------- /l10n/en_GB.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Could not revert: %s", 3 | "Versions" : "Versions", 4 | "Failed to revert {file} to revision {timestamp}." : "Failed to revert {file} to revision {timestamp}.", 5 | "Restore" : "Restore", 6 | "More versions..." : "More versions...", 7 | "No other versions available" : "No other versions available" 8 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 9 | } -------------------------------------------------------------------------------- /l10n/eo.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Ne eblas malfari: %s", 5 | "Versions" : "Versioj", 6 | "Failed to revert {file} to revision {timestamp}." : "Malsukcesis returnigo de {file} al la revizio {timestamp}.", 7 | "Restore" : "Restaŭri", 8 | "No versions available" : "Neniu versio disponebla", 9 | "More versions..." : "Pli da versioj..." 10 | }, 11 | "nplurals=2; plural=(n != 1);"); 12 | -------------------------------------------------------------------------------- /l10n/eo.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Ne eblas malfari: %s", 3 | "Versions" : "Versioj", 4 | "Failed to revert {file} to revision {timestamp}." : "Malsukcesis returnigo de {file} al la revizio {timestamp}.", 5 | "Restore" : "Restaŭri", 6 | "No versions available" : "Neniu versio disponebla", 7 | "More versions..." : "Pli da versioj..." 8 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 9 | } -------------------------------------------------------------------------------- /l10n/es.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "No se puede revertir: %s", 5 | "Versions" : "Revisiones", 6 | "Failed to revert {file} to revision {timestamp}." : "No se ha podido revertir {archivo} a revisión {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"], 8 | "Restore" : "Recuperar", 9 | "No earlier versions available" : "No hay versiones previouses disponibles", 10 | "More versions …" : "Más versiones ...", 11 | "No versions available" : "No hay versiones disponibles", 12 | "More versions..." : "Más versiones..." 13 | }, 14 | "nplurals=2; plural=(n != 1);"); 15 | -------------------------------------------------------------------------------- /l10n/es.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "No se puede revertir: %s", 3 | "Versions" : "Revisiones", 4 | "Failed to revert {file} to revision {timestamp}." : "No se ha podido revertir {archivo} a revisión {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"], 6 | "Restore" : "Recuperar", 7 | "No earlier versions available" : "No hay versiones previouses disponibles", 8 | "More versions …" : "Más versiones ...", 9 | "No versions available" : "No hay versiones disponibles", 10 | "More versions..." : "Más versiones..." 11 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 12 | } -------------------------------------------------------------------------------- /l10n/es_AR.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "No se pudo revertir: %s ", 5 | "Versions" : "Versiones", 6 | "Failed to revert {file} to revision {timestamp}." : "Falló al revertir {file} a la revisión {timestamp}.", 7 | "Restore" : "Recuperar", 8 | "More versions..." : "Más versiones...", 9 | "No other versions available" : "No hay más versiones disponibles" 10 | }, 11 | "nplurals=2; plural=(n != 1);"); 12 | -------------------------------------------------------------------------------- /l10n/es_AR.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "No se pudo revertir: %s ", 3 | "Versions" : "Versiones", 4 | "Failed to revert {file} to revision {timestamp}." : "Falló al revertir {file} a la revisión {timestamp}.", 5 | "Restore" : "Recuperar", 6 | "More versions..." : "Más versiones...", 7 | "No other versions available" : "No hay más versiones disponibles" 8 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 9 | } -------------------------------------------------------------------------------- /l10n/es_MX.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "No fue posible revertir: %s", 5 | "Versions" : "Versiones", 6 | "Failed to revert {file} to revision {timestamp}." : "Falla al revertir {archivo} a revisión {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"], 8 | "Restore" : "Restaurar", 9 | "No earlier versions available" : "No hay versiones más antiguas disponibles", 10 | "More versions …" : "Más versiones ...", 11 | "No versions available" : "No hay versiones disponibles", 12 | "More versions..." : "Más versiones..." 13 | }, 14 | "nplurals=2; plural=(n != 1);"); 15 | -------------------------------------------------------------------------------- /l10n/es_MX.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "No fue posible revertir: %s", 3 | "Versions" : "Versiones", 4 | "Failed to revert {file} to revision {timestamp}." : "Falla al revertir {archivo} a revisión {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"], 6 | "Restore" : "Restaurar", 7 | "No earlier versions available" : "No hay versiones más antiguas disponibles", 8 | "More versions …" : "Más versiones ...", 9 | "No versions available" : "No hay versiones disponibles", 10 | "More versions..." : "Más versiones..." 11 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 12 | } -------------------------------------------------------------------------------- /l10n/et_EE.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Ei suuda taastada faili: %s", 5 | "Versions" : "Versioonid", 6 | "Failed to revert {file} to revision {timestamp}." : "Ebaõnnestus faili {file} taastamine revisjonile {timestamp}", 7 | "Restore" : "Taasta", 8 | "More versions..." : "Rohkem versioone...", 9 | "No other versions available" : "Muid versioone pole saadaval" 10 | }, 11 | "nplurals=2; plural=(n != 1);"); 12 | -------------------------------------------------------------------------------- /l10n/et_EE.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Ei suuda taastada faili: %s", 3 | "Versions" : "Versioonid", 4 | "Failed to revert {file} to revision {timestamp}." : "Ebaõnnestus faili {file} taastamine revisjonile {timestamp}", 5 | "Restore" : "Taasta", 6 | "More versions..." : "Rohkem versioone...", 7 | "No other versions available" : "Muid versioone pole saadaval" 8 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 9 | } -------------------------------------------------------------------------------- /l10n/eu.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Ezin izan da leheneratu: %s", 5 | "Versions" : "Bertsioak", 6 | "Failed to revert {file} to revision {timestamp}." : "Errore bat izan da {fitxategia} {timestamp} bertsiora leheneratzean.", 7 | "Restore" : "Berrezarri", 8 | "More versions..." : "Bertsio gehiago...", 9 | "No other versions available" : "Ez dago bertsio gehiago eskuragarri" 10 | }, 11 | "nplurals=2; plural=(n != 1);"); 12 | -------------------------------------------------------------------------------- /l10n/eu.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Ezin izan da leheneratu: %s", 3 | "Versions" : "Bertsioak", 4 | "Failed to revert {file} to revision {timestamp}." : "Errore bat izan da {fitxategia} {timestamp} bertsiora leheneratzean.", 5 | "Restore" : "Berrezarri", 6 | "More versions..." : "Bertsio gehiago...", 7 | "No other versions available" : "Ez dago bertsio gehiago eskuragarri" 8 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 9 | } -------------------------------------------------------------------------------- /l10n/fa.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "بازگردانی امکان ناپذیر است: %s", 5 | "Versions" : "نسخه ها", 6 | "Failed to revert {file} to revision {timestamp}." : "برگرداندن {file} به نسخه {timestamp} با شکست روبرو شد", 7 | "Restore" : "بازیابی", 8 | "More versions..." : "نسخه های بیشتر", 9 | "No other versions available" : "نسخه ی دیگری در دسترس نیست" 10 | }, 11 | "nplurals=1; plural=0;"); 12 | -------------------------------------------------------------------------------- /l10n/fa.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "بازگردانی امکان ناپذیر است: %s", 3 | "Versions" : "نسخه ها", 4 | "Failed to revert {file} to revision {timestamp}." : "برگرداندن {file} به نسخه {timestamp} با شکست روبرو شد", 5 | "Restore" : "بازیابی", 6 | "More versions..." : "نسخه های بیشتر", 7 | "No other versions available" : "نسخه ی دیگری در دسترس نیست" 8 | },"pluralForm" :"nplurals=1; plural=0;" 9 | } -------------------------------------------------------------------------------- /l10n/fi.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Palautus epäonnistui: %s", 5 | "Versions" : "Versiot", 6 | "Failed to revert {file} to revision {timestamp}." : "Tiedoston {file} palautus versioon {timestamp} epäonnistui.", 7 | "_%n byte_::_%n bytes_" : ["%n tavu","%n tavua"], 8 | "Restore" : "Palauta", 9 | "No earlier versions available" : "Ei aikaisempia versioita saatavilla", 10 | "More versions …" : "Lisää versioita...", 11 | "No versions available" : "Ei versioita saatavilla", 12 | "More versions..." : "Lisää versioita..." 13 | }, 14 | "nplurals=2; plural=(n != 1);"); 15 | -------------------------------------------------------------------------------- /l10n/fi.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Palautus epäonnistui: %s", 3 | "Versions" : "Versiot", 4 | "Failed to revert {file} to revision {timestamp}." : "Tiedoston {file} palautus versioon {timestamp} epäonnistui.", 5 | "_%n byte_::_%n bytes_" : ["%n tavu","%n tavua"], 6 | "Restore" : "Palauta", 7 | "No earlier versions available" : "Ei aikaisempia versioita saatavilla", 8 | "More versions …" : "Lisää versioita...", 9 | "No versions available" : "Ei versioita saatavilla", 10 | "More versions..." : "Lisää versioita..." 11 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 12 | } -------------------------------------------------------------------------------- /l10n/fi_FI.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Palautus epäonnistui: %s", 5 | "Versions" : "Versiot", 6 | "Failed to revert {file} to revision {timestamp}." : "Tiedoston {file} palautus versioon {timestamp} epäonnistui.", 7 | "Restore" : "Palauta", 8 | "More versions..." : "Lisää versioita...", 9 | "No other versions available" : "Ei muita versioita saatavilla" 10 | }, 11 | "nplurals=2; plural=(n != 1);"); 12 | -------------------------------------------------------------------------------- /l10n/fi_FI.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Palautus epäonnistui: %s", 3 | "Versions" : "Versiot", 4 | "Failed to revert {file} to revision {timestamp}." : "Tiedoston {file} palautus versioon {timestamp} epäonnistui.", 5 | "Restore" : "Palauta", 6 | "More versions..." : "Lisää versioita...", 7 | "No other versions available" : "Ei muita versioita saatavilla" 8 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 9 | } -------------------------------------------------------------------------------- /l10n/fr.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Impossible de restaurer %s", 5 | "Versions" : "Versions", 6 | "Failed to revert {file} to revision {timestamp}." : "Échec de la restauration du fichier {file} à la révision {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n octet","%n octets"], 8 | "Restore" : "Restaurer", 9 | "No earlier versions available" : "Aucune version antérieure disponible", 10 | "More versions …" : "Plus de versions ...", 11 | "No versions available" : "Aucune version n'est disponible", 12 | "More versions..." : "Plus de versions..." 13 | }, 14 | "nplurals=2; plural=(n > 1);"); 15 | -------------------------------------------------------------------------------- /l10n/fr.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Impossible de restaurer %s", 3 | "Versions" : "Versions", 4 | "Failed to revert {file} to revision {timestamp}." : "Échec de la restauration du fichier {file} à la révision {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n octet","%n octets"], 6 | "Restore" : "Restaurer", 7 | "No earlier versions available" : "Aucune version antérieure disponible", 8 | "More versions …" : "Plus de versions ...", 9 | "No versions available" : "Aucune version n'est disponible", 10 | "More versions..." : "Plus de versions..." 11 | },"pluralForm" :"nplurals=2; plural=(n > 1);" 12 | } -------------------------------------------------------------------------------- /l10n/gl.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Non foi posíbel reverter: %s", 5 | "Versions" : "Versións", 6 | "Failed to revert {file} to revision {timestamp}." : "Non foi posíbel reverter {file} á revisión {timestamp}.", 7 | "Restore" : "Restabelecer", 8 | "More versions..." : "Máis versións...", 9 | "No other versions available" : "Non hai outras versións dispoñíbeis" 10 | }, 11 | "nplurals=2; plural=(n != 1);"); 12 | -------------------------------------------------------------------------------- /l10n/gl.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Non foi posíbel reverter: %s", 3 | "Versions" : "Versións", 4 | "Failed to revert {file} to revision {timestamp}." : "Non foi posíbel reverter {file} á revisión {timestamp}.", 5 | "Restore" : "Restabelecer", 6 | "More versions..." : "Máis versións...", 7 | "No other versions available" : "Non hai outras versións dispoñíbeis" 8 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 9 | } -------------------------------------------------------------------------------- /l10n/he.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "לא ניתן להחזיר: %s", 5 | "Versions" : "גרסאות", 6 | "Failed to revert {file} to revision {timestamp}." : "נכשל אחזור {file} לגרסה {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n בייט","%n בייטים"], 8 | "Restore" : "שחזור", 9 | "No versions available" : "אין גרסאות זמינות", 10 | "More versions..." : "גרסאות נוספות..." 11 | }, 12 | "nplurals=2; plural=(n != 1);"); 13 | -------------------------------------------------------------------------------- /l10n/he.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "לא ניתן להחזיר: %s", 3 | "Versions" : "גרסאות", 4 | "Failed to revert {file} to revision {timestamp}." : "נכשל אחזור {file} לגרסה {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n בייט","%n בייטים"], 6 | "Restore" : "שחזור", 7 | "No versions available" : "אין גרסאות זמינות", 8 | "More versions..." : "גרסאות נוספות..." 9 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 10 | } -------------------------------------------------------------------------------- /l10n/hr.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Nije moguće vratiti: %s", 5 | "Versions" : "Verzije", 6 | "Failed to revert {file} to revision {timestamp}." : "Nije uspelo vraćanje {file} na reviziju {timestamp}.", 7 | "Restore" : "Obnovite", 8 | "More versions..." : "Više verzija...", 9 | "No other versions available" : "Nikakve druge verzije nisu dostupne" 10 | }, 11 | "nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;"); 12 | -------------------------------------------------------------------------------- /l10n/hr.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Nije moguće vratiti: %s", 3 | "Versions" : "Verzije", 4 | "Failed to revert {file} to revision {timestamp}." : "Nije uspelo vraćanje {file} na reviziju {timestamp}.", 5 | "Restore" : "Obnovite", 6 | "More versions..." : "Više verzija...", 7 | "No other versions available" : "Nikakve druge verzije nisu dostupne" 8 | },"pluralForm" :"nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;" 9 | } -------------------------------------------------------------------------------- /l10n/hu.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Nem sikerült átállni a változatra: %s", 5 | "Versions" : "Verziók", 6 | "Failed to revert {file} to revision {timestamp}." : "{file} fájlt nem sikerült erre visszaállítani: {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n bájt","%n bájt"], 8 | "Restore" : "Visszaállítás", 9 | "No earlier versions available" : "Nincsenek elérhető korábbi verziók", 10 | "More versions …" : "További változatok...", 11 | "No versions available" : "Nincs elérhető verzió", 12 | "More versions..." : "További változatok..." 13 | }, 14 | "nplurals=2; plural=(n != 1);"); 15 | -------------------------------------------------------------------------------- /l10n/hu.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Nem sikerült átállni a változatra: %s", 3 | "Versions" : "Verziók", 4 | "Failed to revert {file} to revision {timestamp}." : "{file} fájlt nem sikerült erre visszaállítani: {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n bájt","%n bájt"], 6 | "Restore" : "Visszaállítás", 7 | "No earlier versions available" : "Nincsenek elérhető korábbi verziók", 8 | "More versions …" : "További változatok...", 9 | "No versions available" : "Nincs elérhető verzió", 10 | "More versions..." : "További változatok..." 11 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 12 | } -------------------------------------------------------------------------------- /l10n/hu_HU.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Nem sikerült átállni a változatra: %s", 5 | "Versions" : "Verziók", 6 | "Failed to revert {file} to revision {timestamp}." : "{file} fájlt nem sikerült erre visszaállítani: {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n bájt","%n bájt"], 8 | "Restore" : "Visszaállítás", 9 | "No versions available" : "Nincs elérhető verzió", 10 | "More versions..." : "További változatok...", 11 | "No other versions available" : "Nincs több elérhető verzió" 12 | }, 13 | "nplurals=2; plural=(n != 1);"); 14 | -------------------------------------------------------------------------------- /l10n/hu_HU.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Nem sikerült átállni a változatra: %s", 3 | "Versions" : "Verziók", 4 | "Failed to revert {file} to revision {timestamp}." : "{file} fájlt nem sikerült erre visszaállítani: {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n bájt","%n bájt"], 6 | "Restore" : "Visszaállítás", 7 | "No versions available" : "Nincs elérhető verzió", 8 | "More versions..." : "További változatok...", 9 | "No other versions available" : "Nincs több elérhető verzió" 10 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 11 | } -------------------------------------------------------------------------------- /l10n/hy.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Versions" : "Տարբերակներ", 5 | "Restore" : "Վերականգնել", 6 | "No other versions available" : "Այլ տարբերակներ չկան" 7 | }, 8 | "nplurals=2; plural=(n != 1);"); 9 | -------------------------------------------------------------------------------- /l10n/hy.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Versions" : "Տարբերակներ", 3 | "Restore" : "Վերականգնել", 4 | "No other versions available" : "Այլ տարբերակներ չկան" 5 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 6 | } -------------------------------------------------------------------------------- /l10n/ia.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Impossibile reverter: %s", 5 | "Versions" : "Versiones", 6 | "Failed to revert {file} to revision {timestamp}." : "Il falleva a reverter {file} a revision {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"], 8 | "Restore" : "Restaurar", 9 | "No earlier versions available" : "Nulle versiones anterior disponibile", 10 | "More versions …" : "Plus versiones …", 11 | "No versions available" : "Nulle versiones disponibile", 12 | "More versions..." : "Plus versiones..." 13 | }, 14 | "nplurals=2; plural=(n != 1);"); 15 | -------------------------------------------------------------------------------- /l10n/ia.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Impossibile reverter: %s", 3 | "Versions" : "Versiones", 4 | "Failed to revert {file} to revision {timestamp}." : "Il falleva a reverter {file} a revision {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"], 6 | "Restore" : "Restaurar", 7 | "No earlier versions available" : "Nulle versiones anterior disponibile", 8 | "More versions …" : "Plus versiones …", 9 | "No versions available" : "Nulle versiones disponibile", 10 | "More versions..." : "Plus versiones..." 11 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 12 | } -------------------------------------------------------------------------------- /l10n/id.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Tidak dapat mengembalikan: %s", 5 | "Versions" : "Versi", 6 | "Failed to revert {file} to revision {timestamp}." : "Gagal mengembalikan {file} ke revisi {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n bytes"], 8 | "Restore" : "Pulihkan", 9 | "No versions available" : "Tidak ada versi yang tersedia", 10 | "More versions..." : "Versi lainnya..." 11 | }, 12 | "nplurals=1; plural=0;"); 13 | -------------------------------------------------------------------------------- /l10n/id.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Tidak dapat mengembalikan: %s", 3 | "Versions" : "Versi", 4 | "Failed to revert {file} to revision {timestamp}." : "Gagal mengembalikan {file} ke revisi {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n bytes"], 6 | "Restore" : "Pulihkan", 7 | "No versions available" : "Tidak ada versi yang tersedia", 8 | "More versions..." : "Versi lainnya..." 9 | },"pluralForm" :"nplurals=1; plural=0;" 10 | } -------------------------------------------------------------------------------- /l10n/is.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Gat ekki endurheimt: %s", 5 | "Versions" : "Útgáfur", 6 | "Failed to revert {file} to revision {timestamp}." : "Mistókst að endurheimta {file} útgáfu {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n bæti","%n bæti"], 8 | "Restore" : "Endurheimta", 9 | "No earlier versions available" : "Engar eldri útgáfur í boði", 10 | "More versions …" : "Fleiri útgáfur ...", 11 | "No versions available" : "Engar aðrar útgáfur í boði", 12 | "More versions..." : "Fleiri útgáfur..." 13 | }, 14 | "nplurals=2; plural=(n % 10 != 1 || n % 100 == 11);"); 15 | -------------------------------------------------------------------------------- /l10n/is.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Gat ekki endurheimt: %s", 3 | "Versions" : "Útgáfur", 4 | "Failed to revert {file} to revision {timestamp}." : "Mistókst að endurheimta {file} útgáfu {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n bæti","%n bæti"], 6 | "Restore" : "Endurheimta", 7 | "No earlier versions available" : "Engar eldri útgáfur í boði", 8 | "More versions …" : "Fleiri útgáfur ...", 9 | "No versions available" : "Engar aðrar útgáfur í boði", 10 | "More versions..." : "Fleiri útgáfur..." 11 | },"pluralForm" :"nplurals=2; plural=(n % 10 != 1 || n % 100 == 11);" 12 | } -------------------------------------------------------------------------------- /l10n/it.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Impossibile ripristinare: %s", 5 | "Versions" : "Versioni", 6 | "Failed to revert {file} to revision {timestamp}." : "Ripristino di {file} alla revisione {timestamp} non riuscito.", 7 | "_%n byte_::_%n bytes_" : ["%n byte","%n byte"], 8 | "Restore" : "Ripristina", 9 | "No earlier versions available" : "Nessuna versione precedente disponibile", 10 | "More versions …" : "Altre versioni...", 11 | "No versions available" : "Nessuna versione disponibile", 12 | "More versions..." : "Altre versioni..." 13 | }, 14 | "nplurals=2; plural=(n != 1);"); 15 | -------------------------------------------------------------------------------- /l10n/it.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Impossibile ripristinare: %s", 3 | "Versions" : "Versioni", 4 | "Failed to revert {file} to revision {timestamp}." : "Ripristino di {file} alla revisione {timestamp} non riuscito.", 5 | "_%n byte_::_%n bytes_" : ["%n byte","%n byte"], 6 | "Restore" : "Ripristina", 7 | "No earlier versions available" : "Nessuna versione precedente disponibile", 8 | "More versions …" : "Altre versioni...", 9 | "No versions available" : "Nessuna versione disponibile", 10 | "More versions..." : "Altre versioni..." 11 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 12 | } -------------------------------------------------------------------------------- /l10n/ja.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "元に戻せませんでした: %s", 5 | "Versions" : "バージョン", 6 | "Failed to revert {file} to revision {timestamp}." : "{file} を {timestamp} のリビジョンに戻すことができません。", 7 | "_%n byte_::_%n bytes_" : ["%n バイト"], 8 | "Restore" : "復元", 9 | "No earlier versions available" : "以前のバージョンは利用できません", 10 | "More versions …" : "他のバージョン …", 11 | "No versions available" : "履歴はありません", 12 | "More versions..." : "他のバージョン..." 13 | }, 14 | "nplurals=1; plural=0;"); 15 | -------------------------------------------------------------------------------- /l10n/ja.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "元に戻せませんでした: %s", 3 | "Versions" : "バージョン", 4 | "Failed to revert {file} to revision {timestamp}." : "{file} を {timestamp} のリビジョンに戻すことができません。", 5 | "_%n byte_::_%n bytes_" : ["%n バイト"], 6 | "Restore" : "復元", 7 | "No earlier versions available" : "以前のバージョンは利用できません", 8 | "More versions …" : "他のバージョン …", 9 | "No versions available" : "履歴はありません", 10 | "More versions..." : "他のバージョン..." 11 | },"pluralForm" :"nplurals=1; plural=0;" 12 | } -------------------------------------------------------------------------------- /l10n/ka_GE.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "ვერ მოხერხდა უკან დაბრუნება: %s", 5 | "Versions" : "ვერსიები", 6 | "Restore" : "აღდგენა" 7 | }, 8 | "nplurals=1; plural=0;"); 9 | -------------------------------------------------------------------------------- /l10n/ka_GE.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "ვერ მოხერხდა უკან დაბრუნება: %s", 3 | "Versions" : "ვერსიები", 4 | "Restore" : "აღდგენა" 5 | },"pluralForm" :"nplurals=1; plural=0;" 6 | } -------------------------------------------------------------------------------- /l10n/km.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "មិនអាចត្រឡប់៖ %s", 5 | "Versions" : "កំណែ", 6 | "Failed to revert {file} to revision {timestamp}." : "មិនអាចត្រឡប់ {file} ទៅកំណែសម្រួល {timestamp} បានទេ។", 7 | "Restore" : "ស្ដារមកវិញ", 8 | "More versions..." : "កំណែច្រើនទៀត...", 9 | "No other versions available" : "មិនមានកំណែផ្សេងទៀតទេ" 10 | }, 11 | "nplurals=1; plural=0;"); 12 | -------------------------------------------------------------------------------- /l10n/km.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "មិនអាចត្រឡប់៖ %s", 3 | "Versions" : "កំណែ", 4 | "Failed to revert {file} to revision {timestamp}." : "មិនអាចត្រឡប់ {file} ទៅកំណែសម្រួល {timestamp} បានទេ។", 5 | "Restore" : "ស្ដារមកវិញ", 6 | "More versions..." : "កំណែច្រើនទៀត...", 7 | "No other versions available" : "មិនមានកំណែផ្សេងទៀតទេ" 8 | },"pluralForm" :"nplurals=1; plural=0;" 9 | } -------------------------------------------------------------------------------- /l10n/kn.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "ಹಿಂತಿರುಗಲಾಗಲಿಲ್ಲ: %s", 5 | "Versions" : "ಆವೃತ್ತಿಗಳು", 6 | "Failed to revert {file} to revision {timestamp}." : "{timestamp} ದ ಪರಿಷ್ಕರಣೆ ಇಂದ {file} ಕಡತವನ್ನು ಹಿಂದಿರುಗಿಸಲು ವಿಫಲವಾಗಿದೆ.", 7 | "Restore" : "ಮರುಸ್ಥಾಪಿಸು", 8 | "More versions..." : "ಇನ್ನಷ್ಟು ಆವೃತ್ತಿಗಳು ...", 9 | "No other versions available" : "ಇನ್ನಿತರೆ ಯಾವುದೇ ಆವೃತ್ತಿಗಳು ಲಭ್ಯವಿಲ್ಲ" 10 | }, 11 | "nplurals=1; plural=0;"); 12 | -------------------------------------------------------------------------------- /l10n/kn.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "ಹಿಂತಿರುಗಲಾಗಲಿಲ್ಲ: %s", 3 | "Versions" : "ಆವೃತ್ತಿಗಳು", 4 | "Failed to revert {file} to revision {timestamp}." : "{timestamp} ದ ಪರಿಷ್ಕರಣೆ ಇಂದ {file} ಕಡತವನ್ನು ಹಿಂದಿರುಗಿಸಲು ವಿಫಲವಾಗಿದೆ.", 5 | "Restore" : "ಮರುಸ್ಥಾಪಿಸು", 6 | "More versions..." : "ಇನ್ನಷ್ಟು ಆವೃತ್ತಿಗಳು ...", 7 | "No other versions available" : "ಇನ್ನಿತರೆ ಯಾವುದೇ ಆವೃತ್ತಿಗಳು ಲಭ್ಯವಿಲ್ಲ" 8 | },"pluralForm" :"nplurals=1; plural=0;" 9 | } -------------------------------------------------------------------------------- /l10n/ko.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "되돌릴 수 없습니다: %s", 5 | "Versions" : "버전", 6 | "Failed to revert {file} to revision {timestamp}." : "{file}을(를) 리비전 {timestamp}으(로) 되돌리는 데 실패했습니다.", 7 | "_%n byte_::_%n bytes_" : ["%n 바이트"], 8 | "Restore" : "복원", 9 | "No earlier versions available" : "이전 버전을 사용할 수 없음", 10 | "More versions …" : "더 많은 버전 …", 11 | "No versions available" : "버전을 사용할 수 없음", 12 | "More versions..." : "더 많은 버전..." 13 | }, 14 | "nplurals=1; plural=0;"); 15 | -------------------------------------------------------------------------------- /l10n/ko.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "되돌릴 수 없습니다: %s", 3 | "Versions" : "버전", 4 | "Failed to revert {file} to revision {timestamp}." : "{file}을(를) 리비전 {timestamp}으(로) 되돌리는 데 실패했습니다.", 5 | "_%n byte_::_%n bytes_" : ["%n 바이트"], 6 | "Restore" : "복원", 7 | "No earlier versions available" : "이전 버전을 사용할 수 없음", 8 | "More versions …" : "더 많은 버전 …", 9 | "No versions available" : "버전을 사용할 수 없음", 10 | "More versions..." : "더 많은 버전..." 11 | },"pluralForm" :"nplurals=1; plural=0;" 12 | } -------------------------------------------------------------------------------- /l10n/ku_IQ.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Versions" : "وهشان" 5 | }, 6 | "nplurals=2; plural=(n != 1);"); 7 | -------------------------------------------------------------------------------- /l10n/ku_IQ.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Versions" : "وهشان" 3 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 4 | } -------------------------------------------------------------------------------- /l10n/lb.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Konnt net zrécksetzen: %s", 5 | "Versions" : "Versiounen", 6 | "Failed to revert {file} to revision {timestamp}." : "Konnt {file} net op d'Versioun {timestamp} zrécksetzen.", 7 | "Restore" : "Zrécksetzen", 8 | "More versions..." : "Méi Versiounen...", 9 | "No other versions available" : "Keng aner Versiounen disponibel" 10 | }, 11 | "nplurals=2; plural=(n != 1);"); 12 | -------------------------------------------------------------------------------- /l10n/lb.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Konnt net zrécksetzen: %s", 3 | "Versions" : "Versiounen", 4 | "Failed to revert {file} to revision {timestamp}." : "Konnt {file} net op d'Versioun {timestamp} zrécksetzen.", 5 | "Restore" : "Zrécksetzen", 6 | "More versions..." : "Méi Versiounen...", 7 | "No other versions available" : "Keng aner Versiounen disponibel" 8 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 9 | } -------------------------------------------------------------------------------- /l10n/lt_LT.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Nepavyko sugrąžinti: %s", 5 | "Versions" : "Versijos", 6 | "Failed to revert {file} to revision {timestamp}." : "Nepavyko sugrąžinti {file} į {timestamp} būseną.", 7 | "_%n byte_::_%n bytes_" : ["%n baitas","%n baitai","%n baitų"], 8 | "Restore" : "Atkurti", 9 | "More versions …" : "Daugiau versijų …", 10 | "No versions available" : "Nėra prieinama jokių versijų", 11 | "More versions..." : "Daugiau versijų..." 12 | }, 13 | "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);"); 14 | -------------------------------------------------------------------------------- /l10n/lt_LT.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Nepavyko sugrąžinti: %s", 3 | "Versions" : "Versijos", 4 | "Failed to revert {file} to revision {timestamp}." : "Nepavyko sugrąžinti {file} į {timestamp} būseną.", 5 | "_%n byte_::_%n bytes_" : ["%n baitas","%n baitai","%n baitų"], 6 | "Restore" : "Atkurti", 7 | "More versions …" : "Daugiau versijų …", 8 | "No versions available" : "Nėra prieinama jokių versijų", 9 | "More versions..." : "Daugiau versijų..." 10 | },"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);" 11 | } -------------------------------------------------------------------------------- /l10n/lv.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Nevarēja atgriezt — %s", 5 | "Versions" : "Versijas", 6 | "Failed to revert {file} to revision {timestamp}." : "Neizdevās atjaunot {file} no rediģējuma {timestamp} ", 7 | "_%n byte_::_%n bytes_" : ["%n baiti","%n baiti","%n baiti"], 8 | "Restore" : "Atjaunot", 9 | "No versions available" : "Nav versijas", 10 | "More versions..." : "Vairāk versiju..." 11 | }, 12 | "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);"); 13 | -------------------------------------------------------------------------------- /l10n/lv.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Nevarēja atgriezt — %s", 3 | "Versions" : "Versijas", 4 | "Failed to revert {file} to revision {timestamp}." : "Neizdevās atjaunot {file} no rediģējuma {timestamp} ", 5 | "_%n byte_::_%n bytes_" : ["%n baiti","%n baiti","%n baiti"], 6 | "Restore" : "Atjaunot", 7 | "No versions available" : "Nav versijas", 8 | "More versions..." : "Vairāk versiju..." 9 | },"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);" 10 | } -------------------------------------------------------------------------------- /l10n/mk.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Не можев да го вратам: %s", 5 | "Versions" : "Верзии", 6 | "Failed to revert {file} to revision {timestamp}." : "Не успеав да го вратам {file} на ревизијата {timestamp}.", 7 | "Restore" : "Врати", 8 | "More versions..." : "Повеќе верзии...", 9 | "No other versions available" : "Не постојат други верзии" 10 | }, 11 | "nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;"); 12 | -------------------------------------------------------------------------------- /l10n/mk.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Не можев да го вратам: %s", 3 | "Versions" : "Верзии", 4 | "Failed to revert {file} to revision {timestamp}." : "Не успеав да го вратам {file} на ревизијата {timestamp}.", 5 | "Restore" : "Врати", 6 | "More versions..." : "Повеќе верзии...", 7 | "No other versions available" : "Не постојат други верзии" 8 | },"pluralForm" :"nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;" 9 | } -------------------------------------------------------------------------------- /l10n/ms_MY.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Tidak dapat kembalikan: %s", 5 | "Versions" : "Versi", 6 | "Failed to revert {file} to revision {timestamp}." : "Gagal kembalikan {file} ke semakan {timestamp}.", 7 | "Restore" : "Pulihkan", 8 | "More versions..." : "Lagi versi...", 9 | "No other versions available" : "Tiada lagi versi lain" 10 | }, 11 | "nplurals=1; plural=0;"); 12 | -------------------------------------------------------------------------------- /l10n/ms_MY.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Tidak dapat kembalikan: %s", 3 | "Versions" : "Versi", 4 | "Failed to revert {file} to revision {timestamp}." : "Gagal kembalikan {file} ke semakan {timestamp}.", 5 | "Restore" : "Pulihkan", 6 | "More versions..." : "Lagi versi...", 7 | "No other versions available" : "Tiada lagi versi lain" 8 | },"pluralForm" :"nplurals=1; plural=0;" 9 | } -------------------------------------------------------------------------------- /l10n/nb.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Klarte ikke å tilbakeføre: %s", 5 | "Versions" : "Versjoner", 6 | "Failed to revert {file} to revision {timestamp}." : "Klarte ikke å tilbakeføre {file} til revisjon {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"], 8 | "Restore" : "Gjenopprett", 9 | "No earlier versions available" : "Ingen tidligere versjoner tilgjengelige", 10 | "More versions …" : "Flere versjoner…", 11 | "No versions available" : "Ingen versjoner tilgjengelig", 12 | "More versions..." : "Flere versjoner" 13 | }, 14 | "nplurals=2; plural=(n != 1);"); 15 | -------------------------------------------------------------------------------- /l10n/nb.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Klarte ikke å tilbakeføre: %s", 3 | "Versions" : "Versjoner", 4 | "Failed to revert {file} to revision {timestamp}." : "Klarte ikke å tilbakeføre {file} til revisjon {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"], 6 | "Restore" : "Gjenopprett", 7 | "No earlier versions available" : "Ingen tidligere versjoner tilgjengelige", 8 | "More versions …" : "Flere versjoner…", 9 | "No versions available" : "Ingen versjoner tilgjengelig", 10 | "More versions..." : "Flere versjoner" 11 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 12 | } -------------------------------------------------------------------------------- /l10n/nb_NO.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Klarte ikke å tilbakeføre: %s", 5 | "Versions" : "Versjoner", 6 | "Failed to revert {file} to revision {timestamp}." : "Klarte ikke å tilbakeføre {file} til revisjon {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"], 8 | "Restore" : "Gjenopprett", 9 | "No versions available" : "Ingen versjoner tilgjengelig", 10 | "More versions..." : "Flere versjoner", 11 | "No other versions available" : "Det finnes ingen andre versjoner" 12 | }, 13 | "nplurals=2; plural=(n != 1);"); 14 | -------------------------------------------------------------------------------- /l10n/nb_NO.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Klarte ikke å tilbakeføre: %s", 3 | "Versions" : "Versjoner", 4 | "Failed to revert {file} to revision {timestamp}." : "Klarte ikke å tilbakeføre {file} til revisjon {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"], 6 | "Restore" : "Gjenopprett", 7 | "No versions available" : "Ingen versjoner tilgjengelig", 8 | "More versions..." : "Flere versjoner", 9 | "No other versions available" : "Det finnes ingen andre versjoner" 10 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 11 | } -------------------------------------------------------------------------------- /l10n/nl.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Kon niet terugdraaien: %s", 5 | "Versions" : "Versies", 6 | "Failed to revert {file} to revision {timestamp}." : "Kon {file} niet terugdraaien naar revisie {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"], 8 | "Restore" : "Herstellen", 9 | "No earlier versions available" : "Geen oudere versies beschikbaar", 10 | "More versions …" : "Meer versies...", 11 | "No versions available" : "Geen versies beschikbaar", 12 | "More versions..." : "Meer versies..." 13 | }, 14 | "nplurals=2; plural=(n != 1);"); 15 | -------------------------------------------------------------------------------- /l10n/nl.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Kon niet terugdraaien: %s", 3 | "Versions" : "Versies", 4 | "Failed to revert {file} to revision {timestamp}." : "Kon {file} niet terugdraaien naar revisie {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"], 6 | "Restore" : "Herstellen", 7 | "No earlier versions available" : "Geen oudere versies beschikbaar", 8 | "More versions …" : "Meer versies...", 9 | "No versions available" : "Geen versies beschikbaar", 10 | "More versions..." : "Meer versies..." 11 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 12 | } -------------------------------------------------------------------------------- /l10n/nn_NO.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Klarte ikkje å tilbakestilla: %s", 5 | "Versions" : "Utgåver", 6 | "Failed to revert {file} to revision {timestamp}." : "Klarte ikkje å tilbakestilla {file} til utgåva {timestamp}.", 7 | "Restore" : "Gjenopprett", 8 | "More versions..." : "Fleire utgåver …", 9 | "No other versions available" : "Ingen andre utgåver tilgjengeleg" 10 | }, 11 | "nplurals=2; plural=(n != 1);"); 12 | -------------------------------------------------------------------------------- /l10n/nn_NO.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Klarte ikkje å tilbakestilla: %s", 3 | "Versions" : "Utgåver", 4 | "Failed to revert {file} to revision {timestamp}." : "Klarte ikkje å tilbakestilla {file} til utgåva {timestamp}.", 5 | "Restore" : "Gjenopprett", 6 | "More versions..." : "Fleire utgåver …", 7 | "No other versions available" : "Ingen andre utgåver tilgjengeleg" 8 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 9 | } -------------------------------------------------------------------------------- /l10n/oc.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Impossible de restablir %s", 5 | "Versions" : "Versions", 6 | "Failed to revert {file} to revision {timestamp}." : "Fracàs del retorn del fichièr {file} a la revision {timestamp}.", 7 | "Restore" : "Restablir", 8 | "No other versions available" : "Cap d'autra version es pas disponibla", 9 | "More versions..." : "Mai de versions..." 10 | }, 11 | "nplurals=2; plural=(n > 1);"); 12 | -------------------------------------------------------------------------------- /l10n/oc.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Impossible de restablir %s", 3 | "Versions" : "Versions", 4 | "Failed to revert {file} to revision {timestamp}." : "Fracàs del retorn del fichièr {file} a la revision {timestamp}.", 5 | "Restore" : "Restablir", 6 | "No other versions available" : "Cap d'autra version es pas disponibla", 7 | "More versions..." : "Mai de versions..." 8 | },"pluralForm" :"nplurals=2; plural=(n > 1);" 9 | } -------------------------------------------------------------------------------- /l10n/pl.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Nie można było przywrócić: %s", 5 | "Versions" : "Wersje", 6 | "Failed to revert {file} to revision {timestamp}." : "Nie udało się przywrócić {file} do wersji z {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n bajt","%n bajtów","%n bajtów","%n bajtów"], 8 | "Restore" : "Przywróć", 9 | "No earlier versions available" : "Brak dostępnych wcześniejszych wersji", 10 | "More versions …" : "Więcej wersji...", 11 | "No versions available" : "Brak wersji", 12 | "More versions..." : "Więcej wersji..." 13 | }, 14 | "nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>=14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);"); 15 | -------------------------------------------------------------------------------- /l10n/pl.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Nie można było przywrócić: %s", 3 | "Versions" : "Wersje", 4 | "Failed to revert {file} to revision {timestamp}." : "Nie udało się przywrócić {file} do wersji z {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n bajt","%n bajtów","%n bajtów","%n bajtów"], 6 | "Restore" : "Przywróć", 7 | "No earlier versions available" : "Brak dostępnych wcześniejszych wersji", 8 | "More versions …" : "Więcej wersji...", 9 | "No versions available" : "Brak wersji", 10 | "More versions..." : "Więcej wersji..." 11 | },"pluralForm" :"nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>=14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);" 12 | } -------------------------------------------------------------------------------- /l10n/pt_BR.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Impossível reverter: %s", 5 | "Versions" : "Versões", 6 | "Failed to revert {file} to revision {timestamp}." : "Falha ao reverter {file} para a revisão {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"], 8 | "Restore" : "Restaurar", 9 | "No earlier versions available" : "Não há versões mais novas disponíveis", 10 | "More versions …" : "Mais versões...", 11 | "No versions available" : "Não há versões disponíveis", 12 | "More versions..." : "Mais versões..." 13 | }, 14 | "nplurals=2; plural=(n > 1);"); 15 | -------------------------------------------------------------------------------- /l10n/pt_BR.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Impossível reverter: %s", 3 | "Versions" : "Versões", 4 | "Failed to revert {file} to revision {timestamp}." : "Falha ao reverter {file} para a revisão {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"], 6 | "Restore" : "Restaurar", 7 | "No earlier versions available" : "Não há versões mais novas disponíveis", 8 | "More versions …" : "Mais versões...", 9 | "No versions available" : "Não há versões disponíveis", 10 | "More versions..." : "Mais versões..." 11 | },"pluralForm" :"nplurals=2; plural=(n > 1);" 12 | } -------------------------------------------------------------------------------- /l10n/pt_PT.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Não foi possível reverter: %s", 5 | "Versions" : "Versões", 6 | "Failed to revert {file} to revision {timestamp}." : "Falhou a recuperação do ficheiro {file} para a revisão {timestamp}.", 7 | "Restore" : "Restaurar", 8 | "More versions..." : "Mais versões...", 9 | "No other versions available" : "Não existem versões mais antigas" 10 | }, 11 | "nplurals=2; plural=(n != 1);"); 12 | -------------------------------------------------------------------------------- /l10n/pt_PT.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Não foi possível reverter: %s", 3 | "Versions" : "Versões", 4 | "Failed to revert {file} to revision {timestamp}." : "Falhou a recuperação do ficheiro {file} para a revisão {timestamp}.", 5 | "Restore" : "Restaurar", 6 | "More versions..." : "Mais versões...", 7 | "No other versions available" : "Não existem versões mais antigas" 8 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 9 | } -------------------------------------------------------------------------------- /l10n/ro.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Nu s-a putut reveni: %s", 5 | "Versions" : "Versiuni", 6 | "Failed to revert {file} to revision {timestamp}." : "S-a eșuat restaurarea fișierului {file} la revizia {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n byte","%n byți","%n byți"], 8 | "Restore" : "Restaurare", 9 | "No versions available" : "Nu există versiuni disponibile", 10 | "More versions..." : "Mai multe versiuni..." 11 | }, 12 | "nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));"); 13 | -------------------------------------------------------------------------------- /l10n/ro.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Nu s-a putut reveni: %s", 3 | "Versions" : "Versiuni", 4 | "Failed to revert {file} to revision {timestamp}." : "S-a eșuat restaurarea fișierului {file} la revizia {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n byte","%n byți","%n byți"], 6 | "Restore" : "Restaurare", 7 | "No versions available" : "Nu există versiuni disponibile", 8 | "More versions..." : "Mai multe versiuni..." 9 | },"pluralForm" :"nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));" 10 | } -------------------------------------------------------------------------------- /l10n/ru.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Невозможно откатить: %s", 5 | "Versions" : "Версии", 6 | "Failed to revert {file} to revision {timestamp}." : "Не удалось откатить {file} к ревизии {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n байт","%n байта","%n байт","%n байт"], 8 | "Restore" : "Откатить", 9 | "No earlier versions available" : "Нет более ранних версий…", 10 | "More versions …" : "Ещё версии…", 11 | "No versions available" : "Нет доступных версий", 12 | "More versions..." : "Ещё версии..." 13 | }, 14 | "nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);"); 15 | -------------------------------------------------------------------------------- /l10n/ru.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Невозможно откатить: %s", 3 | "Versions" : "Версии", 4 | "Failed to revert {file} to revision {timestamp}." : "Не удалось откатить {file} к ревизии {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n байт","%n байта","%n байт","%n байт"], 6 | "Restore" : "Откатить", 7 | "No earlier versions available" : "Нет более ранних версий…", 8 | "More versions …" : "Ещё версии…", 9 | "No versions available" : "Нет доступных версий", 10 | "More versions..." : "Ещё версии..." 11 | },"pluralForm" :"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);" 12 | } -------------------------------------------------------------------------------- /l10n/si_LK.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Versions" : "අනුවාද" 5 | }, 6 | "nplurals=2; plural=(n != 1);"); 7 | -------------------------------------------------------------------------------- /l10n/si_LK.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Versions" : "අනුවාද" 3 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 4 | } -------------------------------------------------------------------------------- /l10n/sk.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Nemožno obnoviť: %s", 5 | "Versions" : "Verzie", 6 | "Failed to revert {file} to revision {timestamp}." : "Zlyhalo obnovenie súboru {file} na verziu {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n bajt","%n bajtov","%n bajtov"], 8 | "Restore" : "Obnoviť", 9 | "No versions available" : "Žiadne verzie nie sú dostupné", 10 | "More versions..." : "Viac verzií..." 11 | }, 12 | "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"); 13 | -------------------------------------------------------------------------------- /l10n/sk.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Nemožno obnoviť: %s", 3 | "Versions" : "Verzie", 4 | "Failed to revert {file} to revision {timestamp}." : "Zlyhalo obnovenie súboru {file} na verziu {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n bajt","%n bajtov","%n bajtov"], 6 | "Restore" : "Obnoviť", 7 | "No versions available" : "Žiadne verzie nie sú dostupné", 8 | "More versions..." : "Viac verzií..." 9 | },"pluralForm" :"nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;" 10 | } -------------------------------------------------------------------------------- /l10n/sk_SK.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Nemožno obnoviť: %s", 5 | "Versions" : "Verzie", 6 | "Failed to revert {file} to revision {timestamp}." : "Zlyhalo obnovenie súboru {file} na verziu {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n bajt","%n bajtov","%n bajtov"], 8 | "Restore" : "Obnoviť", 9 | "No versions available" : "Žiadne verzie nie sú dostupné", 10 | "More versions..." : "Viac verzií...", 11 | "No other versions available" : "Žiadne ďalšie verzie nie sú dostupné" 12 | }, 13 | "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"); 14 | -------------------------------------------------------------------------------- /l10n/sk_SK.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Nemožno obnoviť: %s", 3 | "Versions" : "Verzie", 4 | "Failed to revert {file} to revision {timestamp}." : "Zlyhalo obnovenie súboru {file} na verziu {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n bajt","%n bajtov","%n bajtov"], 6 | "Restore" : "Obnoviť", 7 | "No versions available" : "Žiadne verzie nie sú dostupné", 8 | "More versions..." : "Viac verzií...", 9 | "No other versions available" : "Žiadne ďalšie verzie nie sú dostupné" 10 | },"pluralForm" :"nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;" 11 | } -------------------------------------------------------------------------------- /l10n/sl.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Ni mogoče povrniti: %s", 5 | "Versions" : "Različice", 6 | "Failed to revert {file} to revision {timestamp}." : "Povrnitev datoteke {file} na objavo {timestamp} je spodletelo.", 7 | "_%n byte_::_%n bytes_" : ["%n byte","%n byte-a","%n byte-i","%n byte-ov"], 8 | "Restore" : "Obnovi", 9 | "No versions available" : "Ni verzij na voljo", 10 | "More versions..." : "Več različic" 11 | }, 12 | "nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);"); 13 | -------------------------------------------------------------------------------- /l10n/sl.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Ni mogoče povrniti: %s", 3 | "Versions" : "Različice", 4 | "Failed to revert {file} to revision {timestamp}." : "Povrnitev datoteke {file} na objavo {timestamp} je spodletelo.", 5 | "_%n byte_::_%n bytes_" : ["%n byte","%n byte-a","%n byte-i","%n byte-ov"], 6 | "Restore" : "Obnovi", 7 | "No versions available" : "Ni verzij na voljo", 8 | "More versions..." : "Več različic" 9 | },"pluralForm" :"nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);" 10 | } -------------------------------------------------------------------------------- /l10n/sq.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "S’u rikthye dot: %s", 5 | "Versions" : "Versione", 6 | "Failed to revert {file} to revision {timestamp}." : "Dështoi në rikthimin e {file} te rishikimi {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n bajte","%n bajte"], 8 | "Restore" : "Riktheje", 9 | "No earlier versions available" : "Nuk ka versione të tjera të gatshme", 10 | "No versions available" : "Ska versione të gatshme", 11 | "More versions..." : "Më shumë versione…" 12 | }, 13 | "nplurals=2; plural=(n != 1);"); 14 | -------------------------------------------------------------------------------- /l10n/sq.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "S’u rikthye dot: %s", 3 | "Versions" : "Versione", 4 | "Failed to revert {file} to revision {timestamp}." : "Dështoi në rikthimin e {file} te rishikimi {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n bajte","%n bajte"], 6 | "Restore" : "Riktheje", 7 | "No earlier versions available" : "Nuk ka versione të tjera të gatshme", 8 | "No versions available" : "Ska versione të gatshme", 9 | "More versions..." : "Më shumë versione…" 10 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 11 | } -------------------------------------------------------------------------------- /l10n/sr.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Не могу да вратим: %s", 5 | "Versions" : "Верзије", 6 | "Failed to revert {file} to revision {timestamp}." : "Не могу да вратим {file} на ревизију {timestamp}.", 7 | "Restore" : "Врати", 8 | "More versions..." : "Још верзија...", 9 | "No other versions available" : "Нема других верзија" 10 | }, 11 | "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"); 12 | -------------------------------------------------------------------------------- /l10n/sr.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Не могу да вратим: %s", 3 | "Versions" : "Верзије", 4 | "Failed to revert {file} to revision {timestamp}." : "Не могу да вратим {file} на ревизију {timestamp}.", 5 | "Restore" : "Врати", 6 | "More versions..." : "Још верзија...", 7 | "No other versions available" : "Нема других верзија" 8 | },"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" 9 | } -------------------------------------------------------------------------------- /l10n/sr@latin.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Ne mogu da vratim: %s", 5 | "Versions" : "Verzije", 6 | "Failed to revert {file} to revision {timestamp}." : "Ne mogu da vratim {file} na reviziju {timestamp}.", 7 | "Restore" : "Vrati", 8 | "No other versions available" : "Nema drugih verzija", 9 | "More versions..." : "Još verzija..." 10 | }, 11 | "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"); 12 | -------------------------------------------------------------------------------- /l10n/sr@latin.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Ne mogu da vratim: %s", 3 | "Versions" : "Verzije", 4 | "Failed to revert {file} to revision {timestamp}." : "Ne mogu da vratim {file} na reviziju {timestamp}.", 5 | "Restore" : "Vrati", 6 | "No other versions available" : "Nema drugih verzija", 7 | "More versions..." : "Još verzija..." 8 | },"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" 9 | } -------------------------------------------------------------------------------- /l10n/sv.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Kunde inte återställa: %s", 5 | "Versions" : "Versioner", 6 | "Failed to revert {file} to revision {timestamp}." : "Kunde inte återställa {file} till {timestamp}.", 7 | "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"], 8 | "Restore" : "Återskapa", 9 | "No earlier versions available" : "Inga tidigare versioner tillgänliga", 10 | "More versions …" : "Fler versioner ...", 11 | "No versions available" : "Inga versioner tillgängliga", 12 | "More versions..." : "Fler versioner..." 13 | }, 14 | "nplurals=2; plural=(n != 1);"); 15 | -------------------------------------------------------------------------------- /l10n/sv.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Kunde inte återställa: %s", 3 | "Versions" : "Versioner", 4 | "Failed to revert {file} to revision {timestamp}." : "Kunde inte återställa {file} till {timestamp}.", 5 | "_%n byte_::_%n bytes_" : ["%n byte","%n bytes"], 6 | "Restore" : "Återskapa", 7 | "No earlier versions available" : "Inga tidigare versioner tillgänliga", 8 | "More versions …" : "Fler versioner ...", 9 | "No versions available" : "Inga versioner tillgängliga", 10 | "More versions..." : "Fler versioner..." 11 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 12 | } -------------------------------------------------------------------------------- /l10n/ta_LK.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Versions" : "பதிப்புகள்" 5 | }, 6 | "nplurals=2; plural=(n != 1);"); 7 | -------------------------------------------------------------------------------- /l10n/ta_LK.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Versions" : "பதிப்புகள்" 3 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 4 | } -------------------------------------------------------------------------------- /l10n/th.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "ไม่สามารถย้อนกลับ: %s", 5 | "Versions" : "รุ่น", 6 | "Failed to revert {file} to revision {timestamp}." : "{file} ล้มเหลวที่จะย้อนกลับ มีการแก้ไขเมื่อ {timestamp}", 7 | "Restore" : "คืนค่า", 8 | "More versions..." : "รุ่นอื่นๆ ...", 9 | "No other versions available" : "ยังไม่มีรุ่นที่ใหม่กว่า" 10 | }, 11 | "nplurals=1; plural=0;"); 12 | -------------------------------------------------------------------------------- /l10n/th.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "ไม่สามารถย้อนกลับ: %s", 3 | "Versions" : "รุ่น", 4 | "Failed to revert {file} to revision {timestamp}." : "{file} ล้มเหลวที่จะย้อนกลับ มีการแก้ไขเมื่อ {timestamp}", 5 | "Restore" : "คืนค่า", 6 | "More versions..." : "รุ่นอื่นๆ ...", 7 | "No other versions available" : "ยังไม่มีรุ่นที่ใหม่กว่า" 8 | },"pluralForm" :"nplurals=1; plural=0;" 9 | } -------------------------------------------------------------------------------- /l10n/th_TH.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "ไม่สามารถย้อนกลับ: %s", 5 | "Versions" : "รุ่น", 6 | "Failed to revert {file} to revision {timestamp}." : "{file} ล้มเหลวที่จะย้อนกลับ มีการแก้ไขเมื่อ {timestamp}", 7 | "Restore" : "คืนค่า", 8 | "More versions..." : "รุ่นอื่นๆ ...", 9 | "No other versions available" : "ยังไม่มีรุ่นที่ใหม่กว่า" 10 | }, 11 | "nplurals=1; plural=0;"); 12 | -------------------------------------------------------------------------------- /l10n/th_TH.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "ไม่สามารถย้อนกลับ: %s", 3 | "Versions" : "รุ่น", 4 | "Failed to revert {file} to revision {timestamp}." : "{file} ล้มเหลวที่จะย้อนกลับ มีการแก้ไขเมื่อ {timestamp}", 5 | "Restore" : "คืนค่า", 6 | "More versions..." : "รุ่นอื่นๆ ...", 7 | "No other versions available" : "ยังไม่มีรุ่นที่ใหม่กว่า" 8 | },"pluralForm" :"nplurals=1; plural=0;" 9 | } -------------------------------------------------------------------------------- /l10n/tr.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Geri alınamadı: %s", 5 | "Versions" : "Sürümler", 6 | "Failed to revert {file} to revision {timestamp}." : "{file} dosyası {timestamp} sürümüne geri alınamadı.", 7 | "_%n byte_::_%n bytes_" : ["%n bayt","%n bayt"], 8 | "Restore" : "Geri yükle", 9 | "No earlier versions available" : "Kullanılabilecek daha önceki bir sürüm yok", 10 | "More versions …" : "Diğer sürümler ...", 11 | "No versions available" : "Herhangi bir sürüm yok", 12 | "More versions..." : "Diğer sürümler..." 13 | }, 14 | "nplurals=2; plural=(n > 1);"); 15 | -------------------------------------------------------------------------------- /l10n/tr.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Geri alınamadı: %s", 3 | "Versions" : "Sürümler", 4 | "Failed to revert {file} to revision {timestamp}." : "{file} dosyası {timestamp} sürümüne geri alınamadı.", 5 | "_%n byte_::_%n bytes_" : ["%n bayt","%n bayt"], 6 | "Restore" : "Geri yükle", 7 | "No earlier versions available" : "Kullanılabilecek daha önceki bir sürüm yok", 8 | "More versions …" : "Diğer sürümler ...", 9 | "No versions available" : "Herhangi bir sürüm yok", 10 | "More versions..." : "Diğer sürümler..." 11 | },"pluralForm" :"nplurals=2; plural=(n > 1);" 12 | } -------------------------------------------------------------------------------- /l10n/ug.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "ئەسلىگە قايتۇرالمايدۇ: %s", 5 | "Versions" : "نەشرى" 6 | }, 7 | "nplurals=1; plural=0;"); 8 | -------------------------------------------------------------------------------- /l10n/ug.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "ئەسلىگە قايتۇرالمايدۇ: %s", 3 | "Versions" : "نەشرى" 4 | },"pluralForm" :"nplurals=1; plural=0;" 5 | } -------------------------------------------------------------------------------- /l10n/uk.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Не вдалося відновити: %s", 5 | "Versions" : "Версії", 6 | "Failed to revert {file} to revision {timestamp}." : "Не вдалося повернути {file} до ревізії {timestamp}.", 7 | "Restore" : "Відновити", 8 | "More versions..." : "Більше версій ...", 9 | "No other versions available" : "Інші версії недоступні" 10 | }, 11 | "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"); 12 | -------------------------------------------------------------------------------- /l10n/uk.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Не вдалося відновити: %s", 3 | "Versions" : "Версії", 4 | "Failed to revert {file} to revision {timestamp}." : "Не вдалося повернути {file} до ревізії {timestamp}.", 5 | "Restore" : "Відновити", 6 | "More versions..." : "Більше версій ...", 7 | "No other versions available" : "Інші версії недоступні" 8 | },"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" 9 | } -------------------------------------------------------------------------------- /l10n/ur_PK.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Restore" : "بحال" 5 | }, 6 | "nplurals=2; plural=(n != 1);"); 7 | -------------------------------------------------------------------------------- /l10n/ur_PK.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Restore" : "بحال" 3 | },"pluralForm" :"nplurals=2; plural=(n != 1);" 4 | } -------------------------------------------------------------------------------- /l10n/vi.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "Không thể khôi phục: %s", 5 | "Versions" : "Phiên bản", 6 | "Failed to revert {file} to revision {timestamp}." : "Thất bại khi trở lại {file} khi sử đổi {timestamp}.", 7 | "Restore" : "Khôi phục", 8 | "No versions available" : "Không có phiên bản có sẵn", 9 | "More versions..." : "Nhiều phiên bản ..." 10 | }, 11 | "nplurals=1; plural=0;"); 12 | -------------------------------------------------------------------------------- /l10n/vi.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "Không thể khôi phục: %s", 3 | "Versions" : "Phiên bản", 4 | "Failed to revert {file} to revision {timestamp}." : "Thất bại khi trở lại {file} khi sử đổi {timestamp}.", 5 | "Restore" : "Khôi phục", 6 | "No versions available" : "Không có phiên bản có sẵn", 7 | "More versions..." : "Nhiều phiên bản ..." 8 | },"pluralForm" :"nplurals=1; plural=0;" 9 | } -------------------------------------------------------------------------------- /l10n/zh_CN.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "无法恢复:%s", 5 | "Versions" : "版本", 6 | "Failed to revert {file} to revision {timestamp}." : "无法恢复 {file} 到 {timestamp} 的版本。", 7 | "_%n byte_::_%n bytes_" : ["%n 比特"], 8 | "Restore" : "恢复", 9 | "No earlier versions available" : "无可用的更早的版本", 10 | "More versions …" : "更多版本…", 11 | "No versions available" : "没有可用的版本", 12 | "More versions..." : "更多版本..." 13 | }, 14 | "nplurals=1; plural=0;"); 15 | -------------------------------------------------------------------------------- /l10n/zh_CN.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "无法恢复:%s", 3 | "Versions" : "版本", 4 | "Failed to revert {file} to revision {timestamp}." : "无法恢复 {file} 到 {timestamp} 的版本。", 5 | "_%n byte_::_%n bytes_" : ["%n 比特"], 6 | "Restore" : "恢复", 7 | "No earlier versions available" : "无可用的更早的版本", 8 | "More versions …" : "更多版本…", 9 | "No versions available" : "没有可用的版本", 10 | "More versions..." : "更多版本..." 11 | },"pluralForm" :"nplurals=1; plural=0;" 12 | } -------------------------------------------------------------------------------- /l10n/zh_HK.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Versions" : "版本" 5 | }, 6 | "nplurals=1; plural=0;"); 7 | -------------------------------------------------------------------------------- /l10n/zh_HK.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Versions" : "版本" 3 | },"pluralForm" :"nplurals=1; plural=0;" 4 | } -------------------------------------------------------------------------------- /l10n/zh_TW.js: -------------------------------------------------------------------------------- 1 | OC.L10N.register( 2 | "files_versions", 3 | { 4 | "Could not revert: %s" : "無法還原:%s", 5 | "Versions" : "版本", 6 | "Failed to revert {file} to revision {timestamp}." : "無法還原檔案 {file} 至版本 {timestamp}", 7 | "Restore" : "復原", 8 | "More versions..." : "更多版本…", 9 | "No other versions available" : "沒有其他版本了" 10 | }, 11 | "nplurals=1; plural=0;"); 12 | -------------------------------------------------------------------------------- /l10n/zh_TW.json: -------------------------------------------------------------------------------- 1 | { "translations": { 2 | "Could not revert: %s" : "無法還原:%s", 3 | "Versions" : "版本", 4 | "Failed to revert {file} to revision {timestamp}." : "無法還原檔案 {file} 至版本 {timestamp}", 5 | "Restore" : "復原", 6 | "More versions..." : "更多版本…", 7 | "No other versions available" : "沒有其他版本了" 8 | },"pluralForm" :"nplurals=1; plural=0;" 9 | } -------------------------------------------------------------------------------- /lib/AppInfo/Application.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * @license GNU AGPL version 3 or any later version 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU Affero General Public License as 10 | * published by the Free Software Foundation, either version 3 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Affero General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Affero General Public License 19 | * along with this program. If not, see . 20 | * 21 | */ 22 | 23 | namespace OCA\Files_Snapshots\AppInfo; 24 | 25 | use OCA\Files_Snapshots\SnapshotManager; 26 | use OCP\AppFramework\App; 27 | use OCP\AppFramework\IAppContainer; 28 | 29 | class Application extends App { 30 | public function __construct(array $urlParams = []) { 31 | parent::__construct('files_snapshots', $urlParams); 32 | 33 | $container = $this->getContainer(); 34 | 35 | $container->registerService(SnapshotManager::class, function (IAppContainer $appContainer) { 36 | $config = $appContainer->getServer()->getConfig(); 37 | return new SnapshotManager( 38 | $config->getAppValue('files_snapshots', 'snap_format'), 39 | $config->getAppValue('files_snapshots', 'date_format', 'Y-m-d_H:i:s') 40 | ); 41 | }); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/Controller/AdminController.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * @license GNU AGPL version 3 or any later version 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU Affero General Public License as 10 | * published by the Free Software Foundation, either version 3 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Affero General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Affero General Public License 19 | * along with this program. If not, see . 20 | * 21 | */ 22 | 23 | namespace OCA\Files_Snapshots\Controller; 24 | 25 | use OCA\Files_Snapshots\Snapshot; 26 | use OCA\Files_Snapshots\SnapshotManager; 27 | use OCP\AppFramework\Controller; 28 | use OCP\IConfig; 29 | use OCP\IRequest; 30 | 31 | class AdminController extends Controller { 32 | /** @var SnapshotManager */ 33 | private $snapshotManager; 34 | 35 | /** @var IConfig */ 36 | private $config; 37 | 38 | public function __construct($appName, 39 | IRequest $request, 40 | SnapshotManager $snapshotManager, 41 | IConfig $config, 42 | ) { 43 | parent::__construct($appName, $request); 44 | $this->snapshotManager = $snapshotManager; 45 | $this->config = $config; 46 | } 47 | 48 | /** 49 | * @param string $snapshotFormat 50 | * @param string $dateFormat 51 | * @return array 52 | */ 53 | public function testSettings($snapshotFormat, $dateFormat) { 54 | $manager = new SnapshotManager($snapshotFormat, $dateFormat); 55 | $snapshots = iterator_to_array($manager->listAllSnapshots()); 56 | usort($snapshots, function (Snapshot $a, Snapshot $b) { 57 | return strcmp($a->getName(), $b->getName()); 58 | }); 59 | 60 | $names = array_map(function (Snapshot $snapshot) { 61 | return $snapshot->getName(); 62 | }, $snapshots); 63 | 64 | $dates = array_map(function (Snapshot $snapshot) use ($dateFormat) { 65 | return $snapshot->getSnapshotDate()->format('Y-m-d H:i:s'); 66 | }, $snapshots); 67 | 68 | return array_combine($names, $dates); 69 | } 70 | 71 | /** 72 | * @param string $snapshotFormat 73 | * @param string $dateFormat 74 | */ 75 | public function save($snapshotFormat, $dateFormat) { 76 | $this->config->setAppValue('files_snapshots', 'snap_format', $snapshotFormat); 77 | $this->config->setAppValue('files_snapshots', 'date_format', $dateFormat); 78 | return [$snapshotFormat]; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /lib/Settings/Admin.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * @license GNU AGPL version 3 or any later version 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU Affero General Public License as 10 | * published by the Free Software Foundation, either version 3 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Affero General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Affero General Public License 19 | * along with this program. If not, see . 20 | * 21 | */ 22 | 23 | namespace OCA\Files_Snapshots\Settings; 24 | 25 | use OCP\AppFramework\Http\TemplateResponse; 26 | use OCP\IConfig; 27 | use OCP\Settings\ISettings; 28 | 29 | class Admin implements ISettings { 30 | /** @var IConfig */ 31 | private $config; 32 | 33 | public function __construct(IConfig $config) { 34 | $this->config = $config; 35 | } 36 | 37 | /** 38 | * @return TemplateResponse 39 | */ 40 | public function getForm() { 41 | $parameters = [ 42 | 'snapshot_format' => $this->config->getAppValue('files_snapshots', 'snap_format'), 43 | 'date_format' => $this->config->getAppValue('files_snapshots', 'date_format', 'Y-m-d_H:i:s') 44 | ]; 45 | 46 | return new TemplateResponse('files_snapshots', 'settings', $parameters); 47 | } 48 | 49 | /** 50 | * @return string the section ID, e.g. 'sharing' 51 | */ 52 | public function getSection() { 53 | return 'files_snapshots'; 54 | } 55 | 56 | /** 57 | * @return int whether the form should be rather on the top or bottom of 58 | * the admin section. The forms are arranged in ascending order of the 59 | * priority values. It is required to return a value between 0 and 100. 60 | * 61 | * E.g.: 70 62 | */ 63 | public function getPriority() { 64 | return 5; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lib/Settings/Section.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * @license GNU AGPL version 3 or any later version 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU Affero General Public License as 10 | * published by the Free Software Foundation, either version 3 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Affero General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Affero General Public License 19 | * along with this program. If not, see . 20 | * 21 | */ 22 | 23 | namespace OCA\Files_Snapshots\Settings; 24 | 25 | use OCP\IL10N; 26 | use OCP\IURLGenerator; 27 | use OCP\Settings\IIconSection; 28 | 29 | class Section implements IIconSection { 30 | /** @var IL10N */ 31 | private $l; 32 | /** @var IURLGenerator */ 33 | private $url; 34 | 35 | /** 36 | * @param IURLGenerator $url 37 | * @param IL10N $l 38 | */ 39 | public function __construct(IURLGenerator $url, IL10N $l) { 40 | $this->url = $url; 41 | $this->l = $l; 42 | } 43 | 44 | /** 45 | * returns the ID of the section. It is supposed to be a lower case string, 46 | * e.g. 'ldap' 47 | * 48 | * @returns string 49 | */ 50 | public function getID() { 51 | return 'files_snapshots'; 52 | } 53 | 54 | /** 55 | * returns the translated name as it should be displayed, e.g. 'LDAP / AD 56 | * integration'. Use the L10N service to translate it. 57 | * 58 | * @return string 59 | */ 60 | public function getName() { 61 | return $this->l->t('Snapshots'); 62 | } 63 | 64 | /** 65 | * @return int whether the form should be rather on the top or bottom of 66 | * the settings navigation. The sections are arranged in ascending order of 67 | * the priority values. It is required to return a value between 0 and 99. 68 | * 69 | * E.g.: 70 70 | */ 71 | public function getPriority() { 72 | return 25; 73 | } 74 | 75 | /** 76 | * {@inheritdoc} 77 | */ 78 | public function getIcon() { 79 | return $this->url->imagePath('core', 'actions/history.svg'); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /lib/Snapshot.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * @license GNU AGPL version 3 or any later version 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU Affero General Public License as 10 | * published by the Free Software Foundation, either version 3 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Affero General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Affero General Public License 19 | * along with this program. If not, see . 20 | * 21 | */ 22 | 23 | namespace OCA\Files_Snapshots; 24 | 25 | use DateTime; 26 | 27 | class Snapshot { 28 | /** @var string */ 29 | private $path; 30 | 31 | /** @var string */ 32 | private $name; 33 | 34 | /** @var string */ 35 | private $dateFormat; 36 | 37 | /** 38 | * Snapshot constructor. 39 | * 40 | * @param string $path 41 | * @param string $name 42 | * @param string $dateFormat 43 | */ 44 | public function __construct(string $path, string $name, string $dateFormat) { 45 | $this->path = rtrim($path, '/'); 46 | $this->name = $name; 47 | $this->dateFormat = $dateFormat; 48 | } 49 | 50 | public function getPath(): string { 51 | return $this->path; 52 | } 53 | 54 | public function getName(): string { 55 | return $this->name; 56 | } 57 | 58 | public function getFilePath($file): string { 59 | return $this->path . '/' . $file; 60 | } 61 | 62 | public function hasFile($file): bool { 63 | return file_exists($this->getFilePath($file)); 64 | } 65 | 66 | public function getMtime($file): int { 67 | return (int)filemtime($this->getFilePath($file)); 68 | } 69 | 70 | public function getSize($file): int { 71 | return (int)filesize($this->getFilePath($file)); 72 | } 73 | 74 | public function getSnapshotDate(): DateTime { 75 | $date = DateTime::createFromFormat($this->dateFormat, $this->getName()); 76 | if (!$date) { 77 | $date = new DateTime(); 78 | $mtime = $this->getMtime(''); 79 | $date->setTimestamp($mtime); 80 | } 81 | return $date; 82 | } 83 | 84 | /** 85 | * @param string $file 86 | * @return resource|false 87 | */ 88 | public function readFile(string $file) { 89 | return fopen($this->getFilePath($file), 'r'); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /lib/SnapshotManager.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * @license GNU AGPL version 3 or any later version 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU Affero General Public License as 10 | * published by the Free Software Foundation, either version 3 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Affero General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Affero General Public License 19 | * along with this program. If not, see . 20 | * 21 | */ 22 | 23 | namespace OCA\Files_Snapshots; 24 | 25 | use Traversable; 26 | 27 | class SnapshotManager { 28 | /** @var string */ 29 | private $snapshotFormat; 30 | 31 | /** @var string|null */ 32 | private $snapshotPrefix; 33 | 34 | /** @var string|null */ 35 | private $snapshotPostfix; 36 | 37 | /** @var string */ 38 | private $dateFormat; 39 | 40 | public function __construct(string $snapshotFormat, string $dateFormat) { 41 | $this->snapshotFormat = $snapshotFormat; 42 | $this->dateFormat = $dateFormat; 43 | 44 | if (strpos($this->snapshotFormat, '/%snapshot%/') !== false) { 45 | [$this->snapshotPrefix, $this->snapshotPostfix] = explode('/%snapshot%/', $this->snapshotFormat); 46 | } else { 47 | $this->snapshotPrefix = null; 48 | $this->snapshotPostfix = null; 49 | } 50 | } 51 | 52 | /** 53 | * @return Traversable 54 | */ 55 | public function listAllSnapshots(): Traversable { 56 | if ($this->snapshotPrefix === null) { 57 | return; 58 | } 59 | foreach (glob($this->snapshotPrefix, GLOB_ONLYDIR) as $dir) { 60 | $dh = opendir($dir); 61 | while ($file = readdir($dh)) { 62 | $path = $dir . '/' . $file; 63 | if ($file[0] !== '.' && is_dir($path) && is_dir($path . '/' . $this->snapshotPostfix)) { 64 | yield new Snapshot($path . '/' . $this->snapshotPostfix, $file, $this->dateFormat); 65 | } 66 | } 67 | closedir($dh); 68 | } 69 | } 70 | 71 | /** 72 | * @param $file 73 | * @return Snapshot[] 74 | */ 75 | public function listSnapshotsForFile(string $file): array { 76 | if ($this->snapshotPrefix === null) { 77 | return []; 78 | } 79 | $lastMtime = 0; 80 | $allSnapshots = array_filter(iterator_to_array($this->listAllSnapshots()), function (Snapshot $snapshot) use ($file) { 81 | return $snapshot->hasFile($file); 82 | }); 83 | 84 | usort($allSnapshots, function (Snapshot $a, Snapshot $b) { 85 | return $a->getSnapshotDate()->getTimestamp() <=> $b->getSnapshotDate()->getTimestamp(); 86 | }); 87 | $a = 1; 88 | return array_values(array_filter($allSnapshots, function (Snapshot $snapshot) use (&$lastMtime, $file) { 89 | $snapshotMtime = $snapshot->getMtime($file); 90 | if ($snapshotMtime > $lastMtime) { 91 | $lastMtime = $snapshotMtime; 92 | return true; 93 | } 94 | return false; 95 | })); 96 | } 97 | 98 | public function getSnapshot(string $id): ?Snapshot { 99 | if ($this->snapshotPrefix === null) { 100 | return null; 101 | } 102 | $path = $path = $this->snapshotPrefix . '/' . $id . '/' . $this->snapshotPostfix; 103 | return is_dir($path) ? new Snapshot($path, $id, $this->dateFormat) : null; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /lib/Versions/SnapshotPreviewFile.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * @license GNU AGPL version 3 or any later version 8 | * 9 | * This program is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Affero General Public License as 11 | * published by the Free Software Foundation, either version 3 of the 12 | * License, or (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU Affero General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Affero General Public License 20 | * along with this program. If not, see . 21 | * 22 | */ 23 | 24 | namespace OCA\Files_Snapshots\Versions; 25 | 26 | use OCP\Files\File; 27 | use OCP\Files\FileInfo; 28 | use OCP\Files\ForbiddenException; 29 | use OCP\Preview\IVersionedPreviewFile; 30 | 31 | class SnapshotPreviewFile implements File, IVersionedPreviewFile { 32 | private $sourceFile; 33 | private $contentProvider; 34 | private $revisionId; 35 | 36 | public function __construct(FileInfo $sourceFile, callable $contentProvider, string $revisionId) { 37 | $this->sourceFile = $sourceFile; 38 | $this->contentProvider = $contentProvider; 39 | $this->revisionId = $revisionId; 40 | } 41 | 42 | public function getContent() { 43 | return (string)stream_get_contents(($this->contentProvider)()); 44 | } 45 | 46 | public function putContent($data) { 47 | throw new ForbiddenException('Preview files are read only', false); 48 | } 49 | 50 | public function fopen($mode) { 51 | if ($mode === 'r' || $mode === 'rb') { 52 | return ($this->contentProvider)(); 53 | } else { 54 | throw new ForbiddenException('Preview files are read only', false); 55 | } 56 | } 57 | 58 | public function hash($type, $raw = false) { 59 | throw new \Exception('not implemented'); 60 | } 61 | 62 | public function getChecksum() { 63 | return ''; 64 | } 65 | 66 | /** 67 | * @inheritDoc 68 | */ 69 | public function getMtime() { 70 | return $this->sourceFile->getMtime(); 71 | } 72 | 73 | /** 74 | * @inheritDoc 75 | */ 76 | public function getMimetype() { 77 | return $this->sourceFile->getMimeType(); 78 | } 79 | 80 | /** 81 | * @inheritDoc 82 | */ 83 | public function getMimePart() { 84 | return $this->sourceFile->getMimePart(); 85 | } 86 | 87 | /** 88 | * @inheritDoc 89 | */ 90 | public function isEncrypted() { 91 | return $this->sourceFile->isEncrypted(); 92 | } 93 | 94 | /** 95 | * @inheritDoc 96 | */ 97 | public function getType() { 98 | return $this->sourceFile->getType(); 99 | } 100 | 101 | /** 102 | * @inheritDoc 103 | */ 104 | public function isCreatable() { 105 | return $this->sourceFile->isCreatable(); 106 | } 107 | 108 | /** 109 | * @inheritDoc 110 | */ 111 | public function isShared() { 112 | return $this->sourceFile->isShared(); 113 | } 114 | 115 | /** 116 | * @inheritDoc 117 | */ 118 | public function isMounted() { 119 | return $this->sourceFile->isMounted(); 120 | } 121 | 122 | /** 123 | * @inheritDoc 124 | */ 125 | public function getMountPoint() { 126 | return $this->sourceFile->getMountPoint(); 127 | } 128 | 129 | /** 130 | * @inheritDoc 131 | */ 132 | public function getOwner() { 133 | return $this->sourceFile->getOwner(); 134 | } 135 | 136 | /** 137 | * @inheritDoc 138 | */ 139 | public function getExtension(): string { 140 | return $this->sourceFile->getExtension(); 141 | } 142 | 143 | /** 144 | * @inheritDoc 145 | */ 146 | public function getPreviewVersion(): string { 147 | return $this->revisionId; 148 | } 149 | 150 | /** 151 | * @inheritDoc 152 | */ 153 | public function move($targetPath) { 154 | throw new ForbiddenException('Preview files are read only', false); 155 | } 156 | 157 | /** 158 | * @inheritDoc 159 | */ 160 | public function delete() { 161 | throw new ForbiddenException('Preview files are read only', false); 162 | } 163 | 164 | /** 165 | * @inheritDoc 166 | */ 167 | public function copy($targetPath) { 168 | throw new ForbiddenException('Preview files are read only', false); 169 | } 170 | 171 | /** 172 | * @inheritDoc 173 | */ 174 | public function touch($mtime = null) { 175 | throw new ForbiddenException('Preview files are read only', false); 176 | } 177 | 178 | /** 179 | * @inheritDoc 180 | */ 181 | public function getStorage() { 182 | return $this->sourceFile->getStorage(); 183 | } 184 | 185 | /** 186 | * @inheritDoc 187 | */ 188 | public function getPath() { 189 | return $this->sourceFile->getPath(); 190 | } 191 | 192 | /** 193 | * @inheritDoc 194 | */ 195 | public function getInternalPath() { 196 | return $this->sourceFile->getInternalPath(); 197 | } 198 | 199 | /** 200 | * @inheritDoc 201 | */ 202 | public function getId() { 203 | $id = $this->sourceFile->getId(); 204 | if ($id === null) { 205 | throw new \Exception('invalid source file'); 206 | } else { 207 | return $id; 208 | } 209 | } 210 | 211 | /** 212 | * @inheritDoc 213 | */ 214 | public function stat() { 215 | return [ 216 | 'mtime' => $this->getMtime(), 217 | 'size' => $this->getSize() 218 | ]; 219 | } 220 | 221 | /** 222 | * @inheritDoc 223 | */ 224 | public function getSize($includeMounts = true) { 225 | return $this->sourceFile->getSize(); 226 | } 227 | 228 | /** 229 | * @inheritDoc 230 | */ 231 | public function getEtag() { 232 | return $this->revisionId; 233 | } 234 | 235 | /** 236 | * @inheritDoc 237 | */ 238 | public function getPermissions() { 239 | return $this->sourceFile->getPermissions(); 240 | } 241 | 242 | /** 243 | * @inheritDoc 244 | */ 245 | public function isReadable() { 246 | return $this->sourceFile->isReadable(); 247 | } 248 | 249 | /** 250 | * @inheritDoc 251 | */ 252 | public function isUpdateable() { 253 | return $this->sourceFile->isUpdateable(); 254 | } 255 | 256 | /** 257 | * @inheritDoc 258 | */ 259 | public function isDeletable() { 260 | return $this->sourceFile->isDeletable(); 261 | } 262 | 263 | /** 264 | * @inheritDoc 265 | */ 266 | public function isShareable() { 267 | return $this->sourceFile->isShareable(); 268 | } 269 | 270 | /** 271 | * @inheritDoc 272 | */ 273 | public function getParent() { 274 | if ($this->sourceFile instanceof File) { 275 | return $this->sourceFile->getParent(); 276 | } else { 277 | throw new \Exception('invalid source file'); 278 | } 279 | } 280 | 281 | /** 282 | * @inheritDoc 283 | */ 284 | public function getName() { 285 | return $this->sourceFile->getName(); 286 | } 287 | 288 | /** 289 | * @inheritDoc 290 | */ 291 | public function lock($type) { 292 | // noop 293 | } 294 | 295 | /** 296 | * @inheritDoc 297 | */ 298 | public function changeLock($targetType) { 299 | // noop 300 | } 301 | 302 | /** 303 | * @inheritDoc 304 | */ 305 | public function unlock($type) { 306 | // noop 307 | } 308 | 309 | /** 310 | * @inheritDoc 311 | */ 312 | public function getCreationTime(): int { 313 | return 0; 314 | } 315 | 316 | /** 317 | * @inheritDoc 318 | */ 319 | public function getUploadTime(): int { 320 | return 0; 321 | } 322 | 323 | public function getParentId(): int { 324 | return $this->getParent()->getId(); 325 | } 326 | 327 | public function getMetadata(): array { 328 | return []; 329 | } 330 | } 331 | -------------------------------------------------------------------------------- /lib/Versions/SnapshotVersion.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * @license GNU AGPL version 3 or any later version 8 | * 9 | * This program is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Affero General Public License as 11 | * published by the Free Software Foundation, either version 3 of the 12 | * License, or (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU Affero General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Affero General Public License 20 | * along with this program. If not, see . 21 | * 22 | */ 23 | 24 | namespace OCA\Files_Snapshots\Versions; 25 | 26 | use OCA\Files_Snapshots\Snapshot; 27 | use OCA\Files_Versions\Versions\IVersion; 28 | use OCA\Files_Versions\Versions\IVersionBackend; 29 | use OCP\Files\FileInfo; 30 | use OCP\IUser; 31 | 32 | class SnapshotVersion implements IVersion { 33 | private $backend; 34 | private $snapshot; 35 | private $sourceFile; 36 | private $user; 37 | 38 | public function __construct(SnapshotVersionBackend $backend, Snapshot $snapshot, FileInfo $sourceFile, IUser $user) { 39 | $this->backend = $backend; 40 | $this->snapshot = $snapshot; 41 | $this->sourceFile = $sourceFile; 42 | $this->user = $user; 43 | } 44 | 45 | public function getBackend(): IVersionBackend { 46 | return $this->backend; 47 | } 48 | 49 | public function getSourceFile(): FileInfo { 50 | return $this->sourceFile; 51 | } 52 | 53 | public function getRevisionId() { 54 | return $this->snapshot->getName(); 55 | } 56 | 57 | public function getTimestamp(): int { 58 | return $this->snapshot->getMtime($this->getVersionPath()); 59 | } 60 | 61 | public function getSize(): int { 62 | return $this->snapshot->getSize($this->getVersionPath()); 63 | } 64 | 65 | public function getSourceFileName(): string { 66 | return $this->sourceFile->getName(); 67 | } 68 | 69 | public function getMimeType(): string { 70 | return $this->sourceFile->getMimetype(); 71 | } 72 | 73 | public function getVersionPath(): string { 74 | return $this->user->getUID() . '/' . $this->sourceFile->getInternalPath(); 75 | } 76 | 77 | public function getUser(): IUser { 78 | return $this->user; 79 | } 80 | 81 | public function getSnapshot(): Snapshot { 82 | return $this->snapshot; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/Versions/SnapshotVersionBackend.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * @license GNU AGPL version 3 or any later version 8 | * 9 | * This program is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Affero General Public License as 11 | * published by the Free Software Foundation, either version 3 of the 12 | * License, or (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU Affero General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Affero General Public License 20 | * along with this program. If not, see . 21 | * 22 | */ 23 | 24 | namespace OCA\Files_Snapshots\Versions; 25 | 26 | use OC\Files\Storage\Local; 27 | use OCA\Files_Snapshots\Snapshot; 28 | use OCA\Files_Snapshots\SnapshotManager; 29 | use OCA\Files_Versions\Versions\IVersion; 30 | use OCA\Files_Versions\Versions\IVersionBackend; 31 | use OCP\Files\File; 32 | use OCP\Files\FileInfo; 33 | use OCP\Files\Storage\IStorage; 34 | use OCP\IUser; 35 | 36 | class SnapshotVersionBackend implements IVersionBackend { 37 | protected $versionProvider; 38 | 39 | public function __construct(SnapshotManager $versionProvider) { 40 | $this->versionProvider = $versionProvider; 41 | } 42 | 43 | public function useBackendForStorage(IStorage $storage): bool { 44 | return true; 45 | } 46 | 47 | public function getVersionsForFile(IUser $user, FileInfo $file): array { 48 | $snapshots = $this->versionProvider->listSnapshotsForFile($user->getUID() . '/' . $file->getInternalPath()); 49 | 50 | return array_map(function (Snapshot $snapshot) use ($file, $user) { 51 | return new SnapshotVersion( 52 | $this, 53 | $snapshot, 54 | $file, 55 | $user 56 | ); 57 | }, $snapshots); 58 | } 59 | 60 | public function createVersion(IUser $user, FileInfo $file) { 61 | // noop 62 | } 63 | 64 | public function rollback(IVersion $version) { 65 | $source = $version->getSourceFile(); 66 | $storage = $source->getStorage(); 67 | 68 | if ($version instanceof SnapshotVersion) { 69 | $versionStorage = new Local(['datadir' => $version->getSnapshot()->getPath()]); 70 | return $storage->copyFromStorage($versionStorage, $version->getVersionPath(), $source->getInternalPath()); 71 | } else { 72 | return false; 73 | } 74 | } 75 | 76 | public function read(IVersion $version) { 77 | if ($version instanceof SnapshotVersion) { 78 | return $version->getSnapshot()->readFile($version->getVersionPath()); 79 | } else { 80 | return false; 81 | } 82 | } 83 | 84 | public function getVersionFile(IUser $user, FileInfo $sourceFile, $revision): File { 85 | return new SnapshotPreviewFile($sourceFile, function () use ($sourceFile, $revision, $user) { 86 | return $this->versionProvider->getSnapshot($revision)->readFile($user->getUID() . '/' . $sourceFile->getInternalPath()); 87 | }, $revision); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /psalm.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /screenshots/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icewind1991/files_snapshots/d8ba3c3a5707e18a147c180421d1ff2283fde4ad/screenshots/settings.png -------------------------------------------------------------------------------- /screenshots/versions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icewind1991/files_snapshots/d8ba3c3a5707e18a147c180421d1ff2283fde4ad/screenshots/versions.png -------------------------------------------------------------------------------- /templates/settings.php: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | t('Snapshots')); ?> 11 | t('Access filesystem snapshots from Nextcloud.')); ?> 12 | 13 | 14 | 15 | 16 | t('Snapshot format')); ?> 17 | 18 | 19 | 22 | 23 | 24 | 25 | 26 | 27 | t('Date format')); ?> 28 | 29 | 30 | 33 | 35 | 36 | 37 | 38 | 39 | t('If no date can be parsed from the snapshot name, the mtime of the snapshot directory will be used')); ?> 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | t('Discovered Snapshots')); ?> 49 | 50 | 51 | 52 | 53 | t('Snapshot')); ?> 54 | t('Date')); ?> 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /tests/SnapshotManagerTest.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * @license GNU AGPL version 3 or any later version 8 | * 9 | * This program is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Affero General Public License as 11 | * published by the Free Software Foundation, either version 3 of the 12 | * License, or (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU Affero General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Affero General Public License 20 | * along with this program. If not, see . 21 | * 22 | */ 23 | 24 | namespace OCA\Files_Snapshots\Tests; 25 | 26 | use DateTime; 27 | use OCA\Files_Snapshots\Snapshot; 28 | use OCA\Files_Snapshots\SnapshotManager; 29 | use OCP\ITempManager; 30 | use Test\TestCase; 31 | 32 | class SnapshotManagerTest extends TestCase { 33 | /** @var ITempManager */ 34 | private $tempManager; 35 | /** @var string */ 36 | private $baseDir; 37 | 38 | protected function setUp(): void { 39 | parent::setUp(); 40 | 41 | $this->tempManager = \OC::$server->query(ITempManager::class); 42 | 43 | $basedir = $this->tempManager->getTemporaryFolder(); 44 | mkdir("$basedir/pre1"); 45 | $this->baseDir = $basedir; 46 | 47 | // oldest snapshot, contains the file 48 | mkdir("$basedir/pre1/autosnap_2021-02-21_19:16:36_daily/sub", 0777, true); 49 | file_put_contents("$basedir/pre1/autosnap_2021-02-21_19:16:36_daily/sub/test.txt", 'old'); 50 | touch("$basedir/pre1/autosnap_2021-02-21_19:16:36_daily/sub/test.txt", 100); 51 | 52 | // newer snapshot, but file remains unchanged 53 | mkdir("$basedir/pre1/autosnap_2021-02-21_20:16:36_hourly/sub", 0777, true); 54 | file_put_contents("$basedir/pre1/autosnap_2021-02-21_20:16:36_hourly/sub/test.txt", 'old'); 55 | touch("$basedir/pre1/autosnap_2021-02-21_20:16:36_hourly/sub/test.txt", 100); 56 | 57 | // new snapshot, file has been updated 58 | mkdir("$basedir/pre1/autosnap_2021-02-22_12:53:43_weekly/sub", 0777, true); 59 | file_put_contents("$basedir/pre1/autosnap_2021-02-22_12:53:43_weekly/sub/test.txt", 'new'); 60 | touch("$basedir/pre1/autosnap_2021-02-21_19:16:36_daily/sub/test.txt", 110); 61 | 62 | // new snapshot that no longer contains the file 63 | mkdir("$basedir/pre1/autosnap_2021-02-23_12:53:43_daily/sub", 0777, true); 64 | // snapshot that doesn't match the autosnap date 65 | mkdir("$basedir/pre1/non-date-snap/sub", 0777, true); 66 | touch("$basedir/pre1/non-date-snap/sub", 1714137760); 67 | // snapshots with a different prefix 68 | mkdir("$basedir/pre2/autosnap_2021-02-24_12:53:43_daily/sub", 0777, true); 69 | 70 | // snapshots without a date 71 | mkdir("$basedir/nodate/snap1/sub", 0777, true); 72 | file_put_contents("$basedir/nodate/snap1/sub/test.txt", 'old'); 73 | touch("$basedir/nodate/snap1/sub/test.txt", 100); 74 | touch("$basedir/nodate/snap1/sub", 100); 75 | mkdir("$basedir/nodate/snap2/sub", 0777, true); 76 | file_put_contents("$basedir/nodate/snap2/sub/test.txt", 'new'); 77 | touch("$basedir/nodate/snap2/sub/test.txt", 110); 78 | touch("$basedir/nodate/snap2/sub", 110); 79 | } 80 | 81 | public function testListSnapshotsNotConfigured() { 82 | $manager = new SnapshotManager('', '*Y-m-d_H:i:s*'); 83 | $this->assertEquals([], iterator_to_array($manager->listAllSnapshots())); 84 | $this->assertEquals([], $manager->listSnapshotsForFile('dummy')); 85 | $this->assertEquals(null, $manager->getSnapshot('dummy')); 86 | } 87 | 88 | public function testListSnapshots() { 89 | $manager = new SnapshotManager('/' . $this->baseDir . '/pre1/%snapshot%/sub', '*Y-m-d_H:i:s*'); 90 | 91 | /** @var Snapshot[] $snapshots */ 92 | $snapshots = iterator_to_array($manager->listAllSnapshots()); 93 | $this->assertCount(5, $snapshots); 94 | usort($snapshots, function (Snapshot $a, Snapshot $b) { 95 | return $a->getName() <=> $b->getName(); 96 | }); 97 | $this->assertEquals(DateTime::createFromFormat('Y-m-d_H:i:s', '2021-02-21_19:16:36'), $snapshots[0]->getSnapshotDate()); 98 | $this->assertEquals(DateTime::createFromFormat('Y-m-d_H:i:s', '2021-02-21_20:16:36'), $snapshots[1]->getSnapshotDate()); 99 | $this->assertEquals(DateTime::createFromFormat('Y-m-d_H:i:s', '2021-02-22_12:53:43'), $snapshots[2]->getSnapshotDate()); 100 | $this->assertEquals(DateTime::createFromFormat('Y-m-d_H:i:s', '2021-02-23_12:53:43'), $snapshots[3]->getSnapshotDate()); 101 | $this->assertEquals(new DateTime('@1714137760'), $snapshots[4]->getSnapshotDate()); 102 | } 103 | 104 | public function testListSnapshotsForFile() { 105 | $manager = new SnapshotManager('/' . $this->baseDir . '/pre1/%snapshot%/sub', '*Y-m-d_H:i:s*'); 106 | 107 | $snapshots = $manager->listSnapshotsForFile('test.txt'); 108 | $this->assertCount(2, $snapshots); 109 | $this->assertEquals(DateTime::createFromFormat('Y-m-d_H:i:s', '2021-02-21_19:16:36'), $snapshots[0]->getSnapshotDate()); 110 | $this->assertEquals(DateTime::createFromFormat('Y-m-d_H:i:s', '2021-02-22_12:53:43'), $snapshots[1]->getSnapshotDate()); 111 | 112 | $this->assertEquals('old', stream_get_contents($snapshots[0]->readFile('test.txt'))); 113 | $this->assertEquals('new', stream_get_contents($snapshots[1]->readFile('test.txt'))); 114 | } 115 | 116 | public function testListSnapshotsForFileNoDate() { 117 | $manager = new SnapshotManager('/' . $this->baseDir . '/nodate/%snapshot%/sub', '*snap*'); 118 | 119 | $snapshots = $manager->listSnapshotsForFile('test.txt'); 120 | $this->assertCount(2, $snapshots); 121 | 122 | $this->assertEquals('old', stream_get_contents($snapshots[0]->readFile('test.txt'))); 123 | $this->assertEquals('new', stream_get_contents($snapshots[1]->readFile('test.txt'))); 124 | } 125 | 126 | public function testListSnapshotsGlob() { 127 | $manager = new SnapshotManager('/' . $this->baseDir . '/pre*/%snapshot%/sub', '*Y-m-d_H:i:s*'); 128 | 129 | /** @var Snapshot[] $snapshots */ 130 | $snapshots = iterator_to_array($manager->listAllSnapshots()); 131 | $this->assertCount(6, $snapshots); 132 | usort($snapshots, function (Snapshot $a, Snapshot $b) { 133 | return $a->getPath() <=> $b->getPath(); 134 | }); 135 | $this->assertEquals(DateTime::createFromFormat('Y-m-d_H:i:s', '2021-02-21_19:16:36'), $snapshots[0]->getSnapshotDate()); 136 | $this->assertEquals(DateTime::createFromFormat('Y-m-d_H:i:s', '2021-02-21_20:16:36'), $snapshots[1]->getSnapshotDate()); 137 | $this->assertEquals(DateTime::createFromFormat('Y-m-d_H:i:s', '2021-02-22_12:53:43'), $snapshots[2]->getSnapshotDate()); 138 | $this->assertEquals(DateTime::createFromFormat('Y-m-d_H:i:s', '2021-02-23_12:53:43'), $snapshots[3]->getSnapshotDate()); 139 | $this->assertEquals(DateTime::createFromFormat('Y-m-d_H:i:s', '2021-02-24_12:53:43'), $snapshots[5]->getSnapshotDate()); 140 | $this->assertEquals(new DateTime('@1714137760'), $snapshots[4]->getSnapshotDate()); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | addPsr4('Test\\', OC::$SERVERROOT . '/tests/lib/', true); 8 | \OC::$composerAutoloader->addPsr4('Tests\\', OC::$SERVERROOT . '/tests/', true); 9 | 10 | OC_App::loadApp('files_snapshots'); 11 | 12 | OC_Hook::clear(); 13 | -------------------------------------------------------------------------------- /tests/phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | . 9 | 10 | 11 | 12 | ../ 13 | 14 | ../tests 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /tests/stubs/psalm.phpstub: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * @license GNU AGPL version 3 or any later version 8 | * 9 | * This program is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Affero General Public License as 11 | * published by the Free Software Foundation, either version 3 of the 12 | * License, or (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU Affero General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Affero General Public License 20 | * along with this program. If not, see . 21 | * 22 | */ 23 | 24 | namespace OCA\Files_Versions\Versions { 25 | 26 | use OCP\Files\File; 27 | use OCP\Files\FileInfo; 28 | use OCP\Files\Storage\IStorage; 29 | use OCP\IUser; 30 | 31 | interface IVersionBackend { 32 | 33 | public function useBackendForStorage(IStorage $storage): bool; 34 | 35 | /** 36 | * Get all versions for a file 37 | * 38 | * @param IUser $user 39 | * @param FileInfo $file 40 | * @return IVersion[] 41 | * @since 15.0.0 42 | */ 43 | public function getVersionsForFile(IUser $user, FileInfo $file): array; 44 | 45 | public function createVersion(IUser $user, FileInfo $file); 46 | 47 | public function rollback(IVersion $version); 48 | 49 | public function read(IVersion $version); 50 | 51 | public function getVersionFile(IUser $user, FileInfo $sourceFile, $revision): File; 52 | } 53 | 54 | interface IVersion { 55 | public function getBackend(): IVersionBackend; 56 | 57 | public function getSourceFile(): FileInfo; 58 | 59 | /** 60 | * @return int|string 61 | */ 62 | public function getRevisionId(); 63 | 64 | public function getTimestamp(): int; 65 | 66 | public function getSize(): int; 67 | 68 | public function getSourceFileName(): string; 69 | 70 | public function getMimeType(): string; 71 | 72 | public function getVersionPath(): string; 73 | 74 | public function getUser(): IUser; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /vendor-bin/cs-fixer/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require-dev": { 3 | "nextcloud/coding-standard": "^1.3.1" 4 | }, 5 | "config": { 6 | "platform": { 7 | "php": "8.1" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /vendor-bin/cs-fixer/composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "b80be9f75e57093d11f0a5065039b255", 8 | "packages": [], 9 | "packages-dev": [ 10 | { 11 | "name": "kubawerlos/php-cs-fixer-custom-fixers", 12 | "version": "v3.24.0", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers.git", 16 | "reference": "93222100a91399314c3726857e249e76c4a7d760" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/kubawerlos/php-cs-fixer-custom-fixers/zipball/93222100a91399314c3726857e249e76c4a7d760", 21 | "reference": "93222100a91399314c3726857e249e76c4a7d760", 22 | "shasum": "" 23 | }, 24 | "require": { 25 | "ext-filter": "*", 26 | "ext-tokenizer": "*", 27 | "friendsofphp/php-cs-fixer": "^3.61.1", 28 | "php": "^7.4 || ^8.0" 29 | }, 30 | "require-dev": { 31 | "phpunit/phpunit": "^9.6.22 || 10.5.45 || ^11.5.7" 32 | }, 33 | "type": "library", 34 | "autoload": { 35 | "psr-4": { 36 | "PhpCsFixerCustomFixers\\": "src" 37 | } 38 | }, 39 | "notification-url": "https://packagist.org/downloads/", 40 | "license": [ 41 | "MIT" 42 | ], 43 | "authors": [ 44 | { 45 | "name": "Kuba Werłos", 46 | "email": "werlos@gmail.com" 47 | } 48 | ], 49 | "description": "A set of custom fixers for PHP CS Fixer", 50 | "support": { 51 | "issues": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers/issues", 52 | "source": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers/tree/v3.24.0" 53 | }, 54 | "time": "2025-03-22T16:51:39+00:00" 55 | }, 56 | { 57 | "name": "nextcloud/coding-standard", 58 | "version": "v1.3.2", 59 | "source": { 60 | "type": "git", 61 | "url": "https://github.com/nextcloud/coding-standard.git", 62 | "reference": "9c719c4747fa26efc12f2e8b21c14a9a75c6ba6d" 63 | }, 64 | "dist": { 65 | "type": "zip", 66 | "url": "https://api.github.com/repos/nextcloud/coding-standard/zipball/9c719c4747fa26efc12f2e8b21c14a9a75c6ba6d", 67 | "reference": "9c719c4747fa26efc12f2e8b21c14a9a75c6ba6d", 68 | "shasum": "" 69 | }, 70 | "require": { 71 | "kubawerlos/php-cs-fixer-custom-fixers": "^3.22", 72 | "php": "^7.3|^8.0", 73 | "php-cs-fixer/shim": "^3.17" 74 | }, 75 | "type": "library", 76 | "autoload": { 77 | "psr-4": { 78 | "Nextcloud\\CodingStandard\\": "src" 79 | } 80 | }, 81 | "notification-url": "https://packagist.org/downloads/", 82 | "license": [ 83 | "MIT" 84 | ], 85 | "authors": [ 86 | { 87 | "name": "Christoph Wurst", 88 | "email": "christoph@winzerhof-wurst.at" 89 | } 90 | ], 91 | "description": "Nextcloud coding standards for the php cs fixer", 92 | "support": { 93 | "issues": "https://github.com/nextcloud/coding-standard/issues", 94 | "source": "https://github.com/nextcloud/coding-standard/tree/v1.3.2" 95 | }, 96 | "time": "2024-10-14T16:49:05+00:00" 97 | }, 98 | { 99 | "name": "php-cs-fixer/shim", 100 | "version": "v3.75.0", 101 | "source": { 102 | "type": "git", 103 | "url": "https://github.com/PHP-CS-Fixer/shim.git", 104 | "reference": "eea219a577085bd13ff0cb644a422c20798316c7" 105 | }, 106 | "dist": { 107 | "type": "zip", 108 | "url": "https://api.github.com/repos/PHP-CS-Fixer/shim/zipball/eea219a577085bd13ff0cb644a422c20798316c7", 109 | "reference": "eea219a577085bd13ff0cb644a422c20798316c7", 110 | "shasum": "" 111 | }, 112 | "require": { 113 | "ext-json": "*", 114 | "ext-tokenizer": "*", 115 | "php": "^7.4 || ^8.0" 116 | }, 117 | "replace": { 118 | "friendsofphp/php-cs-fixer": "self.version" 119 | }, 120 | "suggest": { 121 | "ext-dom": "For handling output formats in XML", 122 | "ext-mbstring": "For handling non-UTF8 characters." 123 | }, 124 | "bin": [ 125 | "php-cs-fixer", 126 | "php-cs-fixer.phar" 127 | ], 128 | "type": "application", 129 | "notification-url": "https://packagist.org/downloads/", 130 | "license": [ 131 | "MIT" 132 | ], 133 | "authors": [ 134 | { 135 | "name": "Fabien Potencier", 136 | "email": "fabien@symfony.com" 137 | }, 138 | { 139 | "name": "Dariusz Rumiński", 140 | "email": "dariusz.ruminski@gmail.com" 141 | } 142 | ], 143 | "description": "A tool to automatically fix PHP code style", 144 | "support": { 145 | "issues": "https://github.com/PHP-CS-Fixer/shim/issues", 146 | "source": "https://github.com/PHP-CS-Fixer/shim/tree/v3.75.0" 147 | }, 148 | "time": "2025-03-31T18:45:02+00:00" 149 | } 150 | ], 151 | "aliases": [], 152 | "minimum-stability": "stable", 153 | "stability-flags": {}, 154 | "prefer-stable": false, 155 | "prefer-lowest": false, 156 | "platform": {}, 157 | "platform-dev": {}, 158 | "platform-overrides": { 159 | "php": "8.1" 160 | }, 161 | "plugin-api-version": "2.6.0" 162 | } 163 | -------------------------------------------------------------------------------- /vendor-bin/phpunit/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require-dev": { 3 | "phpunit/phpunit": "^9" 4 | }, 5 | "config": { 6 | "platform": { 7 | "php": "8.1" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /vendor-bin/psalm/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require-dev": { 3 | "vimeo/psalm": "^6" 4 | }, 5 | "config": { 6 | "platform": { 7 | "php": "8.1.17" 8 | } 9 | } 10 | } 11 | --------------------------------------------------------------------------------
t('Access filesystem snapshots from Nextcloud.')); ?>