Compare commits

...

95 Commits

Author SHA1 Message Date
Arthur Schiwon 62cfd3b4c9 Merge pull request #37312 from nextcloud/release/26.0.0
26.0.0
2023-03-21 10:19:37 +01:00
Nextcloud bot 2ea7537ca6 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-21 02:27:29 +00:00
Arthur Schiwon e480563a54 26.0.0
Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
2023-03-20 19:28:10 +01:00
Arthur Schiwon 2db99590b9 Merge pull request #37310 from nextcloud/bugfix/37277/caldav-sync-stable26
[stable26] fix(session): Fix DAVx5 sync problems by partial reverting session ch…
2023-03-20 19:27:00 +01:00
Joas Schilling c6f424bddd fix(session): Fix DAVx5 sync problems by partial reverting session changes
Temporary disabled the short cut again to solve issues with CalDAV/CardDAV
clients like DAVx5 that use cookies and need a session. See
https://github.com/nextcloud/server/issues/37277#issuecomment-1476366147
and the other comments for further information.

Signed-off-by: Joas Schilling <coding@schilljs.com>
2023-03-20 17:20:23 +01:00
Nextcloud bot 164021dee4 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-20 02:27:29 +00:00
Nextcloud bot bdf17e5252 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-19 02:27:37 +00:00
Nextcloud bot 5ece6f29c3 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-18 02:27:33 +00:00
Nextcloud bot a6e89e0410 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-17 02:27:25 +00:00
Arthur Schiwon 335b871810 Merge pull request #37202 from nextcloud/release/26.0.0_rc3
26.0.0 RC3
2023-03-16 12:48:19 +01:00
Arthur Schiwon 106fb14183 Merge pull request #37031 from nextcloud/dependabot/npm_and_yarn/stable26/nextcloud/webpack-vue-config-516d77c
chore(deps-dev): Bump @nextcloud/webpack-vue-config to `5.5.0`
2023-03-16 12:12:26 +01:00
Arthur Schiwon 17a29c865b Merge pull request #37251 from nextcloud/automated/noid/stable26-update-psalm-baseline
[stable26] Update psalm-baseline.xml
2023-03-16 11:10:20 +01:00
Arthur Schiwon 0b4cc1b83f Merge pull request #37247 from nextcloud/backport/37010/stable26
[stable26] Fix Cache-Control header of non-versioned assets
2023-03-16 11:09:36 +01:00
Arthur Schiwon 45ecf37248 Merge pull request #37235 from nextcloud/backport/37227/stable26
[stable26] chore: use local variable for remote address
2023-03-16 10:38:24 +01:00
Arthur Schiwon 221bf33245 Merge pull request #37253 from nextcloud/backport/37252/stable26
[stable26] fix(workflow): Check tag attribute
2023-03-16 10:30:23 +01:00
Arthur Schiwon 6b54bfb7b2 Merge pull request #37246 from nextcloud/backport/37242/stable26
[stable26] Reduce list
2023-03-16 10:23:29 +01:00
dependabot[bot] c2bdb02144 chore(deps-dev): Bump @nextcloud/webpack-vue-config
Bumps [@nextcloud/webpack-vue-config](https://github.com/nextcloud/webpack-vue-config) from `53df7bb` to `516d77c`.
- [Release notes](https://github.com/nextcloud/webpack-vue-config/releases)
- [Commits](https://github.com/nextcloud/webpack-vue-config/compare/53df7bbe61e4a6d960c1d13e63597ce361f3795d...516d77c7012711a741baee53be745168c0456605)

---
updated-dependencies:
- dependency-name: "@nextcloud/webpack-vue-config"
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
2023-03-16 09:13:43 +00:00
Joas Schilling ce8ec36184 fix(workflow): Check tag attribute
Signed-off-by: Joas Schilling <coding@schilljs.com>
2023-03-16 08:47:29 +01:00
nextcloud-command 3094e70350 Update psalm baseline
Signed-off-by: GitHub <noreply@github.com>
2023-03-16 04:55:12 +00:00
Nextcloud bot 5ac1b3533b Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-16 02:28:18 +00:00
Nicolas Guichard 4bcb38c0b2 Fix Cache-Control header of non-versioned assets
Non-cache-busted assets such as /dist/core-main.js also matched the
regex meant for cache-busted assets (note the ? at the end of the
regex).
The FilesMatch directive for cache-busted assets coming after the
non-cache-busted version all assets actually got the immutable flag
in their Cache-Control header. This caused client-side errors on
updates.

Query strings are not actually passed to FilesMatch directives so we
need another way to tell cache-busted/versionned assets apart from
non-versioned assets, here using If/Else directives.

Signed-off-by: Nicolas Guichard <nicolas@guichard.eu>
2023-03-15 22:35:18 +00:00
Joas Schilling 78e591d0d4 Reduce list
Signed-off-by: Joas Schilling <coding@schilljs.com>
2023-03-15 21:50:04 +00:00
Côme Chilliet 4c161a70a4 Merge pull request #37233 from nextcloud/backport/37197/stable26
[stable26] Do not send a pagination control with size = 0 if cookie is empty
2023-03-15 18:16:24 +01:00
Joas Schilling ae34be566e Merge pull request #37240 from nextcloud/backport/37239/stable26
[stable26] Extend list
2023-03-15 17:20:24 +01:00
Joas Schilling dc3c44a84f Extend list
Signed-off-by: Joas Schilling <coding@schilljs.com>
2023-03-15 16:19:40 +00:00
Daniel Kesselberg d6a3fe7e83 chore(tests): add tests for handleLoginFailed
Signed-off-by: Daniel Kesselberg <mail@danielkesselberg.de>
2023-03-15 14:22:36 +00:00
Daniel Kesselberg a086db37cd chore: use local variable for remote address
Signed-off-by: Daniel Kesselberg <mail@danielkesselberg.de>
2023-03-15 14:22:36 +00:00
Côme Chilliet d62643b43e Do not send a pagination control with size = 0 if cookie is empty
It only makes sense to send a pagination control with size 0 with a
 cookie to abandon a paged search.

Signed-off-by: Côme Chilliet <come.chilliet@nextcloud.com>
2023-03-15 13:47:21 +00:00
Arthur Schiwon 826766d3bd Merge pull request #37212 from nextcloud/backport/37029/stable26
[stable26] Add chunking in SystemTagObjectMapper::getTagIdsForObjects
2023-03-15 14:45:25 +01:00
Arthur Schiwon dd3f6516c5 Merge pull request #37072 from nextcloud/backport/36883/stable26
[stable26] dispatch BeforeUserLoggedInEvent
2023-03-15 14:44:58 +01:00
Joas Schilling 259530ed5a Merge pull request #37218 from nextcloud/backport/36852/stable26
[stable26] fix(user_status): Fix the user status automation on the day availablity rules are adjusted
2023-03-15 12:11:45 +01:00
Joas Schilling 15d7fb35f4 Merge pull request #37224 from nextcloud/backport/37221/stable26
[stable26] Save some CI time
2023-03-15 10:26:58 +01:00
Joas Schilling 333d6bcc45 Save some CI time
Signed-off-by: Joas Schilling <coding@schilljs.com>
2023-03-15 09:30:38 +01:00
Nextcloud bot bcc9ee4011 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-15 02:26:49 +00:00
Joas Schilling 6f8d75bd24 fix(CI): Add unit test for nextcloud/server#37167
Signed-off-by: Joas Schilling <coding@schilljs.com>
2023-03-14 16:39:01 +00:00
Joas Schilling a9cf423321 fix(user_status): Fix the user status automation on the day availability rules are adjusted
Signed-off-by: Joas Schilling <coding@schilljs.com>
2023-03-14 16:39:01 +00:00
Joas Schilling 3d6a864210 Merge pull request #37199 from nextcloud/backport/37167/stable26
[stable26] fix(dav): Handle no next potential toggle in availability detection
2023-03-14 17:21:35 +01:00
Côme Chilliet e7c6ff1709 Add chunking in SystemTagObjectMapper::getTagIdsForObjects
This avoids crashing on Oracle with more than 1000 objects

Signed-off-by: Côme Chilliet <come.chilliet@nextcloud.com>
2023-03-14 14:25:05 +01:00
Nextcloud bot ee38128f3d Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-14 02:27:20 +00:00
Arthur Schiwon 05b6ff5e7b 26.0.0 RC3
Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
2023-03-13 20:37:59 +01:00
Thomas Citharel bddab7d302 fix(dav): Handle no next potential toggle in availability detection
Fixes:  min(): Array must contain at least one element at /var/www/nc/nextcloud/apps/dav/lib/BackgroundJob/UserStatusAutomation.php#142
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2023-03-13 19:24:58 +01:00
Nextcloud bot 958f9c9147 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-13 02:28:58 +00:00
Nextcloud bot ac2a53a4bd Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-12 02:27:53 +00:00
Nextcloud bot 0b2ad6cefc Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-11 02:28:08 +00:00
Simon L 71b74992e5 Merge pull request #37163 from nextcloud/backport/37126/stable26
[stable26] fix white scrollbar corner in dark mode
2023-03-10 16:18:57 +01:00
Simon L c18e5fe8a9 Merge pull request #37157 from nextcloud/backport/37070/stable26
[stable26] add a check for disk_free_space in Config.php
2023-03-10 16:17:44 +01:00
Simon L 226c601d1d Merge pull request #37155 from nextcloud/backport/37140/stable26
[stable26] imaginary - fix autorotate for heic and improve the logic
2023-03-10 16:16:57 +01:00
Arthur Schiwon cf73f6e8bf Merge pull request #37161 from nextcloud/backport/37116/stable26
[stable26] postgresql installation - add quotes around user names
2023-03-10 09:46:59 +01:00
Simon L 5f6579fb6a fix white scrollbar corner in dark mode
Signed-off-by: Simon L <szaimen@e.mail.de>
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
2023-03-10 02:32:21 +00:00
Nextcloud bot 6a120bfda1 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-10 02:27:25 +00:00
Simon L df8b19aea3 postgresql - add quotes around user names
fix https://github.com/nextcloud/server/issues/37114

Signed-off-by: Simon L <szaimen@e.mail.de>
2023-03-10 02:04:00 +00:00
Simon L 703043a024 add a check for disk_free_space in Config.php
Signed-off-by: Simon L <szaimen@e.mail.de>
2023-03-09 23:24:38 +00:00
Simon L 865fb8092b imaginary - fix autorotate and improve the logic
Signed-off-by: Simon L <szaimen@e.mail.de>
2023-03-09 22:25:57 +00:00
Arthur Schiwon 51c76884bc Merge pull request #37078 from nextcloud/release/26.0.0_rc2
26.0.0 RC2
2023-03-09 17:38:27 +01:00
Arthur Schiwon e3c7bcc61d Merge pull request #37119 from nextcloud/backport/36640/stable26
[stable26] Create headings for apps, users, settings pages
2023-03-09 17:37:28 +01:00
Arthur Schiwon 92b8a5ef1e Merge pull request #37057 from nextcloud/backport/36904/stable26
[stable26] fix(files): Fix controller setup for guests
2023-03-09 17:30:42 +01:00
Arthur Schiwon 72cf710ec8 Merge pull request #37141 from nextcloud/backport/37139/stable26
[stable26] Share type sciencemesh
2023-03-09 17:29:54 +01:00
Arthur Schiwon 2b404e2a04 Merge pull request #37151 from nextcloud/backport/27034/stable26
[stable26] Use MultipartUpload for uploading chunks to s3
2023-03-09 17:25:17 +01:00
Julius Härtl ae911a21d2 tests(integration): Fix catching error only on object store
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2023-03-09 15:31:26 +01:00
Julius Härtl a7e5e7e4a1 chore: Bump bundles
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2023-03-09 15:31:22 +01:00
Julius Härtl 609badf6a2 chore(psalm): Make psalm aware of sabre/uri
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2023-03-09 15:31:17 +01:00
Julius Härtl 2664036b57 feat(s3): Use multipart upload for chunked uploading
This allows to stream file chunks directly to S3 during upload.

Signed-off-by: Julius Härtl <jus@bitgrid.net>
2023-03-09 15:31:12 +01:00
Joas Schilling 442bce3e0b fix(files): Fix controller setup for guests
Signed-off-by: Joas Schilling <coding@schilljs.com>
2023-03-09 12:21:07 +00:00
Arthur Schiwon 5943d0a715 Merge pull request #37066 from nextcloud/backport/34835/stable26
[stable26] Run WebDAV integration tests against S3
2023-03-09 13:16:59 +01:00
julia.kirschenheuter f5ab3123df Create headings for settings pages
Signed-off-by: julia.kirschenheuter <julia.kirschenheuter@nextcloud.com>
2023-03-09 13:14:48 +01:00
Arthur Schiwon d29551a46d Merge pull request #37064 from nextcloud/backport/36772/stable26
[stable26] Add label and switch ocdialog close button to button element
2023-03-09 13:05:20 +01:00
Julius Härtl ffb1a39bba Merge pull request #37073 from nextcloud/backport/37026/stable26
[stable26] fix: Avoid log spam on 404 routes not using GET
2023-03-09 12:44:40 +01:00
Christopher Ng 0446703202 Add label and switch ocdialog close button to button element
Signed-off-by: Christopher Ng <chrng8@gmail.com>
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
2023-03-09 09:09:24 +01:00
Nextcloud bot 89b396da95 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-09 02:29:24 +00:00
Louis Chemineau c4c02afb62 Compile assets
Signed-off-by: Louis Chemineau <louis@chmn.me>
2023-03-08 17:48:40 +00:00
Michiel de Jong b2c8be171d Add SHARE_TYPE_SCIENCEMESH
Signed-off-by: Michiel de Jong <michiel@unhosted.org>
2023-03-08 17:48:39 +00:00
Joas Schilling b9c4112f47 Merge pull request #37122 from nextcloud/backport/37121/stable26
[stable26] fix(docs): Fix URL to docs of deprecated function humanFileSize
2023-03-08 13:35:17 +01:00
nextcloud-command 82a3b6a311 Compile assets
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
2023-03-08 11:06:47 +00:00
Joas Schilling 62866bb097 fix(docs): Fix URL to docs of deprecated function humanFileSize
Signed-off-by: Joas Schilling <coding@schilljs.com>
2023-03-08 10:53:00 +00:00
Nextcloud bot f30c7834d8 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-08 02:28:55 +00:00
Arthur Schiwon 69ca730bd1 26.0.0 RC2
Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
2023-03-07 19:53:16 +01:00
Simon L f7fa2fd974 Merge pull request #37074 from nextcloud/backport/37069/stable26
[stable26] fix(CI): Fix acceptance test password field selector after @nextcloud…
2023-03-07 15:57:09 +01:00
Joas Schilling 4edfeab4a7 fix(CI): Fix acceptance test password field selector after @nextcloud/vue lib update
Signed-off-by: Joas Schilling <coding@schilljs.com>
2023-03-07 09:56:33 +00:00
Julius Härtl a5607754cf fix: Avoid log spam on 404 routes not using GET
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2023-03-07 09:56:12 +00:00
Maxence Lange 0cd9ca5be2 dispatch BeforeUserLoggedInEvent
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
2023-03-07 09:20:45 +00:00
Julius Härtl bc759977d2 Merge pull request #37068 from nextcloud/ci/profiler-26
[stable26] ci(performance): Use proper profiler branch for 26
2023-03-07 10:07:54 +01:00
Julius Härtl 54a93e9252 ci(performance): Use proper profiler branch for 26
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2023-03-07 08:57:49 +01:00
Julius Härtl 4ca6c3af7a fix: Use proper path for quota fetching
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2023-03-07 07:21:20 +00:00
Julius Härtl cab4f8eca3 fix: Recalculate storage statistics on updating the quota
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2023-03-07 07:21:20 +00:00
Julius Härtl 8477b1e408 Run webdav related integration tests on github actions
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2023-03-07 07:21:20 +00:00
Nextcloud bot 0a518bd5ff Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-07 02:26:43 +00:00
Arthur Schiwon f1ced06cd5 Merge pull request #37042 from nextcloud/backport/37028/stable26
[stable26] Add distraction free backgrounds for Nextcloud 26
2023-03-06 17:37:18 +01:00
Nextcloud bot b21ef4881f Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-06 02:27:12 +00:00
Nextcloud bot 5323b8caf1 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-05 02:27:59 +00:00
Nextcloud bot 1ca288f0a4 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-04 02:27:30 +00:00
Jan C. Borchardt 126db69108 Add distraction free backgrounds for Nextcloud 26
Signed-off-by: Jan C. Borchardt <hey@jancborchardt.net>
2023-03-03 15:02:20 +00:00
Joas Schilling 3d7ae18660 Merge pull request #37038 from nextcloud/backport/37023/stable26
[stable26] chore(security): Bump "Expires" of well-known/security.txt
2023-03-03 12:12:39 +01:00
Joas Schilling 0d51e1d3b5 chore(security): Bump "Expires" of well-known/security.txt
Signed-off-by: Joas Schilling <coding@schilljs.com>
2023-03-03 10:53:40 +00:00
Joas Schilling 7b7909f767 Merge pull request #37024 from nextcloud/test-with-26-apps-on-stable26
[stable26] Test against matching Talk version on stable branch
2023-03-03 11:19:23 +01:00
Joas Schilling b846f10e7b chore(CI): Test against matching Talk version on stable26 branch
Signed-off-by: Joas Schilling <coding@schilljs.com>
2023-03-03 10:12:31 +01:00
665 changed files with 4314 additions and 1550 deletions
+2 -2
View File
@@ -1238,9 +1238,9 @@ steps:
- name: install-talk
image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
commands:
# JavaScript files are not used in integration tests so it is not needed to
# JavaScript files are not used in integration tests, so it is not needed to
# build them.
- git clone --depth 1 https://github.com/nextcloud/spreed apps/spreed
- git clone --depth 1 --branch stable26 https://github.com/nextcloud/spreed apps/spreed
- cd apps/spreed
- composer --version
- composer self-update --2
+2
View File
@@ -16,6 +16,8 @@ jobs:
init:
runs-on: ubuntu-latest
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
steps:
- name: Checkout server
uses: actions/checkout@v3
+2
View File
@@ -17,6 +17,8 @@ jobs:
ftp-tests:
runs-on: ubuntu-latest
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
strategy:
# do not stop on another job's failure
fail-fast: false
+3
View File
@@ -10,6 +10,9 @@ on:
jobs:
versions:
runs-on: ubuntu-latest
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
outputs:
nodeVersion: ${{ steps.versions.outputs.nodeVersion }}
npmVersion: ${{ steps.versions.outputs.npmVersion }}
+2
View File
@@ -13,6 +13,8 @@ jobs:
phpunit-oci:
runs-on: ubuntu-20.04
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
strategy:
matrix:
php-versions: ['8.0', '8.1', '8.2']
+3 -1
View File
@@ -6,6 +6,8 @@ jobs:
performance-testing:
runs-on: ubuntu-latest
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
strategy:
fail-fast: false
matrix:
@@ -50,7 +52,7 @@ jobs:
curl -s -u test:test -T README.md http://localhost:8080/remote.php/dav/files/test/new_file.txt
curl -s -u test:test -X DELETE http://localhost:8080/remote.php/dav/files/test/new_file.txt
output: before.json
profiler-branch: master
profiler-branch: stable26
- name: Apply PR
run: |
+3
View File
@@ -15,6 +15,9 @@ concurrency:
jobs:
phpunit-32bits:
runs-on: ubuntu-latest
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
container: shivammathur/node:latest-i386
strategy:
+4
View File
@@ -17,6 +17,8 @@ jobs:
s3-external-tests-minio:
runs-on: ubuntu-latest
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
strategy:
# do not stop on another job's failure
fail-fast: false
@@ -68,6 +70,8 @@ jobs:
s3-external-tests-localstack:
runs-on: ubuntu-latest
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
strategy:
# do not stop on another job's failure
fail-fast: false
@@ -0,0 +1,84 @@
name: S3 primary storage integration tests
on:
pull_request:
push:
branches:
- master
- stable*
jobs:
s3-primary-integration-tests-minio:
runs-on: ubuntu-20.04
strategy:
# do not stop on another job's failure
fail-fast: false
matrix:
php-versions: ['8.0']
key: ['objectstore', 'objectstore_multibucket']
name: php${{ matrix.php-versions }}-${{ matrix.key }}-minio
services:
redis:
image: redis
ports:
- "6379:6379"
minio:
env:
MINIO_ACCESS_KEY: minio
MINIO_SECRET_KEY: minio123
image: bitnami/minio:2021.12.29
ports:
- "9000:9000"
steps:
- name: Checkout server
uses: actions/checkout@v3
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
tools: phpunit:9
extensions: mbstring, fileinfo, intl, sqlite, pdo_sqlite, zip, gd, redis
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Wait for S3
run: |
sleep 10
curl -f -m 1 --retry-connrefused --retry 10 --retry-delay 10 http://localhost:9000/minio/health/ready
- name: Set up Nextcloud
run: |
mkdir data
echo '<?php $CONFIG=["${{ matrix.key }}" => ["class" => "OC\Files\ObjectStore\S3", "arguments" => ["bucket" => "nextcloud", "autocreate" => true, "key" => "minio", "secret" => "minio123", "hostname" => "localhost", "port" => 9000, "use_ssl" => false, "use_path_style" => true, "uploadPartSize" => 52428800]]];' > config/config.php
echo '<?php $CONFIG=["redis" => ["host" => "localhost", "port" => 6379], "memcache.local" => "\OC\Memcache\Redis", "memcache.distributed" => "\OC\Memcache\Redis"];' > config/redis.config.php
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-host=127.0.0.1 --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
php -f index.php
- name: Integration
run: |
cd build/integration
bash run.sh --tags "~@failure-s3" features/webdav-related.feature
- name: S3 logs
if: always()
run: |
cat data/nextcloud.log
docker ps -a
docker ps -aq | while read container ; do IMAGE=$(docker inspect --format='{{.Config.Image}}' $container); echo $IMAGE; docker logs $container; echo "\n\n" ; done
s3-primary-integration-summary:
runs-on: ubuntu-latest
needs: [s3-primary-integration-tests-minio]
if: always()
steps:
- name: Summary status
run: if ${{ needs.s3-primary-integration-tests-minio.result != 'success' }}; then exit 1; fi
+2
View File
@@ -10,6 +10,8 @@ jobs:
s3-primary-tests-minio:
runs-on: ubuntu-20.04
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
strategy:
# do not stop on another job's failure
fail-fast: false
+2
View File
@@ -16,6 +16,8 @@ jobs:
smb-kerberos-tests:
runs-on: ubuntu-latest
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
name: smb-kerberos-sso
steps:
+5 -4
View File
@@ -7,12 +7,13 @@ on:
jobs:
stale:
runs-on: ubuntu-latest
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
permissions:
issues: write
steps:
- uses: actions/stale@v5
with:
@@ -29,4 +30,4 @@ jobs:
days-before-stale: 30
days-before-close: 14
# debug-only: true
@@ -11,6 +11,8 @@ jobs:
static-code-analysis:
runs-on: ubuntu-latest
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
steps:
- name: Checkout
uses: actions/checkout@v3
@@ -9,6 +9,8 @@ jobs:
update-psalm-baseline:
runs-on: ubuntu-latest
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
strategy:
fail-fast: false
matrix:
+6 -5
View File
@@ -41,11 +41,12 @@
# Add cache control for static resources
<FilesMatch "\.(css|js|svg|gif|png|jpg|ico|wasm|tflite)$">
Header set Cache-Control "max-age=15778463"
</FilesMatch>
<FilesMatch "\.(css|js|svg|gif|png|jpg|ico|wasm|tflite)(\?v=.*)?$">
Header set Cache-Control "max-age=15778463, immutable"
<If "%{QUERY_STRING} =~ /(^|&)v=/">
Header set Cache-Control "max-age=15778463, immutable"
</If>
<Else>
Header set Cache-Control "max-age=15778463"
</Else>
</FilesMatch>
# Let browsers cache WOFF files for a week
+7
View File
@@ -0,0 +1,7 @@
OC.L10N.register(
"admin_audit",
{
"Auditing / Logging" : "Աուդիտ / Տեղեկագրում",
"Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "Nextcloud ֊ի համար տրամադրում է տեղեկագրման հնարավորություն՝ նիշքերի հասանելիության և զգայուն գործողություինների պահպանումը տեղեկամատյանում։"
},
"nplurals=2; plural=(n != 1);");
+5
View File
@@ -0,0 +1,5 @@
{ "translations": {
"Auditing / Logging" : "Աուդիտ / Տեղեկագրում",
"Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "Nextcloud ֊ի համար տրամադրում է տեղեկագրման հնարավորություն՝ նիշքերի հասանելիության և զգայուն գործողություինների պահպանումը տեղեկամատյանում։"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}
+2 -1
View File
@@ -1,6 +1,7 @@
OC.L10N.register(
"admin_audit",
{
"Auditing / Logging" : "Ревизија / Евиденција"
"Auditing / Logging" : "Ревизија / Евиденција",
"Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "Обезбедува можности за евидентирање на Nextcloud, како што се евидентирање пристапи до датотеки или на друг начин чувствителни дејства."
},
"nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;");
+2 -1
View File
@@ -1,4 +1,5 @@
{ "translations": {
"Auditing / Logging" : "Ревизија / Евиденција"
"Auditing / Logging" : "Ревизија / Евиденција",
"Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "Обезбедува можности за евидентирање на Nextcloud, како што се евидентирање пристапи до датотеки или на друг начин чувствителни дејства."
},"pluralForm" :"nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;"
}
+25
View File
@@ -160,6 +160,19 @@ class Sharing extends Action {
'id',
]
);
} elseif ($params['shareType'] === IShare::TYPE_SCIENCEMESH) {
$this->log(
'The %s "%s" with ID "%s" has been shared to the sciencemesh user "%s" with permissions "%s" (Share ID: %s)',
$params,
[
'itemType',
'path',
'itemSource',
'shareWith',
'permissions',
'id',
]
);
}
}
@@ -276,6 +289,18 @@ class Sharing extends Action {
'id',
]
);
} elseif ($params['shareType'] === IShare::TYPE_SCIENCEMESH) {
$this->log(
'The %s "%s" with ID "%s" has been unshared from the sciencemesh user "%s" (Share ID: %s)',
$params,
[
'itemType',
'fileTarget',
'itemSource',
'shareWith',
'id',
]
);
}
}
+1 -1
View File
@@ -2,7 +2,7 @@ OC.L10N.register(
"cloud_federation_api",
{
"Cloud Federation API" : "API pro federovaný cloud",
"Enable clouds to communicate with each other and exchange data" : "Umožňuje cloudům navzájem komunikovat a vyměňovat si data",
"Enable clouds to communicate with each other and exchange data" : "Umožňuje cloudům vzájem komunikovat a vyměňovat si data",
"The Cloud Federation API enables various Nextcloud instances to communicate with each other and to exchange data." : "API pro federovaný cloud umožňuje různým instancím Nextcloud vzájemně komunikovat a vyměňovat si data."
},
"nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;");
+1 -1
View File
@@ -1,6 +1,6 @@
{ "translations": {
"Cloud Federation API" : "API pro federovaný cloud",
"Enable clouds to communicate with each other and exchange data" : "Umožňuje cloudům navzájem komunikovat a vyměňovat si data",
"Enable clouds to communicate with each other and exchange data" : "Umožňuje cloudům vzájem komunikovat a vyměňovat si data",
"The Cloud Federation API enables various Nextcloud instances to communicate with each other and to exchange data." : "API pro federovaný cloud umožňuje různým instancím Nextcloud vzájemně komunikovat a vyměňovat si data."
},"pluralForm" :"nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;"
}
+1
View File
@@ -9,6 +9,7 @@ OC.L10N.register(
"%1$s commented on %2$s" : "%1$s كتب تعليق على %2$s",
"{author} commented on {file}" : "{author} علّق على {file}",
"<strong>Comments</strong> for files" : "<strong>تعليقات</strong> على الملفات",
"You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "تمت الإشارة إليك في \"{file}\" في تعليق لمستخدم. لكن هذا المستخدم تم حذف حسابه بعدها",
"{user} mentioned you in a comment on \"{file}\"" : "أشار إليك {user} في تعليق على {file}",
"Files app plugin to add comments to files" : "المكوِّن الإضافي لتطبيق الملفات لإضافة تعليقات إلى الملفات",
"Edit comment" : "تعديل التعليق",
+1
View File
@@ -7,6 +7,7 @@
"%1$s commented on %2$s" : "%1$s كتب تعليق على %2$s",
"{author} commented on {file}" : "{author} علّق على {file}",
"<strong>Comments</strong> for files" : "<strong>تعليقات</strong> على الملفات",
"You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "تمت الإشارة إليك في \"{file}\" في تعليق لمستخدم. لكن هذا المستخدم تم حذف حسابه بعدها",
"{user} mentioned you in a comment on \"{file}\"" : "أشار إليك {user} في تعليق على {file}",
"Files app plugin to add comments to files" : "المكوِّن الإضافي لتطبيق الملفات لإضافة تعليقات إلى الملفات",
"Edit comment" : "تعديل التعليق",
+1 -31
View File
@@ -1,33 +1,3 @@
# Dashboard
## Background picture credits
- Default background: [Clouds (Kamil Porembiński, CC BY-SA)](https://www.flickr.com/photos/paszczak000/8715851521/) original 4k, color modified and sky color changed to Nextcloud blue.
- Default dark mode background: [Pedra azul milky way (Eduardo Neves, CC BY-SA)](https://commons.wikimedia.org/wiki/File:Pedra_Azul_Milky_Way.jpg) original 5k.
- [Butterfly wing scale (Anatoly Mikhaltsov, CC BY-SA)](https://commons.wikimedia.org/wiki/File:%D0%A7%D0%B5%D1%88%D1%83%D0%B9%D0%BA%D0%B8_%D0%BA%D1%80%D1%8B%D0%BB%D0%B0_%D0%B1%D0%B0%D0%B1%D0%BE%D1%87%D0%BA%D0%B8.jpg) original 5k, cropped to use top right and retouched away a bright spot, now 4k.
- [Cetonia aurata take off composition (Bernie, Public Domain)](https://commons.wikimedia.org/wiki/File:Cetonia_aurata_take_off_composition_05172009.jpg) original 8k.
- [Ribbed red metal (Dejan Krsmanovic, CC BY)](https://www.flickr.com/photos/dejankrsmanovic/42971456774/) original 5k.
- [Barents bloom (European Space Agency, CC BY-SA)](https://www.esa.int/ESA_Multimedia/Images/2016/08/Barents_bloom) original 2k (its fine since the motive is blurry anyway), rotated 90° right.
- [Flippity floppity (Hannes Fritz, CC BY-SA)](http://hannes.photos/flippity-floppity) original 4k, cropped to top left (2k) so the sharp parts are not part of the photo, looks better.
- [Roulette (Hannes Fritz, CC BY-SA)](http://hannes.photos/roulette) original 4k.
- [Sea spray (Hannes Fritz, CC BY-SA)](http://hannes.photos/sea-spray) original 6k.
- [New zealand fern (Bernard Spragg, CC0)](https://commons.wikimedia.org/wiki/File:NZ_Fern.(Blechnum_chambersii)_(11263534936).jpg) original 2.5k.
- [Pink tapioca bubbles (Rawpixel, CC BY)](https://www.flickr.com/photos/byrawpixel/27665140298/in/photostream/) original 6k.
- [Waxing crescent moon (NASA, Public Domain)](https://www.nasa.gov/image-feature/a-waxing-crescent-moon)
- [Cityscape (Tommy Chau, CC BY)](https://www.flickr.com/photos/90975693@N05/16910999368) original 6k.
- [Lion rock hill (Tommy Chau, CC BY)](https://www.flickr.com/photos/90975693@N05/17136440246) original 6k.
- [Yellow bricks (Lali Masriera, CC BY)](https://www.flickr.com/photos/visualpanic/3982464447) original 4k, color modified for visibility of icons, and slightly cropped on the left so motive is centered.
## Background picture requirements
A reference to why it was very difficult to actually find good background pictures there are quite some requirements when it comes to picking:
- It needs to be an exceptionally good photo of course since when chosen, people will see it every day.
- We need to have a good balance of different motives, e.g. not too many landscape pics.
- Same for a good balance of different colors.
- The photo needs to work as a background. Photos with objects focused in the middle dont really work as they will be overlapped by the widgets anyway.
- Especially the top part cannot have too much differing contrast, as then its not possible to see the navigation icons.
- We serve the pictures at 4k resolution and most of the selected images are also available in 6k or higher so it is future-proof.
- For the search of course we had to limit to CC0, CC By and CC By-Sa. Only CC0 would have been practically impossible cause theres just not so many good ones which fit.
Background image documentation moved to theming folder at `apps/theming/README.md`.
+1 -1
View File
@@ -3,7 +3,7 @@ OC.L10N.register(
{
"Dashboard" : "Dasbor",
"Dashboard app" : "Aplikasi dasbor",
"Start your day informed\n\nThe Nextcloud Dashboard is your starting point of the day, giving you an\noverview of your upcoming appointments, urgent emails, chat messages,\nincoming tickets, latest tweets and much more! Users can add the widgets\nthey like and change the background to their liking." : "Mulai harimu sama berita\n\nDasbor Nextcloud memberi kamu ikhtisar janji temumu yang akan datang, email mendesak, pesan obrolan, tiket masuk, tweet terbaru, dan lebih banyak! Pengguna bisa tambahkan widget-widget yang mereka suka dan berubah mereka dapat mengubah latar belakang sesuai keinginan mereka.",
"Start your day informed\n\nThe Nextcloud Dashboard is your starting point of the day, giving you an\noverview of your upcoming appointments, urgent emails, chat messages,\nincoming tickets, latest tweets and much more! Users can add the widgets\nthey like and change the background to their liking." : "Mulai hari Anda sama berita\n\nDasbor Nextcloud memberi Anda ikhtisar janji temu Anda yang akan datang, surel mendesak, pesan obrolan, tiket masuk, tweet terbaru, dan lebih banyak! Pengguna bisa tambahkan widget-widget yang mereka suka dan berubah mereka dapat mengubah latar belakang sesuai keinginan mereka.",
"Customize" : "Sesuaikan",
"Edit widgets" : "Edit widget",
"Get more widgets from the App Store" : "Dapatkan lebih banyak widget dari App Store",
+1 -1
View File
@@ -1,7 +1,7 @@
{ "translations": {
"Dashboard" : "Dasbor",
"Dashboard app" : "Aplikasi dasbor",
"Start your day informed\n\nThe Nextcloud Dashboard is your starting point of the day, giving you an\noverview of your upcoming appointments, urgent emails, chat messages,\nincoming tickets, latest tweets and much more! Users can add the widgets\nthey like and change the background to their liking." : "Mulai harimu sama berita\n\nDasbor Nextcloud memberi kamu ikhtisar janji temumu yang akan datang, email mendesak, pesan obrolan, tiket masuk, tweet terbaru, dan lebih banyak! Pengguna bisa tambahkan widget-widget yang mereka suka dan berubah mereka dapat mengubah latar belakang sesuai keinginan mereka.",
"Start your day informed\n\nThe Nextcloud Dashboard is your starting point of the day, giving you an\noverview of your upcoming appointments, urgent emails, chat messages,\nincoming tickets, latest tweets and much more! Users can add the widgets\nthey like and change the background to their liking." : "Mulai hari Anda sama berita\n\nDasbor Nextcloud memberi Anda ikhtisar janji temu Anda yang akan datang, surel mendesak, pesan obrolan, tiket masuk, tweet terbaru, dan lebih banyak! Pengguna bisa tambahkan widget-widget yang mereka suka dan berubah mereka dapat mengubah latar belakang sesuai keinginan mereka.",
"Customize" : "Sesuaikan",
"Edit widgets" : "Edit widget",
"Get more widgets from the App Store" : "Dapatkan lebih banyak widget dari App Store",
@@ -310,8 +310,10 @@ return array(
'OCA\\DAV\\Traits\\PrincipalProxyTrait' => $baseDir . '/../lib/Traits/PrincipalProxyTrait.php',
'OCA\\DAV\\Upload\\AssemblyStream' => $baseDir . '/../lib/Upload/AssemblyStream.php',
'OCA\\DAV\\Upload\\ChunkingPlugin' => $baseDir . '/../lib/Upload/ChunkingPlugin.php',
'OCA\\DAV\\Upload\\ChunkingV2Plugin' => $baseDir . '/../lib/Upload/ChunkingV2Plugin.php',
'OCA\\DAV\\Upload\\CleanupService' => $baseDir . '/../lib/Upload/CleanupService.php',
'OCA\\DAV\\Upload\\FutureFile' => $baseDir . '/../lib/Upload/FutureFile.php',
'OCA\\DAV\\Upload\\PartFile' => $baseDir . '/../lib/Upload/PartFile.php',
'OCA\\DAV\\Upload\\RootCollection' => $baseDir . '/../lib/Upload/RootCollection.php',
'OCA\\DAV\\Upload\\UploadFile' => $baseDir . '/../lib/Upload/UploadFile.php',
'OCA\\DAV\\Upload\\UploadFolder' => $baseDir . '/../lib/Upload/UploadFolder.php',
@@ -325,8 +325,10 @@ class ComposerStaticInitDAV
'OCA\\DAV\\Traits\\PrincipalProxyTrait' => __DIR__ . '/..' . '/../lib/Traits/PrincipalProxyTrait.php',
'OCA\\DAV\\Upload\\AssemblyStream' => __DIR__ . '/..' . '/../lib/Upload/AssemblyStream.php',
'OCA\\DAV\\Upload\\ChunkingPlugin' => __DIR__ . '/..' . '/../lib/Upload/ChunkingPlugin.php',
'OCA\\DAV\\Upload\\ChunkingV2Plugin' => __DIR__ . '/..' . '/../lib/Upload/ChunkingV2Plugin.php',
'OCA\\DAV\\Upload\\CleanupService' => __DIR__ . '/..' . '/../lib/Upload/CleanupService.php',
'OCA\\DAV\\Upload\\FutureFile' => __DIR__ . '/..' . '/../lib/Upload/FutureFile.php',
'OCA\\DAV\\Upload\\PartFile' => __DIR__ . '/..' . '/../lib/Upload/PartFile.php',
'OCA\\DAV\\Upload\\RootCollection' => __DIR__ . '/..' . '/../lib/Upload/RootCollection.php',
'OCA\\DAV\\Upload\\UploadFile' => __DIR__ . '/..' . '/../lib/Upload/UploadFile.php',
'OCA\\DAV\\Upload\\UploadFolder' => __DIR__ . '/..' . '/../lib/Upload/UploadFolder.php',
+3
View File
@@ -72,8 +72,11 @@ OC.L10N.register(
"Where: %s" : "On: %s",
"%1$s via %2$s" : "%1$s mitjançant %2$s",
"Cancelled: %1$s" : "Cancel·lat: %1$s",
"\"%1$s\" has been canceled" : "\"%1$s\" s'ha cancel·lat",
"Re: %1$s" : "Re: %1$s",
"%1$s has responded to your invitation" : "%1$s ha respost a la teva invitació",
"Invitation: %1$s" : "Invitació: %1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s vol convidar-vos a \"%2$s\"",
"Organizer:" : "Organitzador:",
"Attendees:" : "Assistents:",
"Title:" : "Títol:",
+3
View File
@@ -70,8 +70,11 @@
"Where: %s" : "On: %s",
"%1$s via %2$s" : "%1$s mitjançant %2$s",
"Cancelled: %1$s" : "Cancel·lat: %1$s",
"\"%1$s\" has been canceled" : "\"%1$s\" s'ha cancel·lat",
"Re: %1$s" : "Re: %1$s",
"%1$s has responded to your invitation" : "%1$s ha respost a la teva invitació",
"Invitation: %1$s" : "Invitació: %1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s vol convidar-vos a \"%2$s\"",
"Organizer:" : "Organitzador:",
"Attendees:" : "Assistents:",
"Title:" : "Títol:",
+3 -1
View File
@@ -75,6 +75,8 @@ OC.L10N.register(
"\"%1$s\" has been canceled" : "„%1$s“ bylo zrušeno",
"Re: %1$s" : "Odp.: %1$s",
"%1$s has responded to your invitation" : "%1$s odpověděl(a) na vaši pozvánku",
"Invitation updated: %1$s" : "Pozvánka aktualizována: %1$s",
"%1$s updated the event \"%2$s\"" : "%1$s zaktualizoval(a) událost „%2$s",
"Invitation: %1$s" : "Pozvánka: %1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s by vás ráda pozval(a) na „%2$s“",
"Organizer:" : "Organizátor:",
@@ -129,7 +131,7 @@ OC.L10N.register(
"Could not rename part file assembled from chunks" : "Nedaří se přejmenovat částečný soubor složený ze shluků",
"Failed to write file contents: %1$s" : "Nepodařilo se zapsat obsahy souborů: %1$s",
"File not found: %1$s" : "Soubor nenalezen: %1$s",
"System is in maintenance mode." : "Na systému právě probíhá údržba.",
"System is in maintenance mode." : "Systém se právě nachází v režimu údržby.",
"Upgrade needed" : "Je třeba přejít na novější verzi",
"Your %s needs to be configured to use HTTPS in order to use CalDAV and CardDAV with iOS/macOS." : "Váš %s potřebuje být nastavený aby používal HTTPS, aby bylo možné používat CalDAV a CardDAV s iOS/macOS.",
"Configures a CalDAV account" : "Nastaví CalDAV účet",
+3 -1
View File
@@ -73,6 +73,8 @@
"\"%1$s\" has been canceled" : "„%1$s“ bylo zrušeno",
"Re: %1$s" : "Odp.: %1$s",
"%1$s has responded to your invitation" : "%1$s odpověděl(a) na vaši pozvánku",
"Invitation updated: %1$s" : "Pozvánka aktualizována: %1$s",
"%1$s updated the event \"%2$s\"" : "%1$s zaktualizoval(a) událost „%2$s",
"Invitation: %1$s" : "Pozvánka: %1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s by vás ráda pozval(a) na „%2$s“",
"Organizer:" : "Organizátor:",
@@ -127,7 +129,7 @@
"Could not rename part file assembled from chunks" : "Nedaří se přejmenovat částečný soubor složený ze shluků",
"Failed to write file contents: %1$s" : "Nepodařilo se zapsat obsahy souborů: %1$s",
"File not found: %1$s" : "Soubor nenalezen: %1$s",
"System is in maintenance mode." : "Na systému právě probíhá údržba.",
"System is in maintenance mode." : "Systém se právě nachází v režimu údržby.",
"Upgrade needed" : "Je třeba přejít na novější verzi",
"Your %s needs to be configured to use HTTPS in order to use CalDAV and CardDAV with iOS/macOS." : "Váš %s potřebuje být nastavený aby používal HTTPS, aby bylo možné používat CalDAV a CardDAV s iOS/macOS.",
"Configures a CalDAV account" : "Nastaví CalDAV účet",
+3 -1
View File
@@ -72,9 +72,11 @@ OC.L10N.register(
"Where: %s" : "Ort: %s",
"%1$s via %2$s" : "%1$s über %2$s",
"Cancelled: %1$s" : "Abgesagt: %1$s",
"\"%1$s\" has been canceled" : "\"%1$s\" wurde abgebrochen",
"\"%1$s\" has been canceled" : "\"%1$s wurde abgesagt.",
"Re: %1$s" : "Re: %1$s",
"%1$s has responded to your invitation" : "%1$s hat auf Ihre Einladung geantwortet",
"Invitation updated: %1$s" : "Einladung aktualisiert: %1$s",
"%1$s updated the event \"%2$s\"" : "%1$s hat die Veranstaltung \"%2$s\" aktualisiert",
"Invitation: %1$s" : "Einladung: %1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s möchte Sie zu \"%2$s\" einladen",
"Organizer:" : "Organisator:",
+3 -1
View File
@@ -70,9 +70,11 @@
"Where: %s" : "Ort: %s",
"%1$s via %2$s" : "%1$s über %2$s",
"Cancelled: %1$s" : "Abgesagt: %1$s",
"\"%1$s\" has been canceled" : "\"%1$s\" wurde abgebrochen",
"\"%1$s\" has been canceled" : "\"%1$s wurde abgesagt.",
"Re: %1$s" : "Re: %1$s",
"%1$s has responded to your invitation" : "%1$s hat auf Ihre Einladung geantwortet",
"Invitation updated: %1$s" : "Einladung aktualisiert: %1$s",
"%1$s updated the event \"%2$s\"" : "%1$s hat die Veranstaltung \"%2$s\" aktualisiert",
"Invitation: %1$s" : "Einladung: %1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s möchte Sie zu \"%2$s\" einladen",
"Organizer:" : "Organisator:",
+2
View File
@@ -75,6 +75,8 @@ OC.L10N.register(
"\"%1$s\" has been canceled" : "\"%1$s\" has been cancelled",
"Re: %1$s" : "Re: %1$s",
"%1$s has responded to your invitation" : "%1$s has responded to your invitation",
"Invitation updated: %1$s" : "Invitation updated: %1$s",
"%1$s updated the event \"%2$s\"" : "%1$s updated the event \"%2$s\"",
"Invitation: %1$s" : "Invitation: %1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s would like to invite you to \"%2$s\"",
"Organizer:" : "Organiser:",
+2
View File
@@ -73,6 +73,8 @@
"\"%1$s\" has been canceled" : "\"%1$s\" has been cancelled",
"Re: %1$s" : "Re: %1$s",
"%1$s has responded to your invitation" : "%1$s has responded to your invitation",
"Invitation updated: %1$s" : "Invitation updated: %1$s",
"%1$s updated the event \"%2$s\"" : "%1$s updated the event \"%2$s\"",
"Invitation: %1$s" : "Invitation: %1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s would like to invite you to \"%2$s\"",
"Organizer:" : "Organiser:",
+3 -1
View File
@@ -75,6 +75,8 @@ OC.L10N.register(
"\"%1$s\" has been canceled" : "\"%1$s\" a été annulé(e)",
"Re: %1$s" : "Re : %1$s",
"%1$s has responded to your invitation" : "%1$s a répondu à votre invitation",
"Invitation updated: %1$s" : "Invitation mise à jour : %1$s",
"%1$s updated the event \"%2$s\"" : "%1$s a mis à jour l'évènement %2$s",
"Invitation: %1$s" : "Invitation : %1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s souhaite vous inviter à \"%2$s\"",
"Organizer:" : "Organisateur :",
@@ -85,7 +87,7 @@ OC.L10N.register(
"Link:" : "Lien :",
"Accept" : "Accepter",
"Decline" : "Refuser",
"More options …" : "Plus d'options …",
"More options …" : "Plus d'options…",
"More options at %s" : "Plus d'options à %s",
"Contacts" : "Contacts",
"{actor} created address book {addressbook}" : "{actor} a créé le carnet d'adresses {addressbook}",
+3 -1
View File
@@ -73,6 +73,8 @@
"\"%1$s\" has been canceled" : "\"%1$s\" a été annulé(e)",
"Re: %1$s" : "Re : %1$s",
"%1$s has responded to your invitation" : "%1$s a répondu à votre invitation",
"Invitation updated: %1$s" : "Invitation mise à jour : %1$s",
"%1$s updated the event \"%2$s\"" : "%1$s a mis à jour l'évènement %2$s",
"Invitation: %1$s" : "Invitation : %1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s souhaite vous inviter à \"%2$s\"",
"Organizer:" : "Organisateur :",
@@ -83,7 +85,7 @@
"Link:" : "Lien :",
"Accept" : "Accepter",
"Decline" : "Refuser",
"More options …" : "Plus d'options …",
"More options …" : "Plus d'options…",
"More options at %s" : "Plus d'options à %s",
"Contacts" : "Contacts",
"{actor} created address book {addressbook}" : "{actor} a créé le carnet d'adresses {addressbook}",
+1 -1
View File
@@ -173,7 +173,7 @@ OC.L10N.register(
"Notifications are sent via background jobs, so these must occur often enough." : "As notificacións enviaranse mediante procesos en segundo plano, polo que estes teñen que suceder con frecuencia.",
"Send reminder notifications to calendar sharees as well" : "Envía notificacións de recordatorio tamén aos que comparten calendario",
"Reminders are always sent to organizers and attendees." : "Os recordatorios sempre se envían aos organizadores e aos asistentes.",
"Enable notifications for events via push" : "Activar o envío de notificacións do servidor para eventos",
"Enable notifications for events via push" : "Activar o envío de notificacións do automáticas para eventos",
"Also install the {calendarappstoreopen}Calendar app{linkclose}, or {calendardocopen}connect your desktop & mobile for syncing ↗{linkclose}." : "Instale tamén a {calendarappstoreopen}aplicación do Calendario{linkclose} ou {calendardocopen}conecte os seus escritorio e móbil para sincronizalos ↗{linkclose}.",
"Please make sure to properly set up {emailopen}the email server{linkclose}." : "Asegúrese de ter configurado correctamente {emailopen}o servidor de correo-e{linkclose}.",
"There was an error updating your attendance status." : "Produciuse un erro ao actualizar o seu estado de asistencia.",
+1 -1
View File
@@ -171,7 +171,7 @@
"Notifications are sent via background jobs, so these must occur often enough." : "As notificacións enviaranse mediante procesos en segundo plano, polo que estes teñen que suceder con frecuencia.",
"Send reminder notifications to calendar sharees as well" : "Envía notificacións de recordatorio tamén aos que comparten calendario",
"Reminders are always sent to organizers and attendees." : "Os recordatorios sempre se envían aos organizadores e aos asistentes.",
"Enable notifications for events via push" : "Activar o envío de notificacións do servidor para eventos",
"Enable notifications for events via push" : "Activar o envío de notificacións do automáticas para eventos",
"Also install the {calendarappstoreopen}Calendar app{linkclose}, or {calendardocopen}connect your desktop & mobile for syncing ↗{linkclose}." : "Instale tamén a {calendarappstoreopen}aplicación do Calendario{linkclose} ou {calendardocopen}conecte os seus escritorio e móbil para sincronizalos ↗{linkclose}.",
"Please make sure to properly set up {emailopen}the email server{linkclose}." : "Asegúrese de ter configurado correctamente {emailopen}o servidor de correo-e{linkclose}.",
"There was an error updating your attendance status." : "Produciuse un erro ao actualizar o seu estado de asistencia.",
+20
View File
@@ -72,8 +72,13 @@ OC.L10N.register(
"Where: %s" : "Где: %s",
"%1$s via %2$s" : "%1$s через %2$s",
"Cancelled: %1$s" : "Событие отменено: %1$s",
"\"%1$s\" has been canceled" : "Событие «%1$s» отменено",
"Re: %1$s" : "Re: %1$s",
"%1$s has responded to your invitation" : "%1$s ответил(а) на ваше приглашение",
"Invitation updated: %1$s" : "Изменение приглашения: %1$s",
"%1$s updated the event \"%2$s\"" : "%1$s изменил(а) событие «%2$s»",
"Invitation: %1$s" : "Приглашение: %1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s приглашает вас принять участие в событии «%2$s»",
"Organizer:" : "Организатор:",
"Attendees:" : "Участники:",
"Title:" : "Название:",
@@ -110,11 +115,20 @@ OC.L10N.register(
"You updated contact {card} in address book {addressbook}" : "Вы изменили запись {card} в адресной книге {addressbook}",
"A <strong>contact</strong> or <strong>address book</strong> was modified" : "Изменение <strong>контакта</strong> или <strong>адресной книги</strong>",
"File is not updatable: %1$s" : "Файл не подлежит обновлению: %1$s",
"Could not write to final file, canceled by hook" : "Не удалось записать результирующий файл, запись отменена вызовом обработчика",
"Could not write file contents" : "Не удалось записать содержимое файла",
"_%n byte_::_%n bytes_" : ["%n байт","%n байта","%n байт","%n байта"],
"Error while copying file to target location (copied: %1$s, expected filesize: %2$s)" : "Ошибка при копировании в целевое расположение, скопировано: %1$s, ожидаемый размер файла: %2$s",
"Expected filesize of %1$s but read (from Nextcloud client) and wrote (to Nextcloud storage) %2$s. Could either be a network problem on the sending side or a problem writing to the storage on the server side." : "Ожидаемый размер файла составляет %1$s, но из клиента приложения Nextcloud было прочитано и записано в хранилище %2$s. К этому могла привести ошибка при передаче данных на стороне отправителя либо проблема в подсистеме хранения данных на стороне сервера.",
"Could not rename part file to final file, canceled by hook" : "Не удалось переименовать временный файл в результирующий, операция отменена вызовом обработчика",
"Could not rename part file to final file" : "Не удалось переименовать временный файл в результирующий",
"Failed to check file size: %1$s" : "Не удалось проверить размер файла: %1$s",
"Could not open file" : "Не удалось открыть файл",
"Encryption not ready: %1$s" : "Подсистема шифрования не готова: %1$s",
"Failed to open file: %1$s" : "Не удалось открыть файл: %1$s",
"Failed to unlink: %1$s" : "Не удалось разорвать связь: %1$s",
"Invalid chunk name" : "Недопустимое имя сегмента",
"Could not rename part file assembled from chunks" : "Не удалось переименовать временный файл, сформированный из сегментов",
"Failed to write file contents: %1$s" : "Не удалось записать содержимое файла: %1$s",
"File not found: %1$s" : "Файл не найден: %1$s",
"System is in maintenance mode." : "Сервер находится в режиме обслуживания.",
@@ -128,6 +142,7 @@ OC.L10N.register(
"Completed on %s" : "Завершено %s",
"Due on %s by %s" : "До %s %s",
"Due on %s" : "До %s",
"Migrated calendar (%1$s)" : "Перенос календаря (%1$s)",
"Calendars including events, details and attendees" : "Календари, в том числе события, подробные сведения и участники",
"Contacts and groups" : "Контакты и группы",
"WebDAV" : "WebDAV",
@@ -146,8 +161,11 @@ OC.L10N.register(
"Friday" : "Пятница",
"Saturday" : "Суббота",
"Sunday" : "Воскресенье",
"Automatically set user status to \"Do not disturb\" outside of availability to mute all notifications." : "Автоматически изменять статус на «Не беспокоить» вне интервала доступности для отключения уведомлений.",
"Save" : "Сохранить",
"Failed to load availability" : "Не удалось получить сведения о доступности",
"Saved availability" : "Сведения о доступности сохранены",
"Failed to save availability" : "Не удалось сохранить сведения о доступности",
"Calendar server" : "Сервер календаря",
"Send invitations to attendees" : "Отправить приглашения",
"Automatically generate a birthday calendar" : "Создавать календарь дней рождения автоматически",
@@ -155,6 +173,8 @@ OC.L10N.register(
"Hence they will not be available immediately after enabling but will show up after some time." : "И поэтому они станут доступны не моментально, а через некоторое время.",
"Send notifications for events" : "Отправлять уведомления о событиях",
"Notifications are sent via background jobs, so these must occur often enough." : "Уведомления будут отправляться через фоновые задания, поэтому они должны выполняться достаточно часто.",
"Send reminder notifications to calendar sharees as well" : "Отправлять напоминания всем пользователям, имеющим доступ к календарю",
"Reminders are always sent to organizers and attendees." : "Организаторам и участникам уведомления отправляются во всех случаях.",
"Enable notifications for events via push" : "Включить уведомления о событиях с помощью push",
"Also install the {calendarappstoreopen}Calendar app{linkclose}, or {calendardocopen}connect your desktop & mobile for syncing ↗{linkclose}." : "Также установите {calendarappstoreopen}приложение Calendar{linkclose}, или {calendardocopen}подключите ваш ПК и мобильное устройство для синхронизации ↗{linkclose}.",
"Please make sure to properly set up {emailopen}the email server{linkclose}." : "Проверьте правильность настройки {emailopen}почтового сервера{linkclose}.",
+20
View File
@@ -70,8 +70,13 @@
"Where: %s" : "Где: %s",
"%1$s via %2$s" : "%1$s через %2$s",
"Cancelled: %1$s" : "Событие отменено: %1$s",
"\"%1$s\" has been canceled" : "Событие «%1$s» отменено",
"Re: %1$s" : "Re: %1$s",
"%1$s has responded to your invitation" : "%1$s ответил(а) на ваше приглашение",
"Invitation updated: %1$s" : "Изменение приглашения: %1$s",
"%1$s updated the event \"%2$s\"" : "%1$s изменил(а) событие «%2$s»",
"Invitation: %1$s" : "Приглашение: %1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s приглашает вас принять участие в событии «%2$s»",
"Organizer:" : "Организатор:",
"Attendees:" : "Участники:",
"Title:" : "Название:",
@@ -108,11 +113,20 @@
"You updated contact {card} in address book {addressbook}" : "Вы изменили запись {card} в адресной книге {addressbook}",
"A <strong>contact</strong> or <strong>address book</strong> was modified" : "Изменение <strong>контакта</strong> или <strong>адресной книги</strong>",
"File is not updatable: %1$s" : "Файл не подлежит обновлению: %1$s",
"Could not write to final file, canceled by hook" : "Не удалось записать результирующий файл, запись отменена вызовом обработчика",
"Could not write file contents" : "Не удалось записать содержимое файла",
"_%n byte_::_%n bytes_" : ["%n байт","%n байта","%n байт","%n байта"],
"Error while copying file to target location (copied: %1$s, expected filesize: %2$s)" : "Ошибка при копировании в целевое расположение, скопировано: %1$s, ожидаемый размер файла: %2$s",
"Expected filesize of %1$s but read (from Nextcloud client) and wrote (to Nextcloud storage) %2$s. Could either be a network problem on the sending side or a problem writing to the storage on the server side." : "Ожидаемый размер файла составляет %1$s, но из клиента приложения Nextcloud было прочитано и записано в хранилище %2$s. К этому могла привести ошибка при передаче данных на стороне отправителя либо проблема в подсистеме хранения данных на стороне сервера.",
"Could not rename part file to final file, canceled by hook" : "Не удалось переименовать временный файл в результирующий, операция отменена вызовом обработчика",
"Could not rename part file to final file" : "Не удалось переименовать временный файл в результирующий",
"Failed to check file size: %1$s" : "Не удалось проверить размер файла: %1$s",
"Could not open file" : "Не удалось открыть файл",
"Encryption not ready: %1$s" : "Подсистема шифрования не готова: %1$s",
"Failed to open file: %1$s" : "Не удалось открыть файл: %1$s",
"Failed to unlink: %1$s" : "Не удалось разорвать связь: %1$s",
"Invalid chunk name" : "Недопустимое имя сегмента",
"Could not rename part file assembled from chunks" : "Не удалось переименовать временный файл, сформированный из сегментов",
"Failed to write file contents: %1$s" : "Не удалось записать содержимое файла: %1$s",
"File not found: %1$s" : "Файл не найден: %1$s",
"System is in maintenance mode." : "Сервер находится в режиме обслуживания.",
@@ -126,6 +140,7 @@
"Completed on %s" : "Завершено %s",
"Due on %s by %s" : "До %s %s",
"Due on %s" : "До %s",
"Migrated calendar (%1$s)" : "Перенос календаря (%1$s)",
"Calendars including events, details and attendees" : "Календари, в том числе события, подробные сведения и участники",
"Contacts and groups" : "Контакты и группы",
"WebDAV" : "WebDAV",
@@ -144,8 +159,11 @@
"Friday" : "Пятница",
"Saturday" : "Суббота",
"Sunday" : "Воскресенье",
"Automatically set user status to \"Do not disturb\" outside of availability to mute all notifications." : "Автоматически изменять статус на «Не беспокоить» вне интервала доступности для отключения уведомлений.",
"Save" : "Сохранить",
"Failed to load availability" : "Не удалось получить сведения о доступности",
"Saved availability" : "Сведения о доступности сохранены",
"Failed to save availability" : "Не удалось сохранить сведения о доступности",
"Calendar server" : "Сервер календаря",
"Send invitations to attendees" : "Отправить приглашения",
"Automatically generate a birthday calendar" : "Создавать календарь дней рождения автоматически",
@@ -153,6 +171,8 @@
"Hence they will not be available immediately after enabling but will show up after some time." : "И поэтому они станут доступны не моментально, а через некоторое время.",
"Send notifications for events" : "Отправлять уведомления о событиях",
"Notifications are sent via background jobs, so these must occur often enough." : "Уведомления будут отправляться через фоновые задания, поэтому они должны выполняться достаточно часто.",
"Send reminder notifications to calendar sharees as well" : "Отправлять напоминания всем пользователям, имеющим доступ к календарю",
"Reminders are always sent to organizers and attendees." : "Организаторам и участникам уведомления отправляются во всех случаях.",
"Enable notifications for events via push" : "Включить уведомления о событиях с помощью push",
"Also install the {calendarappstoreopen}Calendar app{linkclose}, or {calendardocopen}connect your desktop & mobile for syncing ↗{linkclose}." : "Также установите {calendarappstoreopen}приложение Calendar{linkclose}, или {calendardocopen}подключите ваш ПК и мобильное устройство для синхронизации ↗{linkclose}.",
"Please make sure to properly set up {emailopen}the email server{linkclose}." : "Проверьте правильность настройки {emailopen}почтового сервера{linkclose}.",
+2
View File
@@ -75,6 +75,8 @@ OC.L10N.register(
"\"%1$s\" has been canceled" : "„%1$s” је отказано",
"Re: %1$s" : "Одг: %1$s",
"%1$s has responded to your invitation" : "%1$s је одговорио на вашу позивницу",
"Invitation updated: %1$s" : "Позивница је ажурирана: %1$s",
"%1$s updated the event \"%2$s\"" : "%1$s је ажурирао догађај „%2$s”",
"Invitation: %1$s" : "Позивница: %1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s жели да вас позове на „%2$s",
"Organizer:" : "Организатор:",
+2
View File
@@ -73,6 +73,8 @@
"\"%1$s\" has been canceled" : "„%1$s” је отказано",
"Re: %1$s" : "Одг: %1$s",
"%1$s has responded to your invitation" : "%1$s је одговорио на вашу позивницу",
"Invitation updated: %1$s" : "Позивница је ажурирана: %1$s",
"%1$s updated the event \"%2$s\"" : "%1$s је ажурирао догађај „%2$s”",
"Invitation: %1$s" : "Позивница: %1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s жели да вас позове на „%2$s",
"Organizer:" : "Организатор:",
+2
View File
@@ -75,6 +75,8 @@ OC.L10N.register(
"\"%1$s\" has been canceled" : "\"%1$s\" har avbrutits",
"Re: %1$s" : "Sv: %1$s",
"%1$s has responded to your invitation" : "%1$s har svarat på din inbjudan",
"Invitation updated: %1$s" : "Inbjudan uppdaterad: %1$s",
"%1$s updated the event \"%2$s\"" : "%1$s uppdaterade händelse \"%2$s\"",
"Invitation: %1$s" : "Inbjudan: %1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s skulle vilja bjuda in dig till \"%2$s\"",
"Organizer:" : "Arrangör:",
+2
View File
@@ -73,6 +73,8 @@
"\"%1$s\" has been canceled" : "\"%1$s\" har avbrutits",
"Re: %1$s" : "Sv: %1$s",
"%1$s has responded to your invitation" : "%1$s har svarat på din inbjudan",
"Invitation updated: %1$s" : "Inbjudan uppdaterad: %1$s",
"%1$s updated the event \"%2$s\"" : "%1$s uppdaterade händelse \"%2$s\"",
"Invitation: %1$s" : "Inbjudan: %1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s skulle vilja bjuda in dig till \"%2$s\"",
"Organizer:" : "Arrangör:",
+2
View File
@@ -75,6 +75,8 @@ OC.L10N.register(
"\"%1$s\" has been canceled" : "\"%1$s\" iptal edildi",
"Re: %1$s" : "Ynt: %1$s",
"%1$s has responded to your invitation" : "%1$s çağrınızı yanıtladı",
"Invitation updated: %1$s" : "Çağrı güncellendi: %1$s",
"%1$s updated the event \"%2$s\"" : "%1$s, \"%2$s\" etkinliğini güncelledi",
"Invitation: %1$s" : "Çağrı: %1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s, size \"%2$s\" için çağrı gönderdi",
"Organizer:" : "Düzenleyen:",
+2
View File
@@ -73,6 +73,8 @@
"\"%1$s\" has been canceled" : "\"%1$s\" iptal edildi",
"Re: %1$s" : "Ynt: %1$s",
"%1$s has responded to your invitation" : "%1$s çağrınızı yanıtladı",
"Invitation updated: %1$s" : "Çağrı güncellendi: %1$s",
"%1$s updated the event \"%2$s\"" : "%1$s, \"%2$s\" etkinliğini güncelledi",
"Invitation: %1$s" : "Çağrı: %1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s, size \"%2$s\" için çağrı gönderdi",
"Organizer:" : "Düzenleyen:",
+2
View File
@@ -75,6 +75,8 @@ OC.L10N.register(
"\"%1$s\" has been canceled" : "\"%1$s\" 已被取消",
"Re: %1$s" : "關於: %1$s",
"%1$s has responded to your invitation" : "%1$s 已回應您的邀請",
"Invitation updated: %1$s" : "邀請已更新︰%1$s",
"%1$s updated the event \"%2$s\"" : "%1$s 已更新了活動 \"%2$s\"",
"Invitation: %1$s" : "邀請:%1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s 想邀請您加入“%2$s”",
"Organizer:" : "主辦單位:",
+2
View File
@@ -73,6 +73,8 @@
"\"%1$s\" has been canceled" : "\"%1$s\" 已被取消",
"Re: %1$s" : "關於: %1$s",
"%1$s has responded to your invitation" : "%1$s 已回應您的邀請",
"Invitation updated: %1$s" : "邀請已更新︰%1$s",
"%1$s updated the event \"%2$s\"" : "%1$s 已更新了活動 \"%2$s\"",
"Invitation: %1$s" : "邀請:%1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s 想邀請您加入“%2$s”",
"Organizer:" : "主辦單位:",
+2
View File
@@ -75,6 +75,8 @@ OC.L10N.register(
"\"%1$s\" has been canceled" : "「%1$s」已取消",
"Re: %1$s" : "回覆:%1$s",
"%1$s has responded to your invitation" : "%1$s 已回應您的邀請",
"Invitation updated: %1$s" : "邀請已更新:%1$s",
"%1$s updated the event \"%2$s\"" : "%1$s 已更新事件:「%2$s」",
"Invitation: %1$s" : "邀請:%1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s 想邀請您加入「%2$s」",
"Organizer:" : "組織者:",
+2
View File
@@ -73,6 +73,8 @@
"\"%1$s\" has been canceled" : "「%1$s」已取消",
"Re: %1$s" : "回覆:%1$s",
"%1$s has responded to your invitation" : "%1$s 已回應您的邀請",
"Invitation updated: %1$s" : "邀請已更新:%1$s",
"%1$s updated the event \"%2$s\"" : "%1$s 已更新事件:「%2$s」",
"Invitation: %1$s" : "邀請:%1$s",
"%1$s would like to invite you to \"%2$s\"" : "%1$s 想邀請您加入「%2$s」",
"Organizer:" : "組織者:",
@@ -92,7 +92,7 @@ class UserStatusAutomation extends TimedJob {
$isCurrentlyAvailable = false;
$nextPotentialToggles = [];
$now = new \DateTime('now');
$now = $this->time->getDateTime();
$lastMidnight = (clone $now)->setTime(0, 0);
$vObject = Reader::read($property);
@@ -105,9 +105,16 @@ class UserStatusAutomation extends TimedJob {
foreach ($availables as $available) {
/** @var Available $available */
if ($available->name === 'AVAILABLE') {
/** @var \DateTimeInterface $effectiveStart */
/** @var \DateTimeInterface $effectiveEnd */
[$effectiveStart, $effectiveEnd] = $available->getEffectiveStartEnd();
/** @var \DateTimeImmutable $originalStart */
/** @var \DateTimeImmutable $originalEnd */
[$originalStart, $originalEnd] = $available->getEffectiveStartEnd();
// Little shenanigans to fix the automation on the day the rules were adjusted
// Otherwise the $originalStart would match rules for Thursdays on a Friday, etc.
// So we simply wind back a week and then fastForward to the next occurrence
// since today's midnight, which then also accounts for the week days.
$effectiveStart = \DateTime::createFromImmutable($originalStart)->sub(new \DateInterval('P7D'));
$effectiveEnd = \DateTime::createFromImmutable($originalEnd)->sub(new \DateInterval('P7D'));
try {
$it = new RRuleIterator((string) $available->RRULE, $effectiveStart);
@@ -139,12 +146,21 @@ class UserStatusAutomation extends TimedJob {
}
}
if (empty($nextPotentialToggles)) {
$this->logger->info('Removing ' . self::class . ' background job for user "' . $userId . '" because the user has no valid availability rules set');
$this->jobList->remove(self::class, $argument);
$this->manager->revertUserStatus($userId, IUserStatus::MESSAGE_AVAILABILITY, IUserStatus::DND);
return;
}
$nextAutomaticToggle = min($nextPotentialToggles);
$this->setLastRunToNextToggleTime($userId, $nextAutomaticToggle - 1);
if ($isCurrentlyAvailable) {
$this->logger->debug('User is currently available, reverting DND status if applicable');
$this->manager->revertUserStatus($userId, IUserStatus::MESSAGE_AVAILABILITY, IUserStatus::DND);
} else {
$this->logger->debug('User is currently NOT available, reverting call status if applicable and then setting DND');
// The DND status automation is more important than the "Away - In call" so we also restore that one if it exists.
$this->manager->revertUserStatus($userId, IUserStatus::MESSAGE_CALL, IUserStatus::AWAY);
$this->manager->setUserStatus($userId, IUserStatus::MESSAGE_AVAILABILITY, IUserStatus::DND, true);
+8 -4
View File
@@ -35,10 +35,10 @@ namespace OCA\DAV\Connector\Sabre;
use OC\Files\Mount\MoveableMount;
use OC\Files\View;
use OC\Metadata\FileMetadata;
use OC\Metadata\MetadataGroup;
use OCA\DAV\Connector\Sabre\Exception\FileLocked;
use OCA\DAV\Connector\Sabre\Exception\Forbidden;
use OCA\DAV\Connector\Sabre\Exception\InvalidPath;
use OCA\DAV\Upload\FutureFile;
use OCP\Files\FileInfo;
use OCP\Files\Folder;
use OCP\Files\ForbiddenException;
@@ -57,7 +57,6 @@ use Sabre\DAV\INode;
use OCP\Share\IManager as IShareManager;
class Directory extends \OCA\DAV\Connector\Sabre\Node implements \Sabre\DAV\ICollection, \Sabre\DAV\IQuota, \Sabre\DAV\IMoveTarget, \Sabre\DAV\ICopyTarget {
/**
* Cached directory content
* @var \OCP\Files\FileInfo[]
@@ -116,7 +115,6 @@ class Directory extends \OCA\DAV\Connector\Sabre\Node implements \Sabre\DAV\ICol
// for chunked upload also updating a existing file is a "createFile"
// because we create all the chunks before re-assemble them to the existing file.
if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
// exit if we can't create a new file and we don't updatable existing file
$chunkInfo = \OC_FileChunking::decodeName($name);
if (!$this->fileView->isCreatable($this->path) &&
@@ -328,8 +326,14 @@ class Directory extends \OCA\DAV\Connector\Sabre\Node implements \Sabre\DAV\ICol
if ($this->quotaInfo) {
return $this->quotaInfo;
}
$relativePath = $this->fileView->getRelativePath($this->info->getPath());
if ($relativePath === null) {
$logger->warning("error while getting quota as the relative path cannot be found");
return [0, 0];
}
try {
$storageInfo = \OC_Helper::getStorageInfo($this->info->getPath(), $this->info, false);
$storageInfo = \OC_Helper::getStorageInfo($relativePath, $this->info, false);
if ($storageInfo['quota'] === \OCP\Files\FileInfo::SPACE_UNLIMITED) {
$free = \OCP\Files\FileInfo::SPACE_UNLIMITED;
} else {
+4
View File
@@ -261,6 +261,10 @@ abstract class Node implements \Sabre\DAV\INode {
return $this->info->getId();
}
public function getInternalPath(): string {
return $this->info->getInternalPath();
}
/**
* @param string $user
* @return int
@@ -110,6 +110,7 @@ class SharesPlugin extends \Sabre\DAV\ServerPlugin {
IShare::TYPE_ROOM,
IShare::TYPE_CIRCLE,
IShare::TYPE_DECK,
IShare::TYPE_SCIENCEMESH,
];
foreach ($requestedShareTypes as $requestedShareType) {
$shares = $this->shareManager->getSharesBy(
+3
View File
@@ -71,9 +71,11 @@ use OCA\DAV\Profiler\ProfilerPlugin;
use OCA\DAV\Provisioning\Apple\AppleProvisioningPlugin;
use OCA\DAV\SystemTag\SystemTagPlugin;
use OCA\DAV\Upload\ChunkingPlugin;
use OCA\DAV\Upload\ChunkingV2Plugin;
use OCP\AppFramework\Http\Response;
use OCP\Diagnostics\IEventLogger;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\ICacheFactory;
use OCP\IRequest;
use OCP\Profiler\IProfiler;
use OCP\SabrePluginEvent;
@@ -218,6 +220,7 @@ class Server {
$this->server->addPlugin(new CopyEtagHeaderPlugin());
$this->server->addPlugin(new RequestIdHeaderPlugin(\OC::$server->get(IRequest::class)));
$this->server->addPlugin(new ChunkingV2Plugin(\OCP\Server::get(ICacheFactory::class)));
$this->server->addPlugin(new ChunkingPlugin());
// allow setup of additional plugins
+392
View File
@@ -0,0 +1,392 @@
<?php
declare(strict_types=1);
/*
* @copyright Copyright (c) 2021 Julius Härtl <jus@bitgrid.net>
*
* @author Julius Härtl <jus@bitgrid.net>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\DAV\Upload;
use Exception;
use InvalidArgumentException;
use OC\Files\Filesystem;
use OC\Files\ObjectStore\ObjectStoreStorage;
use OC\Files\View;
use OC_Hook;
use OCA\DAV\Connector\Sabre\Directory;
use OCA\DAV\Connector\Sabre\File;
use OCP\Files\IMimeTypeDetector;
use OCP\Files\IRootFolder;
use OCP\Files\ObjectStore\IObjectStoreMultiPartUpload;
use OCP\Files\Storage\IChunkedFileWrite;
use OCP\Files\StorageInvalidException;
use OCP\ICache;
use OCP\ICacheFactory;
use OCP\Lock\ILockingProvider;
use Sabre\DAV\Exception\BadRequest;
use Sabre\DAV\Exception\InsufficientStorage;
use Sabre\DAV\Exception\NotFound;
use Sabre\DAV\Exception\PreconditionFailed;
use Sabre\DAV\ICollection;
use Sabre\DAV\INode;
use Sabre\DAV\Server;
use Sabre\DAV\ServerPlugin;
use Sabre\HTTP\RequestInterface;
use Sabre\HTTP\ResponseInterface;
use Sabre\Uri;
class ChunkingV2Plugin extends ServerPlugin {
/** @var Server */
private $server;
/** @var UploadFolder */
private $uploadFolder;
/** @var ICache */
private $cache;
private ?string $uploadId = null;
private ?string $uploadPath = null;
private const TEMP_TARGET = '.target';
public const CACHE_KEY = 'chunking-v2';
public const UPLOAD_TARGET_PATH = 'upload-target-path';
public const UPLOAD_TARGET_ID = 'upload-target-id';
public const UPLOAD_ID = 'upload-id';
private const DESTINATION_HEADER = 'Destination';
public function __construct(ICacheFactory $cacheFactory) {
$this->cache = $cacheFactory->createDistributed(self::CACHE_KEY);
}
/**
* @inheritdoc
*/
public function initialize(Server $server) {
$server->on('afterMethod:MKCOL', [$this, 'afterMkcol']);
$server->on('beforeMethod:PUT', [$this, 'beforePut']);
$server->on('beforeMethod:DELETE', [$this, 'beforeDelete']);
$server->on('beforeMove', [$this, 'beforeMove'], 90);
$this->server = $server;
}
/**
* @param string $path
* @param bool $createIfNotExists
* @return FutureFile|UploadFile|ICollection|INode
*/
private function getUploadFile(string $path, bool $createIfNotExists = false) {
try {
$actualFile = $this->server->tree->getNodeForPath($path);
// Only directly upload to the target file if it is on the same storage
// There may be further potential to optimize here by also uploading
// to other storages directly. This would require to also carefully pick
// the storage/path used in getStorage()
if ($actualFile instanceof File && $this->uploadFolder->getStorage()->getId() === $actualFile->getNode()->getStorage()->getId()) {
return $actualFile;
}
} catch (NotFound $e) {
// If there is no target file we upload to the upload folder first
}
// Use file in the upload directory that will be copied or moved afterwards
if ($createIfNotExists) {
$this->uploadFolder->createFile(self::TEMP_TARGET);
}
/** @var UploadFile $uploadFile */
$uploadFile = $this->uploadFolder->getChild(self::TEMP_TARGET);
return $uploadFile->getFile();
}
public function afterMkcol(RequestInterface $request, ResponseInterface $response): bool {
try {
$this->prepareUpload($request->getPath());
$this->checkPrerequisites(false);
} catch (BadRequest|StorageInvalidException|NotFound $e) {
return true;
}
$this->uploadPath = $this->server->calculateUri($this->server->httpRequest->getHeader(self::DESTINATION_HEADER));
$targetFile = $this->getUploadFile($this->uploadPath, true);
[$storage, $storagePath] = $this->getUploadStorage($this->uploadPath);
$this->uploadId = $storage->startChunkedWrite($storagePath);
$this->cache->set($this->uploadFolder->getName(), [
self::UPLOAD_ID => $this->uploadId,
self::UPLOAD_TARGET_PATH => $this->uploadPath,
self::UPLOAD_TARGET_ID => $targetFile->getId(),
], 86400);
$response->setStatus(201);
return true;
}
public function beforePut(RequestInterface $request, ResponseInterface $response): bool {
try {
$this->prepareUpload(dirname($request->getPath()));
$this->checkPrerequisites();
} catch (StorageInvalidException|BadRequest|NotFound $e) {
return true;
}
[$storage, $storagePath] = $this->getUploadStorage($this->uploadPath);
$chunkName = basename($request->getPath());
$partId = is_numeric($chunkName) ? (int)$chunkName : -1;
if (!($partId >= 1 && $partId <= 10000)) {
throw new BadRequest('Invalid chunk name, must be numeric between 1 and 10000');
}
$uploadFile = $this->getUploadFile($this->uploadPath);
$tempTargetFile = null;
$additionalSize = (int)$request->getHeader('Content-Length');
if ($this->uploadFolder->childExists(self::TEMP_TARGET) && $this->uploadPath) {
/** @var UploadFile $tempTargetFile */
$tempTargetFile = $this->uploadFolder->getChild(self::TEMP_TARGET);
[$destinationDir, $destinationName] = Uri\split($this->uploadPath);
/** @var Directory $destinationParent */
$destinationParent = $this->server->tree->getNodeForPath($destinationDir);
$free = $storage->free_space($destinationParent->getInternalPath());
$newSize = $tempTargetFile->getSize() + $additionalSize;
if ($free >= 0 && ($tempTargetFile->getSize() > $free || $newSize > $free)) {
throw new InsufficientStorage("Insufficient space in $this->uploadPath");
}
}
$stream = $request->getBodyAsStream();
$storage->putChunkedWritePart($storagePath, $this->uploadId, (string)$partId, $stream, $additionalSize);
$storage->getCache()->update($uploadFile->getId(), ['size' => $uploadFile->getSize() + $additionalSize]);
if ($tempTargetFile) {
$storage->getPropagator()->propagateChange($tempTargetFile->getInternalPath(), time(), $additionalSize);
}
$response->setStatus(201);
return false;
}
public function beforeMove($sourcePath, $destination): bool {
try {
$this->prepareUpload(dirname($sourcePath));
$this->checkPrerequisites();
} catch (StorageInvalidException|BadRequest|NotFound|PreconditionFailed $e) {
return true;
}
[$storage, $storagePath] = $this->getUploadStorage($this->uploadPath);
$targetFile = $this->getUploadFile($this->uploadPath);
[$destinationDir, $destinationName] = Uri\split($destination);
/** @var Directory $destinationParent */
$destinationParent = $this->server->tree->getNodeForPath($destinationDir);
$destinationExists = $destinationParent->childExists($destinationName);
// allow sync clients to send the modification and creation time along in a header
$updateFileInfo = [];
if ($this->server->httpRequest->getHeader('X-OC-MTime') !== null) {
$updateFileInfo['mtime'] = $this->sanitizeMtime($this->server->httpRequest->getHeader('X-OC-MTime'));
$this->server->httpResponse->setHeader('X-OC-MTime', 'accepted');
}
if ($this->server->httpRequest->getHeader('X-OC-CTime') !== null) {
$updateFileInfo['creation_time'] = $this->sanitizeMtime($this->server->httpRequest->getHeader('X-OC-CTime'));
$this->server->httpResponse->setHeader('X-OC-CTime', 'accepted');
}
$updateFileInfo['mimetype'] = \OCP\Server::get(IMimeTypeDetector::class)->detectPath($destinationName);
if ($storage->instanceOfStorage(ObjectStoreStorage::class) && $storage->getObjectStore() instanceof IObjectStoreMultiPartUpload) {
/** @var ObjectStoreStorage $storage */
/** @var IObjectStoreMultiPartUpload $objectStore */
$objectStore = $storage->getObjectStore();
$parts = $objectStore->getMultipartUploads($storage->getURN($targetFile->getId()), $this->uploadId);
$size = 0;
foreach ($parts as $part) {
$size += $part['Size'];
}
$free = $storage->free_space($destinationParent->getInternalPath());
if ($free >= 0 && ($size > $free)) {
throw new InsufficientStorage("Insufficient space in $this->uploadPath");
}
}
$destinationInView = $destinationParent->getFileInfo()->getPath() . '/' . $destinationName;
$this->completeChunkedWrite($destinationInView);
$rootView = new View();
$rootView->putFileInfo($destinationInView, $updateFileInfo);
$sourceNode = $this->server->tree->getNodeForPath($sourcePath);
if ($sourceNode instanceof FutureFile) {
$this->uploadFolder->delete();
}
$this->server->emit('afterMove', [$sourcePath, $destination]);
$this->server->emit('afterUnbind', [$sourcePath]);
$this->server->emit('afterBind', [$destination]);
$response = $this->server->httpResponse;
$response->setHeader('Content-Type', 'application/xml; charset=utf-8');
$response->setHeader('Content-Length', '0');
$response->setStatus($destinationExists ? 204 : 201);
return false;
}
public function beforeDelete(RequestInterface $request, ResponseInterface $response) {
try {
$this->prepareUpload($request->getPath());
if (!$this->uploadFolder instanceof UploadFolder) {
return true;
}
[$storage, $storagePath] = $this->getUploadStorage($this->uploadPath);
$storage->cancelChunkedWrite($storagePath, $this->uploadId);
return true;
} catch (NotFound $e) {
return true;
}
}
/**
* @throws BadRequest
* @throws PreconditionFailed
* @throws StorageInvalidException
*/
private function checkPrerequisites(bool $checkUploadMetadata = true): void {
if (!$this->uploadFolder instanceof UploadFolder || empty($this->server->httpRequest->getHeader(self::DESTINATION_HEADER))) {
throw new BadRequest('Skipping chunked file writing as the destination header was not passed');
}
if (!$this->uploadFolder->getStorage()->instanceOfStorage(IChunkedFileWrite::class)) {
throw new StorageInvalidException('Storage does not support chunked file writing');
}
if ($checkUploadMetadata) {
if ($this->uploadId === null || $this->uploadPath === null) {
throw new PreconditionFailed('Missing metadata for chunked upload');
}
}
}
/**
* @return array [IStorage, string]
*/
private function getUploadStorage(string $targetPath): array {
$storage = $this->uploadFolder->getStorage();
$targetFile = $this->getUploadFile($targetPath);
return [$storage, $targetFile->getInternalPath()];
}
protected function sanitizeMtime(string $mtimeFromRequest): int {
if (!is_numeric($mtimeFromRequest)) {
throw new InvalidArgumentException('X-OC-MTime header must be an integer (unix timestamp).');
}
return (int)$mtimeFromRequest;
}
/**
* @throws NotFound
*/
public function prepareUpload($path): void {
$this->uploadFolder = $this->server->tree->getNodeForPath($path);
$uploadMetadata = $this->cache->get($this->uploadFolder->getName());
$this->uploadId = $uploadMetadata[self::UPLOAD_ID] ?? null;
$this->uploadPath = $uploadMetadata[self::UPLOAD_TARGET_PATH] ?? null;
}
private function completeChunkedWrite(string $targetAbsolutePath): void {
$uploadFile = $this->getUploadFile($this->uploadPath)->getNode();
[$storage, $storagePath] = $this->getUploadStorage($this->uploadPath);
$rootFolder = \OCP\Server::get(IRootFolder::class);
$exists = $rootFolder->nodeExists($targetAbsolutePath);
$uploadFile->lock(ILockingProvider::LOCK_SHARED);
$this->emitPreHooks($targetAbsolutePath, $exists);
try {
$uploadFile->changeLock(ILockingProvider::LOCK_EXCLUSIVE);
$storage->completeChunkedWrite($storagePath, $this->uploadId);
$uploadFile->changeLock(ILockingProvider::LOCK_SHARED);
} catch (Exception $e) {
$uploadFile->unlock(ILockingProvider::LOCK_EXCLUSIVE);
throw $e;
}
// If the file was not uploaded to the user storage directly we need to copy/move it
try {
$uploadFileAbsolutePath = Filesystem::getRoot() . $uploadFile->getPath();
if ($uploadFileAbsolutePath !== $targetAbsolutePath) {
$uploadFile = $rootFolder->get($uploadFile->getFileInfo()->getPath());
if ($exists) {
$uploadFile->copy($targetAbsolutePath);
} else {
$uploadFile->move($targetAbsolutePath);
}
}
$this->emitPostHooks($targetAbsolutePath, $exists);
} catch (Exception $e) {
$uploadFile->unlock(ILockingProvider::LOCK_SHARED);
throw $e;
}
}
private function emitPreHooks(string $target, bool $exists): void {
$hookPath = $this->getHookPath($target);
if (!$exists) {
OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_create, [
Filesystem::signal_param_path => $hookPath,
]);
} else {
OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_update, [
Filesystem::signal_param_path => $hookPath,
]);
}
OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_write, [
Filesystem::signal_param_path => $hookPath,
]);
}
private function emitPostHooks(string $target, bool $exists): void {
$hookPath = $this->getHookPath($target);
if (!$exists) {
OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_create, [
Filesystem::signal_param_path => $hookPath,
]);
} else {
OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_update, [
Filesystem::signal_param_path => $hookPath,
]);
}
OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_write, [
Filesystem::signal_param_path => $hookPath,
]);
}
private function getHookPath(string $path): ?string {
if (!Filesystem::getView()) {
return $path;
}
return Filesystem::getView()->getRelativePath($path);
}
}
+4 -1
View File
@@ -36,7 +36,6 @@ use Sabre\DAV\IFile;
* @package OCA\DAV\Upload
*/
class FutureFile implements \Sabre\DAV\IFile {
/** @var Directory */
private $root;
/** @var string */
@@ -66,6 +65,10 @@ class FutureFile implements \Sabre\DAV\IFile {
return AssemblyStream::wrap($nodes);
}
public function getPath() {
return $this->root->getFileInfo()->getInternalPath() . '/.file';
}
/**
* @inheritdoc
*/
+111
View File
@@ -0,0 +1,111 @@
<?php
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\DAV\Upload;
use OCA\DAV\Connector\Sabre\Directory;
use Sabre\DAV\Exception\Forbidden;
use Sabre\DAV\IFile;
/**
* This class represents an Upload part which is not present on the storage itself
* but handled directly by external storage services like S3 with Multipart Upload
*/
class PartFile implements IFile {
/** @var Directory */
private $root;
/** @var array */
private $partInfo;
public function __construct(Directory $root, array $partInfo) {
$this->root = $root;
$this->partInfo = $partInfo;
}
/**
* @inheritdoc
*/
public function put($data) {
throw new Forbidden('Permission denied to put into this file');
}
/**
* @inheritdoc
*/
public function get() {
throw new Forbidden('Permission denied to get this file');
}
public function getPath() {
return $this->root->getFileInfo()->getInternalPath() . '/' . $this->partInfo['PartNumber'];
}
/**
* @inheritdoc
*/
public function getContentType() {
return 'application/octet-stream';
}
/**
* @inheritdoc
*/
public function getETag() {
return $this->partInfo['ETag'];
}
/**
* @inheritdoc
*/
public function getSize() {
return $this->partInfo['Size'];
}
/**
* @inheritdoc
*/
public function delete() {
$this->root->delete();
}
/**
* @inheritdoc
*/
public function getName() {
return $this->partInfo['PartNumber'];
}
/**
* @inheritdoc
*/
public function setName($name) {
throw new Forbidden('Permission denied to rename this file');
}
/**
* @inheritdoc
*/
public function getLastModified() {
return $this->partInfo['LastModified'];
}
}
+16
View File
@@ -44,6 +44,10 @@ class UploadFile implements IFile {
return $this->file->get();
}
public function getId() {
return $this->file->getId();
}
public function getContentType() {
return $this->file->getContentType();
}
@@ -75,4 +79,16 @@ class UploadFile implements IFile {
public function getLastModified() {
return $this->file->getLastModified();
}
public function getInternalPath(): string {
return $this->file->getInternalPath();
}
public function getFile(): File {
return $this->file;
}
public function getNode() {
return $this->file->getNode();
}
}
+28 -2
View File
@@ -24,20 +24,25 @@
*/
namespace OCA\DAV\Upload;
use OC\Files\ObjectStore\ObjectStoreStorage;
use OCA\DAV\Connector\Sabre\Directory;
use OCP\Files\ObjectStore\IObjectStoreMultiPartUpload;
use OCP\Files\Storage\IStorage;
use Sabre\DAV\Exception\Forbidden;
use Sabre\DAV\ICollection;
class UploadFolder implements ICollection {
/** @var Directory */
private $node;
/** @var CleanupService */
private $cleanupService;
/** @var IStorage */
private $storage;
public function __construct(Directory $node, CleanupService $cleanupService) {
public function __construct(Directory $node, CleanupService $cleanupService, IStorage $storage) {
$this->node = $node;
$this->cleanupService = $cleanupService;
$this->storage = $storage;
}
public function createFile($name, $data = null) {
@@ -66,6 +71,23 @@ class UploadFolder implements ICollection {
$children[] = new UploadFile($child);
}
if ($this->storage->instanceOfStorage(ObjectStoreStorage::class)) {
/** @var ObjectStoreStorage $storage */
$objectStore = $this->storage->getObjectStore();
if ($objectStore instanceof IObjectStoreMultiPartUpload) {
$cache = \OC::$server->getMemCacheFactory()->createDistributed(ChunkingV2Plugin::CACHE_KEY);
$uploadSession = $cache->get($this->getName());
if ($uploadSession) {
$uploadId = $uploadSession[ChunkingV2Plugin::UPLOAD_ID];
$id = $uploadSession[ChunkingV2Plugin::UPLOAD_TARGET_ID];
$parts = $objectStore->getMultipartUploads($this->storage->getURN($id), $uploadId);
foreach ($parts as $part) {
$children[] = new PartFile($this->node, $part);
}
}
}
}
return $children;
}
@@ -94,4 +116,8 @@ class UploadFolder implements ICollection {
public function getLastModified() {
return $this->node->getLastModified();
}
public function getStorage() {
return $this->storage;
}
}
+15 -6
View File
@@ -32,7 +32,6 @@ use Sabre\DAV\Exception\Forbidden;
use Sabre\DAV\ICollection;
class UploadHome implements ICollection {
/** @var array */
private $principalInfo;
/** @var CleanupService */
@@ -55,12 +54,12 @@ class UploadHome implements ICollection {
}
public function getChild($name): UploadFolder {
return new UploadFolder($this->impl()->getChild($name), $this->cleanupService);
return new UploadFolder($this->impl()->getChild($name), $this->cleanupService, $this->getStorage());
}
public function getChildren(): array {
return array_map(function ($node) {
return new UploadFolder($node, $this->cleanupService);
return new UploadFolder($node, $this->cleanupService, $this->getStorage());
}, $this->impl()->getChildren());
}
@@ -89,14 +88,24 @@ class UploadHome implements ICollection {
* @return Directory
*/
private function impl() {
$view = $this->getView();
$rootInfo = $view->getFileInfo('');
return new Directory($view, $rootInfo);
}
private function getView() {
$rootView = new View();
$user = \OC::$server->getUserSession()->getUser();
Filesystem::initMountPoints($user->getUID());
if (!$rootView->file_exists('/' . $user->getUID() . '/uploads')) {
$rootView->mkdir('/' . $user->getUID() . '/uploads');
}
$view = new View('/' . $user->getUID() . '/uploads');
$rootInfo = $view->getFileInfo('');
return new Directory($view, $rootInfo);
return new View('/' . $user->getUID() . '/uploads');
}
private function getStorage() {
$view = $this->getView();
$storage = $view->getFileInfo('')->getStorage();
return $storage;
}
}
@@ -0,0 +1,204 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2023 Joas Schilling <coding@schilljs.com>
*
* @author Joas Schilling <coding@schilljs.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\DAV\Tests\unit\BackgroundJob;
use OCA\DAV\BackgroundJob\UserStatusAutomation;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\IJobList;
use OCP\IConfig;
use OCP\UserStatus\IManager;
use OCP\UserStatus\IUserStatus;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Log\LoggerInterface;
use Test\TestCase;
/**
* @group DB
*/
class UserStatusAutomationTest extends TestCase {
protected MockObject|ITimeFactory $time;
protected MockObject|IJobList $jobList;
protected MockObject|LoggerInterface $logger;
protected MockObject|IManager $statusManager;
protected MockObject|IConfig $config;
protected function setUp(): void {
parent::setUp();
$this->time = $this->createMock(ITimeFactory::class);
$this->jobList = $this->createMock(IJobList::class);
$this->logger = $this->createMock(LoggerInterface::class);
$this->statusManager = $this->createMock(IManager::class);
$this->config = $this->createMock(IConfig::class);
}
protected function getAutomationMock(array $methods): MockObject|UserStatusAutomation {
if (empty($methods)) {
return new UserStatusAutomation(
$this->time,
\OC::$server->getDatabaseConnection(),
$this->jobList,
$this->logger,
$this->statusManager,
$this->config,
);
}
return $this->getMockBuilder(UserStatusAutomation::class)
->setConstructorArgs([
$this->time,
\OC::$server->getDatabaseConnection(),
$this->jobList,
$this->logger,
$this->statusManager,
$this->config,
])
->setMethods($methods)
->getMock();
}
public function dataRun(): array {
return [
['20230217', '2023-02-24 10:49:36.613834', true],
['20230224', '2023-02-24 10:49:36.613834', true],
['20230217', '2023-02-24 13:58:24.479357', false],
['20230224', '2023-02-24 13:58:24.479357', false],
];
}
/**
* @dataProvider dataRun
*/
public function testRun(string $ruleDay, string $currentTime, bool $isAvailable): void {
$this->config->method('getUserValue')
->with('user', 'dav', 'user_status_automation', 'no')
->willReturn('yes');
$this->time->method('getDateTime')
->willReturn(new \DateTime($currentTime, new \DateTimeZone('UTC')));
$automation = $this->getAutomationMock(['getAvailabilityFromPropertiesTable']);
$automation->method('getAvailabilityFromPropertiesTable')
->with('user')
->willReturn('BEGIN:VCALENDAR
PRODID:Nextcloud DAV app
BEGIN:VTIMEZONE
TZID:Europe/Berlin
BEGIN:STANDARD
TZNAME:CET
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19701025T030000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
END:STANDARD
BEGIN:DAYLIGHT
TZNAME:CEST
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19700329T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VAVAILABILITY
BEGIN:AVAILABLE
DTSTART;TZID=Europe/Berlin:' . $ruleDay . 'T090000
DTEND;TZID=Europe/Berlin:' . $ruleDay . 'T170000
UID:3e6feeec-8e00-4265-b822-b73174e8b39f
RRULE:FREQ=WEEKLY;BYDAY=TH
END:AVAILABLE
BEGIN:AVAILABLE
DTSTART;TZID=Europe/Berlin:' . $ruleDay . 'T090000
DTEND;TZID=Europe/Berlin:' . $ruleDay . 'T120000
UID:8a634e99-07cf-443b-b480-005a0e1db323
RRULE:FREQ=WEEKLY;BYDAY=FR
END:AVAILABLE
END:VAVAILABILITY
END:VCALENDAR');
if ($isAvailable) {
$this->statusManager->expects($this->once())
->method('revertUserStatus')
->with('user', IUserStatus::MESSAGE_AVAILABILITY, IUserStatus::DND);
} else {
$this->statusManager->expects($this->once())
->method('revertUserStatus')
->with('user', IUserStatus::MESSAGE_CALL, IUserStatus::AWAY);
$this->statusManager->expects($this->once())
->method('setUserStatus')
->with('user', IUserStatus::MESSAGE_AVAILABILITY, IUserStatus::DND, true);
}
self::invokePrivate($automation, 'run', [['userId' => 'user']]);
}
public function testRunNoMoreAvailabilityDefined(): void {
$this->config->method('getUserValue')
->with('user', 'dav', 'user_status_automation', 'no')
->willReturn('yes');
$this->time->method('getDateTime')
->willReturn(new \DateTime('2023-02-24 13:58:24.479357', new \DateTimeZone('UTC')));
$automation = $this->getAutomationMock(['getAvailabilityFromPropertiesTable']);
$automation->method('getAvailabilityFromPropertiesTable')
->with('user')
->willReturn('BEGIN:VCALENDAR
PRODID:Nextcloud DAV app
BEGIN:VTIMEZONE
TZID:Europe/Berlin
BEGIN:STANDARD
TZNAME:CET
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19701025T030000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
END:STANDARD
BEGIN:DAYLIGHT
TZNAME:CEST
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19700329T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VAVAILABILITY
END:VAVAILABILITY
END:VCALENDAR');
$this->statusManager->expects($this->once())
->method('revertUserStatus')
->with('user', IUserStatus::MESSAGE_AVAILABILITY, IUserStatus::DND);
$this->jobList->expects($this->once())
->method('remove')
->with(UserStatusAutomation::class, ['userId' => 'user']);
self::invokePrivate($automation, 'run', [['userId' => 'user']]);
}
}
@@ -304,6 +304,10 @@ class DirectoryTest extends \Test\TestCase {
->method('free_space')
->willReturn(800);
$this->info->expects($this->any())
->method('getPath')
->willReturn('/admin/files/foo');
$this->info->expects($this->once())
->method('getSize')
->willReturn(200);
@@ -312,6 +316,10 @@ class DirectoryTest extends \Test\TestCase {
->method('getMountPoint')
->willReturn($mountPoint);
$this->view->expects($this->any())
->method('getRelativePath')
->willReturn('/foo');
$mountPoint->method('getMountPoint')
->willReturn('/user/files/mymountpoint');
@@ -359,6 +367,10 @@ class DirectoryTest extends \Test\TestCase {
$mountPoint->method('getMountPoint')
->willReturn('/user/files/mymountpoint');
$this->view->expects($this->any())
->method('getRelativePath')
->willReturn('/foo');
$dir = new Directory($this->view, $this->info);
$this->assertEquals([200, 800], $dir->getQuotaInfo()); //200 used, 800 free
}
@@ -278,6 +278,7 @@ class SharesPluginTest extends \Test\TestCase {
[[IShare::TYPE_REMOTE]],
[[IShare::TYPE_ROOM]],
[[IShare::TYPE_DECK]],
[[IShare::TYPE_SCIENCEMESH]],
[[IShare::TYPE_USER, IShare::TYPE_GROUP]],
[[IShare::TYPE_USER, IShare::TYPE_GROUP, IShare::TYPE_LINK]],
[[IShare::TYPE_USER, IShare::TYPE_LINK]],
+4 -4
View File
@@ -2,7 +2,7 @@ OC.L10N.register(
"encryption",
{
"Missing recovery key password" : "Kata sandi kunci pemulihan tidak ada",
"Please repeat the recovery key password" : "Silahkan ulangi kata sandi kunci pemulihan",
"Please repeat the recovery key password" : "Silakan ulangi kata sandi kunci pemulihan",
"Repeated recovery key password does not match the provided recovery key password" : "Kata sandi kunci pemulihan yang diulangi tidak cocok dengan kata sandi kunci pemulihan yang diberikan",
"Recovery key successfully enabled" : "Kunci pemulihan berhasil diaktifkan",
"Could not enable recovery key. Please check your recovery key password!" : "Tidak dapat mengaktifkan kunci pemulihan. Silakan periksa kata sandi kunci pemulihan Anda!",
@@ -21,8 +21,8 @@ OC.L10N.register(
"The old password was not correct, please try again." : "Kata sandi lama salah, mohon coba lagi.",
"The current log-in password was not correct, please try again." : "Kata sandi masuk saat ini salah, mohon coba lagi.",
"Private key password successfully updated." : "Sandi kunci privat berhasil diperbarui.",
"Invalid private key for encryption app. Please update your private key password in your personal settings to recover access to your encrypted files." : "Kunci privat tidak sah untuk aplikasi enkripsi. Silakan perbarui kata sandi kunci privat anda pada pengaturan pribadi untuk memulihkan akses ke berkas anda yang dienkripsi.",
"Encryption App is enabled, but your keys are not initialized. Please log-out and log-in again." : "Apl Enkripsi telah aktif, tapi kunci anda tidak diinisialisasikan. Harap keluar-log dan masuk-log kembali.",
"Invalid private key for encryption app. Please update your private key password in your personal settings to recover access to your encrypted files." : "Kunci privat tidak sah untuk aplikasi enkripsi. Silakan perbarui kata sandi kunci privat Anda pada pengaturan pribadi untuk memulihkan akses ke berkas Anda yang dienkripsi.",
"Encryption App is enabled, but your keys are not initialized. Please log-out and log-in again." : "Apl Enkripsi telah aktif, tapi kunci Anda tidak diinisialisasikan. Harap keluar-log dan masuk-log kembali.",
"Please enable server side encryption in the admin settings in order to use the encryption module." : "Silakan aktifkan enkripsi sisi-peladen pada setelan admin untuk menggunakan modul enkripsi.",
"Encryption app is enabled and ready" : "Apl enkripsi aktif dan siap",
"Bad Signature" : "Tanda salah",
@@ -40,7 +40,7 @@ OC.L10N.register(
"Enabling this option encrypts all files stored on the main storage, otherwise only files on external storage will be encrypted" : "Mengaktifkan opsi ini akan mengenkripsi semua berkas yang disimpan pada penyimpanan utama, jika tidak diaktifkan maka hanya berkas pada penyimpanan eksternal saja yang akan dienkripsi.",
"Enable recovery key" : "Aktifkan kunci pemulihan",
"Disable recovery key" : "Nonaktifkan kunci pemulihan",
"The recovery key is an extra encryption key that is used to encrypt files. It allows recovery of a user's files if the user forgets his or her password." : "Kunci pemulihan adalah kunci enkripsi tambahan yang digunakan untuk mengenkripsi berkas. Kunci pemulihan memungkinkan untuk memulihkan berkas-berkas pengguna ketika pengguna tersebut melupakan kata sandi mereka.",
"The recovery key is an extra encryption key that is used to encrypt files. It allows recovery of a user's files if the user forgets his or her password." : "Kunci pemulihan adalah kunci enkripsi tambahan yang digunakan untuk mengenkripsi berkas. Kunci pemulihan memungkinkan untuk memulihkan berkas pengguna ketika pengguna tersebut melupakan kata sandi mereka.",
"Recovery key password" : "Kata sandi kunci pemulihan",
"Repeat recovery key password" : "Ulangi kata sandi kunci pemulihan",
"Change recovery key password:" : "Ubah kata sandi kunci pemulihan:",
+4 -4
View File
@@ -1,6 +1,6 @@
{ "translations": {
"Missing recovery key password" : "Kata sandi kunci pemulihan tidak ada",
"Please repeat the recovery key password" : "Silahkan ulangi kata sandi kunci pemulihan",
"Please repeat the recovery key password" : "Silakan ulangi kata sandi kunci pemulihan",
"Repeated recovery key password does not match the provided recovery key password" : "Kata sandi kunci pemulihan yang diulangi tidak cocok dengan kata sandi kunci pemulihan yang diberikan",
"Recovery key successfully enabled" : "Kunci pemulihan berhasil diaktifkan",
"Could not enable recovery key. Please check your recovery key password!" : "Tidak dapat mengaktifkan kunci pemulihan. Silakan periksa kata sandi kunci pemulihan Anda!",
@@ -19,8 +19,8 @@
"The old password was not correct, please try again." : "Kata sandi lama salah, mohon coba lagi.",
"The current log-in password was not correct, please try again." : "Kata sandi masuk saat ini salah, mohon coba lagi.",
"Private key password successfully updated." : "Sandi kunci privat berhasil diperbarui.",
"Invalid private key for encryption app. Please update your private key password in your personal settings to recover access to your encrypted files." : "Kunci privat tidak sah untuk aplikasi enkripsi. Silakan perbarui kata sandi kunci privat anda pada pengaturan pribadi untuk memulihkan akses ke berkas anda yang dienkripsi.",
"Encryption App is enabled, but your keys are not initialized. Please log-out and log-in again." : "Apl Enkripsi telah aktif, tapi kunci anda tidak diinisialisasikan. Harap keluar-log dan masuk-log kembali.",
"Invalid private key for encryption app. Please update your private key password in your personal settings to recover access to your encrypted files." : "Kunci privat tidak sah untuk aplikasi enkripsi. Silakan perbarui kata sandi kunci privat Anda pada pengaturan pribadi untuk memulihkan akses ke berkas Anda yang dienkripsi.",
"Encryption App is enabled, but your keys are not initialized. Please log-out and log-in again." : "Apl Enkripsi telah aktif, tapi kunci Anda tidak diinisialisasikan. Harap keluar-log dan masuk-log kembali.",
"Please enable server side encryption in the admin settings in order to use the encryption module." : "Silakan aktifkan enkripsi sisi-peladen pada setelan admin untuk menggunakan modul enkripsi.",
"Encryption app is enabled and ready" : "Apl enkripsi aktif dan siap",
"Bad Signature" : "Tanda salah",
@@ -38,7 +38,7 @@
"Enabling this option encrypts all files stored on the main storage, otherwise only files on external storage will be encrypted" : "Mengaktifkan opsi ini akan mengenkripsi semua berkas yang disimpan pada penyimpanan utama, jika tidak diaktifkan maka hanya berkas pada penyimpanan eksternal saja yang akan dienkripsi.",
"Enable recovery key" : "Aktifkan kunci pemulihan",
"Disable recovery key" : "Nonaktifkan kunci pemulihan",
"The recovery key is an extra encryption key that is used to encrypt files. It allows recovery of a user's files if the user forgets his or her password." : "Kunci pemulihan adalah kunci enkripsi tambahan yang digunakan untuk mengenkripsi berkas. Kunci pemulihan memungkinkan untuk memulihkan berkas-berkas pengguna ketika pengguna tersebut melupakan kata sandi mereka.",
"The recovery key is an extra encryption key that is used to encrypt files. It allows recovery of a user's files if the user forgets his or her password." : "Kunci pemulihan adalah kunci enkripsi tambahan yang digunakan untuk mengenkripsi berkas. Kunci pemulihan memungkinkan untuk memulihkan berkas pengguna ketika pengguna tersebut melupakan kata sandi mereka.",
"Recovery key password" : "Kata sandi kunci pemulihan",
"Repeat recovery key password" : "Ulangi kata sandi kunci pemulihan",
"Change recovery key password:" : "Ubah kata sandi kunci pemulihan:",
+4
View File
@@ -28,11 +28,15 @@ OC.L10N.register(
"Bad Signature" : "Лош потпис",
"Missing Signature" : "Недостаје потпис",
"one-time password for server-side-encryption" : "једнократна лозинка за шифровање на страни сервера",
"Cannot decrypt this file, probably this is a shared file. Please ask the file owner to reshare the file with you." : "Овај фајл не може да се дешифрује, то је вероватно дељени фајл. Молимо вас да замолите власника да га поново подели са вама.",
"Cannot read this file, probably this is a shared file. Please ask the file owner to reshare the file with you." : "Овај фајл не може да се прочита, то је вероватно дељени фајл. Молимо вас да замолите власника да га поново подели са вама.",
"Default encryption module" : "Подразумевани модул за шифровање",
"Default encryption module for server-side encryption" : "Подразумевани модул за шифровање на серверској страни",
"In order to use this encryption module you need to enable server-side\n\t\tencryption in the admin settings. Once enabled this module will encrypt\n\t\tall your files transparently. The encryption is based on AES 256 keys.\n\t\tThe module won't touch existing files, only new files will be encrypted\n\t\tafter server-side encryption was enabled. It is also not possible to\n\t\tdisable the encryption again and switch back to a unencrypted system.\n\t\tPlease read the documentation to know all implications before you decide\n\t\tto enable server-side encryption." : "Да бисте користили овај модул, морате на серверској страни омогућити\n\t\tшифровање у администраторским поставкама. Једном укључен, овај модул ће шифровати\n\t\tсве фајлове транспарентно. Шифровање је базирано на „AES 256“ кључевима.\n\t\tМодул неће дирати постојеће фајлове, само ће нови фајлови бити шифровани\n\t\tнакон укључења шифровања на серверској страни. Није могуће да\n\t\tсе искључи шифровање и да врати се на нешифровани систем.\n\t\tПрочитајте документацију да сазнате све импликације пре него што се одлучите\n\t\tда укључите шифровање на серверу.",
"Hey there,\n\nThe administration enabled server-side-encryption. Your files were encrypted using the password \"%s\".\n\nPlease login to the web interface, go to the section \"Basic encryption module\" of your personal settings and update your encryption password by entering this password into the \"Old log-in password\" field and your current login-password.\n\n" : "Здраво,\n\nАдминистрација је укључила енкрипцију на страни сервера. Ваши фајлови су шифровани коришћењем лозинке „%s”.\n\nМолимо вас да се пријавите веб интерфејсом, одете на одељак „Модул основне енкрипције” у вашим личним подешавањима и ажурирате лозинку шифрирања уношењем ове лозинке у поље „Стара лозинка за пријаву” и вашу текућу лозинку за пријаву.\n\n",
"The share will expire on %s." : "Дељење истиче %s.",
"Cheers!" : "Здраво!",
"Hey there,<br><br>The administration enabled server-side-encryption. Your files were encrypted using the password <strong>%s</strong>.<br><br>Please login to the web interface, go to the section \"Basic encryption module\" of your personal settings and update your encryption password by entering this password into the \"Old log-in password\" field and your current login-password.<br><br>" : "Здраво,<br><br>Администрација је укључила енкрипцију на страни сервера. Ваши фајлови су шифровани коришћењем лозинке <strong>%s</strong>.<br><br>Молимо вас да се пријавите веб интерфејсом, одете на одељак „Модул основне енкрипције” у вашим личним подешавањима и ажурирате лозинку шифрирања уношењем ове лозинке у поље „Стара лозинка за пријаву” и вашу текућу лозинку за пријаву.<br><br>",
"Encryption app is enabled but your keys are not initialized, please log-out and log-in again" : "Апликација за шифровање је укључена али кључеви још нису иницијализовани. Одјавите се и поново се пријавите.",
"Encrypt the home storage" : "Шифровање главног складишта",
"Enabling this option encrypts all files stored on the main storage, otherwise only files on external storage will be encrypted" : "Укључивање ове опције ће шифровати све фајлове на главном складишту. У супротном ће само фајлови на спољашњем складишту бити шифровани",
+4
View File
@@ -26,11 +26,15 @@
"Bad Signature" : "Лош потпис",
"Missing Signature" : "Недостаје потпис",
"one-time password for server-side-encryption" : "једнократна лозинка за шифровање на страни сервера",
"Cannot decrypt this file, probably this is a shared file. Please ask the file owner to reshare the file with you." : "Овај фајл не може да се дешифрује, то је вероватно дељени фајл. Молимо вас да замолите власника да га поново подели са вама.",
"Cannot read this file, probably this is a shared file. Please ask the file owner to reshare the file with you." : "Овај фајл не може да се прочита, то је вероватно дељени фајл. Молимо вас да замолите власника да га поново подели са вама.",
"Default encryption module" : "Подразумевани модул за шифровање",
"Default encryption module for server-side encryption" : "Подразумевани модул за шифровање на серверској страни",
"In order to use this encryption module you need to enable server-side\n\t\tencryption in the admin settings. Once enabled this module will encrypt\n\t\tall your files transparently. The encryption is based on AES 256 keys.\n\t\tThe module won't touch existing files, only new files will be encrypted\n\t\tafter server-side encryption was enabled. It is also not possible to\n\t\tdisable the encryption again and switch back to a unencrypted system.\n\t\tPlease read the documentation to know all implications before you decide\n\t\tto enable server-side encryption." : "Да бисте користили овај модул, морате на серверској страни омогућити\n\t\tшифровање у администраторским поставкама. Једном укључен, овај модул ће шифровати\n\t\tсве фајлове транспарентно. Шифровање је базирано на „AES 256“ кључевима.\n\t\tМодул неће дирати постојеће фајлове, само ће нови фајлови бити шифровани\n\t\tнакон укључења шифровања на серверској страни. Није могуће да\n\t\tсе искључи шифровање и да врати се на нешифровани систем.\n\t\tПрочитајте документацију да сазнате све импликације пре него што се одлучите\n\t\tда укључите шифровање на серверу.",
"Hey there,\n\nThe administration enabled server-side-encryption. Your files were encrypted using the password \"%s\".\n\nPlease login to the web interface, go to the section \"Basic encryption module\" of your personal settings and update your encryption password by entering this password into the \"Old log-in password\" field and your current login-password.\n\n" : "Здраво,\n\nАдминистрација је укључила енкрипцију на страни сервера. Ваши фајлови су шифровани коришћењем лозинке „%s”.\n\nМолимо вас да се пријавите веб интерфејсом, одете на одељак „Модул основне енкрипције” у вашим личним подешавањима и ажурирате лозинку шифрирања уношењем ове лозинке у поље „Стара лозинка за пријаву” и вашу текућу лозинку за пријаву.\n\n",
"The share will expire on %s." : "Дељење истиче %s.",
"Cheers!" : "Здраво!",
"Hey there,<br><br>The administration enabled server-side-encryption. Your files were encrypted using the password <strong>%s</strong>.<br><br>Please login to the web interface, go to the section \"Basic encryption module\" of your personal settings and update your encryption password by entering this password into the \"Old log-in password\" field and your current login-password.<br><br>" : "Здраво,<br><br>Администрација је укључила енкрипцију на страни сервера. Ваши фајлови су шифровани коришћењем лозинке <strong>%s</strong>.<br><br>Молимо вас да се пријавите веб интерфејсом, одете на одељак „Модул основне енкрипције” у вашим личним подешавањима и ажурирате лозинку шифрирања уношењем ове лозинке у поље „Стара лозинка за пријаву” и вашу текућу лозинку за пријаву.<br><br>",
"Encryption app is enabled but your keys are not initialized, please log-out and log-in again" : "Апликација за шифровање је укључена али кључеви још нису иницијализовани. Одјавите се и поново се пријавите.",
"Encrypt the home storage" : "Шифровање главног складишта",
"Enabling this option encrypts all files stored on the main storage, otherwise only files on external storage will be encrypted" : "Укључивање ове опције ће шифровати све фајлове на главном складишту. У супротном ће само фајлови на спољашњем складишту бити шифровани",
+2
View File
@@ -29,6 +29,8 @@ OC.L10N.register(
"Share with me via Nextcloud" : "Dibagikan pada saya via Nextcloud",
"HTML Code:" : "Kode HTML:",
"Share with me through my #Nextcloud Federated Cloud ID" : "Dibagikan pada saya melalui #Nextcloud Federated Cloud ID saya",
"Copy to clipboard" : "Salin ke papan klip",
"Clipboard is not available" : "Papan klip tidak tersedia",
"Copied!" : "Tersalin!",
"Copy" : "Salin",
"Not supported!" : "Tidak didukung!",
+2
View File
@@ -27,6 +27,8 @@
"Share with me via Nextcloud" : "Dibagikan pada saya via Nextcloud",
"HTML Code:" : "Kode HTML:",
"Share with me through my #Nextcloud Federated Cloud ID" : "Dibagikan pada saya melalui #Nextcloud Federated Cloud ID saya",
"Copy to clipboard" : "Salin ke papan klip",
"Clipboard is not available" : "Papan klip tidak tersedia",
"Copied!" : "Tersalin!",
"Copy" : "Salin",
"Not supported!" : "Tidak didukung!",
+1 -1
View File
@@ -49,7 +49,7 @@ OC.L10N.register(
"Share with me through my #Nextcloud Federated Cloud ID, see {url}" : "Поділіться зі мною через мій #Nextcloud Federated Cloud ID, див. {url}",
"Share with me through my #Nextcloud Federated Cloud ID" : "Поділіться зі мною через мій #Nextcloud Federated Cloud ID",
"Cloud ID copied to the clipboard" : "Cloud ID скопійовано в буфер обміну",
"Copy to clipboard" : "Скопіювати в буфер обміну ",
"Copy to clipboard" : "Копіювати до буферу обміну",
"Clipboard is not available" : "Буфер обміну недоступний",
"Copied!" : "Скопійовано!",
"Copy" : "Копіювати",
+1 -1
View File
@@ -47,7 +47,7 @@
"Share with me through my #Nextcloud Federated Cloud ID, see {url}" : "Поділіться зі мною через мій #Nextcloud Federated Cloud ID, див. {url}",
"Share with me through my #Nextcloud Federated Cloud ID" : "Поділіться зі мною через мій #Nextcloud Federated Cloud ID",
"Cloud ID copied to the clipboard" : "Cloud ID скопійовано в буфер обміну",
"Copy to clipboard" : "Скопіювати в буфер обміну ",
"Copy to clipboard" : "Копіювати до буферу обміну",
"Clipboard is not available" : "Буфер обміну недоступний",
"Copied!" : "Скопійовано!",
"Copy" : "Копіювати",
+16 -3
View File
@@ -269,8 +269,12 @@ OC.FileUpload.prototype = {
&& this.getFile().size > this.uploader.fileUploadParam.maxChunkSize
) {
data.isChunked = true;
var headers = {
Destination: this.uploader.davClient._buildUrl(this.getTargetDestination())
};
chunkFolderPromise = this.uploader.davClient.createDirectory(
'uploads/' + OC.getCurrentUser().uid + '/' + this.getId()
'uploads/' + OC.getCurrentUser().uid + '/' + this.getId(), headers
);
// TODO: if fails, it means same id already existed, need to retry
} else {
@@ -309,17 +313,22 @@ OC.FileUpload.prototype = {
}
if (size) {
headers['OC-Total-Length'] = size;
}
headers['Destination'] = this.uploader.davClient._buildUrl(this.getTargetDestination());
return this.uploader.davClient.move(
'uploads/' + uid + '/' + this.getId() + '/.file',
'files/' + uid + '/' + OC.joinPaths(this.getFullPath(), this.getFileName()),
this.getTargetDestination(),
true,
headers
);
},
getTargetDestination: function() {
var uid = OC.getCurrentUser().uid;
return 'files/' + uid + '/' + OC.joinPaths(this.getFullPath(), this.getFileName());
},
_deleteChunkFolder: function() {
// delete transfer directory for this upload
this.uploader.davClient.remove(
@@ -1326,6 +1335,10 @@ OC.Uploader.prototype = _.extend({
}
var range = data.contentRange.split(' ')[1];
var chunkId = range.split('/')[0].split('-')[0];
// Use a numeric chunk id and set the Destination header on all request for ChunkingV2
chunkId = Math.ceil((data.chunkSize+Number(chunkId)) / upload.uploader.fileUploadParam.maxChunkSize);
data.headers['Destination'] = self.davClient._buildUrl(upload.getTargetDestination());
data.url = OC.getRootPath() +
'/remote.php/dav/uploads' +
'/' + OC.getCurrentUser().uid +
+6
View File
@@ -733,6 +733,12 @@
promise = dfd.promise(),
jqXHR,
upload;
// Dynamically adjust the chunk size for Chunking V2 to fit into the 10000 chunk limit
if (file.size/mcs > 10000) {
mcs = Math.ceil(file.size/10000)
}
if (!(this._isXHRUpload(options) && slice && (ub || mcs < fs)) ||
options.data) {
return false;
+3
View File
@@ -185,12 +185,15 @@ OC.L10N.register(
"Select file or folder to link to" : "Избор на файл или папка, към които да поставите връзка",
"Open the files app settings" : "Отваряне на настройките на приложението за файлове",
"Files settings" : "Настройки на файловете",
"File cannot be accessed" : "Файлът не е достъпен",
"You might not have have permissions to view it, ask the sender to share it" : "Може да нямате права да го видите, помолете подателя да го сподели",
"Show hidden files" : "Показвай и скрити файлове",
"Crop image previews" : "Изрязване на визуализациите на изображение",
"Additional settings" : "Допълнителни настройки",
"WebDAV" : "WebDAV",
"Copy to clipboard" : "Копиране в клипборда",
"Use this address to access your Files via WebDAV" : "Ползвайте този адрес за достъп до файловете си чрез WebDAV",
"If you have enabled 2FA, you must create and use a new app password by clicking here." : "Ако сте активирали 2FA, трябва да създадете и използвате нова парола за приложението, като кликнете тук.",
"Clipboard is not available" : "Клипбордът не е достъпен",
"WebDAV URL copied to clipboard" : "WebDAV URL адрес е копиран в клипборда",
"Unable to change the favourite state of the file" : "Не може да се промени състоянието за предпочитане на файла",
+3
View File
@@ -183,12 +183,15 @@
"Select file or folder to link to" : "Избор на файл или папка, към които да поставите връзка",
"Open the files app settings" : "Отваряне на настройките на приложението за файлове",
"Files settings" : "Настройки на файловете",
"File cannot be accessed" : "Файлът не е достъпен",
"You might not have have permissions to view it, ask the sender to share it" : "Може да нямате права да го видите, помолете подателя да го сподели",
"Show hidden files" : "Показвай и скрити файлове",
"Crop image previews" : "Изрязване на визуализациите на изображение",
"Additional settings" : "Допълнителни настройки",
"WebDAV" : "WebDAV",
"Copy to clipboard" : "Копиране в клипборда",
"Use this address to access your Files via WebDAV" : "Ползвайте този адрес за достъп до файловете си чрез WebDAV",
"If you have enabled 2FA, you must create and use a new app password by clicking here." : "Ако сте активирали 2FA, трябва да създадете и използвате нова парола за приложението, като кликнете тук.",
"Clipboard is not available" : "Клипбордът не е достъпен",
"WebDAV URL copied to clipboard" : "WebDAV URL адрес е копиран в клипборда",
"Unable to change the favourite state of the file" : "Не може да се промени състоянието за предпочитане на файла",
+9
View File
@@ -98,6 +98,7 @@ OC.L10N.register(
"Your storage is almost full ({usedSpacePercent}%)." : "L'emmagatzematge està gairebé ple ({usedSpacePercent}%).",
"_matches \"{filter}\"_::_match \"{filter}\"_" : ["coincideix amb «{filter}»","coincideixen amb «{filter}»"],
"View in folder" : "Visualitza-ho a la carpeta",
"Direct link was copied (only works for users who have access to this file/folder)" : "S'ha copiat l'enllaç directe (només funciona per als usuaris que tenen accés a aquest fitxer/carpeta)",
"Path" : "Ruta",
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "S'ha afegit als preferits",
@@ -165,6 +166,10 @@ OC.L10N.register(
"The ownership transfer of {path} from {user} has completed." : "S'ha completat la transferència de propietat de {path} de {user}.",
"in %s" : "%s",
"File Management" : "Gestió de fitxers",
"Storage informations" : "Informació d'emmagatzematge",
"{usedQuotaByte} used" : "{usedQuotaByte} utilitzat",
"{relative}% used" : "{relative}% used",
"Could not refresh storage stats" : "No s'han pogut actualitzar les estadístiques d'emmagatzematge",
"Transfer ownership of a file or folder" : "Transferiu la propietat d'un fitxer o carpeta",
"Choose file or folder to transfer" : "Tria el fitxer o carpeta que s'ha de transferir",
"Change" : "Canvia",
@@ -178,7 +183,10 @@ OC.L10N.register(
"Ownership transfer request sent" : "S'ha enviat la sol·licitud de transferència de propietat",
"Cannot transfer ownership of a file or folder you do not own" : "No es pot transferir la propietat d'un fitxer o carpeta que no és vostre",
"Select file or folder to link to" : "Seleccioneu el fitxer o la carpeta per enllaçar",
"Open the files app settings" : "Obriu la configuració de l'aplicació de fitxers",
"Files settings" : "Paràmetres dels fitxers",
"File cannot be accessed" : "No es pot accedir al fitxer",
"You might not have have permissions to view it, ask the sender to share it" : "És possible que no tingueu permisos per veure'l, demaneu al remitent que el comparteixi",
"Show hidden files" : "Mostra els fitxers ocults",
"Crop image previews" : "Retalla les previsualitzacions de les imatges",
"Additional settings" : "Paràmetres addicionals",
@@ -186,6 +194,7 @@ OC.L10N.register(
"Copy to clipboard" : "Copia-ho al porta-retalls",
"Use this address to access your Files via WebDAV" : "Utilitzeu aquesta adreça per a accedir als vostres fitxers mitjançant WebDAV",
"Clipboard is not available" : "El porta-retalls no està disponible",
"WebDAV URL copied to clipboard" : "URL de WebDAV copiat al porta-retalls",
"Unable to change the favourite state of the file" : "No s'ha pogut canviar l'estat de preferit del fitxer",
"Error while loading the file data" : "S'ha produït un error en carregar la informació del fitxer",
"Pick a template for {name}" : "Trieu una plantilla per a {name}",
+9
View File
@@ -96,6 +96,7 @@
"Your storage is almost full ({usedSpacePercent}%)." : "L'emmagatzematge està gairebé ple ({usedSpacePercent}%).",
"_matches \"{filter}\"_::_match \"{filter}\"_" : ["coincideix amb «{filter}»","coincideixen amb «{filter}»"],
"View in folder" : "Visualitza-ho a la carpeta",
"Direct link was copied (only works for users who have access to this file/folder)" : "S'ha copiat l'enllaç directe (només funciona per als usuaris que tenen accés a aquest fitxer/carpeta)",
"Path" : "Ruta",
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "S'ha afegit als preferits",
@@ -163,6 +164,10 @@
"The ownership transfer of {path} from {user} has completed." : "S'ha completat la transferència de propietat de {path} de {user}.",
"in %s" : "%s",
"File Management" : "Gestió de fitxers",
"Storage informations" : "Informació d'emmagatzematge",
"{usedQuotaByte} used" : "{usedQuotaByte} utilitzat",
"{relative}% used" : "{relative}% used",
"Could not refresh storage stats" : "No s'han pogut actualitzar les estadístiques d'emmagatzematge",
"Transfer ownership of a file or folder" : "Transferiu la propietat d'un fitxer o carpeta",
"Choose file or folder to transfer" : "Tria el fitxer o carpeta que s'ha de transferir",
"Change" : "Canvia",
@@ -176,7 +181,10 @@
"Ownership transfer request sent" : "S'ha enviat la sol·licitud de transferència de propietat",
"Cannot transfer ownership of a file or folder you do not own" : "No es pot transferir la propietat d'un fitxer o carpeta que no és vostre",
"Select file or folder to link to" : "Seleccioneu el fitxer o la carpeta per enllaçar",
"Open the files app settings" : "Obriu la configuració de l'aplicació de fitxers",
"Files settings" : "Paràmetres dels fitxers",
"File cannot be accessed" : "No es pot accedir al fitxer",
"You might not have have permissions to view it, ask the sender to share it" : "És possible que no tingueu permisos per veure'l, demaneu al remitent que el comparteixi",
"Show hidden files" : "Mostra els fitxers ocults",
"Crop image previews" : "Retalla les previsualitzacions de les imatges",
"Additional settings" : "Paràmetres addicionals",
@@ -184,6 +192,7 @@
"Copy to clipboard" : "Copia-ho al porta-retalls",
"Use this address to access your Files via WebDAV" : "Utilitzeu aquesta adreça per a accedir als vostres fitxers mitjançant WebDAV",
"Clipboard is not available" : "El porta-retalls no està disponible",
"WebDAV URL copied to clipboard" : "URL de WebDAV copiat al porta-retalls",
"Unable to change the favourite state of the file" : "No s'ha pogut canviar l'estat de preferit del fitxer",
"Error while loading the file data" : "S'ha produït un error en carregar la informació del fitxer",
"Pick a template for {name}" : "Trieu una plantilla per a {name}",
+3
View File
@@ -185,12 +185,15 @@ OC.L10N.register(
"Select file or folder to link to" : "Vyberte soubor nebo složku na kterou odkazovat",
"Open the files app settings" : "Otevřít nastavení aplikace soubory",
"Files settings" : "Nastavení pro Soubory",
"File cannot be accessed" : "K souboru se nedaří přistoupit",
"You might not have have permissions to view it, ask the sender to share it" : "Může být, že nemáte oprávnění pro jeho zobrazení požádejte odesilatele aby vám ho nasdílel",
"Show hidden files" : "Zobrazit skryté soubory",
"Crop image previews" : "Oříznout náhledy obrázků",
"Additional settings" : "Další nastavení",
"WebDAV" : "WebDAV",
"Copy to clipboard" : "Zkopírovat do schránky",
"Use this address to access your Files via WebDAV" : "Tuto adresu použijte pro přístup k vašim souborům prostřednictvím protokolu WebDAV",
"If you have enabled 2FA, you must create and use a new app password by clicking here." : "Pokud jste zapnuli 2FA, je třeba kliknutím sem vytvořit a použít nové heslo pro aplikaci.",
"Clipboard is not available" : "Schránka není k dispozici",
"WebDAV URL copied to clipboard" : "WebDAV URL zkopírována do schránky",
"Unable to change the favourite state of the file" : "Nedaří se změnit stav „oblíbené“ souboru",
+3
View File
@@ -183,12 +183,15 @@
"Select file or folder to link to" : "Vyberte soubor nebo složku na kterou odkazovat",
"Open the files app settings" : "Otevřít nastavení aplikace soubory",
"Files settings" : "Nastavení pro Soubory",
"File cannot be accessed" : "K souboru se nedaří přistoupit",
"You might not have have permissions to view it, ask the sender to share it" : "Může být, že nemáte oprávnění pro jeho zobrazení požádejte odesilatele aby vám ho nasdílel",
"Show hidden files" : "Zobrazit skryté soubory",
"Crop image previews" : "Oříznout náhledy obrázků",
"Additional settings" : "Další nastavení",
"WebDAV" : "WebDAV",
"Copy to clipboard" : "Zkopírovat do schránky",
"Use this address to access your Files via WebDAV" : "Tuto adresu použijte pro přístup k vašim souborům prostřednictvím protokolu WebDAV",
"If you have enabled 2FA, you must create and use a new app password by clicking here." : "Pokud jste zapnuli 2FA, je třeba kliknutím sem vytvořit a použít nové heslo pro aplikaci.",
"Clipboard is not available" : "Schránka není k dispozici",
"WebDAV URL copied to clipboard" : "WebDAV URL zkopírována do schránky",
"Unable to change the favourite state of the file" : "Nedaří se změnit stav „oblíbené“ souboru",
+4
View File
@@ -182,8 +182,11 @@ OC.L10N.register(
"Unknown error" : "Ukendt fejl",
"Ownership transfer request sent" : "Anmodning om ejerskabsoverdragelse sendt",
"Cannot transfer ownership of a file or folder you do not own" : "Kan ikke overføre ejerskab af en fil eller mappe, du ikke ejer",
"Select file or folder to link to" : "Vælg fil eller mappe at linke til",
"Open the files app settings" : "Åbn fil-app indstillinger",
"Files settings" : "indstillinger for filer",
"File cannot be accessed" : "Filen kan ikke tilgås",
"You might not have have permissions to view it, ask the sender to share it" : "Du har muligvis ikke tilladelser til at se.... Bed afsenderen om at dele...",
"Show hidden files" : "Vis skjulte filer",
"Crop image previews" : "Beskær forhåndsvisninger af billeder",
"Additional settings" : "Yderligere indstillinger",
@@ -191,6 +194,7 @@ OC.L10N.register(
"Copy to clipboard" : "Kopier til udklipsholder",
"Use this address to access your Files via WebDAV" : "Brug denne adresse til at få adgang til dine filer via WebDAV",
"Clipboard is not available" : "Udklipsholderen er ikke tilgængelig",
"WebDAV URL copied to clipboard" : "WebDAV URL kopieret til udklipsholder",
"Unable to change the favourite state of the file" : "Kan ikke ændre favorittilstanden for filen",
"Error while loading the file data" : "Fejl under indlæsning af fildata",
"Pick a template for {name}" : "Vælg en skabelon til {name}",
+4
View File
@@ -180,8 +180,11 @@
"Unknown error" : "Ukendt fejl",
"Ownership transfer request sent" : "Anmodning om ejerskabsoverdragelse sendt",
"Cannot transfer ownership of a file or folder you do not own" : "Kan ikke overføre ejerskab af en fil eller mappe, du ikke ejer",
"Select file or folder to link to" : "Vælg fil eller mappe at linke til",
"Open the files app settings" : "Åbn fil-app indstillinger",
"Files settings" : "indstillinger for filer",
"File cannot be accessed" : "Filen kan ikke tilgås",
"You might not have have permissions to view it, ask the sender to share it" : "Du har muligvis ikke tilladelser til at se.... Bed afsenderen om at dele...",
"Show hidden files" : "Vis skjulte filer",
"Crop image previews" : "Beskær forhåndsvisninger af billeder",
"Additional settings" : "Yderligere indstillinger",
@@ -189,6 +192,7 @@
"Copy to clipboard" : "Kopier til udklipsholder",
"Use this address to access your Files via WebDAV" : "Brug denne adresse til at få adgang til dine filer via WebDAV",
"Clipboard is not available" : "Udklipsholderen er ikke tilgængelig",
"WebDAV URL copied to clipboard" : "WebDAV URL kopieret til udklipsholder",
"Unable to change the favourite state of the file" : "Kan ikke ændre favorittilstanden for filen",
"Error while loading the file data" : "Fejl under indlæsning af fildata",
"Pick a template for {name}" : "Vælg en skabelon til {name}",
+3
View File
@@ -185,6 +185,8 @@ OC.L10N.register(
"Select file or folder to link to" : "Datei oder Ordner zum Verknüpfen auswählen",
"Open the files app settings" : "Einstellungen der Dateien-App öffnen",
"Files settings" : "Dateien-Einstellungen",
"File cannot be accessed" : "Auf die Datei kann nicht zugegriffen werden",
"You might not have have permissions to view it, ask the sender to share it" : "Möglicherweise hast du nicht die Berechtigung zur Anzeige. Bitte den Absender, die Datei freizugeben.",
"Show hidden files" : "Versteckte Dateien anzeigen",
"Crop image previews" : "Bildvorschauen zuschneiden",
"Additional settings" : "Zusätzliche Einstellungen",
@@ -192,6 +194,7 @@ OC.L10N.register(
"Copy to clipboard" : "In die Zwischenablage kopieren",
"Use this address to access your Files via WebDAV" : "Diese Adresse benutzen, um über WebDAV auf deine Dateien zuzugreifen",
"Clipboard is not available" : "Zwischenablage ist nicht verfügbar",
"WebDAV URL copied to clipboard" : "WebDAV-URL in die Zwischenablage kopiert",
"Unable to change the favourite state of the file" : "Der favorisierte Status der Datei konnte nicht geändert werden",
"Error while loading the file data" : "Fehler beim Laden der Datei-Daten",
"Pick a template for {name}" : "Eine Vorlage für {name} wählen",
+3
View File
@@ -183,6 +183,8 @@
"Select file or folder to link to" : "Datei oder Ordner zum Verknüpfen auswählen",
"Open the files app settings" : "Einstellungen der Dateien-App öffnen",
"Files settings" : "Dateien-Einstellungen",
"File cannot be accessed" : "Auf die Datei kann nicht zugegriffen werden",
"You might not have have permissions to view it, ask the sender to share it" : "Möglicherweise hast du nicht die Berechtigung zur Anzeige. Bitte den Absender, die Datei freizugeben.",
"Show hidden files" : "Versteckte Dateien anzeigen",
"Crop image previews" : "Bildvorschauen zuschneiden",
"Additional settings" : "Zusätzliche Einstellungen",
@@ -190,6 +192,7 @@
"Copy to clipboard" : "In die Zwischenablage kopieren",
"Use this address to access your Files via WebDAV" : "Diese Adresse benutzen, um über WebDAV auf deine Dateien zuzugreifen",
"Clipboard is not available" : "Zwischenablage ist nicht verfügbar",
"WebDAV URL copied to clipboard" : "WebDAV-URL in die Zwischenablage kopiert",
"Unable to change the favourite state of the file" : "Der favorisierte Status der Datei konnte nicht geändert werden",
"Error while loading the file data" : "Fehler beim Laden der Datei-Daten",
"Pick a template for {name}" : "Eine Vorlage für {name} wählen",
+3
View File
@@ -185,12 +185,15 @@ OC.L10N.register(
"Select file or folder to link to" : "Datei oder Ordner zum Verknüpfen auswählen",
"Open the files app settings" : "Einstellungen der Dateien-App öffnen",
"Files settings" : "Dateien-Einstellungen",
"File cannot be accessed" : "Auf die Datei kann nicht zugegriffen werden",
"You might not have have permissions to view it, ask the sender to share it" : "Möglicherweise haben Sie nicht die Berechtigung zur Anzeige. Bitten Sie den Absender, die Datei freizugeben.",
"Show hidden files" : "Versteckte Dateien anzeigen",
"Crop image previews" : "Bildvorschauen zuschneiden",
"Additional settings" : "Zusätzliche Einstellungen",
"WebDAV" : "WebDAV",
"Copy to clipboard" : "In die Zwischenablage kopieren",
"Use this address to access your Files via WebDAV" : "Benutzen Sie diese Adresse, um via WebDAV auf Ihre Dateien zuzugreifen",
"If you have enabled 2FA, you must create and use a new app password by clicking here." : "Wenn Sie 2FA aktiviert haben, müssen Sie ein neues App-Passwort erstellen und verwenden, indem Sie hier klicken.",
"Clipboard is not available" : "Zwischenablage ist nicht verfügbar",
"WebDAV URL copied to clipboard" : "WebDAV-URL in die Zwischenablage kopiert",
"Unable to change the favourite state of the file" : "Der favorisierte Status der Datei kann nicht geändert werden",
+3
View File
@@ -183,12 +183,15 @@
"Select file or folder to link to" : "Datei oder Ordner zum Verknüpfen auswählen",
"Open the files app settings" : "Einstellungen der Dateien-App öffnen",
"Files settings" : "Dateien-Einstellungen",
"File cannot be accessed" : "Auf die Datei kann nicht zugegriffen werden",
"You might not have have permissions to view it, ask the sender to share it" : "Möglicherweise haben Sie nicht die Berechtigung zur Anzeige. Bitten Sie den Absender, die Datei freizugeben.",
"Show hidden files" : "Versteckte Dateien anzeigen",
"Crop image previews" : "Bildvorschauen zuschneiden",
"Additional settings" : "Zusätzliche Einstellungen",
"WebDAV" : "WebDAV",
"Copy to clipboard" : "In die Zwischenablage kopieren",
"Use this address to access your Files via WebDAV" : "Benutzen Sie diese Adresse, um via WebDAV auf Ihre Dateien zuzugreifen",
"If you have enabled 2FA, you must create and use a new app password by clicking here." : "Wenn Sie 2FA aktiviert haben, müssen Sie ein neues App-Passwort erstellen und verwenden, indem Sie hier klicken.",
"Clipboard is not available" : "Zwischenablage ist nicht verfügbar",
"WebDAV URL copied to clipboard" : "WebDAV-URL in die Zwischenablage kopiert",
"Unable to change the favourite state of the file" : "Der favorisierte Status der Datei kann nicht geändert werden",
+3
View File
@@ -185,12 +185,15 @@ OC.L10N.register(
"Select file or folder to link to" : "Select file or folder to link to",
"Open the files app settings" : "Open the files app settings",
"Files settings" : "Files settings",
"File cannot be accessed" : "File cannot be accessed",
"You might not have have permissions to view it, ask the sender to share it" : "You might not have have permissions to view it, ask the sender to share it",
"Show hidden files" : "Show hidden files",
"Crop image previews" : "Crop image previews",
"Additional settings" : "Additional settings",
"WebDAV" : "WebDAV",
"Copy to clipboard" : "Copy to clipboard",
"Use this address to access your Files via WebDAV" : "Use this address to access your Files via WebDAV",
"If you have enabled 2FA, you must create and use a new app password by clicking here." : "If you have enabled 2FA, you must create and use a new app password by clicking here.",
"Clipboard is not available" : "Clipboard is not available",
"WebDAV URL copied to clipboard" : "WebDAV URL copied to clipboard",
"Unable to change the favourite state of the file" : "Unable to change the favourite state of the file",
+3
View File
@@ -183,12 +183,15 @@
"Select file or folder to link to" : "Select file or folder to link to",
"Open the files app settings" : "Open the files app settings",
"Files settings" : "Files settings",
"File cannot be accessed" : "File cannot be accessed",
"You might not have have permissions to view it, ask the sender to share it" : "You might not have have permissions to view it, ask the sender to share it",
"Show hidden files" : "Show hidden files",
"Crop image previews" : "Crop image previews",
"Additional settings" : "Additional settings",
"WebDAV" : "WebDAV",
"Copy to clipboard" : "Copy to clipboard",
"Use this address to access your Files via WebDAV" : "Use this address to access your Files via WebDAV",
"If you have enabled 2FA, you must create and use a new app password by clicking here." : "If you have enabled 2FA, you must create and use a new app password by clicking here.",
"Clipboard is not available" : "Clipboard is not available",
"WebDAV URL copied to clipboard" : "WebDAV URL copied to clipboard",
"Unable to change the favourite state of the file" : "Unable to change the favourite state of the file",
+3
View File
@@ -185,12 +185,15 @@ OC.L10N.register(
"Select file or folder to link to" : "Selecciona archivo o carpeta a enlazar",
"Open the files app settings" : "Abrir la configuración de la app Archivos",
"Files settings" : "Configuración de archivos",
"File cannot be accessed" : "El archivo no puede ser accesado",
"You might not have have permissions to view it, ask the sender to share it" : "Puede que no tenga permisos para verlo, solicite al remitente que lo comparta",
"Show hidden files" : "Mostrar archivos ocultos",
"Crop image previews" : "Recortar la previsualización de las imágenes",
"Additional settings" : "Configuración adicional",
"WebDAV" : "WebDAV",
"Copy to clipboard" : "Copiar al portapapeles",
"Use this address to access your Files via WebDAV" : "Use esta dirección para acceder a tus archivos vía WebDAV",
"If you have enabled 2FA, you must create and use a new app password by clicking here." : "Si ha habilitado 2FA, debe crear y utilizar una nueva contraseña de aplicación haciendo clic aquí.",
"Clipboard is not available" : "El portapapeles no está disponible",
"WebDAV URL copied to clipboard" : "El URL Webdav URL fue copiado al portapapeles",
"Unable to change the favourite state of the file" : "No se ha podido cambiar el estado de favorito del fichero",
+3
View File
@@ -183,12 +183,15 @@
"Select file or folder to link to" : "Selecciona archivo o carpeta a enlazar",
"Open the files app settings" : "Abrir la configuración de la app Archivos",
"Files settings" : "Configuración de archivos",
"File cannot be accessed" : "El archivo no puede ser accesado",
"You might not have have permissions to view it, ask the sender to share it" : "Puede que no tenga permisos para verlo, solicite al remitente que lo comparta",
"Show hidden files" : "Mostrar archivos ocultos",
"Crop image previews" : "Recortar la previsualización de las imágenes",
"Additional settings" : "Configuración adicional",
"WebDAV" : "WebDAV",
"Copy to clipboard" : "Copiar al portapapeles",
"Use this address to access your Files via WebDAV" : "Use esta dirección para acceder a tus archivos vía WebDAV",
"If you have enabled 2FA, you must create and use a new app password by clicking here." : "Si ha habilitado 2FA, debe crear y utilizar una nueva contraseña de aplicación haciendo clic aquí.",
"Clipboard is not available" : "El portapapeles no está disponible",
"WebDAV URL copied to clipboard" : "El URL Webdav URL fue copiado al portapapeles",
"Unable to change the favourite state of the file" : "No se ha podido cambiar el estado de favorito del fichero",
+3
View File
@@ -185,12 +185,15 @@ OC.L10N.register(
"Select file or folder to link to" : "Valitse tiedosto tai kansio, johon linkitetään",
"Open the files app settings" : "Avaa tiedostosovelluksen asetukset",
"Files settings" : "Tiedostojen asetukset",
"File cannot be accessed" : "Tiedostoa ei voi käyttää",
"You might not have have permissions to view it, ask the sender to share it" : "Oikeutesi eivät kenties riitä sen katseluun, pyydä lähettäjää jakamaan se",
"Show hidden files" : "Näytä piilotetut tiedostot",
"Crop image previews" : "Rajaa kuvien esikatseluja",
"Additional settings" : "Lisäasetukset",
"WebDAV" : "WebDAV",
"Copy to clipboard" : "Kopioi leikepöydälle",
"Use this address to access your Files via WebDAV" : "Käytä tätä osoitetta yhdistääksesi tiedostosi WebDAV:in kautta",
"If you have enabled 2FA, you must create and use a new app password by clicking here." : "Jos sinulla on kaksivaiheinen todennus käytössä, sinun täytyy luoda uusi sovellussalasana ja käyttää sitä napsauttamalla tästä.",
"Clipboard is not available" : "Leikepöytä ei ole käytettävissä",
"WebDAV URL copied to clipboard" : "WebDAV-osoite kopioitu leikepöydälle",
"Unable to change the favourite state of the file" : "Suosikki-tilan muuttaminen epäonnistui.",
+3
View File
@@ -183,12 +183,15 @@
"Select file or folder to link to" : "Valitse tiedosto tai kansio, johon linkitetään",
"Open the files app settings" : "Avaa tiedostosovelluksen asetukset",
"Files settings" : "Tiedostojen asetukset",
"File cannot be accessed" : "Tiedostoa ei voi käyttää",
"You might not have have permissions to view it, ask the sender to share it" : "Oikeutesi eivät kenties riitä sen katseluun, pyydä lähettäjää jakamaan se",
"Show hidden files" : "Näytä piilotetut tiedostot",
"Crop image previews" : "Rajaa kuvien esikatseluja",
"Additional settings" : "Lisäasetukset",
"WebDAV" : "WebDAV",
"Copy to clipboard" : "Kopioi leikepöydälle",
"Use this address to access your Files via WebDAV" : "Käytä tätä osoitetta yhdistääksesi tiedostosi WebDAV:in kautta",
"If you have enabled 2FA, you must create and use a new app password by clicking here." : "Jos sinulla on kaksivaiheinen todennus käytössä, sinun täytyy luoda uusi sovellussalasana ja käyttää sitä napsauttamalla tästä.",
"Clipboard is not available" : "Leikepöytä ei ole käytettävissä",
"WebDAV URL copied to clipboard" : "WebDAV-osoite kopioitu leikepöydälle",
"Unable to change the favourite state of the file" : "Suosikki-tilan muuttaminen epäonnistui.",
+3
View File
@@ -185,12 +185,15 @@ OC.L10N.register(
"Select file or folder to link to" : "Sélectionnez le fichier ou le dossier à lier",
"Open the files app settings" : "Ouvrir les paramètres de l'application Fichiers",
"Files settings" : "Paramètres des fichiers",
"File cannot be accessed" : "Impossible d'accéder au fichier",
"You might not have have permissions to view it, ask the sender to share it" : "Vous navez peut-être pas les autorisations pour le voir, demandez à lexpéditeur de le partager.",
"Show hidden files" : "Afficher les fichiers masqués",
"Crop image previews" : "Afficher en miniatures carrées",
"Additional settings" : "Paramètres supplémentaires",
"WebDAV" : "WebDAV",
"Copy to clipboard" : "Copier dans le presse-papiers",
"Use this address to access your Files via WebDAV" : "Utilisez cette adresse pour accéder à vos fichiers via WebDAV",
"If you have enabled 2FA, you must create and use a new app password by clicking here." : "Si vous avez activé l'A2F, vous devez créer et utiliser un nouveau mot de passe d'application en cliquant ici.",
"Clipboard is not available" : "Le presse-papiers n'est pas disponible",
"WebDAV URL copied to clipboard" : "URL WebDAV copiée dans le presse-papier",
"Unable to change the favourite state of the file" : "Impossible de modifier l'état favori du fichier",
+3
View File
@@ -183,12 +183,15 @@
"Select file or folder to link to" : "Sélectionnez le fichier ou le dossier à lier",
"Open the files app settings" : "Ouvrir les paramètres de l'application Fichiers",
"Files settings" : "Paramètres des fichiers",
"File cannot be accessed" : "Impossible d'accéder au fichier",
"You might not have have permissions to view it, ask the sender to share it" : "Vous navez peut-être pas les autorisations pour le voir, demandez à lexpéditeur de le partager.",
"Show hidden files" : "Afficher les fichiers masqués",
"Crop image previews" : "Afficher en miniatures carrées",
"Additional settings" : "Paramètres supplémentaires",
"WebDAV" : "WebDAV",
"Copy to clipboard" : "Copier dans le presse-papiers",
"Use this address to access your Files via WebDAV" : "Utilisez cette adresse pour accéder à vos fichiers via WebDAV",
"If you have enabled 2FA, you must create and use a new app password by clicking here." : "Si vous avez activé l'A2F, vous devez créer et utiliser un nouveau mot de passe d'application en cliquant ici.",
"Clipboard is not available" : "Le presse-papiers n'est pas disponible",
"WebDAV URL copied to clipboard" : "URL WebDAV copiée dans le presse-papier",
"Unable to change the favourite state of the file" : "Impossible de modifier l'état favori du fichier",
+4
View File
@@ -182,14 +182,18 @@ OC.L10N.register(
"Unknown error" : "Erro descoñecido",
"Ownership transfer request sent" : "Enviouse solicitude de transferencia da propiedade",
"Cannot transfer ownership of a file or folder you do not own" : "Non se pode transferir a propiedade dun ficheiro ou cartafol do que non eres propietario",
"Select file or folder to link to" : "Seleccione o ficheiro ou cartafol ao que quere enlazar",
"Open the files app settings" : "Abre a configuración da aplicación de ficheiros",
"Files settings" : "Axustes de ficheiros",
"File cannot be accessed" : "Non se pode acceder ao ficheiro",
"You might not have have permissions to view it, ask the sender to share it" : "É posible que non teñas permisos para velo, pídelle ao remitente que o comparta",
"Show hidden files" : "Amosar os ficheiros agochados",
"Crop image previews" : "Recortar a vista previa das imaxes",
"Additional settings" : "Axustes adicionais",
"WebDAV" : "WebDAV",
"Copy to clipboard" : "Copiar no portapapeis.",
"Use this address to access your Files via WebDAV" : "Empregue este enderezo para acceder ao seu Ficheiros mediante WebDAV",
"If you have enabled 2FA, you must create and use a new app password by clicking here." : "Se activaches 2FA, debes crear e utilizar un novo contrasinal da aplicación facendo clic aquí.",
"Clipboard is not available" : "O portapapeis non está dispoñible",
"WebDAV URL copied to clipboard" : "A URL de WebDAV copiouse no portapapeis",
"Unable to change the favourite state of the file" : "Non é posíbel cambiar o estado favorito do ficheiro",
+4
View File
@@ -180,14 +180,18 @@
"Unknown error" : "Erro descoñecido",
"Ownership transfer request sent" : "Enviouse solicitude de transferencia da propiedade",
"Cannot transfer ownership of a file or folder you do not own" : "Non se pode transferir a propiedade dun ficheiro ou cartafol do que non eres propietario",
"Select file or folder to link to" : "Seleccione o ficheiro ou cartafol ao que quere enlazar",
"Open the files app settings" : "Abre a configuración da aplicación de ficheiros",
"Files settings" : "Axustes de ficheiros",
"File cannot be accessed" : "Non se pode acceder ao ficheiro",
"You might not have have permissions to view it, ask the sender to share it" : "É posible que non teñas permisos para velo, pídelle ao remitente que o comparta",
"Show hidden files" : "Amosar os ficheiros agochados",
"Crop image previews" : "Recortar a vista previa das imaxes",
"Additional settings" : "Axustes adicionais",
"WebDAV" : "WebDAV",
"Copy to clipboard" : "Copiar no portapapeis.",
"Use this address to access your Files via WebDAV" : "Empregue este enderezo para acceder ao seu Ficheiros mediante WebDAV",
"If you have enabled 2FA, you must create and use a new app password by clicking here." : "Se activaches 2FA, debes crear e utilizar un novo contrasinal da aplicación facendo clic aquí.",
"Clipboard is not available" : "O portapapeis non está dispoñible",
"WebDAV URL copied to clipboard" : "A URL de WebDAV copiouse no portapapeis",
"Unable to change the favourite state of the file" : "Non é posíbel cambiar o estado favorito do ficheiro",
+3 -3
View File
@@ -166,10 +166,10 @@ OC.L10N.register(
"The ownership transfer of {path} from {user} has completed." : "A(z) {path} tulajdonjogának átruházása {user} részéről sikeres.",
"in %s" : "itt: %s",
"File Management" : "Fájlkezelés",
"Storage informations" : "Tárhely információk",
"Storage informations" : "Tárhely-információk",
"{usedQuotaByte} used" : "{usedQuotaByte} felhasználva",
"{relative}% used" : "{relative}% felhasználva",
"Could not refresh storage stats" : "Nem sikerült frissíteni a tárolói statisztikákat",
"Could not refresh storage stats" : "Nem sikerült frissíteni a tárhelystatisztikákat",
"Transfer ownership of a file or folder" : "Fájl vagy mappa tulajdonjogának átruházása",
"Choose file or folder to transfer" : "Válasszon egy fájlt vagy mappát az átruházáshoz",
"Change" : "Módosítás",
@@ -183,7 +183,7 @@ OC.L10N.register(
"Ownership transfer request sent" : "Tulajdonjog átruházási kérés elküldve",
"Cannot transfer ownership of a file or folder you do not own" : "Nem ruházható át olyan fájl vagy mappa tulajdonjoga, amely nem Öné",
"Select file or folder to link to" : "Válassza ki a hivatkozandó fájlt vagy mappát",
"Open the files app settings" : "Nyissa meg a fájlalkalmazás beállításait",
"Open the files app settings" : "Nyissa meg a Fájlok lalkalmazás beállításait",
"Files settings" : "Fájlok beállításai",
"Show hidden files" : "Rejtett fájlok megjelenítése",
"Crop image previews" : "Kép előnézetek vágása",

Some files were not shown because too many files have changed in this diff Show More