Compare commits

..

172 Commits

Author SHA1 Message Date
Josh 0de4631714 chore: normalize trailing slash handling
Signed-off-by: Josh <josh.t.richards@gmail.com>
2026-01-10 12:13:46 -05:00
Josh ff6d2fc353 refactor(Filesystem): use PathHelper for canonical normalization
Signed-off-by: Josh <josh.t.richards@gmail.com>
2026-01-09 22:22:53 -05:00
Nextcloud bot d341c2011f fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2026-01-10 00:27:12 +00:00
Raphael Gradenwitz 7eea3b7742 Merge pull request #55433 from nextcloud/ernolf/enh/http2-brotli-client
perf(client): enable HTTP/2 and brotli support in internal HTTP client
2026-01-10 01:09:17 +01:00
Raphael Gradenwitz 7c526b4de3 Merge branch 'master' into ernolf/enh/http2-brotli-client 2026-01-10 00:00:47 +01:00
Sebastian Krupinski 635e26dfdc Merge pull request #57231 from nextcloud/feat/restrict-calendar-invitation-users
feat: restrict calendar invitation participants
2026-01-09 13:42:12 -05:00
Robin Appelman c2cd236411 Merge pull request #57191 from nextcloud/dav-x-user-id
feat: also send x-user-id for dav responses
2026-01-09 18:43:36 +01:00
SebastianKrupinski acfec22652 feat: restrict calendar invitation participants
Signed-off-by: SebastianKrupinski <krupinskis05@gmail.com>
2026-01-09 12:07:18 -05:00
Robin Appelman 328a4608aa Merge pull request #57454 from nextcloud/fix/session/handle-null-logger
fix(session): handle null logger
2026-01-09 17:51:04 +01:00
Christoph Wurst 7e188433a1 fix(session): handle null logger
Signed-off-by: Christoph Wurst <1374172+ChristophWurst@users.noreply.github.com>
2026-01-09 16:42:39 +01:00
Benjamin Gaussorgues acb3e68a93 Merge pull request #56725 from nextcloud/rakekniven-patch-3 2026-01-09 14:38:37 +01:00
nextcloud-command fbb551311e chore(assets): Recompile assets
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
2026-01-09 09:24:00 +00:00
rakekniven c2ae99a668 chore(i18n): Remove strings from i18n and adapted casing
Reported at Transifex

Signed-off-by: rakekniven <2069590+rakekniven@users.noreply.github.com>
Signed-off-by: Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
2026-01-09 10:13:22 +01:00
ernolf 932523e844 style(tests): apply cs-fixer formatting to ClientTest
Signed-off-by: ernolf <raphael.gradenwitz@googlemail.com>
2026-01-09 01:29:59 +01:00
Nextcloud bot 6fd76bfa0e fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2026-01-09 00:14:00 +00:00
Raphael Gradenwitz 510c203dfe Merge branch 'master' into ernolf/enh/http2-brotli-client
Signed-off-by: Raphael Gradenwitz <39901936+ernolf@users.noreply.github.com>
2026-01-08 21:02:07 +01:00
Benjamin Gaussorgues 0514ecfb96 Merge pull request #57398 from nextcloud/release/33.0.0_beta_2 2026-01-08 17:06:21 +01:00
Benjamin Gaussorgues 91a544ef45 Merge pull request #53414 from nextcloud/fix/49584-background-worker-remove-interval 2026-01-08 15:57:05 +01:00
Louis a0c922cc7f Merge pull request #56404 from nextcloud/share-sidebar-hide-external
feat: hide "External Shares" section if no external shares can be created
2026-01-08 14:32:11 +01:00
Côme Chilliet 2da078f258 Merge pull request #55861 from nextcloud/feat/allow-decrypt-all-with-encryption-disabled
feat(encryption): Support running decrypt-all when encryption is already disabled
2026-01-08 14:19:06 +01:00
Benjamin Gaussorgues 36b0d7c189 Merge pull request #55265 from nextcloud/perf/log-slow-dns 2026-01-08 14:06:31 +01:00
Benjamin Gaussorgues fe34ea5ec7 Merge pull request #57407 from nextcloud/carl/fix-php-85-deprecation-image 2026-01-08 13:57:11 +01:00
Benjamin Gaussorgues ae250777fd Merge pull request #56899 from nextcloud/feat/noid/ocm-capabilities 2026-01-08 13:46:09 +01:00
Benjamin Gaussorgues 17aa77e29f Merge pull request #57427 from nextcloud/fix/openmetrics_classes 2026-01-08 13:45:55 +01:00
Salvatore Martire 43f2470f90 fix: use interval value in JobWorker
Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com>
2026-01-08 13:45:11 +01:00
Joas Schilling d5eab95414 Merge pull request #57428 from nextcloud/dependabot/composer/aws/aws-sdk-php-3.369.3
build(deps): bump aws/aws-sdk-php from 3.349.3 to 3.369.9
2026-01-08 13:40:04 +01:00
nextcloud-command 7e4c4f2f3c chore(assets): Recompile assets
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
2026-01-08 11:54:41 +00:00
Robin Appelman de286709f8 feat: hide "External Shares" section if no external shares can be created
Signed-off-by: Robin Appelman <robin@icewind.nl>
2026-01-08 11:49:02 +00:00
Andy Scherzinger d86975e9fa Merge pull request #56923 from nextcloud/fix/update-all
fix(settings): update all button only updates a single app
2026-01-08 12:48:34 +01:00
Joas Schilling 03adb7e184 build(deps): bump aws/aws-sdk-php from 3.349.3 to 3.369.9
Signed-off-by: Joas Schilling <coding@schilljs.com>
2026-01-08 11:52:50 +01:00
Kate 8eb24155c4 Merge pull request #56518 from nextcloud/jtr/feat-appmanager-cleanappid-log 2026-01-08 11:42:04 +01:00
Git'Fellow 377de23bf5 Merge pull request #57291 from nextcloud/fixTypoAdminAuditLog
fix(admin_audit) Fix typo in visibility log message
2026-01-08 11:41:45 +01:00
Louis 73dd45be4f Merge pull request #57289 from nextcloud/feature/54562/drop-mounts-on-full-or-provider-setup
Feature/54562/drop mounts on full or provider setup
2026-01-08 11:26:50 +01:00
Christoph Wurst adf7ea5f0b perf: log slow DNS operations
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
2026-01-08 11:22:15 +01:00
Christoph Wurst cc89a2a2b8 refactor: extract slow operation logging into trait
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
2026-01-08 11:22:15 +01:00
Benjamin Gaussorgues 5403284b23 Merge pull request #55293 from nextcloud/jtr/refactor-dav-quotaplugin 2026-01-08 11:18:02 +01:00
Benjamin Gaussorgues f56f747f46 Merge pull request #57245 from nextcloud/jtr/refactor-versions-DAV-plugin 2026-01-08 11:12:50 +01:00
Benjamin Gaussorgues 7a2606b894 Merge pull request #57267 from nextcloud/jtr/refactor-trashbin-sabre-plugin 2026-01-08 11:11:37 +01:00
Joas Schilling eb91d8671d Merge pull request #57348 from nextcloud/fix/adjust-public-page-footer-logic
fix: adjust public page footer logic
2026-01-08 11:10:07 +01:00
Benjamin Gaussorgues 1a5ad32063 fix(openmetrics): import right classes
Signed-off-by: Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
2026-01-08 10:39:46 +01:00
Benjamin Gaussorgues a1fbd55992 Merge pull request #57395 from nextcloud/feat/exapp-task-proc-endpoints 2026-01-08 09:52:50 +01:00
Benjamin Gaussorgues a6a320498b Merge pull request #55252 from nextcloud/chore/chunked_orphan_delete 2026-01-08 09:50:09 +01:00
Anupam Kumar 3e4e544096 feat(TaskProcessing): add endpoints for ExApp access without userId
Signed-off-by: Anupam Kumar <kyteinsky@gmail.com>
2026-01-08 11:36:08 +05:30
Nextcloud bot 1a7f2f878e fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2026-01-08 00:13:49 +00:00
nextcloud-command f6a783e07b chore(assets): Recompile assets
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
2026-01-07 19:21:14 +00:00
Thomas Lamant 7436340f4c fix: update() function does not return a Promise
Signed-off-by: Thomas Lamant <tom@tmlmt.com>
2026-01-07 19:18:29 +00:00
Thomas Lamant 58c6a8387b fix: update all button only updates a single app
Signed-off-by: Thomas Lamant <tom@tmlmt.com>
2026-01-07 19:18:29 +00:00
Maxence Lange 6af64a5495 feat(ocm): event on ocm discovery and ocm request
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
2026-01-07 17:54:26 -01:00
Joas Schilling 66c8f9c4dc Merge pull request #57414 from nextcloud/bugfix/noid/clean-language
fix(l10n): Fix language selection
2026-01-07 19:05:41 +01:00
Joas Schilling 52cfd57af9 Merge pull request #57413 from nextcloud/bugfix/noid/support-native-int-range
fix(controller): Support native int ranges
2026-01-07 19:05:19 +01:00
Ferdinand Thiessen 6a75cd9454 Merge pull request #57347 from nextcloud/refactor/drop-deprecated-composable
refactor(files): migrate from deprecated `useNavigation` to `activeStore`
2026-01-07 18:06:41 +01:00
Daniel Calviño Sánchez 8e5ae53e02 Merge pull request #56938 from nextcloud/unify-handling-of-exclude-groups-in-contacts-menu-and-sharing
fix: Unify handling of exclude groups in contacts menu and sharing
2026-01-07 18:04:53 +01:00
Joas Schilling ab122ac15d fix(l10n): Fix language selection
Signed-off-by: Joas Schilling <coding@schilljs.com>
2026-01-07 17:41:18 +01:00
Joas Schilling f2e2e4ea21 fix(controller): Support native int ranges
Signed-off-by: Joas Schilling <coding@schilljs.com>
2026-01-07 17:36:57 +01:00
Joas Schilling 15b45975e2 Merge pull request #57410 from nextcloud/bugfix/noid/fix-generate-id
fix(snowflake): Fix generateId() call for SnowflakeEntity
2026-01-07 17:17:33 +01:00
Salvatore Martire 2d22c4f654 fix: update information cached by mount point on rename
Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com>
2026-01-07 17:00:09 +01:00
Salvatore Martire 07eef5eaf4 fix: drop set up partial mounts on setupForUser
Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com>
2026-01-07 17:00:09 +01:00
nextcloud-command 09e0f06678 chore(assets): Recompile assets
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
2026-01-07 16:50:42 +01:00
Ferdinand Thiessen 47acb66b9c refactor(files): migrate from deprecated useNavigation to activeStore
Small preparation for upcoming Vue 3 migration of the files app.

Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
2026-01-07 16:50:42 +01:00
SebastianKrupinski 6b3d3fd2d3 fix: adjust public page footer logic
Signed-off-by: SebastianKrupinski <krupinskis05@gmail.com>
2026-01-07 10:16:35 -05:00
Joas Schilling f42493bf1e Merge pull request #57409 from nextcloud/fix/ci-psalm
ci(static-code-analysis): add missing permissions to upload sarif file
2026-01-07 16:03:58 +01:00
Joas Schilling fe393c5dbf fix(snowflake): Fix generateId() call for SnowflakeEntity
Signed-off-by: Joas Schilling <coding@schilljs.com>
2026-01-07 15:39:09 +01:00
Carl Schwan bd815595d4 fix: Remove NOP ReflectionProperty::setAccessible calls
Doesn't do anything since PHP 8.1 and is deprecated since PHP 8.5
2026-01-07 15:23:20 +01:00
Ferdinand Thiessen 86c90221f1 ci(static-code-analysis): add missing permissions to upload sarif file
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
2026-01-07 15:21:48 +01:00
Maxence Lange 0cdd19271d Merge pull request #56047 from nextcloud/feat/ocm/handle-new-ocm-endpoint
feat(ocm): handle /.well-known/ocm
2026-01-07 13:17:06 -01:00
Carl Schwan 513b37916f fix(image): Remove NOP imagedestroy call
This is NOP since 8.0 and deprecated since 8.5

Signed-off-by: Carl Schwan <carlschwan@kde.org>
2026-01-07 15:13:07 +01:00
Joas Schilling 9e516beb85 Merge pull request #57403 from nextcloud/followup/noid/snowflake-entity
fix(snowflake): Allow SnowflakeAware to overwrite the field types
2026-01-07 15:10:09 +01:00
Joas Schilling 6b6deefee9 Merge pull request #57373 from nextcloud/carl/fix-deprecated-alias
fix: Usage of a deprecated alias
2026-01-07 14:35:32 +01:00
Joas Schilling 8d55b13641 Merge pull request #57367 from nextcloud/work/carl/psalm-unittests
refactor(psalm): Enable psalm for comments unit tests
2026-01-07 14:16:14 +01:00
Joas Schilling 2bd2cc71e5 fix(snowflake): Allow SnowflakeAware to overwrite the field types
Signed-off-by: Joas Schilling <coding@schilljs.com>
2026-01-07 14:06:18 +01:00
Joas Schilling 40b79f5af8 Merge pull request #56795 from nextcloud/feat/noid/extend-entity-to-be-snoflake-aware
feat(snowflake): extend Entity class to support snowflakes
2026-01-07 13:42:49 +01:00
Carl Schwan 6eb1609b35 fix(psalm): Fix InvalidArgument in FilesByType OpenMetrics exporter
Signed-off-by: Carl Schwan <carlschwan@kde.org>
2026-01-07 13:22:39 +01:00
Carl Schwan 58de51160c fix(psalm): Fix return type of TokenService::getTokens
Signed-off-by: Carl Schwan <carlschwan@kde.org>
2026-01-07 13:21:34 +01:00
Carl Schwan a430702caa refactor(psalm): Enable psalm for comments unit tests
This is the first step to enable psalm for our test suite to find issues
also there.

At the moment, this already found some completely broken and unused
method in TestCase and prepare the way for making ICommentsManager work
with snowflake ids by using string instead of int for the ids
consistently.

Signed-off-by: Carl Schwan <carlschwan@kde.org>
2026-01-07 13:21:33 +01:00
Benjamin Gaussorgues 351351a832 Merge pull request #57371 from nextcloud/enh/noid/change-config-to-amr 2026-01-07 12:04:36 +01:00
Worker Builder 944341543e build(hub): 33.0.0 beta 2
Signed-off-by: Worker Builder <worker-builder@nextcloud.com>
2026-01-07 10:53:53 +00:00
Joas Schilling e5c989066f Merge pull request #57394 from nextcloud/bugfix/noid/theming-links
fix(settings): Allow clearing legal and privacy links
2026-01-07 11:06:33 +01:00
Benjamin Gaussorgues 62513dfd92 Merge pull request #57165 from nextcloud/feat/openmetrics 2026-01-07 10:43:56 +01:00
Joas Schilling 649e042568 fix(settings): Fix reset button for legal and privacy
Signed-off-by: Joas Schilling <coding@schilljs.com>
2026-01-07 09:45:48 +01:00
Benjamin Gaussorgues 71fa5937b2 feat(openapi): add OpenMetrics controller into OpenAPI
Signed-off-by: Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
2026-01-07 09:38:13 +01:00
Benjamin Gaussorgues 6ee8325b3e feat(files_sharing): add basic OpenMetrics exporter for files shares
Signed-off-by: Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
2026-01-07 09:38:13 +01:00
Benjamin Gaussorgues 47de164946 feat(comments): add basic OpenMetrics exporter
Signed-off-by: Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
2026-01-07 09:38:13 +01:00
Benjamin Gaussorgues c57c4843e8 feat(openmetrics): introduce OpenMetrics exporter
Expose a `/metrics` endpoint with some basic metrics

Signed-off-by: Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
2026-01-07 09:38:13 +01:00
Joas Schilling 7c64394617 fix(settings): Allow clearing legal and privacy links
Signed-off-by: Joas Schilling <coding@schilljs.com>
2026-01-07 09:29:34 +01:00
Nextcloud bot c09168e911 fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2026-01-07 00:13:32 +00:00
Benjamin Gaussorgues 9f7d4d055e Merge pull request #57361 from nextcloud/release/33.0.0_beta_1 2026-01-06 16:56:21 +01:00
Joas Schilling c3be0b8814 Merge pull request #57380 from nextcloud/automated/noid/master-update-code-signing-crl
[master] fix(security): Update code signing revocation list
2026-01-06 16:54:55 +01:00
nextcloud-command 1432c97584 fix(security): Update code signing revocation list
Signed-off-by: GitHub <noreply@github.com>
2026-01-06 15:38:16 +00:00
Simon L. 178fb77be8 feat(Config.php): change array_merge to array_replace_recursive when merging configs
Signed-off-by: Simon L. <szaimen@e.mail.de>
2026-01-06 16:03:38 +01:00
Benjamin Gaussorgues 86fe44d9f4 Merge pull request #56627 from nextcloud/fix/54953/value-is-already-team-id 2026-01-06 16:00:53 +01:00
Tobias Kaminsky fdfaf6b363 Merge pull request #57372 from nextcloud/feat/adapt-webhook
Feat(webhook_listeners): adapt webhook payload format
2026-01-06 15:55:27 +01:00
Tobias Kaminsky ad13a8acc7 Merge pull request #57235 from nextcloud/enh/noid/testing-ocr-provider
Add fake OCR taskprocessing provider in the testing app
2026-01-06 15:52:10 +01:00
Carl Schwan 693a2263cc fix(entity): Do not call getId when inserting and $id is null
Otherwise this breaks some existing code, in particular PublicKeyToken

Signed-off-by: Carl Schwan <carlschwan@kde.org>
2026-01-06 15:42:03 +01:00
Jana Peper 65d44b0007 docs: adapt docblock
Signed-off-by: Jana Peper <jana.peper@nextcloud.com>
2026-01-06 15:24:40 +01:00
Jana Peper ec9cac90e0 feat: adapt webhook payload format
Signed-off-by: Jana Peper <jana.peper@nextcloud.com>
2026-01-06 15:19:22 +01:00
Carl Schwan e63c4afdab fix: Usage of a deprecated alias
The deprecated warning:

The requested alias "UserId" is deprecated. Please request "userId" directly.

Signed-off-by: Carl Schwan <carlschwan@kde.org>
2026-01-06 15:04:07 +01:00
Julien Veyssier e1d19b2c24 feat: add fake OCR taskprocessing provider in the testing app
Signed-off-by: Julien Veyssier <julien-nc@posteo.net>
2026-01-06 14:36:51 +01:00
Kate 72ad2edcd7 Merge pull request #57118 from nextcloud/test/delete-orphaned-files/improve-count-mounts 2026-01-06 14:36:05 +01:00
Robin Appelman 72632faaf1 Merge pull request #57284 from nextcloud/allow-cross-share-move-delete
fix: allow moving from of non-resharable to other share if the user has delete permissions
2026-01-06 14:23:51 +01:00
Côme Chilliet ebab99ec9a Merge pull request #56779 from nextcloud/jtr/needUpgrade-refactor
feat: improve needUpgrade() output and refactor for clarity
2026-01-06 14:04:13 +01:00
Carl Schwan 7c1a8a4060 feat: Adapt a bit the snowflake ids API
- Rename setId() -> generateId() in SnowflakeAwareEntity

Signed-off-by: Carl Schwan <carlschwan@kde.org>
2026-01-06 12:57:17 +01:00
Anna Larch 5f797ebc32 refactor: move existing usages of snoflake IDs SnowflakeAwareEntity
Signed-off-by: Anna Larch <anna@nextcloud.com>
2026-01-06 12:57:17 +01:00
Anna Larch a100ede789 feat: extend Entity and adjust QBMapper to support Snowflake IDs
Signed-off-by: Anna Larch <anna@nextcloud.com>
2026-01-06 12:57:17 +01:00
Anna Larch f546daada7 refactor: Rename Snowflake Generator and Decoder
And introduce the Snowflake DTO

Signed-off-by: Anna Larch <anna@nextcloud.com>
2026-01-06 12:57:04 +01:00
Côme Chilliet c32009fd32 Merge pull request #57145 from nextcloud/carl/psalm-dav
refactor(dav): fix psalm for dav endpoints
2026-01-06 12:47:29 +01:00
Benjamin Gaussorgues 72be2f41b3 Merge pull request #57099 from nextcloud/carl/fix-32-bits-job-tests 2026-01-06 11:59:28 +01:00
Worker Builder 758a9c26db build(hub): 33.0.0 beta 1
Signed-off-by: Worker Builder <worker-builder@nextcloud.com>
2026-01-06 10:34:50 +00:00
Ferdinand Thiessen 0c6565ea44 fix(birthday-service): Fix on 32 bits system
Signed-off-by: Carl Schwan <carlschwan@kde.org>
2026-01-06 10:44:47 +01:00
Carl Schwan 33e5f2d345 fix(background-jobs): Fix unit tests with 32-bits tests
Signed-off-by: Carl Schwan <carl.schwan@nextcloud.com>
2026-01-06 10:44:21 +01:00
Nextcloud bot 0a3cc4dd6f fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2026-01-06 00:13:48 +00:00
Ferdinand Thiessen c6b095234e Merge pull request #57236 from nextcloud/refactor/profile-vue3-ts
refactor(profile): migrate to script setup and Vue 3
2026-01-05 22:52:49 +01:00
Ferdinand Thiessen f9d4bb2ba8 chore: compile assets
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
2026-01-05 22:21:43 +01:00
Ferdinand Thiessen ad61aa7a30 refactor(profile): migrate to script setup and Vue 3
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
2026-01-05 22:16:48 +01:00
Ferdinand Thiessen 8cc588fc42 Merge pull request #57341 from nextcloud/refactor/federation-vue3
refactor(federation): migrate app frontend (admin settings) to Vue 3
2026-01-05 20:07:18 +01:00
nextcloud-command 35bfa1d2f0 chore(assets): Recompile assets
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
2026-01-05 17:16:35 +00:00
Ferdinand Thiessen 5d3e1f70b2 refactor(federation): migrate app frontend (admin settings) to Vue 3
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
2026-01-05 18:08:29 +01:00
Robin Appelman 8a05a3e01b Merge pull request #57186 from nextcloud/perbucket-without-multibucket
feat: don't gate perBucket object store configuration behind multibucket
2026-01-05 16:49:16 +01:00
Robin Appelman afa23291d6 feat: don't gate perBucket object store configuration behind multibucket
a setup can have multiple bucket without having `multibucket` enabled trough things like per-groupfolder buckets

Signed-off-by: Robin Appelman <robin@icewind.nl>
2026-01-05 16:09:25 +01:00
Ferdinand Thiessen c50c5a9e6b Merge pull request #57277 from nextcloud/refactor/files-sidebar-nodeapi
refactor!: migrate files sidebar to Node API
2026-01-05 13:38:26 +01:00
Maxence Lange eb0369705a Merge pull request #56240 from nextcloud/fix/noid/set-adr-book-local-but-not-system
fix(contacts): allow address book to be local but not system
2026-01-05 09:55:42 -01:00
Joas Schilling fe0c56a1d7 Merge pull request #57332 from nextcloud/jtr/chore-drop-10n-xgettextfiles
chore(l10n): drop unused xgettextfiles
2026-01-05 10:00:42 +01:00
Ferdinand Thiessen 98a4b959ec chore: compile assets
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
2026-01-05 02:23:41 +01:00
Ferdinand Thiessen fd96a32dda test: adjust cypress tests
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
2026-01-05 02:23:30 +01:00
Ferdinand Thiessen 3726596ad0 refactor(systemtags): migrate to new files sidebar API
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
2026-01-05 02:23:15 +01:00
Ferdinand Thiessen f9a137ea87 refactor(files): migrate favorite sidebar action to new Sidebar API
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
2026-01-05 02:23:15 +01:00
Ferdinand Thiessen 7077685bf8 refactor(files_sharing): migrate to new Files Sidebar API
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
2026-01-05 02:23:15 +01:00
Ferdinand Thiessen 34511e9036 refactor(comments): migrate to new Files Sidebar API
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
2026-01-05 02:23:15 +01:00
Ferdinand Thiessen 493c371a22 refactor(files_versions): adjust frontend for new files sidebar API
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
2026-01-05 02:23:15 +01:00
Ferdinand Thiessen 4a9cdeb01f refactor!(files): migrate sidebar API to use Node API
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
2026-01-05 02:23:15 +01:00
Nextcloud bot 7abd46fb53 fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2026-01-05 00:13:26 +00:00
Ferdinand Thiessen fb18804192 chore(deps): update @nextcloud/files to v4.0.0-beta.8
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
2026-01-04 22:30:12 +01:00
github-actions[bot] 513c0cceb6 Merge pull request #57320 from nextcloud/dependabot/npm_and_yarn/build/frontend-legacy/nextcloud/files-4.0.0-beta.8
build(deps): bump @nextcloud/files from 4.0.0-beta.7 to 4.0.0-beta.8 in /build/frontend-legacy
2026-01-04 08:29:45 +00:00
Josh 867a8d1088 chore(l10n): drop unused xgettextfiles
Signed-off-by: Josh <josh.t.richards@gmail.com>
2026-01-03 20:32:45 -05:00
nextcloud-command dc5d199e3a chore(assets): Recompile assets
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
2026-01-03 20:41:28 +00:00
dependabot[bot] 41c739d370 build(deps): bump @nextcloud/files in /build/frontend-legacy
Bumps [@nextcloud/files](https://github.com/nextcloud-libraries/nextcloud-files) from 4.0.0-beta.7 to 4.0.0-beta.8.
- [Release notes](https://github.com/nextcloud-libraries/nextcloud-files/releases)
- [Changelog](https://github.com/nextcloud-libraries/nextcloud-files/blob/main/CHANGELOG.md)
- [Commits](https://github.com/nextcloud-libraries/nextcloud-files/compare/v4.0.0-beta.7...v4.0.0-beta.8)

---
updated-dependencies:
- dependency-name: "@nextcloud/files"
  dependency-version: 4.0.0-beta.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-03 21:33:05 +01:00
Josh 24ec0e85e5 feat(AppManager): log when cleanAppId drops invalid chars
Log a debug message if invalid characters are replaced in app IDs.

Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-12-31 14:30:05 -05:00
Git'Fellow eafbb5a23c fix(admin_audit): Fix typo in visibility log message
Signed-off-by: Git'Fellow <12234510+solracsf@users.noreply.github.com>
2025-12-30 10:09:08 +01:00
Robin Appelman 8cfb49012d test: update cross-share move tests
Signed-off-by: Robin Appelman <robin@icewind.nl>
2025-12-29 17:39:44 +01:00
Robin Appelman 39c8141f0c fix: allow moving from of non-resharable to other share if the user has delete permissions
Signed-off-by: Robin Appelman <robin@icewind.nl>
2025-12-29 17:39:43 +01:00
Josh 5c51b42d3f test(trashbin): Update DAV quotaProvider test cases
Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-12-27 00:40:55 -05:00
Josh 80caedb050 chore: php-cs fixup
Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-12-27 00:30:19 -05:00
Josh 853db93601 chore: typo fixup
Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-12-27 00:26:11 -05:00
Josh 355d6637ff refactor(trashbin): restyle DAV handlers, enhance internal docs, refactor for clarity & robustness
Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-12-27 00:07:19 -05:00
Josh 183136d166 chore: Fix comments and formatting in Plugin.php
Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-12-26 19:07:13 -05:00
Josh b872208285 refactor(files_versions): tidy up UA download header logic and modernize class structure
Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-12-26 18:56:56 -05:00
Maxence Lange b28176458d fix(contacts): not contact, not local
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
2025-12-22 12:36:33 -01:00
Robin Appelman 69249a3ce3 feat: also send x-user-id for dav responses
Signed-off-by: Robin Appelman <robin@icewind.nl>
2025-12-19 18:20:01 +01:00
Carl Schwan 3555e00754 refactor(dav): fix psalm for dav endpoints
Signed-off-by: Carl Schwan <carl.schwan@nextcloud.com>
2025-12-17 15:09:48 +01:00
Côme Chilliet c11cc64470 chore: update psalm baseline
Signed-off-by: Côme Chilliet <come.chilliet@nextcloud.com>
2025-12-16 11:09:46 +01:00
Côme Chilliet a6184661bd feat(encryption): Support running decrypt-all when encryption is already disabled
This was an arbitrary limitation since the first thing the command does
 is disabling encryption anyway, it makes little sence to force the admin
 to enable encryption first.

Signed-off-by: Côme Chilliet <come.chilliet@nextcloud.com>
2025-12-16 11:09:46 +01:00
Maxence Lange 981e987bd0 fix(team-manager): team is already teamid
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
2025-12-16 08:56:46 -01:00
provokateurin f9157c85c2 test(DeleteOrphanedFilesTest): Improve counting mounts
Signed-off-by: provokateurin <kate@provokateurin.de>
2025-12-16 09:11:27 +01:00
Daniel Calviño Sánchez fbe2023d39 fix: Unify handling of exclude groups in contacts menu and sharing
If the current user belongs to both one or more groups excluded from
sharing and one or more groups not excluded from sharing the user is
allowed to share. However, in the contacts menu, as soon as the current
user belonged to a group excluded from sharing the user could not search
for local contacts. This has been unified now with the sharing
behaviour, so local contacts can still be searched if the user also
belongs to a group not excluded from sharing (or to no group at all,
which was also allowed before).

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2025-12-09 19:16:59 +01:00
Daniel Calviño Sánchez d59d8db1d6 test: Add unit test for excluded groups in contacts menu
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2025-12-09 19:16:59 +01:00
Daniel Calviño Sánchez 694651de3a test: Adjust unit test name to better reflect its behaviour
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2025-12-09 19:16:59 +01:00
Daniel Calviño Sánchez 70ed393b34 test: Add integration tests for excluded groups in contacts and sharees
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2025-12-09 19:16:59 +01:00
Josh 3de06a2b33 chore: lint happiness
Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-12-01 12:26:03 -05:00
Josh d3432482cc feat: improve needUpgrade() output and refactor for clarity
- Reorganized logic to improve clarity + eliminate duplication
- Switched app handling to non-deprecated IAppManager API
- Make the HintException clearer and more actionable
- Log disallowed downgrade attempts before throwing

Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-12-01 12:10:52 -05:00
Maxence Lange e456f116b8 feat(ocm): handle /well-known/ocm
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
2025-11-07 08:55:16 -01:00
ernolf b6ea2bc0f5 refactor(http-client): use direct HTTP/2 cURL hint and align tests
Signed-off-by: ernolf <raphael.gradenwitz@googlemail.com>
2025-10-22 12:17:17 +02:00
ernolf 65aa731ef3 test: add unit test for Accept-Encoding with Brotli support
Signed-off-by: ernolf <raphael.gradenwitz@googlemail.com>
2025-09-30 18:01:38 +02:00
ernolf 812f12ecc4 perf(client): enable HTTP/2 and brotli support in internal HTTP client
- Prefer HTTP/2 by setting RequestOptions::VERSION => "2.0" so clients
  that respect PSR-7 request version will prefer HTTP/2.
- Add a curl hint (CURLOPT_HTTP_VERSION) to prefer HTTP/2 via ALPN
  (CURL_HTTP_VERSION_2TLS or CURL_HTTP_VERSION_2_0 fallback) while allowing
  automatic fallback to HTTP/1.1.
- Advertise Brotli ("br") in Accept-Encoding when the php-brotli extension
  is available (detected via function_exists('brotli_uncompress')), otherwise
  fall back to gzip.

Notes:
- The PSR-7 request version is used as a hint for HTTP client libraries;
  setting the version to "2.0" signals a preference for HTTP/2 at the request
  abstraction level.
- The curl option is defensive: it prefers HTTP/2 where libcurl supports it
  (via ALPN), but will not break on older libcurl/builds (uses defined()).

Compatibility:
- Fully backwards compatible: if the php-brotli extension is not present,
  no Brotli usage will occur and behaviour remains equivalent to previous
  (gzip).

Signed-off-by: ernolf <raphael.gradenwitz@googlemail.com>
2025-09-30 17:01:07 +02:00
Josh a9b17a1a16 chore: Add OCP\Util import
Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-09-26 13:42:47 -04:00
Josh 5f5bb77bf3 fix: Update QuotaPlugin to handle 32-bit numeric lengths correctly
Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-09-26 13:40:59 -04:00
Josh fbe5238d7f fix: review input
Co-authored-by: Carl Schwan <carl@carlschwan.eu>
Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-09-26 13:17:47 -04:00
Josh cc96a16df5 fix: Apply suggestions from code review
Co-authored-by: Carl Schwan <carl@carlschwan.eu>
Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-09-26 13:11:51 -04:00
Josh 04f30cad62 chore: drop buildFileViewMock cast and give it a docblock
Updated the buildFileViewMock method to accept int, float, or false as quota type.

Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-09-24 20:53:57 -04:00
Josh 23546013e1 fix(dav): test hint time in buildFileViewMock method wrong
Doesn't match current interface.

Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-09-24 20:46:39 -04:00
Josh 45eb87ba6e chore: Change methods back to public for tests
Tagged with \@internal instead for now.

Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-09-24 18:32:54 -04:00
Josh 01e0ca7298 chore: lint compliance :)
Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-09-24 18:21:49 -04:00
Josh 3bb5ed502a refactor(dav): Clean up QuotaPlugin and add new hints
Add new hints and improve documentation for the QuotaPlugin. This commit also removes unused code and tidies up some code, which improves readability and simplifies maintenance, without introducing breaking changes.

Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-09-24 18:13:48 -04:00
Benjamin Gaussorgues 13bfd8b292 chore: add chunked queries on occ sharing:delete-orphan-shares
Signed-off-by: Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
2025-09-22 11:12:06 +02:00
1343 changed files with 16810 additions and 11313 deletions
@@ -15,6 +15,7 @@ on:
permissions:
contents: read
security-events: write
concurrency:
group: static-code-analysis-${{ github.head_ref || github.run_id }}
@@ -18,7 +18,7 @@ class TagManagement extends Action {
$this->log('System tag "%s" (%s, %s) created',
[
'name' => $tag->getName(),
'visbility' => $tag->isUserVisible() ? 'visible' : 'invisible',
'visibility' => $tag->isUserVisible() ? 'visible' : 'invisible',
'assignable' => $tag->isUserAssignable() ? 'user assignable' : 'system only',
],
['name', 'visibility', 'assignable']
+10 -1
View File
@@ -25,6 +25,15 @@ return [
'url' => '/invite-accepted',
'verb' => 'POST',
'root' => '/ocm',
]
],
// needs to be kept at the bottom of the list
[
'name' => 'OCMRequest#manageOCMRequests',
'url' => '/{ocmPath}',
'requirements' => ['ocmPath' => '.*'],
'verb' => ['GET', 'POST', 'PUT', 'DELETE'],
'root' => '/ocm',
],
],
];
@@ -10,6 +10,7 @@ return array(
'OCA\\CloudFederationAPI\\AppInfo\\Application' => $baseDir . '/../lib/AppInfo/Application.php',
'OCA\\CloudFederationAPI\\Capabilities' => $baseDir . '/../lib/Capabilities.php',
'OCA\\CloudFederationAPI\\Config' => $baseDir . '/../lib/Config.php',
'OCA\\CloudFederationAPI\\Controller\\OCMRequestController' => $baseDir . '/../lib/Controller/OCMRequestController.php',
'OCA\\CloudFederationAPI\\Controller\\RequestHandlerController' => $baseDir . '/../lib/Controller/RequestHandlerController.php',
'OCA\\CloudFederationAPI\\Db\\FederatedInvite' => $baseDir . '/../lib/Db/FederatedInvite.php',
'OCA\\CloudFederationAPI\\Db\\FederatedInviteMapper' => $baseDir . '/../lib/Db/FederatedInviteMapper.php',
@@ -25,6 +25,7 @@ class ComposerStaticInitCloudFederationAPI
'OCA\\CloudFederationAPI\\AppInfo\\Application' => __DIR__ . '/..' . '/../lib/AppInfo/Application.php',
'OCA\\CloudFederationAPI\\Capabilities' => __DIR__ . '/..' . '/../lib/Capabilities.php',
'OCA\\CloudFederationAPI\\Config' => __DIR__ . '/..' . '/../lib/Config.php',
'OCA\\CloudFederationAPI\\Controller\\OCMRequestController' => __DIR__ . '/..' . '/../lib/Controller/OCMRequestController.php',
'OCA\\CloudFederationAPI\\Controller\\RequestHandlerController' => __DIR__ . '/..' . '/../lib/Controller/RequestHandlerController.php',
'OCA\\CloudFederationAPI\\Db\\FederatedInvite' => __DIR__ . '/..' . '/../lib/Db/FederatedInvite.php',
'OCA\\CloudFederationAPI\\Db\\FederatedInviteMapper' => __DIR__ . '/..' . '/../lib/Db/FederatedInviteMapper.php',
@@ -0,0 +1,88 @@
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\CloudFederationAPI\Controller;
use JsonException;
use NCU\Security\Signature\Exceptions\IncomingRequestException;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\BruteForceProtection;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\Attribute\PublicPage;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\Response;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IRequest;
use OCP\OCM\Events\OCMEndpointRequestEvent;
use OCP\OCM\Exceptions\OCMArgumentException;
use OCP\OCM\IOCMDiscoveryService;
use Psr\Log\LoggerInterface;
class OCMRequestController extends Controller {
public function __construct(
string $appName,
IRequest $request,
private readonly IEventDispatcher $eventDispatcher,
private readonly IOCMDiscoveryService $ocmDiscoveryService,
private readonly LoggerInterface $logger,
) {
parent::__construct($appName, $request);
}
/**
* Method will catch any request done to /ocm/[...] and will broadcast an event.
* The first parameter of the remaining subpath (post-/ocm/) is defined as
* capability and should be used by listeners to filter incoming requests.
*
* @see OCMEndpointRequestEvent
* @see OCMEndpointRequestEvent::getArgs
*
* @param string $ocmPath
* @return Response
* @throws OCMArgumentException
*/
#[NoCSRFRequired]
#[PublicPage]
#[BruteForceProtection(action: 'receiveOcmRequest')]
public function manageOCMRequests(string $ocmPath): Response {
if (!mb_check_encoding($ocmPath, 'UTF-8')) {
throw new OCMArgumentException('path is not UTF-8');
}
try {
// if request is signed and well signed, no exceptions are thrown
// if request is not signed and host is known for not supporting signed request, no exceptions are thrown
$signedRequest = $this->ocmDiscoveryService->getIncomingSignedRequest();
} catch (IncomingRequestException $e) {
$this->logger->warning('incoming ocm request exception', ['exception' => $e]);
return new JSONResponse(['message' => $e->getMessage(), 'validationErrors' => []], Http::STATUS_BAD_REQUEST);
}
// assuming that ocm request contains a json array
$payload = $signedRequest?->getBody() ?? file_get_contents('php://input');
try {
$payload = ($payload) ? json_decode($payload, true, 512, JSON_THROW_ON_ERROR) : null;
} catch (JsonException $e) {
$this->logger->debug('json decode error', ['exception' => $e]);
$payload = null;
}
$event = new OCMEndpointRequestEvent(
$this->request->getMethod(),
preg_replace('@/+@', '/', $ocmPath),
$payload,
$signedRequest?->getOrigin()
);
$this->eventDispatcher->dispatchTyped($event);
return $event->getResponse() ?? new DataResponse('', Http::STATUS_NOT_FOUND);
}
}
@@ -11,8 +11,6 @@ use NCU\Federation\ISignedCloudFederationProvider;
use NCU\Security\Signature\Exceptions\IdentityNotFoundException;
use NCU\Security\Signature\Exceptions\IncomingRequestException;
use NCU\Security\Signature\Exceptions\SignatoryNotFoundException;
use NCU\Security\Signature\Exceptions\SignatureException;
use NCU\Security\Signature\Exceptions\SignatureNotFoundException;
use NCU\Security\Signature\IIncomingSignedRequest;
use NCU\Security\Signature\ISignatureManager;
use OC\OCM\OCMSignatoryManager;
@@ -44,6 +42,7 @@ use OCP\IGroupManager;
use OCP\IRequest;
use OCP\IURLGenerator;
use OCP\IUserManager;
use OCP\OCM\IOCMDiscoveryService;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Util;
use Psr\Log\LoggerInterface;
@@ -74,8 +73,8 @@ class RequestHandlerController extends Controller {
private readonly IAppConfig $appConfig,
private ICloudFederationFactory $factory,
private ICloudIdManager $cloudIdManager,
private readonly IOCMDiscoveryService $ocmDiscoveryService,
private readonly ISignatureManager $signatureManager,
private readonly OCMSignatoryManager $signatoryManager,
private ITimeFactory $timeFactory,
) {
parent::__construct($appName, $request);
@@ -108,9 +107,9 @@ class RequestHandlerController extends Controller {
public function addShare($shareWith, $name, $description, $providerId, $owner, $ownerDisplayName, $sharedBy, $sharedByDisplayName, $protocol, $shareType, $resourceType) {
if (!$this->appConfig->getValueBool('core', OCMSignatoryManager::APPCONFIG_SIGN_DISABLED, lazy: true)) {
try {
// if request is signed and well signed, no exception are thrown
// if request is signed and well signed, no exceptions are thrown
// if request is not signed and host is known for not supporting signed request, no exception are thrown
$signedRequest = $this->getSignedRequest();
$signedRequest = $this->ocmDiscoveryService->getIncomingSignedRequest();
$this->confirmSignedOrigin($signedRequest, 'owner', $owner);
} catch (IncomingRequestException $e) {
$this->logger->warning('incoming request exception', ['exception' => $e]);
@@ -360,7 +359,7 @@ class RequestHandlerController extends Controller {
try {
// if request is signed and well signed, no exception are thrown
// if request is not signed and host is known for not supporting signed request, no exception are thrown
$signedRequest = $this->getSignedRequest();
$signedRequest = $this->ocmDiscoveryService->getIncomingSignedRequest();
$this->confirmNotificationIdentity($signedRequest, $resourceType, $notification);
} catch (IncomingRequestException $e) {
$this->logger->warning('incoming request exception', ['exception' => $e]);
@@ -434,37 +433,6 @@ class RequestHandlerController extends Controller {
}
/**
* returns signed request if available.
* throw an exception:
* - if request is signed, but wrongly signed
* - if request is not signed but instance is configured to only accept signed ocm request
*
* @return IIncomingSignedRequest|null null if remote does not (and never did) support signed request
* @throws IncomingRequestException
*/
private function getSignedRequest(): ?IIncomingSignedRequest {
try {
$signedRequest = $this->signatureManager->getIncomingSignedRequest($this->signatoryManager);
$this->logger->debug('signed request available', ['signedRequest' => $signedRequest]);
return $signedRequest;
} catch (SignatureNotFoundException|SignatoryNotFoundException $e) {
$this->logger->debug('remote does not support signed request', ['exception' => $e]);
// remote does not support signed request.
// currently we still accept unsigned request until lazy appconfig
// core.enforce_signed_ocm_request is set to true (default: false)
if ($this->appConfig->getValueBool('core', OCMSignatoryManager::APPCONFIG_SIGN_ENFORCED, lazy: true)) {
$this->logger->notice('ignored unsigned request', ['exception' => $e]);
throw new IncomingRequestException('Unsigned request');
}
} catch (SignatureException $e) {
$this->logger->warning('wrongly signed request', ['exception' => $e]);
throw new IncomingRequestException('Invalid signature');
}
return null;
}
/**
* confirm that the value related to $key entry from the payload is in format userid@hostname
* and compare hostname with the origin of the signed request.
@@ -10,7 +10,6 @@ declare(strict_types=1);
namespace OCA\CloudFederationApi\Tests;
use NCU\Security\Signature\ISignatureManager;
use OC\OCM\OCMSignatoryManager;
use OCA\CloudFederationAPI\Config;
use OCA\CloudFederationAPI\Controller\RequestHandlerController;
use OCA\CloudFederationAPI\Db\FederatedInvite;
@@ -29,6 +28,7 @@ use OCP\IRequest;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\IUserManager;
use OCP\OCM\IOCMDiscoveryService;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Log\LoggerInterface;
use Test\TestCase;
@@ -45,10 +45,11 @@ class RequestHandlerControllerTest extends TestCase {
private FederatedInviteMapper&MockObject $federatedInviteMapper;
private AddressHandler&MockObject $addressHandler;
private IAppConfig&MockObject $appConfig;
private ICloudFederationFactory&MockObject $cloudFederationFactory;
private ICloudIdManager&MockObject $cloudIdManager;
private IOCMDiscoveryService&MockObject $discoveryService;
private ISignatureManager&MockObject $signatureManager;
private OCMSignatoryManager&MockObject $signatoryManager;
private ITimeFactory&MockObject $timeFactory;
private RequestHandlerController $requestHandlerController;
@@ -69,8 +70,8 @@ class RequestHandlerControllerTest extends TestCase {
$this->appConfig = $this->createMock(IAppConfig::class);
$this->cloudFederationFactory = $this->createMock(ICloudFederationFactory::class);
$this->cloudIdManager = $this->createMock(ICloudIdManager::class);
$this->discoveryService = $this->createMock(IOCMDiscoveryService::class);
$this->signatureManager = $this->createMock(ISignatureManager::class);
$this->signatoryManager = $this->createMock(OCMSignatoryManager::class);
$this->timeFactory = $this->createMock(ITimeFactory::class);
$this->requestHandlerController = new RequestHandlerController(
@@ -88,8 +89,8 @@ class RequestHandlerControllerTest extends TestCase {
$this->appConfig,
$this->cloudFederationFactory,
$this->cloudIdManager,
$this->discoveryService,
$this->signatureManager,
$this->signatoryManager,
$this->timeFactory,
);
}
+4
View File
@@ -38,6 +38,10 @@
</providers>
</activity>
<openmetrics>
<exporter>OCA\Comments\OpenMetrics\CommentsCountMetric</exporter>
</openmetrics>
<collaboration>
<plugins>
<plugin type="autocomplete-sort">OCA\Comments\Collaboration\CommentersSorter</plugin>
@@ -22,5 +22,6 @@ return array(
'OCA\\Comments\\MaxAutoCompleteResultsInitialState' => $baseDir . '/../lib/MaxAutoCompleteResultsInitialState.php',
'OCA\\Comments\\Notification\\Listener' => $baseDir . '/../lib/Notification/Listener.php',
'OCA\\Comments\\Notification\\Notifier' => $baseDir . '/../lib/Notification/Notifier.php',
'OCA\\Comments\\OpenMetrics\\CommentsCountMetric' => $baseDir . '/../lib/OpenMetrics/CommentsCountMetric.php',
'OCA\\Comments\\Search\\CommentsSearchProvider' => $baseDir . '/../lib/Search/CommentsSearchProvider.php',
);
@@ -37,6 +37,7 @@ class ComposerStaticInitComments
'OCA\\Comments\\MaxAutoCompleteResultsInitialState' => __DIR__ . '/..' . '/../lib/MaxAutoCompleteResultsInitialState.php',
'OCA\\Comments\\Notification\\Listener' => __DIR__ . '/..' . '/../lib/Notification/Listener.php',
'OCA\\Comments\\Notification\\Notifier' => __DIR__ . '/..' . '/../lib/Notification/Notifier.php',
'OCA\\Comments\\OpenMetrics\\CommentsCountMetric' => __DIR__ . '/..' . '/../lib/OpenMetrics/CommentsCountMetric.php',
'OCA\\Comments\\Search\\CommentsSearchProvider' => __DIR__ . '/..' . '/../lib/Search/CommentsSearchProvider.php',
);
+1
View File
@@ -17,6 +17,7 @@ OC.L10N.register(
"Delete comment" : "Ezabatu iruzkina",
"Cancel edit" : "Utzi editatzeari",
"New comment" : "Iruzkin berria",
"Write a comment …" : "Idatzi iruzkin bat …",
"Post comment" : "Argitaratu iruzkina",
"@ for mentions, : for emoji, / for smart picker" : "@ aipamenetarako, : emojientzako, / hautatzaile adimentsurako",
"Could not reload comments" : "Ezin izan dira iruzkinak freskatu",
+1
View File
@@ -15,6 +15,7 @@
"Delete comment" : "Ezabatu iruzkina",
"Cancel edit" : "Utzi editatzeari",
"New comment" : "Iruzkin berria",
"Write a comment …" : "Idatzi iruzkin bat …",
"Post comment" : "Argitaratu iruzkina",
"@ for mentions, : for emoji, / for smart picker" : "@ aipamenetarako, : emojientzako, / hautatzaile adimentsurako",
"Could not reload comments" : "Ezin izan dira iruzkinak freskatu",
@@ -0,0 +1,52 @@
<?php
/**
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\Comments\OpenMetrics;
use Generator;
use OCP\IDBConnection;
use OCP\OpenMetrics\IMetricFamily;
use OCP\OpenMetrics\Metric;
use OCP\OpenMetrics\MetricType;
use Override;
class CommentsCountMetric implements IMetricFamily {
public function __construct(
private IDBConnection $connection,
) {
}
#[Override]
public function name(): string {
return 'comments';
}
#[Override]
public function type(): MetricType {
return MetricType::gauge;
}
#[Override]
public function unit(): string {
return 'comments';
}
#[Override]
public function help(): string {
return 'Number of comments';
}
#[Override]
public function metrics(): Generator {
$qb = $this->connection->getQueryBuilder();
$result = $qb->select($qb->func()->count())
->from('comments')
->where($qb->expr()->eq('verb', $qb->expr()->literal('comment')))
->executeQuery();
yield new Metric($result->fetchOne(), [], time());
}
}
@@ -180,14 +180,12 @@ describe('Inline unread comments action enabled tests', () => {
describe('Inline unread comments action execute tests', () => {
test('Action opens sidebar', async () => {
const openMock = vi.fn()
const setActiveTabMock = vi.fn()
window.OCA = {
Files: {
// @ts-expect-error Mocking for testing
Sidebar: {
_sidebar: () => ({
open: openMock,
setActiveTab: setActiveTabMock,
},
}),
},
}
@@ -211,22 +209,19 @@ describe('Inline unread comments action execute tests', () => {
})
expect(result).toBe(null)
expect(setActiveTabMock).toBeCalledWith('comments')
expect(openMock).toBeCalledWith('/foobar.txt')
expect(openMock).toBeCalledWith(file, 'comments')
})
test('Action handles sidebar open failure', async () => {
const openMock = vi.fn(() => {
throw new Error('Mock error')
})
const setActiveTabMock = vi.fn()
window.OCA = {
Files: {
// @ts-expect-error Mocking for testing
Sidebar: {
_sidebar: () => ({
open: openMock,
setActiveTab: setActiveTabMock,
},
}),
},
}
vi.spyOn(logger, 'error').mockImplementation(() => vi.fn())
@@ -251,8 +246,7 @@ describe('Inline unread comments action execute tests', () => {
})
expect(result).toBe(false)
expect(setActiveTabMock).toBeCalledWith('comments')
expect(openMock).toBeCalledWith('/foobar.txt')
expect(openMock).toBeCalledWith(file, 'comments')
expect(logger.error).toBeCalledTimes(1)
})
})
@@ -1,9 +1,10 @@
/**
/*!
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import CommentProcessingSvg from '@mdi/svg/svg/comment-processing.svg?raw'
import { FileAction } from '@nextcloud/files'
import { FileAction, getSidebar } from '@nextcloud/files'
import { n, t } from '@nextcloud/l10n'
import logger from '../logger.js'
@@ -34,8 +35,8 @@ export const action = new FileAction({
}
try {
window.OCA.Files.Sidebar.setActiveTab('comments')
await window.OCA.Files.Sidebar.open(nodes[0].path)
const sidebar = getSidebar()
sidebar.open(nodes[0], 'comments')
return null
} catch (error) {
logger.error('Error while opening sidebar', { error })
-59
View File
@@ -1,59 +0,0 @@
/**
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import MessageReplyText from '@mdi/svg/svg/message-reply-text.svg?raw'
import { getCSPNonce } from '@nextcloud/auth'
import { loadState } from '@nextcloud/initial-state'
import { registerCommentsPlugins } from './comments-activity-tab.ts'
// @ts-expect-error __webpack_nonce__ is injected by webpack
__webpack_nonce__ = getCSPNonce()
if (loadState('comments', 'activityEnabled', false) && OCA?.Activity?.registerSidebarAction !== undefined) {
// Do not mount own tab but mount into activity
window.addEventListener('DOMContentLoaded', function() {
registerCommentsPlugins()
})
} else {
// Init Comments tab component
let TabInstance = null
const commentTab = new OCA.Files.Sidebar.Tab({
id: 'comments',
name: t('comments', 'Comments'),
iconSvg: MessageReplyText,
async mount(el, fileInfo, context) {
if (TabInstance) {
TabInstance.$destroy()
}
TabInstance = new OCA.Comments.View('files', {
// Better integration with vue parent component
parent: context,
propsData: {
resourceId: fileInfo.id,
},
})
// Only mount after we have all the info we need
await TabInstance.update(fileInfo.id)
TabInstance.$mount(el)
},
update(fileInfo) {
TabInstance.update(fileInfo.id)
},
destroy() {
TabInstance.$destroy()
TabInstance = null
},
scrollBottomReached() {
TabInstance.onScrollBottomReached()
},
})
window.addEventListener('DOMContentLoaded', function() {
if (OCA.Files && OCA.Files.Sidebar) {
OCA.Files.Sidebar.registerTab(commentTab)
}
})
}
+57
View File
@@ -0,0 +1,57 @@
/**
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import MessageReplyText from '@mdi/svg/svg/message-reply-text.svg?raw'
import { getCSPNonce } from '@nextcloud/auth'
import { registerSidebarTab } from '@nextcloud/files'
import { loadState } from '@nextcloud/initial-state'
import { t } from '@nextcloud/l10n'
import wrap from '@vue/web-component-wrapper'
import { createPinia, PiniaVuePlugin } from 'pinia'
import Vue from 'vue'
import FilesSidebarTab from './views/FilesSidebarTab.vue'
import { registerCommentsPlugins } from './comments-activity-tab.ts'
__webpack_nonce__ = getCSPNonce()
const tagName = 'comments_files-sidebar-tab'
if (loadState('comments', 'activityEnabled', false) && OCA?.Activity?.registerSidebarAction !== undefined) {
// Do not mount own tab but mount into activity
window.addEventListener('DOMContentLoaded', function() {
registerCommentsPlugins()
})
} else {
registerSidebarTab({
id: 'comments',
displayName: t('comments', 'Comments'),
iconSvgInline: MessageReplyText,
order: 50,
tagName,
enabled() {
if (!window.customElements.get(tagName)) {
setupSidebarTab()
}
return true
},
})
}
/**
* Setup the sidebar tab as a web component
*/
function setupSidebarTab() {
Vue.use(PiniaVuePlugin)
Vue.mixin({ pinia: createPinia() })
const webComponent = wrap(Vue, FilesSidebarTab)
// In Vue 2, wrap doesn't support disabling shadow. Disable with a hack
Object.defineProperty(webComponent.prototype, 'attachShadow', {
value() { return this },
})
Object.defineProperty(webComponent.prototype, 'shadowRoot', {
get() { return this },
})
window.customElements.define(tagName, webComponent)
}
+4 -3
View File
@@ -1,8 +1,9 @@
import { getCurrentUser } from '@nextcloud/auth'
/**
/*!
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { getCurrentUser } from '@nextcloud/auth'
import axios from '@nextcloud/axios'
import { loadState } from '@nextcloud/initial-state'
import { generateOcsUrl } from '@nextcloud/router'
@@ -32,7 +33,7 @@ export default defineComponent({
},
methods: {
/**
* Autocomplete @mentions
* Autocomplete `@mentions`
*
* @param search the query
* @param callback the callback to process the results with
@@ -0,0 +1,40 @@
<!--
- SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<script setup lang="ts">
import type { IFolder, INode, IView } from '@nextcloud/files'
import { computed } from 'vue'
import Comments from './Comments.vue'
const props = defineProps<{
node?: INode
// eslint-disable-next-line vue/no-unused-properties -- Required on the web component interface
folder?: IFolder
// eslint-disable-next-line vue/no-unused-properties -- Required on the web component interface
view?: IView
}>()
defineExpose({ setActive })
const resourceId = computed(() => props.node?.fileid)
/**
* Set this tab as active
*
* @param active - The active state
*/
function setActive(active: boolean) {
return active
}
</script>
<template>
<Comments
v-if="resourceId !== undefined"
:key="resourceId"
:resource-id="resourceId"
resource-type="files" />
</template>
+5 -3
View File
@@ -24,6 +24,7 @@ use OCA\DAV\Connector\Sabre\Principal;
use OCP\Accounts\IAccountManager;
use OCP\App\IAppManager;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IAppConfig;
use OCP\ICacheFactory;
use OCP\IConfig;
use OCP\IDBConnection;
@@ -56,7 +57,7 @@ $principalBackend = new Principal(
Server::get(ProxyMapper::class),
Server::get(KnownUserService::class),
Server::get(IConfig::class),
\OC::$server->getL10NFactory(),
Server::get(IL10NFactory::class),
'principals/'
);
$db = Server::get(IDBConnection::class);
@@ -84,7 +85,7 @@ $calDavBackend = new CalDavBackend(
);
$debugging = Server::get(IConfig::class)->getSystemValue('debug', false);
$sendInvitations = Server::get(IConfig::class)->getAppValue('dav', 'sendInvitations', 'yes') === 'yes';
$sendInvitations = Server::get(IAppConfig::class)->getValueBool('dav', 'sendInvitations', true);
// Root nodes
$principalCollection = new \Sabre\CalDAV\Principal\Collection($principalBackend);
@@ -102,6 +103,7 @@ $nodes = [
$server = new \Sabre\DAV\Server($nodes);
$server::$exposeVersion = false;
$server->httpRequest->setUrl(Server::get(IRequest::class)->getRequestUri());
/** @var string $baseuri defined in remote.php */
$server->setBaseUri($baseuri);
// Add plugins
@@ -126,4 +128,4 @@ $server->addPlugin(Server::get(RateLimitingPlugin::class));
$server->addPlugin(Server::get(CalDavValidatePlugin::class));
// And off we go!
$server->exec();
$server->start();
+5 -3
View File
@@ -30,6 +30,7 @@ use OCP\IRequest;
use OCP\ISession;
use OCP\IUserManager;
use OCP\IUserSession;
use OCP\L10N\IFactory as IL10nFactory;
use OCP\Security\Bruteforce\IThrottler;
use OCP\Server;
use Psr\Log\LoggerInterface;
@@ -53,7 +54,7 @@ $principalBackend = new Principal(
Server::get(ProxyMapper::class),
Server::get(KnownUserService::class),
Server::get(IConfig::class),
\OC::$server->getL10NFactory(),
Server::get(IL10nFactory::class),
'principals/'
);
$db = Server::get(IDBConnection::class);
@@ -85,9 +86,10 @@ $nodes = [
$server = new \Sabre\DAV\Server($nodes);
$server::$exposeVersion = false;
$server->httpRequest->setUrl(Server::get(IRequest::class)->getRequestUri());
/** @var string $baseuri defined in remote.php */
$server->setBaseUri($baseuri);
// Add plugins
$server->addPlugin(new MaintenancePlugin(Server::get(IConfig::class), \OC::$server->getL10N('dav')));
$server->addPlugin(new MaintenancePlugin(Server::get(IConfig::class), \OCP\Server::get(IL10nFactory::class)->get('dav')));
$server->addPlugin(new \Sabre\DAV\Auth\Plugin($authBackend));
$server->addPlugin(new Plugin());
@@ -104,4 +106,4 @@ $server->addPlugin(Server::get(CardDavRateLimitingPlugin::class));
$server->addPlugin(Server::get(CardDavValidatePlugin::class));
// And off we go!
$server->exec();
$server->start();
+10 -5
View File
@@ -14,6 +14,7 @@ use OCA\DAV\Files\Sharing\FilesDropPlugin;
use OCA\DAV\Files\Sharing\PublicLinkCheckPlugin;
use OCA\DAV\Storage\PublicOwnerWrapper;
use OCA\FederatedFileSharing\FederatedShareProvider;
use OCP\App\IAppManager;
use OCP\BeforeSabrePubliclyLoadedEvent;
use OCP\Constants;
use OCP\EventDispatcher\IEventDispatcher;
@@ -26,16 +27,19 @@ use OCP\IRequest;
use OCP\ISession;
use OCP\ITagManager;
use OCP\IUserSession;
use OCP\L10N\IFactory as IL10nFactory;
use OCP\Security\Bruteforce\IThrottler;
use OCP\Server;
use Psr\Log\LoggerInterface;
// load needed apps
$RUNTIME_APPTYPES = ['filesystem', 'authentication', 'logging'];
Server::get(IAppManager::class)->loadApps($RUNTIME_APPTYPES);
OC_App::loadApps($RUNTIME_APPTYPES);
OC_Util::obEnd();
// Turn off output buffering to prevent memory problems
while (ob_get_level()) {
ob_end_clean();
}
Server::get(ISession::class)->close();
// Backends
@@ -60,7 +64,7 @@ $serverFactory = new ServerFactory(
Server::get(IRequest::class),
Server::get(IPreview::class),
$eventDispatcher,
\OC::$server->getL10N('dav')
Server::get(IL10nFactory::class)->get('dav')
);
$requestUri = Server::get(IRequest::class)->getRequestUri();
@@ -68,6 +72,7 @@ $requestUri = Server::get(IRequest::class)->getRequestUri();
$linkCheckPlugin = new PublicLinkCheckPlugin();
$filesDropPlugin = new FilesDropPlugin();
/** @var string $baseuri defined in public.php */
$server = $serverFactory->createServer(
true,
$baseuri,
@@ -125,4 +130,4 @@ $event = new BeforeSabrePubliclyLoadedEvent($server);
$eventDispatcher->dispatchTyped($event);
// And off we go!
$server->exec();
$server->start();
+7 -3
View File
@@ -19,6 +19,7 @@ use OCP\IRequest;
use OCP\ISession;
use OCP\ITagManager;
use OCP\IUserSession;
use OCP\L10N\IFactory as IL10nFactory;
use OCP\SabrePluginEvent;
use OCP\Security\Bruteforce\IThrottler;
use OCP\Server;
@@ -31,7 +32,9 @@ if (!str_contains(@ini_get('disable_functions'), 'set_time_limit')) {
ignore_user_abort(true);
// Turn off output buffering to prevent memory problems
\OC_Util::obEnd();
while (ob_get_level()) {
ob_end_clean();
}
$dispatcher = Server::get(IEventDispatcher::class);
@@ -45,7 +48,7 @@ $serverFactory = new ServerFactory(
Server::get(IRequest::class),
Server::get(IPreview::class),
$dispatcher,
\OC::$server->getL10N('dav')
Server::get(IL10nFactory::class)->get('dav')
);
// Backends
@@ -68,6 +71,7 @@ $authPlugin->addBackend($bearerAuthPlugin);
$requestUri = Server::get(IRequest::class)->getRequestUri();
/** @var string $baseuri defined in remote.php */
$server = $serverFactory->createServer(false, $baseuri, $requestUri, $authPlugin, function () {
// use the view for the logged in user
return Filesystem::getView();
@@ -80,4 +84,4 @@ $event = new SabrePluginAddEvent($server);
$dispatcher->dispatchTyped($event);
// And off we go!
$server->exec();
$server->start();
+5 -2
View File
@@ -21,12 +21,15 @@ if (!str_contains(@ini_get('disable_functions'), 'set_time_limit')) {
ignore_user_abort(true);
// Turn off output buffering to prevent memory problems
\OC_Util::obEnd();
while (ob_get_level()) {
ob_end_clean();
}
$requestUri = Server::get(IRequest::class)->getRequestUri();
/** @var ServerFactory $serverFactory */
$serverFactory = Server::get(ServerFactory::class);
/** @var string $baseuri defined in remote.php */
$server = $serverFactory->createServer(
$baseuri,
$requestUri,
@@ -37,4 +40,4 @@ $server = $serverFactory->createServer(
Server::get(IRequest::class)
);
$server->exec();
$server->start();
+7 -2
View File
@@ -17,6 +17,7 @@ use OCA\DAV\Storage\PublicShareWrapper;
use OCA\DAV\Upload\ChunkingPlugin;
use OCA\DAV\Upload\ChunkingV2Plugin;
use OCA\FederatedFileSharing\FederatedShareProvider;
use OCP\App\IAppManager;
use OCP\BeforeSabrePubliclyLoadedEvent;
use OCP\Constants;
use OCP\EventDispatcher\IEventDispatcher;
@@ -41,8 +42,12 @@ use Sabre\DAV\Exception\NotFound;
// load needed apps
$RUNTIME_APPTYPES = ['filesystem', 'authentication', 'logging'];
OC_App::loadApps($RUNTIME_APPTYPES);
OC_Util::obEnd();
Server::get(IAppManager::class)->loadApps($RUNTIME_APPTYPES);
// Turn off output buffering to prevent memory problems
while (ob_get_level()) {
ob_end_clean();
}
$session = Server::get(ISession::class);
$request = Server::get(IRequest::class);
+4 -1
View File
@@ -15,8 +15,11 @@ if (!str_contains(@ini_get('disable_functions'), 'set_time_limit')) {
ignore_user_abort(true);
// Turn off output buffering to prevent memory problems
\OC_Util::obEnd();
while (ob_get_level()) {
ob_end_clean();
}
$request = \OCP\Server::get(IRequest::class);
/** @var string $baseuri defined in remote.php */
$server = new Server($request, $baseuri);
$server->exec();
@@ -254,6 +254,7 @@ return array(
'OCA\\DAV\\Connector\\Sabre\\SharesPlugin' => $baseDir . '/../lib/Connector/Sabre/SharesPlugin.php',
'OCA\\DAV\\Connector\\Sabre\\TagList' => $baseDir . '/../lib/Connector/Sabre/TagList.php',
'OCA\\DAV\\Connector\\Sabre\\TagsPlugin' => $baseDir . '/../lib/Connector/Sabre/TagsPlugin.php',
'OCA\\DAV\\Connector\\Sabre\\UserIdHeaderPlugin' => $baseDir . '/../lib/Connector/Sabre/UserIdHeaderPlugin.php',
'OCA\\DAV\\Connector\\Sabre\\ZipFolderPlugin' => $baseDir . '/../lib/Connector/Sabre/ZipFolderPlugin.php',
'OCA\\DAV\\Controller\\BirthdayCalendarController' => $baseDir . '/../lib/Controller/BirthdayCalendarController.php',
'OCA\\DAV\\Controller\\DirectController' => $baseDir . '/../lib/Controller/DirectController.php',
@@ -269,6 +269,7 @@ class ComposerStaticInitDAV
'OCA\\DAV\\Connector\\Sabre\\SharesPlugin' => __DIR__ . '/..' . '/../lib/Connector/Sabre/SharesPlugin.php',
'OCA\\DAV\\Connector\\Sabre\\TagList' => __DIR__ . '/..' . '/../lib/Connector/Sabre/TagList.php',
'OCA\\DAV\\Connector\\Sabre\\TagsPlugin' => __DIR__ . '/..' . '/../lib/Connector/Sabre/TagsPlugin.php',
'OCA\\DAV\\Connector\\Sabre\\UserIdHeaderPlugin' => __DIR__ . '/..' . '/../lib/Connector/Sabre/UserIdHeaderPlugin.php',
'OCA\\DAV\\Connector\\Sabre\\ZipFolderPlugin' => __DIR__ . '/..' . '/../lib/Connector/Sabre/ZipFolderPlugin.php',
'OCA\\DAV\\Controller\\BirthdayCalendarController' => __DIR__ . '/..' . '/../lib/Controller/BirthdayCalendarController.php',
'OCA\\DAV\\Controller\\DirectController' => __DIR__ . '/..' . '/../lib/Controller/DirectController.php',
+2
View File
@@ -234,6 +234,8 @@ OC.L10N.register(
"Could not rename part file to final file, canceled by hook" : "Could not rename part file to final file, cancelled by hook",
"Could not rename part file to final file" : "Could not rename part file to final file",
"Failed to check file size: %1$s" : "Failed to check file size: %1$s",
"Could not open file: %1$s (%2$d), file does seem to exist" : "Could not open file: %1$s (%2$d), file does seem to exist",
"Could not open file: %1$s (%2$d), file doesn't seem to exist" : "Could not open file: %1$s (%2$d), file doesn't seem to exist",
"Encryption not ready: %1$s" : "Encryption not ready: %1$s",
"Failed to open file: %1$s" : "Failed to open file: %1$s",
"Failed to unlink: %1$s" : "Failed to unlink: %1$s",
+2
View File
@@ -232,6 +232,8 @@
"Could not rename part file to final file, canceled by hook" : "Could not rename part file to final file, cancelled by hook",
"Could not rename part file to final file" : "Could not rename part file to final file",
"Failed to check file size: %1$s" : "Failed to check file size: %1$s",
"Could not open file: %1$s (%2$d), file does seem to exist" : "Could not open file: %1$s (%2$d), file does seem to exist",
"Could not open file: %1$s (%2$d), file doesn't seem to exist" : "Could not open file: %1$s (%2$d), file doesn't seem to exist",
"Encryption not ready: %1$s" : "Encryption not ready: %1$s",
"Failed to open file: %1$s" : "Failed to open file: %1$s",
"Failed to unlink: %1$s" : "Failed to unlink: %1$s",
+32
View File
@@ -73,7 +73,19 @@ OC.L10N.register(
"Where: %s" : "Kus: %s",
"%1$s via %2$s" : "%1$s %2$s kaudu",
"In the past on %1$s for the entire day" : "Minevikus kogu päeva: %1$s",
"_In %n minute on %1$s for the entire day_::_In %n minutes on %1$s for the entire day_" : ["%n minuti pärast %1$s kogu päeva kestel","%n minuti pärast %1$s kogu päeva kestel"],
"_In %n hour on %1$s for the entire day_::_In %n hours on %1$s for the entire day_" : ["%n tunni pärast %1$s kogu päeva kestel","%n tunni pärast %1$s kogu päeva kestel"],
"_In %n day on %1$s for the entire day_::_In %n days on %1$s for the entire day_" : ["%n tunni päeva %1$s kogu päeva kestel","%n tunni pärast %1$s kogu päeva kestel"],
"_In %n week on %1$s for the entire day_::_In %n weeks on %1$s for the entire day_" : ["%n nädala pärast %1$s kogu päeva kestel","%n nädala pärast %1$s kogu päeva kestel"],
"_In %n month on %1$s for the entire day_::_In %n months on %1$s for the entire day_" : ["%n kuu pärast %1$s kogu päeva kestel","%n kuu pärast %1$s kogu päeva kestel"],
"_In %n year on %1$s for the entire day_::_In %n years on %1$s for the entire day_" : ["%n aasta pärast %1$s kogu päeva kestel","%n aasta pärast %1$s kogu päeva kestel"],
"In the past on %1$s between %2$s - %3$s" : "Minevikus: %1$s ajavahemikus %2$s - %3$s",
"_In %n minute on %1$s between %2$s - %3$s_::_In %n minutes on %1$s between %2$s - %3$s_" : ["%n minuti pärast %1$s ajavahemikus %2$s kuni %3$s","%n minuti pärast %1$s ajavahemikus %2$s kuni %3$s"],
"_In %n hour on %1$s between %2$s - %3$s_::_In %n hours on %1$s between %2$s - %3$s_" : ["%n tunni pärast %1$s ajavahemikus %2$s kuni %3$s","%n tunni pärast %1$s ajavahemikus %2$s kuni %3$s"],
"_In %n day on %1$s between %2$s - %3$s_::_In %n days on %1$s between %2$s - %3$s_" : ["%n päeva pärast %1$s ajavahemikus %2$s kuni %3$s","%n päeva pärast %1$s ajavahemikus %2$s kuni %3$s"],
"_In %n week on %1$s between %2$s - %3$s_::_In %n weeks on %1$s between %2$s - %3$s_" : ["%n nädala pärast %1$s ajavahemikus %2$s kuni %3$s","%n nädala pärast %1$s ajavahemikus %2$s kuni %3$s"],
"_In %n month on %1$s between %2$s - %3$s_::_In %n months on %1$s between %2$s - %3$s_" : ["%n kuu pärast %1$s ajavahemikus %2$s kuni %3$s","%n kuu pärast %1$s ajavahemikus %2$s kuni %3$s"],
"_In %n year on %1$s between %2$s - %3$s_::_In %n years on %1$s between %2$s - %3$s_" : ["%n aasta pärast %1$s ajavahemikus %2$s kuni %3$s","%n aasta pärast %1$s ajavahemikus %2$s kuni %3$s"],
"Could not generate when statement" : "Ei õnnestunud koostada tingimuslikku „when“ lausendit",
"Every Day for the entire day" : "Iga päev kogu päeva jooksul",
"Every Day for the entire day until %1$s" : "Iga päev kogu päeva jooksul kuni %1$s",
@@ -111,8 +123,26 @@ OC.L10N.register(
"On specific dates for the entire day until %1$s" : "Kindlatel päevadel kogu päeva jooksul kuni %1$s",
"On specific dates between %1$s - %2$s until %3$s" : "Kindlatel päevadel ajavahemikus %1$s - %2$s kuni %3$s",
"In the past on %1$s" : "Minevikus %1$s",
"_In %n minute on %1$s_::_In %n minutes on %1$s_" : ["%n minuti pärast %1$s","%n minuti pärast %1$s"],
"_In %n hour on %1$s_::_In %n hours on %1$s_" : ["%n tunni pärast %1$s","%n tunni pärast %1$s"],
"_In %n day on %1$s_::_In %n days on %1$s_" : ["%n päeva pärast %1$s","%n päeva pärast %1$s"],
"_In %n week on %1$s_::_In %n weeks on %1$s_" : ["%n nädala pärast %1$s","%n nädala pärast %1$s"],
"_In %n month on %1$s_::_In %n months on %1$s_" : ["%n kuu pärast %1$s","%n kuu pärast %1$s"],
"_In %n year on %1$s_::_In %n years on %1$s_" : ["%n aasta pärast %1$s","%n aasta pärast %1$s"],
"In the past on %1$s then on %2$s" : "Minevikus: %1$s ja siis %2$s",
"_In %n minute on %1$s then on %2$s_::_In %n minutes on %1$s then on %2$s_" : ["%n minuti pärast %1$s, seejärel %2$s","%n minuti pärast %1$s, seejärel %2$s"],
"_In %n hour on %1$s then on %2$s_::_In %n hours on %1$s then on %2$s_" : ["%n tunni pärast %1$s, seejärel %2$s","%n tunni pärast %1$s, seejärel %2$s"],
"_In %n day on %1$s then on %2$s_::_In %n days on %1$s then on %2$s_" : ["%n päeva pärast %1$s, seejärel %2$s","%n päeva pärast %1$s, seejärel %2$s"],
"_In %n week on %1$s then on %2$s_::_In %n weeks on %1$s then on %2$s_" : ["%n nädala pärast %1$s, seejärel %2$s","%n nädala pärast %1$s, seejärel %2$s"],
"_In %n month on %1$s then on %2$s_::_In %n months on %1$s then on %2$s_" : ["%n kuu pärast %1$s, seejärel %2$s","%n kuu pärast %1$s, seejärel %2$s"],
"_In %n year on %1$s then on %2$s_::_In %n years on %1$s then on %2$s_" : ["%n aasta pärast %1$s, seejärel %2$s","%n aasta pärast %1$s, seejärel %2$s"],
"In the past on %1$s then on %2$s and %3$s" : "Minevikus: %1$s ja siis %2$s ning %3$s",
"_In %n minute on %1$s then on %2$s and %3$s_::_In %n minutes on %1$s then on %2$s and %3$s_" : ["%n minuti pärast %1$s, seejärel %2$s ja %3$s","%n minuti pärast %1$s, seejärel %2$s ja %3$s"],
"_In %n hour on %1$s then on %2$s and %3$s_::_In %n hours on %1$s then on %2$s and %3$s_" : ["%n tunni pärast %1$s, seejärel %2$s ja %3$s","%n tunni pärast %1$s, seejärel %2$s ja %3$s"],
"_In %n day on %1$s then on %2$s and %3$s_::_In %n days on %1$s then on %2$s and %3$s_" : ["%n päeva pärast %1$s, seejärel %2$s ja %3$s","%n päeva pärast %1$s, seejärel %2$s ja %3$s"],
"_In %n week on %1$s then on %2$s and %3$s_::_In %n weeks on %1$s then on %2$s and %3$s_" : ["%n nädala pärast %1$s, seejärel %2$s ja %3$s","%n nädala pärast %1$s, seejärel %2$s ja %3$s"],
"_In %n month on %1$s then on %2$s and %3$s_::_In %n months on %1$s then on %2$s and %3$s_" : ["%n kuu pärast %1$s, seejärel %2$s ja %3$s","%n kuu pärast %1$s, seejärel %2$s ja %3$s"],
"_In %n year on %1$s then on %2$s and %3$s_::_In %n years on %1$s then on %2$s and %3$s_" : ["%n aasta pärast %1$s, seejärel %2$s ja %3$s","%n aasta pärast %1$s, seejärel %2$s ja %3$s"],
"Could not generate next recurrence statement" : "Ei õnnestunud koostada korduva ürituse järgmise toimumise lausendit",
"Cancelled: %1$s" : "Tühistatud: %1$s",
"\"%1$s\" has been canceled" : "„%1$s“ on tühistatud",
@@ -204,6 +234,8 @@ OC.L10N.register(
"Could not rename part file to final file, canceled by hook" : "Osalise faili nime muutmine lõplikuks nimeks ei õnnestunud, selle katkestas programmi haak",
"Could not rename part file to final file" : "Osalise faili nime muutmine lõplikuks nimeks ei õnnestunud",
"Failed to check file size: %1$s" : "Faili suuruse kontrollimine ei õnnestunud: %1$s",
"Could not open file: %1$s (%2$d), file does seem to exist" : "„%1$s“ (%2$d) faili avamine ei õnnestunud, aga tundub, et ta on olemas",
"Could not open file: %1$s (%2$d), file doesn't seem to exist" : "„%1$s“ (%2$d) faili avamine ei õnnestunud, tundub, et teda pole olemas",
"Encryption not ready: %1$s" : "Krüptimine pole veel kasutatav: %1$s",
"Failed to open file: %1$s" : "Faili avamine ei õnnestunud: %1$s",
"Failed to unlink: %1$s" : "Lingi eemaldamine ei õnnestunud: %1$s",
+32
View File
@@ -71,7 +71,19 @@
"Where: %s" : "Kus: %s",
"%1$s via %2$s" : "%1$s %2$s kaudu",
"In the past on %1$s for the entire day" : "Minevikus kogu päeva: %1$s",
"_In %n minute on %1$s for the entire day_::_In %n minutes on %1$s for the entire day_" : ["%n minuti pärast %1$s kogu päeva kestel","%n minuti pärast %1$s kogu päeva kestel"],
"_In %n hour on %1$s for the entire day_::_In %n hours on %1$s for the entire day_" : ["%n tunni pärast %1$s kogu päeva kestel","%n tunni pärast %1$s kogu päeva kestel"],
"_In %n day on %1$s for the entire day_::_In %n days on %1$s for the entire day_" : ["%n tunni päeva %1$s kogu päeva kestel","%n tunni pärast %1$s kogu päeva kestel"],
"_In %n week on %1$s for the entire day_::_In %n weeks on %1$s for the entire day_" : ["%n nädala pärast %1$s kogu päeva kestel","%n nädala pärast %1$s kogu päeva kestel"],
"_In %n month on %1$s for the entire day_::_In %n months on %1$s for the entire day_" : ["%n kuu pärast %1$s kogu päeva kestel","%n kuu pärast %1$s kogu päeva kestel"],
"_In %n year on %1$s for the entire day_::_In %n years on %1$s for the entire day_" : ["%n aasta pärast %1$s kogu päeva kestel","%n aasta pärast %1$s kogu päeva kestel"],
"In the past on %1$s between %2$s - %3$s" : "Minevikus: %1$s ajavahemikus %2$s - %3$s",
"_In %n minute on %1$s between %2$s - %3$s_::_In %n minutes on %1$s between %2$s - %3$s_" : ["%n minuti pärast %1$s ajavahemikus %2$s kuni %3$s","%n minuti pärast %1$s ajavahemikus %2$s kuni %3$s"],
"_In %n hour on %1$s between %2$s - %3$s_::_In %n hours on %1$s between %2$s - %3$s_" : ["%n tunni pärast %1$s ajavahemikus %2$s kuni %3$s","%n tunni pärast %1$s ajavahemikus %2$s kuni %3$s"],
"_In %n day on %1$s between %2$s - %3$s_::_In %n days on %1$s between %2$s - %3$s_" : ["%n päeva pärast %1$s ajavahemikus %2$s kuni %3$s","%n päeva pärast %1$s ajavahemikus %2$s kuni %3$s"],
"_In %n week on %1$s between %2$s - %3$s_::_In %n weeks on %1$s between %2$s - %3$s_" : ["%n nädala pärast %1$s ajavahemikus %2$s kuni %3$s","%n nädala pärast %1$s ajavahemikus %2$s kuni %3$s"],
"_In %n month on %1$s between %2$s - %3$s_::_In %n months on %1$s between %2$s - %3$s_" : ["%n kuu pärast %1$s ajavahemikus %2$s kuni %3$s","%n kuu pärast %1$s ajavahemikus %2$s kuni %3$s"],
"_In %n year on %1$s between %2$s - %3$s_::_In %n years on %1$s between %2$s - %3$s_" : ["%n aasta pärast %1$s ajavahemikus %2$s kuni %3$s","%n aasta pärast %1$s ajavahemikus %2$s kuni %3$s"],
"Could not generate when statement" : "Ei õnnestunud koostada tingimuslikku „when“ lausendit",
"Every Day for the entire day" : "Iga päev kogu päeva jooksul",
"Every Day for the entire day until %1$s" : "Iga päev kogu päeva jooksul kuni %1$s",
@@ -109,8 +121,26 @@
"On specific dates for the entire day until %1$s" : "Kindlatel päevadel kogu päeva jooksul kuni %1$s",
"On specific dates between %1$s - %2$s until %3$s" : "Kindlatel päevadel ajavahemikus %1$s - %2$s kuni %3$s",
"In the past on %1$s" : "Minevikus %1$s",
"_In %n minute on %1$s_::_In %n minutes on %1$s_" : ["%n minuti pärast %1$s","%n minuti pärast %1$s"],
"_In %n hour on %1$s_::_In %n hours on %1$s_" : ["%n tunni pärast %1$s","%n tunni pärast %1$s"],
"_In %n day on %1$s_::_In %n days on %1$s_" : ["%n päeva pärast %1$s","%n päeva pärast %1$s"],
"_In %n week on %1$s_::_In %n weeks on %1$s_" : ["%n nädala pärast %1$s","%n nädala pärast %1$s"],
"_In %n month on %1$s_::_In %n months on %1$s_" : ["%n kuu pärast %1$s","%n kuu pärast %1$s"],
"_In %n year on %1$s_::_In %n years on %1$s_" : ["%n aasta pärast %1$s","%n aasta pärast %1$s"],
"In the past on %1$s then on %2$s" : "Minevikus: %1$s ja siis %2$s",
"_In %n minute on %1$s then on %2$s_::_In %n minutes on %1$s then on %2$s_" : ["%n minuti pärast %1$s, seejärel %2$s","%n minuti pärast %1$s, seejärel %2$s"],
"_In %n hour on %1$s then on %2$s_::_In %n hours on %1$s then on %2$s_" : ["%n tunni pärast %1$s, seejärel %2$s","%n tunni pärast %1$s, seejärel %2$s"],
"_In %n day on %1$s then on %2$s_::_In %n days on %1$s then on %2$s_" : ["%n päeva pärast %1$s, seejärel %2$s","%n päeva pärast %1$s, seejärel %2$s"],
"_In %n week on %1$s then on %2$s_::_In %n weeks on %1$s then on %2$s_" : ["%n nädala pärast %1$s, seejärel %2$s","%n nädala pärast %1$s, seejärel %2$s"],
"_In %n month on %1$s then on %2$s_::_In %n months on %1$s then on %2$s_" : ["%n kuu pärast %1$s, seejärel %2$s","%n kuu pärast %1$s, seejärel %2$s"],
"_In %n year on %1$s then on %2$s_::_In %n years on %1$s then on %2$s_" : ["%n aasta pärast %1$s, seejärel %2$s","%n aasta pärast %1$s, seejärel %2$s"],
"In the past on %1$s then on %2$s and %3$s" : "Minevikus: %1$s ja siis %2$s ning %3$s",
"_In %n minute on %1$s then on %2$s and %3$s_::_In %n minutes on %1$s then on %2$s and %3$s_" : ["%n minuti pärast %1$s, seejärel %2$s ja %3$s","%n minuti pärast %1$s, seejärel %2$s ja %3$s"],
"_In %n hour on %1$s then on %2$s and %3$s_::_In %n hours on %1$s then on %2$s and %3$s_" : ["%n tunni pärast %1$s, seejärel %2$s ja %3$s","%n tunni pärast %1$s, seejärel %2$s ja %3$s"],
"_In %n day on %1$s then on %2$s and %3$s_::_In %n days on %1$s then on %2$s and %3$s_" : ["%n päeva pärast %1$s, seejärel %2$s ja %3$s","%n päeva pärast %1$s, seejärel %2$s ja %3$s"],
"_In %n week on %1$s then on %2$s and %3$s_::_In %n weeks on %1$s then on %2$s and %3$s_" : ["%n nädala pärast %1$s, seejärel %2$s ja %3$s","%n nädala pärast %1$s, seejärel %2$s ja %3$s"],
"_In %n month on %1$s then on %2$s and %3$s_::_In %n months on %1$s then on %2$s and %3$s_" : ["%n kuu pärast %1$s, seejärel %2$s ja %3$s","%n kuu pärast %1$s, seejärel %2$s ja %3$s"],
"_In %n year on %1$s then on %2$s and %3$s_::_In %n years on %1$s then on %2$s and %3$s_" : ["%n aasta pärast %1$s, seejärel %2$s ja %3$s","%n aasta pärast %1$s, seejärel %2$s ja %3$s"],
"Could not generate next recurrence statement" : "Ei õnnestunud koostada korduva ürituse järgmise toimumise lausendit",
"Cancelled: %1$s" : "Tühistatud: %1$s",
"\"%1$s\" has been canceled" : "„%1$s“ on tühistatud",
@@ -202,6 +232,8 @@
"Could not rename part file to final file, canceled by hook" : "Osalise faili nime muutmine lõplikuks nimeks ei õnnestunud, selle katkestas programmi haak",
"Could not rename part file to final file" : "Osalise faili nime muutmine lõplikuks nimeks ei õnnestunud",
"Failed to check file size: %1$s" : "Faili suuruse kontrollimine ei õnnestunud: %1$s",
"Could not open file: %1$s (%2$d), file does seem to exist" : "„%1$s“ (%2$d) faili avamine ei õnnestunud, aga tundub, et ta on olemas",
"Could not open file: %1$s (%2$d), file doesn't seem to exist" : "„%1$s“ (%2$d) faili avamine ei õnnestunud, tundub, et teda pole olemas",
"Encryption not ready: %1$s" : "Krüptimine pole veel kasutatav: %1$s",
"Failed to open file: %1$s" : "Faili avamine ei õnnestunud: %1$s",
"Failed to unlink: %1$s" : "Lingi eemaldamine ei õnnestunud: %1$s",
+2
View File
@@ -234,6 +234,8 @@ OC.L10N.register(
"Could not rename part file to final file, canceled by hook" : "Níorbh fhéidir páirtchomhad a athainmniú go comhad deiridh, curtha ar ceal le hook",
"Could not rename part file to final file" : "Níorbh fhéidir páirtchomhad a athainmniú go dtí an comhad deiridh",
"Failed to check file size: %1$s" : "Níorbh fhéidir méid an chomhaid a sheiceáil: %1$s",
"Could not open file: %1$s (%2$d), file does seem to exist" : "Níorbh fhéidir an comhad a oscailt: %1$s (%2$d), is cosúil go bhfuil an comhad ann",
"Could not open file: %1$s (%2$d), file doesn't seem to exist" : "Níorbh fhéidir an comhad a oscailt: %1$s (%2$d), is cosúil nach bhfuil an comhad ann.",
"Encryption not ready: %1$s" : "Níl an criptiúchán réidh: %1$s",
"Failed to open file: %1$s" : "Níorbh fhéidir an comhad a oscailt: %1$s",
"Failed to unlink: %1$s" : "Theip ar dhínascadh: %1$s",
+2
View File
@@ -232,6 +232,8 @@
"Could not rename part file to final file, canceled by hook" : "Níorbh fhéidir páirtchomhad a athainmniú go comhad deiridh, curtha ar ceal le hook",
"Could not rename part file to final file" : "Níorbh fhéidir páirtchomhad a athainmniú go dtí an comhad deiridh",
"Failed to check file size: %1$s" : "Níorbh fhéidir méid an chomhaid a sheiceáil: %1$s",
"Could not open file: %1$s (%2$d), file does seem to exist" : "Níorbh fhéidir an comhad a oscailt: %1$s (%2$d), is cosúil go bhfuil an comhad ann",
"Could not open file: %1$s (%2$d), file doesn't seem to exist" : "Níorbh fhéidir an comhad a oscailt: %1$s (%2$d), is cosúil nach bhfuil an comhad ann.",
"Encryption not ready: %1$s" : "Níl an criptiúchán réidh: %1$s",
"Failed to open file: %1$s" : "Níorbh fhéidir an comhad a oscailt: %1$s",
"Failed to unlink: %1$s" : "Theip ar dhínascadh: %1$s",
+2
View File
@@ -234,6 +234,8 @@ OC.L10N.register(
"Could not rename part file to final file, canceled by hook" : "Non foi posíbel cambiar o nome do ficheiro parcial ao ficheiro final, foi cancelado polo sistema",
"Could not rename part file to final file" : "Non foi posíbel cambiar o nome do ficheiro parcial ao ficheiro final",
"Failed to check file size: %1$s" : "Produciuse un erro ao comprobar o tamaño do ficheiro: %1$s",
"Could not open file: %1$s (%2$d), file does seem to exist" : "Non foi posíbel abrir o ficheiro: %1$s (%2$d), semella o ficheiro existe",
"Could not open file: %1$s (%2$d), file doesn't seem to exist" : "Non foi posíbel abrir o ficheiro: %1$s (%2$d), semella o ficheiro non existe",
"Encryption not ready: %1$s" : "A cifraxe non está preparada: %1$s",
"Failed to open file: %1$s" : "Produciuse un erro ao abrir o ficheiro: %1$s",
"Failed to unlink: %1$s" : "Produciuse un erro ao desligar: %1$s",
+2
View File
@@ -232,6 +232,8 @@
"Could not rename part file to final file, canceled by hook" : "Non foi posíbel cambiar o nome do ficheiro parcial ao ficheiro final, foi cancelado polo sistema",
"Could not rename part file to final file" : "Non foi posíbel cambiar o nome do ficheiro parcial ao ficheiro final",
"Failed to check file size: %1$s" : "Produciuse un erro ao comprobar o tamaño do ficheiro: %1$s",
"Could not open file: %1$s (%2$d), file does seem to exist" : "Non foi posíbel abrir o ficheiro: %1$s (%2$d), semella o ficheiro existe",
"Could not open file: %1$s (%2$d), file doesn't seem to exist" : "Non foi posíbel abrir o ficheiro: %1$s (%2$d), semella o ficheiro non existe",
"Encryption not ready: %1$s" : "A cifraxe non está preparada: %1$s",
"Failed to open file: %1$s" : "Produciuse un erro ao abrir o ficheiro: %1$s",
"Failed to unlink: %1$s" : "Produciuse un erro ao desligar: %1$s",
+2
View File
@@ -234,6 +234,8 @@ OC.L10N.register(
"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: %1$s (%2$d), file does seem to exist" : "无法打开文件:%1$s%2$d),文件似乎不存在",
"Could not open file: %1$s (%2$d), file doesn't seem to exist" : "无法打开文件:%1$s%2$d),文件似乎不存在",
"Encryption not ready: %1$s" : "加密不可用:%1$s",
"Failed to open file: %1$s" : "打开文件失败:%1$s",
"Failed to unlink: %1$s" : "解除链接失败:%1$s",
+2
View File
@@ -232,6 +232,8 @@
"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: %1$s (%2$d), file does seem to exist" : "无法打开文件:%1$s%2$d),文件似乎不存在",
"Could not open file: %1$s (%2$d), file doesn't seem to exist" : "无法打开文件:%1$s%2$d),文件似乎不存在",
"Encryption not ready: %1$s" : "加密不可用:%1$s",
"Failed to open file: %1$s" : "打开文件失败:%1$s",
"Failed to unlink: %1$s" : "解除链接失败:%1$s",
+2
View File
@@ -234,6 +234,8 @@ OC.L10N.register(
"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: %1$s (%2$d), file does seem to exist" : "無法開啟檔案:%1$s (%2$d),檔案似乎存在",
"Could not open file: %1$s (%2$d), file doesn't seem to exist" : "無法開啟檔案:%1$s%2$d),檔案似乎不存在",
"Encryption not ready: %1$s" : "尚未準備好加密:%1$s",
"Failed to open file: %1$s" : "開啟檔案失敗:%1$s",
"Failed to unlink: %1$s" : "解除連結失敗:%1$s",
+2
View File
@@ -232,6 +232,8 @@
"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: %1$s (%2$d), file does seem to exist" : "無法開啟檔案:%1$s (%2$d),檔案似乎存在",
"Could not open file: %1$s (%2$d), file doesn't seem to exist" : "無法開啟檔案:%1$s%2$d),檔案似乎不存在",
"Encryption not ready: %1$s" : "尚未準備好加密:%1$s",
"Failed to open file: %1$s" : "開啟檔案失敗:%1$s",
"Failed to unlink: %1$s" : "解除連結失敗:%1$s",
+1 -1
View File
@@ -217,7 +217,7 @@ class BirthdayService {
$vEvent->DTSTART['VALUE'] = 'DATE';
$vEvent->add('DTEND');
$dtEndDate = (new \DateTime())->setTimestamp($date->getTimeStamp());
$dtEndDate = \DateTime::createFromInterface($date);
$dtEndDate->add(new \DateInterval('P1D'));
$vEvent->DTEND->setDateTime(
$dtEndDate
@@ -126,6 +126,18 @@ class IMipPlugin extends SabreIMipPlugin {
$iTipMessage->scheduleStatus = '5.0; EMail delivery failed';
return;
}
// Check if external attendees are disabled
$externalAttendeesDisabled = $this->config->getValueBool('dav', 'caldav_external_attendees_disabled', false);
if ($externalAttendeesDisabled && !$this->imipService->isSystemUser($recipient)) {
$this->logger->debug('Invitation not sent to external attendee (external attendees disabled)', [
'uid' => $iTipMessage->uid,
'attendee' => $recipient,
]);
$iTipMessage->scheduleStatus = '5.0; External attendees are disabled';
return;
}
$recipientName = $iTipMessage->recipientName ? (string)$iTipMessage->recipientName : null;
$newEvents = $iTipMessage->message;
@@ -875,6 +875,16 @@ class IMipService {
return $dtStart->getDateTime()->getTimeStamp();
}
/**
* Check if an email address belongs to a system user
*
* @param string $email
* @return bool True if the email belongs to a system user, false otherwise
*/
public function isSystemUser(string $email): bool {
return !empty($this->userManager->getByEmail($email));
}
/**
* @param Property $attendee
*/
+161 -109
View File
@@ -1,16 +1,20 @@
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
* SPDX-FileCopyrightText: 2012 entreCables S.L. All rights reserved
* SPDX-License-Identifier: AGPL-3.0-only
* SPDX-FileContributor: Sergio Cambra
* SPDX-License-Identifier: AGPL-3.0-only AND BSD-3-Clause
*/
namespace OCA\DAV\Connector\Sabre;
use OC\Files\View;
use OCA\DAV\Upload\UploadFolder;
use OCP\Files\StorageNotAvailableException;
use OCP\Util;
use Sabre\DAV\Exception\InsufficientStorage;
use Sabre\DAV\Exception\ServiceUnavailable;
use Sabre\DAV\IFile;
@@ -19,42 +23,41 @@ use Sabre\HTTP\RequestInterface;
use Sabre\HTTP\ResponseInterface;
/**
* This plugin check user quota and deny creating files when they exceeds the quota.
* This plugin enforces user storage quotas by preventing file operations that would
* exceed the users allotted quota.
*
* @author Sergio Cambra
* @copyright Copyright (C) 2012 entreCables S.L. All rights reserved.
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
* @property-read View $view The Nextcloud file view for quota operations.
*/
class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
/**
* Reference to main server object
* The Sabre\DAV server instance (set during initialize()).
*
* @var \Sabre\DAV\Server
* @var \Sabre\DAV\Server|null
*/
private $server;
private ?\Sabre\DAV\Server $server = null;
/**
* @param View $view
* QuotaPlugin constructor.
*
* @param View $view The Nextcloud Files View instance.
*/
public function __construct(
private $view,
private View $view,
) {
}
/**
* This initializes the plugin.
* Initializes the quota plugin and subscribes to relevant Sabre\DAV server events.
*
* This function is called by \Sabre\DAV\Server, after
* addPlugin is called.
* @link https://sabre.io/dav/writing-plugins/#events
*
* This method should set up the requires event subscriptions.
*
* @param \Sabre\DAV\Server $server
* @param \Sabre\DAV\Server $server The Sabre\DAV server instance.
* @return void
*/
public function initialize(\Sabre\DAV\Server $server) {
public function initialize(\Sabre\DAV\Server $server): void {
$this->server = $server;
// Register event handlers for quota checks on various file operations
$server->on('beforeWriteContent', [$this, 'beforeWriteContent'], 10);
$server->on('beforeCreateFile', [$this, 'beforeCreateFile'], 10);
$server->on('method:MKCOL', [$this, 'onCreateCollection'], 30);
@@ -63,78 +66,91 @@ class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
}
/**
* Check quota before creating file
* Checks quota before creating a new file.
* For chunked uploads (with 'Destination' and 'OC-Total-Length'), checks quota for the destination folder.
* Otherwise, checks quota for the parent node plus the new filename.
*
* @param string $uri target file URI
* @param resource $data data
* @param INode $parent Sabre Node
* @param bool $modified modified
* @param string $uri Target file URI (unused).
* @param resource $data The data to write (unused).
* @param INode $parent Parent Sabre node.
* @param bool $modified Whether the node is modified (unused).
* @return bool True if quota is sufficient, otherwise throws InsufficientStorage.
*/
public function beforeCreateFile($uri, $data, INode $parent, $modified) {
public function beforeCreateFile(string $uri, $data, INode $parent, bool $modified): bool {
$request = $this->server->httpRequest;
// Check quota during chunked uploads
if ($parent instanceof UploadFolder && $request->getHeader('Destination')) {
// If chunked upload and Total-Length header is set, use that
// value for quota check. This allows us to also check quota while
// uploading chunks and not only when the file is assembled.
$length = $request->getHeader('OC-Total-Length');
$destinationPath = $this->server->calculateUri($request->getHeader('Destination'));
$totalLength = $request->getHeader('OC-Total-Length');
$destinationUri = $request->getHeader('Destination');
$destinationPath = $this->server->calculateUri($destinationUri);
$quotaPath = $this->getPathForDestination($destinationPath);
if ($quotaPath && is_numeric($length)) {
return $this->checkQuota($quotaPath, (int)$length);
if ($quotaPath && is_numeric($totalLength)) {
return $this->checkQuota($quotaPath, Util::numericToNumber($totalLength));
}
// If quota cannot be checked, allow by default
// NOTE: We can still check during assembly.
return true;
}
if (!$parent instanceof Node) {
return;
// No quota check for non-Node parents
return true;
}
return $this->checkQuota($parent->getPath() . '/' . basename($uri));
$filePath = $parent->getPath() . '/' . basename($uri);
return $this->checkQuota($filePath);
}
/**
* Check quota before creating directory
* Checks quota before creating a new collection (directory) via MKCOL.
* Assumes a fixed size (4096 bytes) for quota check as MKCOL lacks a Content-Length header.
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @return bool
* @throws InsufficientStorage
* @throws \Sabre\DAV\Exception\Forbidden
* @param RequestInterface $request The HTTP request for the MKCOL operation.
* @param ResponseInterface $response The HTTP response object.
* @return bool True if there is enough quota, otherwise throws InsufficientStorage or \Sabre\DAV\Exception\Forbidden (?).
*/
public function onCreateCollection(RequestInterface $request, ResponseInterface $response): bool {
try {
$destinationPath = $this->server->calculateUri($request->getUrl());
$quotaPath = $this->getPathForDestination($destinationPath);
$collectionPath = $this->getPathForDestination($destinationPath);
} catch (\Exception $e) {
return true;
// Optionally log: e.g. ('Quota check failed during onCreateCollection: ' . $e->getMessage());
return true; // Quota cannot be checked, allow by default
}
if ($quotaPath) {
// MKCOL does not have a Content-Length header, so we can use
// a fixed value for the quota check.
return $this->checkQuota($quotaPath, 4096, true);
if ($collectionPath) {
// Default directory size for quota check since MKCOL doesn't specify one
return $this->checkQuota($collectionPath, 4096, true);
}
return true;
return true; // No path to check, allow by default
}
/**
* Check quota before writing content
* Checks quota before writing content to a node.
*
* @param string $uri target file URI
* @param INode $node Sabre Node
* @param resource $data data
* @param bool $modified modified
* @param string $uri Target file URI (unused).
* @param INode $node Sabre node to which content will be written.
* @param resource $data Content data (unused).
* @param bool $modified Whether the node is modified (unused).
* @return bool True if there is enough quota, otherwise throws InsufficientStorage.
*/
public function beforeWriteContent($uri, INode $node, $data, $modified) {
public function beforeWriteContent(string $uri, INode $node, $data, bool $modified): bool {
if (!$node instanceof Node) {
return;
// No quota check for non-Node objects
return true;
}
return $this->checkQuota($node->getPath());
}
/**
* Check if we're moving a FutureFile in which case we need to check
* the quota on the target destination.
* Checks quota before moving a FutureFile node to a new destination.
*
* @param string $sourcePath Path to the source node.
* @param string $destinationPath Path where the node will be moved to.
* @return bool True if there is enough quota, otherwise throws InsufficientStorage.
*/
public function beforeMove(string $sourcePath, string $destinationPath): bool {
$sourceNode = $this->server->tree->getNodeForPath($sourcePath);
@@ -143,17 +159,22 @@ class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
}
try {
// The final path is not known yet, we check the quota on the parent
$path = $this->getPathForDestination($destinationPath);
// The final path is not known yet, check quota on the parent of the destination
$quotaPath = $this->getPathForDestination($destinationPath);
} catch (\Exception $e) {
// Optionally log: e.g. ('Quota check failed during beforeMove: ' . $e->getMessage());
return true;
}
return $this->checkQuota($path, $sourceNode->getSize());
return $this->checkQuota($quotaPath, $sourceNode->getSize());
}
/**
* Check quota on the target destination before a copy.
* Checks quota before allowing a file copy operation.
*
* @param string $sourcePath Path to the source node.
* @param string $destinationPath Path where the node will be copied to.
* @return bool True if there is enough quota, otherwise throws InsufficientStorage.
*/
public function beforeCopy(string $sourcePath, string $destinationPath): bool {
$sourceNode = $this->server->tree->getNodeForPath($sourcePath);
@@ -162,101 +183,132 @@ class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
}
try {
$path = $this->getPathForDestination($destinationPath);
$quotaPath = $this->getPathForDestination($destinationPath);
} catch (\Exception $e) {
// Optionally log: e.g. ('Quota check failed during beforeCopy: ' . $e->getMessage());
return true;
}
return $this->checkQuota($path, $sourceNode->getSize());
return $this->checkQuota($quotaPath, $sourceNode->getSize());
}
/**
* Resolves the path for quota checking, given a destination path.
*
* If the destination node exists, returns its internal path.
* If it does not exist, returns the internal path of its parent node.
* Throws an exception if the relevant node is not a valid Node instance.
*
* @param string $destinationPath Destination path within the virtual file tree.
* @return string Internal path to use for quota checking.
* @throws \Exception If the destination or parent node is not a valid Node.
*/
private function getPathForDestination(string $destinationPath): string {
// get target node for proper path conversion
// If the node exists, return its actual path
if ($this->server->tree->nodeExists($destinationPath)) {
$destinationNode = $this->server->tree->getNodeForPath($destinationPath);
if (!$destinationNode instanceof Node) {
throw new \Exception('Invalid destination node');
throw new \Exception("Destination node at '$destinationPath' is not a valid Node instance.");
}
return $destinationNode->getPath();
}
// Otherwise, use the parent directory's path
$parent = dirname($destinationPath);
if ($parent === '.') {
$parent = '';
}
$parent = ($parent === '.') ? '' : $parent;
$parentNode = $this->server->tree->getNodeForPath($parent);
if (!$parentNode instanceof Node) {
throw new \Exception('Invalid destination node');
throw new \Exception("Parent node at '$parent' is not a valid Node instance.");
}
return $parentNode->getPath();
}
/**
* This method is called before any HTTP method and validates there is enough free space to store the file
* Validates there is enough free space to store the file at the given path.
*
* @param string $path relative to the users home
* @param int|float|null $length
* Called before relevant HTTP DAV events (when there is an associated View).
* @see initialize() for specific events we're registered for.
*
* @internal
* @param string $path Path relative to the user's home.
* @param int|float|null $length Size to check for, or null to auto-detect.
* @param bool $isDir Whether the target is a directory.
* @throws InsufficientStorage
* @return bool
* @return bool True if there is enough space, otherwise throws.
*/
public function checkQuota(string $path, $length = null, $isDir = false) {
public function checkQuota(string $path, int|float|null $length = null, bool $isDir = false): bool {
// Auto-detect length if not provided
if ($length === null) {
$length = $this->getLength();
}
if (empty($length)) {
return true; // No length to check, assume okay
}
if ($length) {
[$parentPath, $newName] = \Sabre\Uri\split($path);
if (is_null($parentPath)) {
$parentPath = '';
}
$req = $this->server->httpRequest;
$normalizedPath = str_replace('//', '/', $path);
$freeSpace = $this->getFreeSpace($normalizedPath);
// Strip any duplicate slashes
$path = str_replace('//', '/', $path);
// Explicitly handle unknown/invalid free space
if ($freeSpace === false || $freeSpace < 0) {
// You might log here; currently allows the operation
return true;
}
$freeSpace = $this->getFreeSpace($path);
if ($freeSpace >= 0 && $length > $freeSpace) {
if ($isDir) {
throw new InsufficientStorage("Insufficient space in $path. $freeSpace available. Cannot create directory");
}
throw new InsufficientStorage("Insufficient space in $path, $length required, $freeSpace available");
}
if ($length > $freeSpace) {
$msg = $isDir
? "Insufficient space in $normalizedPath. $freeSpace available. Cannot create directory"
: "Insufficient space in $normalizedPath, $length required, $freeSpace available";
throw new InsufficientStorage($msg);
}
return true;
}
public function getLength() {
$req = $this->server->httpRequest;
$length = $req->getHeader('X-Expected-Entity-Length');
if (!is_numeric($length)) {
$length = $req->getHeader('Content-Length');
$length = is_numeric($length) ? $length : null;
}
/**
* Returns the largest valid content length found in any of the following HTTP headers:
* - X-Expected-Entity-Length
* - Content-Length
* - OC-Total-Length
*
* Only numeric values are considered. If none of the headers contain a valid numeric value,
* returns null.
*
* @internal
* @return int|float|null The largest valid content length, or null if none is found.
*/
public function getLength(): int|float|null {
$request = $this->server->httpRequest;
$ocLength = $req->getHeader('OC-Total-Length');
if (!is_numeric($ocLength)) {
return $length;
}
if (!is_numeric($length)) {
return $ocLength;
}
return max($length, $ocLength);
// Get headers as strings
$expectedLength = $request->getHeader('X-Expected-Entity-Length');
$contentLength = $request->getHeader('Content-Length');
$ocTotalLength = $request->getHeader('OC-Total-Length');
// Filter out non-numeric values, use Util::numericToNumber for safe conversion
$lengths = array_filter([
is_numeric($expectedLength) ? Util::numericToNumber($expectedLength) : null,
is_numeric($contentLength) ? Util::numericToNumber($contentLength) : null,
is_numeric($ocTotalLength) ? Util::numericToNumber($ocTotalLength) : null,
], fn ($v) => $v !== null);
// Return the largest valid length, or null if none
return !empty($lengths) ? max($lengths) : null;
}
/**
* @param string $uri
* @return mixed
* @throws ServiceUnavailable
* Returns the available free space for the given URI.
*
* TODO: `false` can probably be dropped here, if not now when free_space is cleaned up.
*
* @param string $uri The resource URI whose free space is being queried.
* @return int|float|false The amount of free space in bytes,
* @throws ServiceUnavailable If the underlying storage is not available.
*/
public function getFreeSpace($uri) {
private function getFreeSpace(string $uri): int|float|false {
try {
$freeSpace = $this->view->free_space(ltrim($uri, '/'));
return $freeSpace;
return $this->view->free_space(ltrim($uri, '/'));
} catch (StorageNotAvailableException $e) {
throw new ServiceUnavailable($e->getMessage());
}
@@ -103,6 +103,7 @@ class ServerFactory {
$server->addPlugin(new LockPlugin());
$server->addPlugin(new RequestIdHeaderPlugin($this->request));
$server->addPlugin(new UserIdHeaderPlugin($this->userSession));
$server->addPlugin(new ZipFolderPlugin(
$tree,
@@ -261,6 +261,14 @@ class SharesPlugin extends \Sabre\DAV\ServerPlugin {
return true;
}
}
// if the share recipient is allow to delete from the share, they are allowed to move the file out of the share
// the user moving the file out of the share to their home storage would give them share permissions and allow moving into the share
//
// since the 2-step move is allowed, we also allow both steps at once
if ($sourceNode->isDeletable()) {
return true;
}
}
throw new Forbidden('You cannot move a non-shareable node into a share');
@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\DAV\Connector\Sabre;
use OCP\IUserSession;
use Sabre\HTTP\RequestInterface;
use Sabre\HTTP\ResponseInterface;
class UserIdHeaderPlugin extends \Sabre\DAV\ServerPlugin {
public function __construct(
private readonly IUserSession $userSession,
) {
}
public function initialize(\Sabre\DAV\Server $server): void {
$server->on('afterMethod:*', [$this, 'afterMethod']);
}
/**
* Add the request id as a header in the response
*
* @param RequestInterface $request request
* @param ResponseInterface $response response
*/
public function afterMethod(RequestInterface $request, ResponseInterface $response): void {
if ($user = $this->userSession->getUser()) {
$response->setHeader('X-User-Id', $user->getUID());
}
}
}
+2
View File
@@ -51,6 +51,7 @@ use OCA\DAV\Connector\Sabre\QuotaPlugin;
use OCA\DAV\Connector\Sabre\RequestIdHeaderPlugin;
use OCA\DAV\Connector\Sabre\SharesPlugin;
use OCA\DAV\Connector\Sabre\TagsPlugin;
use OCA\DAV\Connector\Sabre\UserIdHeaderPlugin;
use OCA\DAV\Connector\Sabre\ZipFolderPlugin;
use OCA\DAV\DAV\CustomPropertiesBackend;
use OCA\DAV\DAV\PublicAuth;
@@ -244,6 +245,7 @@ class Server {
// performance improvement plugins
$this->server->addPlugin(new CopyEtagHeaderPlugin());
$this->server->addPlugin(new RequestIdHeaderPlugin(\OCP\Server::get(IRequest::class)));
$this->server->addPlugin(new UserIdHeaderPlugin(\OCP\Server::get(IUserSession::class)));
$this->server->addPlugin(new UploadAutoMkcolPlugin());
$this->server->addPlugin(new ChunkingV2Plugin(\OCP\Server::get(ICacheFactory::class)));
$this->server->addPlugin(new ChunkingPlugin());
@@ -130,6 +130,10 @@ class IMipPluginTest extends TestCase {
$message->senderName = 'Mr. Wizard';
$message->recipient = 'mailto:' . 'frodo@hobb.it';
$message->significantChange = false;
$this->config->expects(self::never())
->method('getValueBool');
$this->plugin->schedule($message);
$this->assertEquals('1.0', $message->getScheduleStatus());
}
@@ -177,6 +181,12 @@ class IMipPluginTest extends TestCase {
$this->service->expects(self::once())
->method('getLastOccurrence')
->willReturn(1496912700);
$this->config->expects(self::exactly(2))
->method('getValueBool')
->willReturnMap([
['dav', 'caldav_external_attendees_disabled', false, false],
['core', 'mail_providers_enabled', true, false],
]);
$this->eventComparisonService->expects(self::once())
->method('findModified')
->willReturn(['new' => [$newVevent], 'old' => [$oldVEvent]]);
@@ -280,6 +290,10 @@ class IMipPluginTest extends TestCase {
$this->service->expects(self::once())
->method('getLastOccurrence')
->willReturn(1496912700);
$this->config->expects(self::once())
->method('getValueBool')
->with('dav', 'caldav_external_attendees_disabled', false)
->willReturn(false);
$this->eventComparisonService->expects(self::once())
->method('findModified')
->willReturn(['new' => [$newVevent], 'old' => [$oldVEvent]]);
@@ -354,6 +368,10 @@ class IMipPluginTest extends TestCase {
$this->service->expects(self::once())
->method('getLastOccurrence')
->willReturn(1496912700);
$this->config->expects(self::once())
->method('getValueBool')
->with('dav', 'caldav_external_attendees_disabled', false)
->willReturn(false);
$this->eventComparisonService->expects(self::once())
->method('findModified')
->willReturn(['new' => [$newVevent], 'old' => null]);
@@ -455,6 +473,12 @@ class IMipPluginTest extends TestCase {
$this->service->expects(self::once())
->method('getLastOccurrence')
->willReturn(1496912700);
$this->config->expects(self::exactly(2))
->method('getValueBool')
->willReturnMap([
['dav', 'caldav_external_attendees_disabled', false, false],
['core', 'mail_providers_enabled', true, false],
]);
$this->eventComparisonService->expects(self::once())
->method('findModified')
->willReturn(['old' => [] ,'new' => [$newVevent]]);
@@ -695,6 +719,12 @@ class IMipPluginTest extends TestCase {
$this->service->expects(self::once())
->method('getLastOccurrence')
->willReturn(1496912700);
$this->config->expects(self::exactly(2))
->method('getValueBool')
->willReturnMap([
['dav', 'caldav_external_attendees_disabled', false, false],
['core', 'mail_providers_enabled', true, true],
]);
$this->service->expects(self::once())
->method('getCurrentAttendee')
->with($message)
@@ -837,10 +867,12 @@ class IMipPluginTest extends TestCase {
->method('getValueString')
->with('dav', 'invitation_link_recipients', 'yes')
->willReturn('yes');
$this->config->expects(self::once())
$this->config->expects(self::exactly(2))
->method('getValueBool')
->with('core', 'mail_providers_enabled', true)
->willReturn(false);
->willReturnMap([
['dav', 'caldav_external_attendees_disabled', false, false],
['core', 'mail_providers_enabled', true, false],
]);
$this->service->expects(self::once())
->method('createInvitationToken')
->with($message, $newVevent, 1496912700)
@@ -888,6 +920,12 @@ class IMipPluginTest extends TestCase {
$this->service->expects(self::once())
->method('getLastOccurrence')
->willReturn(1496912700);
$this->config->expects(self::exactly(2))
->method('getValueBool')
->willReturnMap([
['dav', 'caldav_external_attendees_disabled', false, false],
['core', 'mail_providers_enabled', true, false],
]);
$this->eventComparisonService->expects(self::once())
->method('findModified')
->with($newVCalendar, null)
@@ -981,6 +1019,12 @@ class IMipPluginTest extends TestCase {
$this->service->expects(self::once())
->method('getLastOccurrence')
->willReturn(1496912700);
$this->config->expects(self::exactly(2))
->method('getValueBool')
->willReturnMap([
['dav', 'caldav_external_attendees_disabled', false, false],
['core', 'mail_providers_enabled', true, false],
]);
$this->eventComparisonService->expects(self::once())
->method('findModified')
->with($newVCalendar, null)
@@ -1040,4 +1084,156 @@ class IMipPluginTest extends TestCase {
$this->plugin->schedule($message);
$this->assertEquals('1.1', $message->getScheduleStatus());
}
public function testExternalAttendeesDisabledForExternalUser(): void {
$message = new Message();
$message->method = 'REQUEST';
$newVCalendar = new VCalendar();
$newVevent = new VEvent($newVCalendar, 'one', array_merge([
'UID' => 'uid-1234',
'SEQUENCE' => 1,
'SUMMARY' => 'Fellowship meeting',
'DTSTART' => new \DateTime('2016-01-01 00:00:00')
], []));
$newVevent->add('ORGANIZER', 'mailto:gandalf@wiz.ard');
$newVevent->add('ATTENDEE', 'mailto:external@example.com', ['RSVP' => 'TRUE', 'CN' => 'External User']);
$message->message = $newVCalendar;
$message->sender = 'mailto:gandalf@wiz.ard';
$message->senderName = 'Mr. Wizard';
$message->recipient = 'mailto:external@example.com';
$this->service->expects(self::once())
->method('getLastOccurrence')
->willReturn(1496912700);
$this->config->expects(self::once())
->method('getValueBool')
->with('dav', 'caldav_external_attendees_disabled', false)
->willReturn(true);
$this->service->expects(self::once())
->method('isSystemUser')
->with('external@example.com')
->willReturn(false);
$this->eventComparisonService->expects(self::never())
->method('findModified');
$this->service->expects(self::never())
->method('getCurrentAttendee');
$this->mailer->expects(self::never())
->method('send');
$this->plugin->schedule($message);
$this->assertEquals('5.0', $message->getScheduleStatus());
}
public function testExternalAttendeesDisabledForSystemUser(): void {
$message = new Message();
$message->method = 'REQUEST';
$newVCalendar = new VCalendar();
$newVevent = new VEvent($newVCalendar, 'one', array_merge([
'UID' => 'uid-1234',
'SEQUENCE' => 1,
'SUMMARY' => 'Fellowship meeting',
'DTSTART' => new \DateTime('2016-01-01 00:00:00')
], []));
$newVevent->add('ORGANIZER', 'mailto:gandalf@wiz.ard');
$newVevent->add('ATTENDEE', 'mailto:frodo@hobb.it', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
$message->message = $newVCalendar;
$message->sender = 'mailto:gandalf@wiz.ard';
$message->senderName = 'Mr. Wizard';
$message->recipient = 'mailto:frodo@hobb.it';
$oldVCalendar = new VCalendar();
$oldVEvent = new VEvent($oldVCalendar, 'one', [
'UID' => 'uid-1234',
'SEQUENCE' => 0,
'SUMMARY' => 'Fellowship meeting',
'DTSTART' => new \DateTime('2016-01-01 00:00:00')
]);
$oldVEvent->add('ORGANIZER', 'mailto:gandalf@wiz.ard');
$oldVEvent->add('ATTENDEE', 'mailto:frodo@hobb.it', ['RSVP' => 'TRUE', 'CN' => 'Frodo']);
$oldVCalendar->add($oldVEvent);
$data = ['invitee_name' => 'Mr. Wizard',
'meeting_title' => 'Fellowship meeting',
'attendee_name' => 'frodo@hobb.it'
];
$attendees = $newVevent->select('ATTENDEE');
$atnd = '';
foreach ($attendees as $attendee) {
if (strcasecmp($attendee->getValue(), $message->recipient) === 0) {
$atnd = $attendee;
}
}
$this->plugin->setVCalendar($oldVCalendar);
$this->service->expects(self::once())
->method('getLastOccurrence')
->willReturn(1496912700);
$this->config->expects(self::exactly(2))
->method('getValueBool')
->willReturnMap([
['dav', 'caldav_external_attendees_disabled', false, true],
['core', 'mail_providers_enabled', true, false],
]);
$this->service->expects(self::once())
->method('isSystemUser')
->with('frodo@hobb.it')
->willReturn(true);
$this->eventComparisonService->expects(self::once())
->method('findModified')
->willReturn(['new' => [$newVevent], 'old' => [$oldVEvent]]);
$this->service->expects(self::once())
->method('getCurrentAttendee')
->with($message)
->willReturn($atnd);
$this->service->expects(self::once())
->method('isRoomOrResource')
->with($atnd)
->willReturn(false);
$this->service->expects(self::once())
->method('isCircle')
->with($atnd)
->willReturn(false);
$this->service->expects(self::once())
->method('buildBodyData')
->with($newVevent, $oldVEvent)
->willReturn($data);
$this->user->expects(self::any())
->method('getUID')
->willReturn('user1');
$this->user->expects(self::any())
->method('getDisplayName')
->willReturn('Mr. Wizard');
$this->userSession->expects(self::any())
->method('getUser')
->willReturn($this->user);
$this->service->expects(self::once())
->method('getFrom');
$this->service->expects(self::once())
->method('addSubjectAndHeading')
->with($this->emailTemplate, 'request', 'Mr. Wizard', 'Fellowship meeting', true);
$this->service->expects(self::once())
->method('addBulletList')
->with($this->emailTemplate, $newVevent, $data);
$this->service->expects(self::once())
->method('getAttendeeRsvpOrReqForParticipant')
->willReturn(true);
$this->config->expects(self::once())
->method('getValueString')
->with('dav', 'invitation_link_recipients', 'yes')
->willReturn('yes');
$this->service->expects(self::once())
->method('createInvitationToken')
->with($message, $newVevent, 1496912700)
->willReturn('token');
$this->service->expects(self::once())
->method('addResponseButtons')
->with($this->emailTemplate, 'token');
$this->service->expects(self::once())
->method('addMoreOptionsButton')
->with($this->emailTemplate, 'token');
$this->mailer->expects(self::once())
->method('send')
->willReturn([]);
$this->plugin->schedule($message);
$this->assertEquals('1.1', $message->getScheduleStatus());
}
}
@@ -161,6 +161,31 @@ class IMipServiceTest extends TestCase {
$this->assertEquals($expected, $actual);
}
public function testIsSystemUserWhenUserExists(): void {
$email = 'user@example.com';
$user = $this->createMock(\OCP\IUser::class);
$this->userManager->expects(self::once())
->method('getByEmail')
->with($email)
->willReturn([$user]);
$result = $this->service->isSystemUser($email);
$this->assertTrue($result);
}
public function testIsSystemUserWhenUserDoesNotExist(): void {
$email = 'external@example.com';
$this->userManager->expects(self::once())
->method('getByEmail')
->with($email)
->willReturn([]);
$result = $this->service->isSystemUser($email);
$this->assertFalse($result);
}
public function testBuildBodyDataCreated(): void {
// construct l10n return(s)
@@ -19,7 +19,7 @@ class QuotaPluginTest extends TestCase {
private QuotaPlugin $plugin;
private function init(int $quota, string $checkedPath = ''): void {
$view = $this->buildFileViewMock((string)$quota, $checkedPath);
$view = $this->buildFileViewMock($quota, $checkedPath);
$this->server = new \Sabre\DAV\Server();
$this->plugin = new QuotaPlugin($view);
$this->plugin->initialize($this->server);
@@ -136,7 +136,14 @@ class QuotaPluginTest extends TestCase {
];
}
private function buildFileViewMock(string $quota, string $checkedPath): View {
/**
* Build a mock for the View class with a controlled free_space() response.
*
* @param int|float|false $quota The quota value to return from free_space().
* @param string $checkedPath The path expected as a parameter to free_space().
* @return View&\PHPUnit\Framework\MockObject\MockObject
*/
private function buildFileViewMock(int|float|false $quota, string $checkedPath): View {
// mock filesystem
$view = $this->getMockBuilder(View::class)
->onlyMethods(['free_space'])
@@ -44,7 +44,6 @@ use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IManager;
use OCP\Share\IProviderFactory;
use OCP\Share\IShare;
use OCP\Snowflake\IGenerator;
use OCP\Util;
use Override;
use Psr\Log\LoggerInterface;
@@ -70,7 +69,6 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
private readonly IFilenameValidator $filenameValidator,
private readonly IProviderFactory $shareProviderFactory,
private readonly SetupManager $setupManager,
private readonly IGenerator $snowflakeGenerator,
private readonly ExternalShareMapper $externalShareMapper,
) {
}
@@ -145,7 +143,7 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
}
$externalShare = new ExternalShare();
$externalShare->setId($this->snowflakeGenerator->nextId());
$externalShare->generateId();
$externalShare->setRemote($remote);
$externalShare->setRemoteId($remoteId);
$externalShare->setShareToken($token);
@@ -177,9 +175,9 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
->setType('remote_share')
->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/'), $ownerDisplayName])
->setAffectedUser($shareWith)
->setObject('remote_share', $externalShare->getId(), $name);
->setObject('remote_share', (string)$externalShare->getId(), $name);
Server::get(IActivityManager::class)->publish($event);
$this->notifyAboutNewShare($shareWith, $externalShare->getId(), $ownerFederatedId, $sharedByFederatedId, $name, $ownerDisplayName);
$this->notifyAboutNewShare($shareWith, (string)$externalShare->getId(), $ownerFederatedId, $sharedByFederatedId, $name, $ownerDisplayName);
// If auto-accept is enabled, accept the share
if ($this->federatedShareProvider->isFederatedTrustedShareAutoAccept() && $trustedServers?->isTrustedServer($remote) === true) {
@@ -193,9 +191,9 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
->setType('remote_share')
->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/'), $ownerDisplayName])
->setAffectedUser($user->getUID())
->setObject('remote_share', $externalShare->getId(), $name);
->setObject('remote_share', (string)$externalShare->getId(), $name);
Server::get(IActivityManager::class)->publish($event);
$this->notifyAboutNewShare($user->getUID(), $externalShare->getId(), $ownerFederatedId, $sharedByFederatedId, $name, $ownerDisplayName);
$this->notifyAboutNewShare($user->getUID(), (string)$externalShare->getId(), $ownerFederatedId, $sharedByFederatedId, $name, $ownerDisplayName);
// If auto-accept is enabled, accept the share
if ($this->federatedShareProvider->isFederatedTrustedShareAutoAccept() && $trustedServers?->isTrustedServer($remote) === true) {
@@ -204,7 +202,7 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
}
}
return $externalShare->getId();
return (string)$externalShare->getId();
} catch (\Exception $e) {
$this->logger->error('Server can not add remote share.', [
'app' => 'files_sharing',
@@ -466,7 +464,7 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
$notification = $this->notificationManager->createNotification();
$notification->setApp('files_sharing')
->setUser($share->getUser())
->setObject('remote_share', $share->getId());
->setObject('remote_share', (string)$share->getId());
$this->notificationManager->markProcessed($notification);
$event = $this->activityManager->generateEvent();
-116
View File
@@ -1,116 +0,0 @@
/*!
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
* SPDX-License-Identifier: AGPL-3.0-only
*/
/**
* @param $ - The jQuery instance
*/
(function($) {
// ocFederationAddServer
$.fn.ocFederationAddServer = function() {
/* Go easy on jquery and define some vars
========================================================================== */
const $wrapper = $(this),
// Buttons
$btnAddServer = $wrapper.find('#ocFederationAddServerButton'),
$btnSubmit = $wrapper.find('#ocFederationSubmit'),
// Inputs
$inpServerUrl = $wrapper.find('#serverUrl'),
// misc
$msgBox = $wrapper.find('#ocFederationAddServer .msg'),
$srvList = $wrapper.find('#listOfTrustedServers')
/* Interaction
========================================================================== */
$btnAddServer.on('click', function() {
$btnAddServer.addClass('hidden')
$wrapper.find('.serverUrl').removeClass('hidden')
$inpServerUrl
.focus()
})
// trigger server removal
$srvList.on('click', 'li > .icon-delete', function() {
const $this = $(this).parent()
const id = $this.attr('id')
removeServer(id)
})
$btnSubmit.on('click', function() {
addServer($inpServerUrl.val())
})
$inpServerUrl.on('change keyup', function(e) {
const url = $(this).val()
// toggle add-button visibility based on input length
if (url.length > 0) { $btnSubmit.removeClass('hidden') } else { $btnSubmit.addClass('hidden') }
if (e.keyCode === 13) { // add server on "enter"
addServer(url)
} else if (e.keyCode === 27) { // hide input filed again in ESC
$btnAddServer.removeClass('hidden')
$inpServerUrl.val('').addClass('hidden')
$btnSubmit.addClass('hidden')
}
})
}
/* private Functions
========================================================================== */
/**
*
* @param url
*/
function addServer(url) {
OC.msg.startSaving('#ocFederationAddServer .msg')
$.post(
OC.getRootPath() + '/ocs/v2.php/apps/federation/trusted-servers',
{
url,
},
null,
'json',
).done(function({ ocs }) {
const data = ocs.data
$('#serverUrl').attr('value', '')
$('#listOfTrustedServers').prepend($('<li>')
.attr('id', data.id)
.html('<span class="status indeterminate"></span>'
+ data.url
+ '<span class="icon icon-delete"></span>'))
OC.msg.finishedSuccess('#ocFederationAddServer .msg', data.message)
})
.fail(function(jqXHR) {
OC.msg.finishedError('#ocFederationAddServer .msg', JSON.parse(jqXHR.responseText).ocs.meta.message)
})
}
/**
*
* @param id
*/
function removeServer(id) {
$.ajax({
url: OC.getRootPath() + '/ocs/v2.php/apps/federation/trusted-servers/' + id,
type: 'DELETE',
success: function(response) {
$('#ocFederationSettings').find('#' + id).remove()
},
})
}
})(jQuery)
window.addEventListener('DOMContentLoaded', function() {
$('#ocFederationSettings').ocFederationAddServer()
})
+4 -3
View File
@@ -11,11 +11,12 @@ OC.L10N.register(
"Federation" : "الربط عبر السحابة الموحدة",
"Federation allows you to connect with other trusted servers to exchange the account directory." : "يسمح لك الاتحاد بالاتصال بخوادم موثوقة أخرى لتبادل أدلة الحسابات معها.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing." : "يسمح لك الاتحاد بالاتصال بخوادم موثوقة أخرى لتبادل أدلة الحسابات معها. على سبيل المثال، سيتم استخدام هذا للإكمال التلقائي للحسابات الخارجية عند المشاركة عبر السحابة الموحدة federated sharing.",
"External documentation for Federated Cloud Sharing" : "التوثيق الخارجي لمشاركة السحابة الاتحادية",
"Add" : "إضافة",
"Delete" : "حذف",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share." : "يسمح لك الاتحاد بالاتصال بخوادم موثوقة أخرى لتبادل أدلة الحسابات معها. على سبيل المثال، سيتم استخدام هذا للإكمال التلقائي للحسابات الخارجية عند المشاركة الاتحادية. ليس من الضروري إضافة خادم كخادم موثوق به لإنشاء مشاركة السحابة الموحدة.",
"Each server must validate the other. This process may require a few cron cycles." : "يجب على كل خادوم أن يُصادِق على الآخر. هذه العملية يمكن أن تستغرق عدة دورات من مهام الخلفية cron.",
"External documentation for Federated Cloud Sharing" : "التوثيق الخارجي لمشاركة السحابة الاتحادية",
"+ Add trusted server" : "+ إضافة خادم موثوق",
"Trusted server" : "خادم موثوق",
"Add" : "إضافة"
"Trusted server" : "خادم موثوق"
},
"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;");
+4 -3
View File
@@ -9,11 +9,12 @@
"Federation" : "الربط عبر السحابة الموحدة",
"Federation allows you to connect with other trusted servers to exchange the account directory." : "يسمح لك الاتحاد بالاتصال بخوادم موثوقة أخرى لتبادل أدلة الحسابات معها.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing." : "يسمح لك الاتحاد بالاتصال بخوادم موثوقة أخرى لتبادل أدلة الحسابات معها. على سبيل المثال، سيتم استخدام هذا للإكمال التلقائي للحسابات الخارجية عند المشاركة عبر السحابة الموحدة federated sharing.",
"External documentation for Federated Cloud Sharing" : "التوثيق الخارجي لمشاركة السحابة الاتحادية",
"Add" : "إضافة",
"Delete" : "حذف",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share." : "يسمح لك الاتحاد بالاتصال بخوادم موثوقة أخرى لتبادل أدلة الحسابات معها. على سبيل المثال، سيتم استخدام هذا للإكمال التلقائي للحسابات الخارجية عند المشاركة الاتحادية. ليس من الضروري إضافة خادم كخادم موثوق به لإنشاء مشاركة السحابة الموحدة.",
"Each server must validate the other. This process may require a few cron cycles." : "يجب على كل خادوم أن يُصادِق على الآخر. هذه العملية يمكن أن تستغرق عدة دورات من مهام الخلفية cron.",
"External documentation for Federated Cloud Sharing" : "التوثيق الخارجي لمشاركة السحابة الاتحادية",
"+ Add trusted server" : "+ إضافة خادم موثوق",
"Trusted server" : "خادم موثوق",
"Add" : "إضافة"
"Trusted server" : "خادم موثوق"
},"pluralForm" :"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;"
}
-17
View File
@@ -1,17 +0,0 @@
OC.L10N.register(
"federation",
{
"Added to the list of trusted servers" : "Amestóse a la llista de sirvidores d'enfotu",
"Server is already in the list of trusted servers." : "El sirvidor yá ta na llista de los sirvidores d'enfotu.",
"No server to federate with found" : "Nun s'atopó nengún sirvidor col que se federar",
"Could not add server" : "Nun se pudo amestar el sirvidor",
"Trusted servers" : "Sirvidores d'enfotu",
"Federation" : "Federación",
"Federation allows you to connect with other trusted servers to exchange the account directory." : "La federación permíte que te conectes con otros sirvidores d'enfotu pa intercambiar el direutoriu de cuentes.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing." : "La federación permite que te conectes a otros sirvidores d'enfotu pa intercambiar el direutoriu de cuentes. Por exemplu, va usase pa completar automáticamente les cuentes esternes de la compartición federada.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share." : "La federación permite que te conectes a otros sirvidores d'enfotu pa intercambiar el direutoriu de cuentes. Por exemplu, va usase pa completar automáticamente les cuentes esternes de la compartición federada. Nun ye necesario amestar un sirvidor como sirvidor d'enfotu pa crear una compartición federada.",
"+ Add trusted server" : "+ Amestar un sirvidor d'enfotu",
"Trusted server" : "Sirvidor d'enfotu",
"Add" : "Amestar"
},
"nplurals=2; plural=(n != 1);");
-15
View File
@@ -1,15 +0,0 @@
{ "translations": {
"Added to the list of trusted servers" : "Amestóse a la llista de sirvidores d'enfotu",
"Server is already in the list of trusted servers." : "El sirvidor yá ta na llista de los sirvidores d'enfotu.",
"No server to federate with found" : "Nun s'atopó nengún sirvidor col que se federar",
"Could not add server" : "Nun se pudo amestar el sirvidor",
"Trusted servers" : "Sirvidores d'enfotu",
"Federation" : "Federación",
"Federation allows you to connect with other trusted servers to exchange the account directory." : "La federación permíte que te conectes con otros sirvidores d'enfotu pa intercambiar el direutoriu de cuentes.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing." : "La federación permite que te conectes a otros sirvidores d'enfotu pa intercambiar el direutoriu de cuentes. Por exemplu, va usase pa completar automáticamente les cuentes esternes de la compartición federada.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share." : "La federación permite que te conectes a otros sirvidores d'enfotu pa intercambiar el direutoriu de cuentes. Por exemplu, va usase pa completar automáticamente les cuentes esternes de la compartición federada. Nun ye necesario amestar un sirvidor como sirvidor d'enfotu pa crear una compartición federada.",
"+ Add trusted server" : "+ Amestar un sirvidor d'enfotu",
"Trusted server" : "Sirvidor d'enfotu",
"Add" : "Amestar"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}
-14
View File
@@ -1,14 +0,0 @@
OC.L10N.register(
"federation",
{
"Added to the list of trusted servers" : "Добавен към списъка с доверени сървъри",
"Server is already in the list of trusted servers." : "Сървъра вече присъства в списъка с доверени сървъри",
"No server to federate with found" : "Не е намерен сървър за федериране",
"Could not add server" : "Не можа да се добави сървър",
"Trusted servers" : "Доверени сървъри",
"Federation" : "Федерация",
"+ Add trusted server" : "+ Добави доверен сървър",
"Trusted server" : "Доверен сървър",
"Add" : "Добави"
},
"nplurals=2; plural=(n != 1);");
-12
View File
@@ -1,12 +0,0 @@
{ "translations": {
"Added to the list of trusted servers" : "Добавен към списъка с доверени сървъри",
"Server is already in the list of trusted servers." : "Сървъра вече присъства в списъка с доверени сървъри",
"No server to federate with found" : "Не е намерен сървър за федериране",
"Could not add server" : "Не можа да се добави сървър",
"Trusted servers" : "Доверени сървъри",
"Federation" : "Федерация",
"+ Add trusted server" : "+ Добави доверен сървър",
"Trusted server" : "Доверен сървър",
"Add" : "Добави"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}
-14
View File
@@ -1,14 +0,0 @@
OC.L10N.register(
"federation",
{
"Added to the list of trusted servers" : "Ouzhpennañ d'ar roll ar servijourienn fiziet",
"Server is already in the list of trusted servers." : "Er roll ar servijour fiziet eo dija",
"No server to federate with found" : "Servijour da gevredañ ebet kavet",
"Could not add server" : "Dibosupl ouzhpennañ ar servijour",
"Trusted servers" : "Servijourienn fiziet",
"Federation" : "Kevread",
"+ Add trusted server" : "+ Ouzhpenna ur servijour fiziet",
"Trusted server" : "Servijour fiziet",
"Add" : "Ouzhpennañ"
},
"nplurals=5; plural=((n%10 == 1) && (n%100 != 11) && (n%100 !=71) && (n%100 !=91) ? 0 :(n%10 == 2) && (n%100 != 12) && (n%100 !=72) && (n%100 !=92) ? 1 :(n%10 ==3 || n%10==4 || n%10==9) && (n%100 < 10 || n% 100 > 19) && (n%100 < 70 || n%100 > 79) && (n%100 < 90 || n%100 > 99) ? 2 :(n != 0 && n % 1000000 == 0) ? 3 : 4);");
-12
View File
@@ -1,12 +0,0 @@
{ "translations": {
"Added to the list of trusted servers" : "Ouzhpennañ d'ar roll ar servijourienn fiziet",
"Server is already in the list of trusted servers." : "Er roll ar servijour fiziet eo dija",
"No server to federate with found" : "Servijour da gevredañ ebet kavet",
"Could not add server" : "Dibosupl ouzhpennañ ar servijour",
"Trusted servers" : "Servijourienn fiziet",
"Federation" : "Kevread",
"+ Add trusted server" : "+ Ouzhpenna ur servijour fiziet",
"Trusted server" : "Servijour fiziet",
"Add" : "Ouzhpennañ"
},"pluralForm" :"nplurals=5; plural=((n%10 == 1) && (n%100 != 11) && (n%100 !=71) && (n%100 !=91) ? 0 :(n%10 == 2) && (n%100 != 12) && (n%100 !=72) && (n%100 !=92) ? 1 :(n%10 ==3 || n%10==4 || n%10==9) && (n%100 < 10 || n% 100 > 19) && (n%100 < 70 || n%100 > 79) && (n%100 < 90 || n%100 > 99) ? 2 :(n != 0 && n % 1000000 == 0) ? 3 : 4);"
}
+4 -3
View File
@@ -11,11 +11,12 @@ OC.L10N.register(
"Federation" : "Federació",
"Federation allows you to connect with other trusted servers to exchange the account directory." : "La federació us permet connectar-vos amb altres servidors de confiança per a intercanviar la carpeta del compte.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing." : "La federació us permet connectar-vos amb altres servidors de confiança per a intercanviar carpetes de compte. Per exemple, s'utilitzarà per a proporcionar resultats d'emplenament automàtic de comptes externs per a l'ús compartit federat.",
"External documentation for Federated Cloud Sharing" : "Documentació externa per a compartició federada de núvol",
"Add" : "Afegeix",
"Delete" : "Suprimir",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share." : "La federació us permet connectar-vos amb altres servidors de confiança per a intercanviar carpetes de compte. Per exemple, s'utilitzarà per a proporcionar resultats d'emplenament automàtic de comptes externs per a l'ús compartit federat. No cal afegir un servidor com a servidor de confiança per a crear un recurs d'ús compartit federat.",
"Each server must validate the other. This process may require a few cron cycles." : "Cada servidor ha de validar l'altre. Aquest procés pot requerir uns quants cicles cron.",
"External documentation for Federated Cloud Sharing" : "Documentació externa per a compartició federada de núvol",
"+ Add trusted server" : "+ Afegeix un servidor de confiança",
"Trusted server" : "Servidor de confiança",
"Add" : "Afegeix"
"Trusted server" : "Servidor de confiança"
},
"nplurals=2; plural=(n != 1);");
+4 -3
View File
@@ -9,11 +9,12 @@
"Federation" : "Federació",
"Federation allows you to connect with other trusted servers to exchange the account directory." : "La federació us permet connectar-vos amb altres servidors de confiança per a intercanviar la carpeta del compte.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing." : "La federació us permet connectar-vos amb altres servidors de confiança per a intercanviar carpetes de compte. Per exemple, s'utilitzarà per a proporcionar resultats d'emplenament automàtic de comptes externs per a l'ús compartit federat.",
"External documentation for Federated Cloud Sharing" : "Documentació externa per a compartició federada de núvol",
"Add" : "Afegeix",
"Delete" : "Suprimir",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share." : "La federació us permet connectar-vos amb altres servidors de confiança per a intercanviar carpetes de compte. Per exemple, s'utilitzarà per a proporcionar resultats d'emplenament automàtic de comptes externs per a l'ús compartit federat. No cal afegir un servidor com a servidor de confiança per a crear un recurs d'ús compartit federat.",
"Each server must validate the other. This process may require a few cron cycles." : "Cada servidor ha de validar l'altre. Aquest procés pot requerir uns quants cicles cron.",
"External documentation for Federated Cloud Sharing" : "Documentació externa per a compartició federada de núvol",
"+ Add trusted server" : "+ Afegeix un servidor de confiança",
"Trusted server" : "Servidor de confiança",
"Add" : "Afegeix"
"Trusted server" : "Servidor de confiança"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}
+4 -3
View File
@@ -11,11 +11,12 @@ OC.L10N.register(
"Federation" : "Federování",
"Federation allows you to connect with other trusted servers to exchange the account directory." : "Federování umožňuje propojit s ostatními servery, kterým věříte a vyměňovat si tak adresář účtů.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing." : "Federování umožňuje propojit s ostatními servery, kterým věříte a vyměňovat si tak adresář uživatelských účtů. Používá se toho například pro automatické doplňování externích účtů při federovaném sdílení.",
"External documentation for Federated Cloud Sharing" : "Externí dokumentace pro sdílení v rámci federovaného cloudu",
"Add" : "Přidat",
"Delete" : "Smazat",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share." : "Federování umožňuje propojit se s ostatními servery, kterým věříte a vyměňovat si tak adresář uživatelských účtů. Používá se toho například pro automatické dokončování externích účtů při federovaném sdílení. Nicméně pro vytvoření federovaného sdílení jako takového není nezbytné přidávat server jako důvěryhodný.",
"Each server must validate the other. This process may require a few cron cycles." : "Je třeba, aby každý server ověřil ten druhý. Tento proces může vyžadovat několik cyklů plánovače.",
"External documentation for Federated Cloud Sharing" : "Externí dokumentace pro sdílení v rámci federovaného cloudu",
"+ Add trusted server" : "+ Přidat důvěryhodný server",
"Trusted server" : "Důvěryhodný server",
"Add" : "Přidat"
"Trusted server" : "Důvěryhodný server"
},
"nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;");
+4 -3
View File
@@ -9,11 +9,12 @@
"Federation" : "Federování",
"Federation allows you to connect with other trusted servers to exchange the account directory." : "Federování umožňuje propojit s ostatními servery, kterým věříte a vyměňovat si tak adresář účtů.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing." : "Federování umožňuje propojit s ostatními servery, kterým věříte a vyměňovat si tak adresář uživatelských účtů. Používá se toho například pro automatické doplňování externích účtů při federovaném sdílení.",
"External documentation for Federated Cloud Sharing" : "Externí dokumentace pro sdílení v rámci federovaného cloudu",
"Add" : "Přidat",
"Delete" : "Smazat",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share." : "Federování umožňuje propojit se s ostatními servery, kterým věříte a vyměňovat si tak adresář uživatelských účtů. Používá se toho například pro automatické dokončování externích účtů při federovaném sdílení. Nicméně pro vytvoření federovaného sdílení jako takového není nezbytné přidávat server jako důvěryhodný.",
"Each server must validate the other. This process may require a few cron cycles." : "Je třeba, aby každý server ověřil ten druhý. Tento proces může vyžadovat několik cyklů plánovače.",
"External documentation for Federated Cloud Sharing" : "Externí dokumentace pro sdílení v rámci federovaného cloudu",
"+ Add trusted server" : "+ Přidat důvěryhodný server",
"Trusted server" : "Důvěryhodný server",
"Add" : "Přidat"
"Trusted server" : "Důvěryhodný server"
},"pluralForm" :"nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;"
}
+4 -3
View File
@@ -11,11 +11,12 @@ OC.L10N.register(
"Federation" : "Sammenkobling",
"Federation allows you to connect with other trusted servers to exchange the account directory." : "Sammenkobling giver dig mulighed for at oprette forbindelse til andre betroede servere for at udveksle kontobiblioteket.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing." : "Sammenkobling giver dig mulighed for at oprette forbindelse til andre betroede servere for at udveksle kontobiblioteket. For eksempel vil dette blive brugt til automatisk at fuldføre eksterne konti til deling.",
"External documentation for Federated Cloud Sharing" : "Ekstern dokumentation for Sammenkoblings Cloud deling",
"Add" : "Tilføj",
"Delete" : "Slet",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share." : "Føderering giver dig mulighed for at oprette forbindelse til andre betroede servere for at udveksle kontobiblioteket. For eksempel vil dette blive brugt til automatisk at fuldføre eksterne konti til fødereret deling. Det er ikke nødvendigt at tilføje en server som betroet server for at oprette en fødereret deling.",
"Each server must validate the other. This process may require a few cron cycles." : "Hver server skal validere den anden. Denne proces kan kræve et par cron cyklusser.",
"External documentation for Federated Cloud Sharing" : "Ekstern dokumentation for Sammenkoblings Cloud deling",
"+ Add trusted server" : "+ Tilføj pålidelig server",
"Trusted server" : "Pålidelig server",
"Add" : "Tilføj"
"Trusted server" : "Pålidelig server"
},
"nplurals=2; plural=(n != 1);");
+4 -3
View File
@@ -9,11 +9,12 @@
"Federation" : "Sammenkobling",
"Federation allows you to connect with other trusted servers to exchange the account directory." : "Sammenkobling giver dig mulighed for at oprette forbindelse til andre betroede servere for at udveksle kontobiblioteket.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing." : "Sammenkobling giver dig mulighed for at oprette forbindelse til andre betroede servere for at udveksle kontobiblioteket. For eksempel vil dette blive brugt til automatisk at fuldføre eksterne konti til deling.",
"External documentation for Federated Cloud Sharing" : "Ekstern dokumentation for Sammenkoblings Cloud deling",
"Add" : "Tilføj",
"Delete" : "Slet",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share." : "Føderering giver dig mulighed for at oprette forbindelse til andre betroede servere for at udveksle kontobiblioteket. For eksempel vil dette blive brugt til automatisk at fuldføre eksterne konti til fødereret deling. Det er ikke nødvendigt at tilføje en server som betroet server for at oprette en fødereret deling.",
"Each server must validate the other. This process may require a few cron cycles." : "Hver server skal validere den anden. Denne proces kan kræve et par cron cyklusser.",
"External documentation for Federated Cloud Sharing" : "Ekstern dokumentation for Sammenkoblings Cloud deling",
"+ Add trusted server" : "+ Tilføj pålidelig server",
"Trusted server" : "Pålidelig server",
"Add" : "Tilføj"
"Trusted server" : "Pålidelig server"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}
+15 -3
View File
@@ -11,11 +11,23 @@ OC.L10N.register(
"Federation" : "Federation",
"Federation allows you to connect with other trusted servers to exchange the account directory." : "Federation ermöglicht die Verbindung mit anderen vertrauenswürdigen Servern, um das Kontenverzeichnis auszutauschen.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing." : "Federation ermöglicht es dir, dich mit anderen vertrauenswürdigen Servern zu verbinden, um das Kontoverzeichnis auszutauschen. Dies wird zum Beispiel für die automatische Vervollständigung externer Konten beim Federated-Sharing verwendet.",
"External documentation for Federated Cloud Sharing" : "Externe Dokumentation für das Teilen über Federated Cloud",
"Could not add trusted server. Please try again later." : "Vertrauenswürdiger Server konnte nicht hinzugefügt werden. Bitte später erneut versuchen.",
"Add trusted server" : "Vertrauenswürdigen Server hinzufügen",
"Server url" : "Server-URL",
"Add" : "Hinzufügen",
"Server ok" : "Server OK",
"User list was exchanged at least once successfully with the remote server." : "Die Benutzerliste wurde mindestens einmal erfolgreich mit dem Remote-Server ausgetauscht.",
"Server pending" : "Server ausstehend",
"Waiting for shared secret or initial user list exchange." : "Warten auf den Austausch gemeinsamer Geheimnisse oder erster Benutzerliste.",
"Server access revoked" : "Serverzugriff widerrufen",
"Server failure" : "Serverfehler",
"Connection to the remote server failed or the remote server is misconfigured." : "Die Verbindung zum Remote-Server ist fehlgeschlagen oder der Remote-Server ist falsch konfiguriert.",
"Failed to delete trusted server. Please try again later." : "Vertrauenswürdiger Server konnte nicht gelöscht werden. Bitte später erneut versuchen.",
"Delete" : "Löschen",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share." : "Federation ermöglicht es dir, dich mit anderen vertrauenswürdigen Servern zu verbinden, um das Kontoverzeichnis auszutauschen. Dies wird zum Beispiel für die automatische Vervollständigung externer Konten beim Federated-Sharing verwendet. Es ist nicht erforderlich einen Server als vertrauenswürdig hinzuzufügen, um eine \"federated\" Freigabe zu erstellen.",
"Each server must validate the other. This process may require a few cron cycles." : "Jeder Server muss den anderen validieren. Dieser Vorgang kann einige Cron-Zyklen benötigen.",
"External documentation for Federated Cloud Sharing" : "Externe Dokumentation für das Teilen über Federated Cloud",
"+ Add trusted server" : "+ Vertrauenswürdigen Server hinzufügen",
"Trusted server" : "Vertrauenswürdiger Server",
"Add" : "Hinzufügen"
"Trusted server" : "Vertrauenswürdiger Server"
},
"nplurals=2; plural=(n != 1);");
+15 -3
View File
@@ -9,11 +9,23 @@
"Federation" : "Federation",
"Federation allows you to connect with other trusted servers to exchange the account directory." : "Federation ermöglicht die Verbindung mit anderen vertrauenswürdigen Servern, um das Kontenverzeichnis auszutauschen.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing." : "Federation ermöglicht es dir, dich mit anderen vertrauenswürdigen Servern zu verbinden, um das Kontoverzeichnis auszutauschen. Dies wird zum Beispiel für die automatische Vervollständigung externer Konten beim Federated-Sharing verwendet.",
"External documentation for Federated Cloud Sharing" : "Externe Dokumentation für das Teilen über Federated Cloud",
"Could not add trusted server. Please try again later." : "Vertrauenswürdiger Server konnte nicht hinzugefügt werden. Bitte später erneut versuchen.",
"Add trusted server" : "Vertrauenswürdigen Server hinzufügen",
"Server url" : "Server-URL",
"Add" : "Hinzufügen",
"Server ok" : "Server OK",
"User list was exchanged at least once successfully with the remote server." : "Die Benutzerliste wurde mindestens einmal erfolgreich mit dem Remote-Server ausgetauscht.",
"Server pending" : "Server ausstehend",
"Waiting for shared secret or initial user list exchange." : "Warten auf den Austausch gemeinsamer Geheimnisse oder erster Benutzerliste.",
"Server access revoked" : "Serverzugriff widerrufen",
"Server failure" : "Serverfehler",
"Connection to the remote server failed or the remote server is misconfigured." : "Die Verbindung zum Remote-Server ist fehlgeschlagen oder der Remote-Server ist falsch konfiguriert.",
"Failed to delete trusted server. Please try again later." : "Vertrauenswürdiger Server konnte nicht gelöscht werden. Bitte später erneut versuchen.",
"Delete" : "Löschen",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share." : "Federation ermöglicht es dir, dich mit anderen vertrauenswürdigen Servern zu verbinden, um das Kontoverzeichnis auszutauschen. Dies wird zum Beispiel für die automatische Vervollständigung externer Konten beim Federated-Sharing verwendet. Es ist nicht erforderlich einen Server als vertrauenswürdig hinzuzufügen, um eine \"federated\" Freigabe zu erstellen.",
"Each server must validate the other. This process may require a few cron cycles." : "Jeder Server muss den anderen validieren. Dieser Vorgang kann einige Cron-Zyklen benötigen.",
"External documentation for Federated Cloud Sharing" : "Externe Dokumentation für das Teilen über Federated Cloud",
"+ Add trusted server" : "+ Vertrauenswürdigen Server hinzufügen",
"Trusted server" : "Vertrauenswürdiger Server",
"Add" : "Hinzufügen"
"Trusted server" : "Vertrauenswürdiger Server"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}
+15 -3
View File
@@ -11,11 +11,23 @@ OC.L10N.register(
"Federation" : "Federation",
"Federation allows you to connect with other trusted servers to exchange the account directory." : "Federation ermöglicht die Verbindung mit anderen vertrauenswürdigen Servern, um das Kontenverzeichnis auszutauschen.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing." : "Federation ermöglicht es Ihnen, sich mit anderen vertrauenswürdigen Servern zu verbinden, um das Kontoverzeichnis auszutauschen. Dies wird zum Beispiel für die automatische Vervollständigung externer Konten beim Federated-Sharing verwendet.",
"External documentation for Federated Cloud Sharing" : "Externe Dokumentation für Teilen über Federated Cloud",
"Could not add trusted server. Please try again later." : "Vertrauenswürdiger Server konnte nicht hinzugefügt werden. Bitte später erneut versuchen.",
"Add trusted server" : "Vertrauenswürdigen Server hinzufügen",
"Server url" : "Server-URL",
"Add" : "Hinzufügen",
"Server ok" : "Server OK",
"User list was exchanged at least once successfully with the remote server." : "Die Benutzerliste wurde mindestens einmal erfolgreich mit dem Remote-Server ausgetauscht.",
"Server pending" : "Server ausstehend",
"Waiting for shared secret or initial user list exchange." : "Warten auf den Austausch gemeinsamer Geheimnisse oder erster Benutzerliste.",
"Server access revoked" : "Serverzugriff widerrufen",
"Server failure" : "Serverfehler",
"Connection to the remote server failed or the remote server is misconfigured." : "Die Verbindung zum Remote-Server ist fehlgeschlagen oder der Remote-Server ist falsch konfiguriert.",
"Failed to delete trusted server. Please try again later." : "Vertrauenswürdiger Server konnte nicht gelöscht werden. Bitte später erneut versuchen.",
"Delete" : "Löschen",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share." : "Federation ermöglicht es Ihnen, sich mit anderen vertrauenswürdigen Servern zu verbinden, um das Kontoverzeichnis auszutauschen. Dies wird zum Beispiel für die automatische Vervollständigung externer Konten beim Federated-Sharing verwendet. Es ist nicht erforderlich einen Server als vertrauenswürdig hinzuzufügen, um eine \"federated\" Freigabe zu erstellen.",
"Each server must validate the other. This process may require a few cron cycles." : "Jeder Server muss den anderen validieren. Dieser Vorgang kann einige Cron-Zyklen erfordern.",
"External documentation for Federated Cloud Sharing" : "Externe Dokumentation für Teilen über Federated Cloud",
"+ Add trusted server" : "+ Vertrauenswürdigen Server hinzufügen",
"Trusted server" : "Vertrauenswürdiger Server",
"Add" : "Hinzufügen"
"Trusted server" : "Vertrauenswürdiger Server"
},
"nplurals=2; plural=(n != 1);");
+15 -3
View File
@@ -9,11 +9,23 @@
"Federation" : "Federation",
"Federation allows you to connect with other trusted servers to exchange the account directory." : "Federation ermöglicht die Verbindung mit anderen vertrauenswürdigen Servern, um das Kontenverzeichnis auszutauschen.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing." : "Federation ermöglicht es Ihnen, sich mit anderen vertrauenswürdigen Servern zu verbinden, um das Kontoverzeichnis auszutauschen. Dies wird zum Beispiel für die automatische Vervollständigung externer Konten beim Federated-Sharing verwendet.",
"External documentation for Federated Cloud Sharing" : "Externe Dokumentation für Teilen über Federated Cloud",
"Could not add trusted server. Please try again later." : "Vertrauenswürdiger Server konnte nicht hinzugefügt werden. Bitte später erneut versuchen.",
"Add trusted server" : "Vertrauenswürdigen Server hinzufügen",
"Server url" : "Server-URL",
"Add" : "Hinzufügen",
"Server ok" : "Server OK",
"User list was exchanged at least once successfully with the remote server." : "Die Benutzerliste wurde mindestens einmal erfolgreich mit dem Remote-Server ausgetauscht.",
"Server pending" : "Server ausstehend",
"Waiting for shared secret or initial user list exchange." : "Warten auf den Austausch gemeinsamer Geheimnisse oder erster Benutzerliste.",
"Server access revoked" : "Serverzugriff widerrufen",
"Server failure" : "Serverfehler",
"Connection to the remote server failed or the remote server is misconfigured." : "Die Verbindung zum Remote-Server ist fehlgeschlagen oder der Remote-Server ist falsch konfiguriert.",
"Failed to delete trusted server. Please try again later." : "Vertrauenswürdiger Server konnte nicht gelöscht werden. Bitte später erneut versuchen.",
"Delete" : "Löschen",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share." : "Federation ermöglicht es Ihnen, sich mit anderen vertrauenswürdigen Servern zu verbinden, um das Kontoverzeichnis auszutauschen. Dies wird zum Beispiel für die automatische Vervollständigung externer Konten beim Federated-Sharing verwendet. Es ist nicht erforderlich einen Server als vertrauenswürdig hinzuzufügen, um eine \"federated\" Freigabe zu erstellen.",
"Each server must validate the other. This process may require a few cron cycles." : "Jeder Server muss den anderen validieren. Dieser Vorgang kann einige Cron-Zyklen erfordern.",
"External documentation for Federated Cloud Sharing" : "Externe Dokumentation für Teilen über Federated Cloud",
"+ Add trusted server" : "+ Vertrauenswürdigen Server hinzufügen",
"Trusted server" : "Vertrauenswürdiger Server",
"Add" : "Hinzufügen"
"Trusted server" : "Vertrauenswürdiger Server"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}
+4 -3
View File
@@ -11,11 +11,12 @@ OC.L10N.register(
"Federation" : "Ομοσπονδία",
"Federation allows you to connect with other trusted servers to exchange the account directory." : "Η ομοσπονδία σας επιτρέπει να συνδέεστε με άλλους έμπιστους διακομιστές για ανταλλαγή καταλόγου λογαριασμών.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing." : "Η ομοσπονδία σας επιτρέπει να συνδέεστε με άλλους έμπιστους διακομιστές για ανταλλαγή καταλόγου λογαριασμών. Για παράδειγμα, χρησιμοποιείται για την αυτομάτη συμπλήρωση εξωτερικών λογαριασμών κατά τη συνένωση κοινής χρήσης.",
"External documentation for Federated Cloud Sharing" : "Εξωτερική τεκμηρίωση για τον διαμοιρασμό σε ομοσπονδοποιημένο υπολογιστικό νέφος",
"Add" : "Προσθήκη",
"Delete" : "Διαγραφή",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share." : "Η ομοσπονδία σας επιτρέπει να συνδέεστε με άλλους έμπιστους διακομιστές για ανταλλαγή καταλόγου λογαριασμών. Για παράδειγμα, χρησιμοποιείται για την αυτομάτη συμπλήρωση εξωτερικών λογαριασμών κατά τη συνένωση κοινής χρήσης. Δεν είναι απαραίτητο να προσθέσετε έναν διακομιστή ως έμπιστο για τη δημιουργία μιας συνενωμένης κοινής χρήσης.",
"Each server must validate the other. This process may require a few cron cycles." : "Κάθε διακομιστής πρέπει να επικυρώσει τον άλλο. Αυτή η διαδικασία μπορεί να απαιτήσει μερικούς κύκλους cron.",
"External documentation for Federated Cloud Sharing" : "Εξωτερική τεκμηρίωση για τον διαμοιρασμό σε ομοσπονδοποιημένο υπολογιστικό νέφος",
"+ Add trusted server" : "+Προσθήκη έμπιστων διακομιστών",
"Trusted server" : "Έμπιστοι διακομιστές",
"Add" : "Προσθήκη"
"Trusted server" : "Έμπιστοι διακομιστές"
},
"nplurals=2; plural=(n != 1);");
+4 -3
View File
@@ -9,11 +9,12 @@
"Federation" : "Ομοσπονδία",
"Federation allows you to connect with other trusted servers to exchange the account directory." : "Η ομοσπονδία σας επιτρέπει να συνδέεστε με άλλους έμπιστους διακομιστές για ανταλλαγή καταλόγου λογαριασμών.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing." : "Η ομοσπονδία σας επιτρέπει να συνδέεστε με άλλους έμπιστους διακομιστές για ανταλλαγή καταλόγου λογαριασμών. Για παράδειγμα, χρησιμοποιείται για την αυτομάτη συμπλήρωση εξωτερικών λογαριασμών κατά τη συνένωση κοινής χρήσης.",
"External documentation for Federated Cloud Sharing" : "Εξωτερική τεκμηρίωση για τον διαμοιρασμό σε ομοσπονδοποιημένο υπολογιστικό νέφος",
"Add" : "Προσθήκη",
"Delete" : "Διαγραφή",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share." : "Η ομοσπονδία σας επιτρέπει να συνδέεστε με άλλους έμπιστους διακομιστές για ανταλλαγή καταλόγου λογαριασμών. Για παράδειγμα, χρησιμοποιείται για την αυτομάτη συμπλήρωση εξωτερικών λογαριασμών κατά τη συνένωση κοινής χρήσης. Δεν είναι απαραίτητο να προσθέσετε έναν διακομιστή ως έμπιστο για τη δημιουργία μιας συνενωμένης κοινής χρήσης.",
"Each server must validate the other. This process may require a few cron cycles." : "Κάθε διακομιστής πρέπει να επικυρώσει τον άλλο. Αυτή η διαδικασία μπορεί να απαιτήσει μερικούς κύκλους cron.",
"External documentation for Federated Cloud Sharing" : "Εξωτερική τεκμηρίωση για τον διαμοιρασμό σε ομοσπονδοποιημένο υπολογιστικό νέφος",
"+ Add trusted server" : "+Προσθήκη έμπιστων διακομιστών",
"Trusted server" : "Έμπιστοι διακομιστές",
"Add" : "Προσθήκη"
"Trusted server" : "Έμπιστοι διακομιστές"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}
+4 -3
View File
@@ -11,11 +11,12 @@ OC.L10N.register(
"Federation" : "Federation",
"Federation allows you to connect with other trusted servers to exchange the account directory." : "Federation allows you to connect with other trusted servers to exchange the account directory.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing." : "Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing.",
"External documentation for Federated Cloud Sharing" : "External documentation for Federated Cloud Sharing",
"Add" : "Add",
"Delete" : "Delete",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share." : "Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share.",
"Each server must validate the other. This process may require a few cron cycles." : "Each server must validate the other. This process may require a few cron cycles.",
"External documentation for Federated Cloud Sharing" : "External documentation for Federated Cloud Sharing",
"+ Add trusted server" : "+ Add trusted server",
"Trusted server" : "Trusted server",
"Add" : "Add"
"Trusted server" : "Trusted server"
},
"nplurals=2; plural=(n != 1);");
+4 -3
View File
@@ -9,11 +9,12 @@
"Federation" : "Federation",
"Federation allows you to connect with other trusted servers to exchange the account directory." : "Federation allows you to connect with other trusted servers to exchange the account directory.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing." : "Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing.",
"External documentation for Federated Cloud Sharing" : "External documentation for Federated Cloud Sharing",
"Add" : "Add",
"Delete" : "Delete",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share." : "Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share.",
"Each server must validate the other. This process may require a few cron cycles." : "Each server must validate the other. This process may require a few cron cycles.",
"External documentation for Federated Cloud Sharing" : "External documentation for Federated Cloud Sharing",
"+ Add trusted server" : "+ Add trusted server",
"Trusted server" : "Trusted server",
"Add" : "Add"
"Trusted server" : "Trusted server"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}
-14
View File
@@ -1,14 +0,0 @@
OC.L10N.register(
"federation",
{
"Added to the list of trusted servers" : "Aldonita al la listo de fidindaj serviloj",
"Server is already in the list of trusted servers." : "Servilo jam estas en la listo de fidindaj serviloj.",
"No server to federate with found" : "Neniu federota servilo trovata",
"Could not add server" : "Ne eblas aldoni servilon",
"Trusted servers" : "Fidindaj serviloj",
"Federation" : "Federado",
"+ Add trusted server" : "+ Aldoni fidindan servilon",
"Trusted server" : "Fidinda servilo",
"Add" : "Aldoni"
},
"nplurals=2; plural=(n != 1);");
-12
View File
@@ -1,12 +0,0 @@
{ "translations": {
"Added to the list of trusted servers" : "Aldonita al la listo de fidindaj serviloj",
"Server is already in the list of trusted servers." : "Servilo jam estas en la listo de fidindaj serviloj.",
"No server to federate with found" : "Neniu federota servilo trovata",
"Could not add server" : "Ne eblas aldoni servilon",
"Trusted servers" : "Fidindaj serviloj",
"Federation" : "Federado",
"+ Add trusted server" : "+ Aldoni fidindan servilon",
"Trusted server" : "Fidinda servilo",
"Add" : "Aldoni"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}
+4 -3
View File
@@ -11,11 +11,12 @@ OC.L10N.register(
"Federation" : "Federación",
"Federation allows you to connect with other trusted servers to exchange the account directory." : "La federación le permite conectarse con otros servidores de confianza para intercambiar el directorio de usuarios.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing." : "La Federación le permite conectarse con otros servidores de confianza para intercambiar el directorio de usuarios. Por ejemplo, esto se utilizará para auto-completar a los usuarios externos para el intercambio federado.",
"External documentation for Federated Cloud Sharing" : "Documentación externa para Compartir con Nube Federada",
"Add" : "Añadir",
"Delete" : "Eliminar",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share." : "La Federación le permite conectarse con otros servidores de confianza para intercambiar el directorio de usuarios. Por ejemplo, esto se utilizará para auto-completar a los usuarios externos para el intercambio federado. No es necesario añadir un servidor como servidor de confianza para crear una recurso compartido federado.",
"Each server must validate the other. This process may require a few cron cycles." : "Cada servidor debe validar al otro. Este proceso puede necesitar algunos ciclos de cron.",
"External documentation for Federated Cloud Sharing" : "Documentación externa para Compartir con Nube Federada",
"+ Add trusted server" : "+ Añadir servidor de confianza",
"Trusted server" : "Servidor de confianza",
"Add" : "Añadir"
"Trusted server" : "Servidor de confianza"
},
"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");
+4 -3
View File
@@ -9,11 +9,12 @@
"Federation" : "Federación",
"Federation allows you to connect with other trusted servers to exchange the account directory." : "La federación le permite conectarse con otros servidores de confianza para intercambiar el directorio de usuarios.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing." : "La Federación le permite conectarse con otros servidores de confianza para intercambiar el directorio de usuarios. Por ejemplo, esto se utilizará para auto-completar a los usuarios externos para el intercambio federado.",
"External documentation for Federated Cloud Sharing" : "Documentación externa para Compartir con Nube Federada",
"Add" : "Añadir",
"Delete" : "Eliminar",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share." : "La Federación le permite conectarse con otros servidores de confianza para intercambiar el directorio de usuarios. Por ejemplo, esto se utilizará para auto-completar a los usuarios externos para el intercambio federado. No es necesario añadir un servidor como servidor de confianza para crear una recurso compartido federado.",
"Each server must validate the other. This process may require a few cron cycles." : "Cada servidor debe validar al otro. Este proceso puede necesitar algunos ciclos de cron.",
"External documentation for Federated Cloud Sharing" : "Documentación externa para Compartir con Nube Federada",
"+ Add trusted server" : "+ Añadir servidor de confianza",
"Trusted server" : "Servidor de confianza",
"Add" : "Añadir"
"Trusted server" : "Servidor de confianza"
},"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
}
-14
View File
@@ -1,14 +0,0 @@
OC.L10N.register(
"federation",
{
"Added to the list of trusted servers" : "Agregado a la lista de servidores de confianza",
"Server is already in the list of trusted servers." : "El servidor ya se encuentra en la lista de servidores de confianza.",
"No server to federate with found" : "No se encontraron servidores para integrar a la federación",
"Could not add server" : "No fue posible agregar el servidor",
"Trusted servers" : "Servidores de confianza",
"Federation" : "Federación",
"+ Add trusted server" : "+ Agregar servidor de confianza",
"Trusted server" : "Servidor de confianza",
"Add" : "Agregar"
},
"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");
-12
View File
@@ -1,12 +0,0 @@
{ "translations": {
"Added to the list of trusted servers" : "Agregado a la lista de servidores de confianza",
"Server is already in the list of trusted servers." : "El servidor ya se encuentra en la lista de servidores de confianza.",
"No server to federate with found" : "No se encontraron servidores para integrar a la federación",
"Could not add server" : "No fue posible agregar el servidor",
"Trusted servers" : "Servidores de confianza",
"Federation" : "Federación",
"+ Add trusted server" : "+ Agregar servidor de confianza",
"Trusted server" : "Servidor de confianza",
"Add" : "Agregar"
},"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
}
-14
View File
@@ -1,14 +0,0 @@
OC.L10N.register(
"federation",
{
"Added to the list of trusted servers" : "Agregado a la lista de servidores de confianza",
"Server is already in the list of trusted servers." : "El servidor ya se encuentra en la lista de servidores de confianza.",
"No server to federate with found" : "No se encontraron servidores para integrar a la federación",
"Could not add server" : "No fue posible agregar el servidor",
"Trusted servers" : "Servidores de confianza",
"Federation" : "Federación",
"+ Add trusted server" : "+ Agregar servidor de confianza",
"Trusted server" : "Servidor de confianza",
"Add" : "Agregar"
},
"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");
-12
View File
@@ -1,12 +0,0 @@
{ "translations": {
"Added to the list of trusted servers" : "Agregado a la lista de servidores de confianza",
"Server is already in the list of trusted servers." : "El servidor ya se encuentra en la lista de servidores de confianza.",
"No server to federate with found" : "No se encontraron servidores para integrar a la federación",
"Could not add server" : "No fue posible agregar el servidor",
"Trusted servers" : "Servidores de confianza",
"Federation" : "Federación",
"+ Add trusted server" : "+ Agregar servidor de confianza",
"Trusted server" : "Servidor de confianza",
"Add" : "Agregar"
},"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
}
-14
View File
@@ -1,14 +0,0 @@
OC.L10N.register(
"federation",
{
"Added to the list of trusted servers" : "Agregado a la lista de servidores de confianza",
"Server is already in the list of trusted servers." : "El servidor ya se encuentra en la lista de servidores de confianza.",
"No server to federate with found" : "No se encontraron servidores para integrar a la federación",
"Could not add server" : "No fue posible agregar el servidor",
"Trusted servers" : "Servidores de confianza",
"Federation" : "Federación",
"+ Add trusted server" : "+ Agregar servidor de confianza",
"Trusted server" : "Servidor de confianza",
"Add" : "Agregar"
},
"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");
-12
View File
@@ -1,12 +0,0 @@
{ "translations": {
"Added to the list of trusted servers" : "Agregado a la lista de servidores de confianza",
"Server is already in the list of trusted servers." : "El servidor ya se encuentra en la lista de servidores de confianza.",
"No server to federate with found" : "No se encontraron servidores para integrar a la federación",
"Could not add server" : "No fue posible agregar el servidor",
"Trusted servers" : "Servidores de confianza",
"Federation" : "Federación",
"+ Add trusted server" : "+ Agregar servidor de confianza",
"Trusted server" : "Servidor de confianza",
"Add" : "Agregar"
},"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
}
-14
View File
@@ -1,14 +0,0 @@
OC.L10N.register(
"federation",
{
"Added to the list of trusted servers" : "Agregado a la lista de servidores de confianza",
"Server is already in the list of trusted servers." : "El servidor ya se encuentra en la lista de servidores de confianza.",
"No server to federate with found" : "No se encontraron servidores para integrar a la federación",
"Could not add server" : "No fue posible agregar el servidor",
"Trusted servers" : "Servidores de confianza",
"Federation" : "Federación",
"+ Add trusted server" : "+ Agregar servidor de confianza",
"Trusted server" : "Servidor de confianza",
"Add" : "Agregar"
},
"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");
-12
View File
@@ -1,12 +0,0 @@
{ "translations": {
"Added to the list of trusted servers" : "Agregado a la lista de servidores de confianza",
"Server is already in the list of trusted servers." : "El servidor ya se encuentra en la lista de servidores de confianza.",
"No server to federate with found" : "No se encontraron servidores para integrar a la federación",
"Could not add server" : "No fue posible agregar el servidor",
"Trusted servers" : "Servidores de confianza",
"Federation" : "Federación",
"+ Add trusted server" : "+ Agregar servidor de confianza",
"Trusted server" : "Servidor de confianza",
"Add" : "Agregar"
},"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
}
-14
View File
@@ -1,14 +0,0 @@
OC.L10N.register(
"federation",
{
"Added to the list of trusted servers" : "Agregado a la lista de servidores de confianza",
"Server is already in the list of trusted servers." : "El servidor ya se encuentra en la lista de servidores de confianza.",
"No server to federate with found" : "No se encontraron servidores para integrar a la federación",
"Could not add server" : "No fue posible agregar el servidor",
"Trusted servers" : "Servidores de confianza",
"Federation" : "Federación",
"+ Add trusted server" : "+ Agregar servidor de confianza",
"Trusted server" : "Servidor de confianza",
"Add" : "Agregar"
},
"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");
-12
View File
@@ -1,12 +0,0 @@
{ "translations": {
"Added to the list of trusted servers" : "Agregado a la lista de servidores de confianza",
"Server is already in the list of trusted servers." : "El servidor ya se encuentra en la lista de servidores de confianza.",
"No server to federate with found" : "No se encontraron servidores para integrar a la federación",
"Could not add server" : "No fue posible agregar el servidor",
"Trusted servers" : "Servidores de confianza",
"Federation" : "Federación",
"+ Add trusted server" : "+ Agregar servidor de confianza",
"Trusted server" : "Servidor de confianza",
"Add" : "Agregar"
},"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
}
-14
View File
@@ -1,14 +0,0 @@
OC.L10N.register(
"federation",
{
"Added to the list of trusted servers" : "Agregado a la lista de servidores de confianza",
"Server is already in the list of trusted servers." : "El servidor ya se encuentra en la lista de servidores de confianza.",
"No server to federate with found" : "No se encontraron servidores para integrar a la federación",
"Could not add server" : "No fue posible agregar el servidor",
"Trusted servers" : "Servidores de confianza",
"Federation" : "Federación",
"+ Add trusted server" : "+ Agregar servidor de confianza",
"Trusted server" : "Servidor de confianza",
"Add" : "Agregar"
},
"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");
-12
View File
@@ -1,12 +0,0 @@
{ "translations": {
"Added to the list of trusted servers" : "Agregado a la lista de servidores de confianza",
"Server is already in the list of trusted servers." : "El servidor ya se encuentra en la lista de servidores de confianza.",
"No server to federate with found" : "No se encontraron servidores para integrar a la federación",
"Could not add server" : "No fue posible agregar el servidor",
"Trusted servers" : "Servidores de confianza",
"Federation" : "Federación",
"+ Add trusted server" : "+ Agregar servidor de confianza",
"Trusted server" : "Servidor de confianza",
"Add" : "Agregar"
},"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
}
-14
View File
@@ -1,14 +0,0 @@
OC.L10N.register(
"federation",
{
"Added to the list of trusted servers" : "Agregado a la lista de servidores de confianza",
"Server is already in the list of trusted servers." : "El servidor ya se encuentra en la lista de servidores de confianza.",
"No server to federate with found" : "No se encontraron servidores para integrar a la federación",
"Could not add server" : "No fue posible agregar el servidor",
"Trusted servers" : "Servidores de confianza",
"Federation" : "Federación",
"+ Add trusted server" : "+ Agregar servidor de confianza",
"Trusted server" : "Servidor de confianza",
"Add" : "Agregar"
},
"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");
-12
View File
@@ -1,12 +0,0 @@
{ "translations": {
"Added to the list of trusted servers" : "Agregado a la lista de servidores de confianza",
"Server is already in the list of trusted servers." : "El servidor ya se encuentra en la lista de servidores de confianza.",
"No server to federate with found" : "No se encontraron servidores para integrar a la federación",
"Could not add server" : "No fue posible agregar el servidor",
"Trusted servers" : "Servidores de confianza",
"Federation" : "Federación",
"+ Add trusted server" : "+ Agregar servidor de confianza",
"Trusted server" : "Servidor de confianza",
"Add" : "Agregar"
},"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
}
-14
View File
@@ -1,14 +0,0 @@
OC.L10N.register(
"federation",
{
"Added to the list of trusted servers" : "Agregado a la lista de servidores de confianza",
"Server is already in the list of trusted servers." : "El servidor ya se encuentra en la lista de servidores de confianza.",
"No server to federate with found" : "No se encontraron servidores para integrar a la federación",
"Could not add server" : "No fue posible agregar el servidor",
"Trusted servers" : "Servidores de confianza",
"Federation" : "Federación",
"+ Add trusted server" : "+ Agregar servidor de confianza",
"Trusted server" : "Servidor de confianza",
"Add" : "Agregar"
},
"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");
-12
View File
@@ -1,12 +0,0 @@
{ "translations": {
"Added to the list of trusted servers" : "Agregado a la lista de servidores de confianza",
"Server is already in the list of trusted servers." : "El servidor ya se encuentra en la lista de servidores de confianza.",
"No server to federate with found" : "No se encontraron servidores para integrar a la federación",
"Could not add server" : "No fue posible agregar el servidor",
"Trusted servers" : "Servidores de confianza",
"Federation" : "Federación",
"+ Add trusted server" : "+ Agregar servidor de confianza",
"Trusted server" : "Servidor de confianza",
"Add" : "Agregar"
},"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
}
-14
View File
@@ -1,14 +0,0 @@
OC.L10N.register(
"federation",
{
"Added to the list of trusted servers" : "Agregado a la lista de servidores de confianza",
"Server is already in the list of trusted servers." : "El servidor ya se encuentra en la lista de servidores de confianza.",
"No server to federate with found" : "No se encontraron servidores para integrar a la federación",
"Could not add server" : "No fue posible agregar el servidor",
"Trusted servers" : "Servidores de confianza",
"Federation" : "Federación",
"+ Add trusted server" : "+ Agregar servidor de confianza",
"Trusted server" : "Servidor de confianza",
"Add" : "Agregar"
},
"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");
-12
View File
@@ -1,12 +0,0 @@
{ "translations": {
"Added to the list of trusted servers" : "Agregado a la lista de servidores de confianza",
"Server is already in the list of trusted servers." : "El servidor ya se encuentra en la lista de servidores de confianza.",
"No server to federate with found" : "No se encontraron servidores para integrar a la federación",
"Could not add server" : "No fue posible agregar el servidor",
"Trusted servers" : "Servidores de confianza",
"Federation" : "Federación",
"+ Add trusted server" : "+ Agregar servidor de confianza",
"Trusted server" : "Servidor de confianza",
"Add" : "Agregar"
},"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
}
-17
View File
@@ -1,17 +0,0 @@
OC.L10N.register(
"federation",
{
"Added to the list of trusted servers" : "Agregado a la lista de servidores de confianza",
"Server is already in the list of trusted servers." : "El servidor ya se encuentra en la lista de servidores de confianza.",
"No server to federate with found" : "No se encontraron servidores para integrar a la federación",
"Could not add server" : "No fue posible agregar el servidor",
"Trusted servers" : "Servidores de confianza",
"Federation" : "Federación",
"Federation allows you to connect with other trusted servers to exchange the account directory." : "La Federación permite conectarse con otros servidores de confianza para intercambiar el directorio de usuarios.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing." : "La Federación permite conectarse con otros servidores de confianza para intercambiar el directorio de usuarios. Por ejemplo, esto se usará para autocompletar usuarios externos en el recurso compartido federado.",
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share." : "La Federación permite conectarse con otros servidores de confianza para intercambiar el directorio de usuarios. Por ejemplo, esto se usará para autocompletar usuarios externos en el recurso compartido federado. No es necesario añadir un servidor como servidor de confianza para crear un recurso compartido federado.",
"+ Add trusted server" : "+ Agregar servidor de confianza",
"Trusted server" : "Servidor de confianza",
"Add" : "Agregar"
},
"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");

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