Compare commits

...

164 Commits

Author SHA1 Message Date
Josh 0ca558d47b chore: fixup for lint
Signed-off-by: Josh <josh.t.richards@gmail.com>
2026-01-01 13:17:56 -05:00
Josh 38a91680b3 chore: fixup for lint
Signed-off-by: Josh <josh.t.richards@gmail.com>
2026-01-01 13:17:21 -05:00
Josh 33618a14cf chore: fixup for lint
Signed-off-by: Josh <josh.t.richards@gmail.com>
2026-01-01 13:16:12 -05:00
Josh e041305011 chore: fixup for lint
Signed-off-by: Josh <josh.t.richards@gmail.com>
2026-01-01 13:15:04 -05:00
Josh f801fe74ec test: fix setMiddlewareExpectations method to match implementation
Wasn't a problem before that it was null here because getStatusHeader() lacked an explicit return type. 

Signed-off-by: Josh <josh.t.richards@gmail.com>
2026-01-01 13:05:06 -05:00
Josh 590620d7e5 chore: Remove internal annotation from Http class
Removed internal annotation from the Http class.

Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-12-31 14:32:06 -05:00
Josh b7a15b7c62 chore: update Http service registration
Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-12-31 13:53:48 -05:00
Josh 2b748f0ae5 chore: update/expand unit tests for getStatusHeader
Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-12-31 13:46:44 -05:00
Josh e6e528defe refactor(appframework/http): extract status messages to constant and remove unused properties
Modernize this class

Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-12-31 13:13:44 -05:00
Kate 6a2e0f819c Merge pull request #52442 from nextcloud/ext-store-check-update-filter 2025-12-31 12:50:59 +01:00
Robin Appelman 047ff27e46 test: add tests for watcher check filter
Signed-off-by: Robin Appelman <robin@icewind.nl>
2025-12-31 12:23:04 +01:00
Robin Appelman 4720c39048 fix: use interfaces instead of classes in Cache\Watcher type hints
Signed-off-by: Robin Appelman <robin@icewind.nl>
2025-12-31 12:23:04 +01:00
Robin Appelman 5c625b7a07 feat: add an option to filter what paths get checked for updates
Signed-off-by: Robin Appelman <robin@icewind.nl>
2025-12-31 12:23:04 +01:00
Nextcloud bot b33fdaf085 fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2025-12-31 00:14:02 +00:00
Andy Scherzinger d40263b2aa Merge pull request #57285 from nextcloud/feature/54562/support-partial-share-providers
feat: introduce API for partial share providers
2025-12-30 19:25:16 +01:00
Salvatore Martire a449af6460 feat: introduce API for partial share providers
Adds support for retrieval of shares by path

Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com>
2025-12-30 16:43:09 +01:00
Salvatore Martire ed6d0e59bb Merge pull request #57286 from nextcloud/fix/54562/add-forchildren-to-setupforpath
fix: add $forChildren parameter to IPartialMountProvider
2025-12-30 16:37:50 +01:00
Robin Appelman c614a13d4b Merge pull request #57158 from nextcloud/users-for-share
feat: add api to get users for share
2025-12-30 14:24:10 +01:00
Andy Scherzinger 32327c6285 Merge pull request #56773 from nextcloud/carl/remove-sciencemesh
refactor(share): Remove code related to science mesh integration
2025-12-30 14:18:53 +01:00
Maksim Sukharev 752d90c57c Merge pull request #57233 from nextcloud/bugfix/prevent_admin_group_subadmin 2025-12-30 13:26:15 +01:00
nextcloud-command a31d42d47a chore(assets): Recompile assets
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
2025-12-30 10:44:10 +00:00
Arsalan Ul Haq Sohni c81422ed37 fix(NewUserDialog): update group selection to prevent admin group from being assigned as subadmin
Signed-off-by: Arsalan Ul Haq Sohni <arsalan-ul-haq.sohni@strato.de>
2025-12-30 11:33:28 +01:00
Salvatore Martire 6e9ba894a2 fix: add $forChildren parameter to IPartialMountProvider
Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com>
2025-12-29 18:06:12 +01:00
Nextcloud bot 4283f4790b fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2025-12-29 00:13:35 +00:00
github-actions[bot] 3945981f0d Merge pull request #57251 from nextcloud/dependabot/npm_and_yarn/build/frontend-legacy/msw-2.12.6
build(deps-dev): bump msw from 2.12.4 to 2.12.6 in /build/frontend-legacy
2025-12-28 09:41:37 +00:00
Nextcloud bot 5d05c8d61e fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2025-12-28 00:13:28 +00:00
github-actions[bot] 25ee57fc60 Merge pull request #57246 from nextcloud/dependabot/composer/vendor-bin/rector/rector/rector-2.3.0
build(deps-dev): bump rector/rector from 2.2.14 to 2.3.0 in /vendor-bin/rector
2025-12-27 19:05:49 +01:00
github-actions[bot] e90c114730 Merge pull request #57248 from nextcloud/dependabot/npm_and_yarn/jsdom-27.4.0
build(deps-dev): bump jsdom from 27.3.0 to 27.4.0
2025-12-27 18:49:43 +01:00
Joas Schilling 41feb5d29d Merge pull request #57262 from nextcloud/automated/noid/master-update-code-signing-crl
[master] fix(security): Update code signing revocation list
2025-12-27 12:45:34 +01:00
nextcloud-command 06d99eba17 fix(security): Update code signing revocation list
Signed-off-by: GitHub <noreply@github.com>
2025-12-27 02:53:11 +00:00
dependabot[bot] 6f6c655b46 build(deps-dev): bump msw in /build/frontend-legacy
Bumps [msw](https://github.com/mswjs/msw) from 2.12.4 to 2.12.6.
- [Release notes](https://github.com/mswjs/msw/releases)
- [Changelog](https://github.com/mswjs/msw/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mswjs/msw/compare/v2.12.4...v2.12.6)

---
updated-dependencies:
- dependency-name: msw
  dependency-version: 2.12.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-27 02:14:45 +00:00
dependabot[bot] 0c4bc3e495 build(deps-dev): bump jsdom from 27.3.0 to 27.4.0
Bumps [jsdom](https://github.com/jsdom/jsdom) from 27.3.0 to 27.4.0.
- [Release notes](https://github.com/jsdom/jsdom/releases)
- [Changelog](https://github.com/jsdom/jsdom/blob/main/Changelog.md)
- [Commits](https://github.com/jsdom/jsdom/compare/27.3.0...27.4.0)

---
updated-dependencies:
- dependency-name: jsdom
  dependency-version: 27.4.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-27 02:14:16 +00:00
dependabot[bot] b307db6b19 build(deps-dev): bump rector/rector in /vendor-bin/rector
Bumps [rector/rector](https://github.com/rectorphp/rector) from 2.2.14 to 2.3.0.
- [Release notes](https://github.com/rectorphp/rector/releases)
- [Commits](https://github.com/rectorphp/rector/compare/2.2.14...2.3.0)

---
updated-dependencies:
- dependency-name: rector/rector
  dependency-version: 2.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-27 02:08:27 +00:00
Nextcloud bot d79cf95ece fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2025-12-27 00:13:32 +00:00
Nextcloud bot a366ec367a fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2025-12-26 00:13:26 +00:00
Nextcloud bot 0c8f89c9d7 fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2025-12-25 00:13:37 +00:00
Nextcloud bot bed17ca424 fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2025-12-24 00:13:41 +00:00
github-actions[bot] 5cb262391f Merge pull request #57201 from nextcloud/dependabot/npm_and_yarn/nextcloud/files-4.0.0-beta.5
build(deps): Bump @nextcloud/files from 4.0.0-beta.4 to 4.0.0-beta.7
2025-12-23 20:27:57 +00:00
nextcloud-command 0934814a05 chore(assets): Recompile assets
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
2025-12-23 21:10:41 +01:00
Ferdinand Thiessen 9919c2bc91 chore(files): adjust getContents to use AbortController
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
2025-12-23 21:08:33 +01:00
Ferdinand Thiessen 77f9897060 chore(files): adjust code for breaking change of Navigation.setActive
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
2025-12-23 20:17:34 +01:00
Ferdinand Thiessen 461d0edecd build(deps): Bump @nextcloud/files from 4.0.0-beta.4 to 4.0.0-beta.6
Bumps [@nextcloud/files](https://github.com/nextcloud-libraries/nextcloud-files) from 4.0.0-beta.4 to 4.0.0-beta.5.
- [Release notes](https://github.com/nextcloud-libraries/nextcloud-files/releases)
- [Changelog](https://github.com/nextcloud-libraries/nextcloud-files/blob/main/CHANGELOG.md)
- [Commits](nextcloud-libraries/nextcloud-files@v4.0.0-beta.4...v4.0.0-beta.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
2025-12-23 20:17:33 +01:00
Ferdinand Thiessen 75e57760c7 Merge pull request #57163 from nextcloud/refactor/themeing-vue3-ts
refactor(theming): migrate to Typescript and Vue 3
2025-12-23 19:38:30 +01:00
Ferdinand Thiessen 105398699d Merge pull request #56780 from nextcloud/jtr/chore-drop-getUserQuota-legacy
chore(legacy): Remove deprecated getUserQuota method
2025-12-23 18:09:32 +01:00
nextcloud-command b820518a2a chore(assets): Recompile assets
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
2025-12-23 17:00:41 +01:00
Ferdinand Thiessen 32508c1f78 test(theming): adjust cypress tests for Vue3
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
2025-12-23 17:00:41 +01:00
Ferdinand Thiessen 754422aa00 refactor(theming): migrate to Typescript and Vue 3
- migrate all components to Typescript
- use script setup where feasible
- migrate to Vue 3

Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
2025-12-23 17:00:40 +01:00
Ferdinand Thiessen be8b2bfa8b Merge pull request #57228 from nextcloud/fix/setup-for-path-caching
fix: adjust authoritative setup path caching logic
2025-12-23 16:49:05 +01:00
Ferdinand Thiessen 8c90d4f822 Merge pull request #56919 from nextcloud/jtr/fix-mime-detection-tests
fix(files/type): preserve numeric keys (follow-up)
2025-12-23 16:01:01 +01:00
Andy Scherzinger f791d91c00 Merge pull request #57224 from nextcloud/jtr/docs-iusersession
docs(IUserSession): Improve interface docs
2025-12-23 13:12:20 +01:00
Nextcloud bot 6acf2a6a1b fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2025-12-23 00:13:51 +00:00
Josh fc37abd35a docs(IUserSession): Improve interface docs
Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-12-22 11:26:48 -05:00
Salvatore Martire 6c19fbcf4d fix: adjust authoritative setup path caching logic
Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com>
2025-12-22 15:52:52 +01:00
Robin Appelman bbabf50984 feat: add api to get users for share
Signed-off-by: Robin Appelman <robin@icewind.nl>
2025-12-22 15:34:23 +01:00
github-actions[bot] 22ca454130 Merge pull request #57058 from nextcloud/dependabot/npm_and_yarn/eslint-9.39.2
build(deps-dev): bump eslint from 9.39.1 to 9.39.2
2025-12-22 11:56:32 +00:00
dependabot[bot] 299039e2f2 build(deps-dev): bump eslint from 9.39.1 to 9.39.2
Bumps [eslint](https://github.com/eslint/eslint) from 9.39.1 to 9.39.2.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/compare/v9.39.1...v9.39.2)

---
updated-dependencies:
- dependency-name: eslint
  dependency-version: 9.39.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-22 11:09:35 +00:00
github-actions[bot] 993c359830 Merge pull request #56952 from nextcloud/dependabot/npm_and_yarn/jsdom-27.3.0
build(deps-dev): bump jsdom from 27.2.0 to 27.3.0
2025-12-22 11:07:27 +00:00
dependabot[bot] 1c8a31c36a build(deps-dev): bump jsdom from 27.2.0 to 27.3.0
Bumps [jsdom](https://github.com/jsdom/jsdom) from 27.2.0 to 27.3.0.
- [Release notes](https://github.com/jsdom/jsdom/releases)
- [Changelog](https://github.com/jsdom/jsdom/blob/main/Changelog.md)
- [Commits](https://github.com/jsdom/jsdom/compare/27.2.0...27.3.0)

---
updated-dependencies:
- dependency-name: jsdom
  dependency-version: 27.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-22 11:50:13 +01:00
github-actions[bot] c38e604e5e Merge pull request #56889 from nextcloud/dependabot/npm_and_yarn/build/frontend-legacy/msw-2.12.4
build(deps-dev): bump msw from 2.12.3 to 2.12.4 in /build/frontend-legacy
2025-12-22 08:29:37 +00:00
dependabot[bot] 6498c7d552 build(deps-dev): bump msw in /build/frontend-legacy
Bumps [msw](https://github.com/mswjs/msw) from 2.12.3 to 2.12.4.
- [Release notes](https://github.com/mswjs/msw/releases)
- [Changelog](https://github.com/mswjs/msw/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mswjs/msw/compare/v2.12.3...v2.12.4)

---
updated-dependencies:
- dependency-name: msw
  dependency-version: 2.12.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-22 09:13:45 +01:00
github-actions[bot] 2835d0cde4 Merge pull request #56979 from nextcloud/dependabot/npm_and_yarn/build/frontend-legacy/dompurify-3.3.1
build(deps): bump dompurify from 3.3.0 to 3.3.1 in /build/frontend-legacy
2025-12-22 08:09:53 +00:00
nextcloud-command 6fdfa436e1 chore(assets): Recompile assets
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
2025-12-22 07:51:39 +00:00
dependabot[bot] 0fddb6be2d build(deps): bump dompurify in /build/frontend-legacy
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.3.0 to 3.3.1.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.3.0...3.3.1)

---
updated-dependencies:
- dependency-name: dompurify
  dependency-version: 3.3.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-22 08:43:42 +01:00
github-actions[bot] 8c0c0454bd Merge pull request #57203 from nextcloud/dependabot/npm_and_yarn/nextcloud/paths-3.0.0
build(deps): Bump @nextcloud/paths from 2.3.0 to 3.0.0
2025-12-22 03:05:46 +00:00
Ferdinand Thiessen 58fd2d3df8 test(cypress): adjust for breaking changes of @nextcloud/paths
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
2025-12-22 03:04:35 +01:00
nextcloud-command 34330db471 chore(assets): Recompile assets
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
2025-12-22 01:20:41 +00:00
Ferdinand Thiessen 9a1fd7a629 chore: adjust code for breaking changes of @nextcloud/paths v3
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
2025-12-22 02:12:19 +01:00
dependabot[bot] 0d890d4217 build(deps): Bump @nextcloud/paths from 2.3.0 to 3.0.0
Bumps [@nextcloud/paths](https://github.com/nextcloud-libraries/nextcloud-paths) from 2.3.0 to 3.0.0.
- [Release notes](https://github.com/nextcloud-libraries/nextcloud-paths/releases)
- [Changelog](https://github.com/nextcloud-libraries/nextcloud-paths/blob/main/CHANGELOG.md)
- [Commits](https://github.com/nextcloud-libraries/nextcloud-paths/compare/v2.3.0...v3.0.0)

---
updated-dependencies:
- dependency-name: "@nextcloud/paths"
  dependency-version: 3.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-22 02:12:18 +01:00
github-actions[bot] a8e186dba9 Merge pull request #57196 from nextcloud/dependabot/npm_and_yarn/vitest-238d3985db
build(deps-dev): Bump the vitest group across 2 directories with 3 updates
2025-12-22 02:06:45 +01:00
github-actions[bot] 34267ef563 Merge pull request #57200 from nextcloud/dependabot/npm_and_yarn/nextcloud/dialogs-7.2.0
build(deps): Bump @nextcloud/dialogs from 7.1.0 to 7.2.0
2025-12-22 00:45:51 +00:00
github-actions[bot] f9132111ab Merge pull request #56878 from nextcloud/dependabot/composer/vendor-bin/openapi-extractor/nextcloud/openapi-extractor-1.8.7
build(deps): bump nextcloud/openapi-extractor from 1.8.6 to 1.8.7 in /vendor-bin/openapi-extractor
2025-12-22 01:39:54 +01:00
dependabot[bot] 84e52327f3 build(deps-dev): Bump the vitest group across 2 directories with 3 updates
Bumps the vitest group with 1 update in the / directory: [@vitest/coverage-istanbul](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-istanbul).
Bumps the vitest group with 2 updates in the /build/frontend-legacy directory: [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) and [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8).


Updates `@vitest/coverage-istanbul` from 4.0.15 to 4.0.16
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.16/packages/coverage-istanbul)

Updates `vitest` from 4.0.15 to 4.0.16
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.16/packages/vitest)

Updates `vitest` from 4.0.15 to 4.0.16
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.16/packages/vitest)

Updates `@vitest/coverage-v8` from 4.0.15 to 4.0.16
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.16/packages/coverage-v8)

---
updated-dependencies:
- dependency-name: "@vitest/coverage-istanbul"
  dependency-version: 4.0.16
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: vitest
- dependency-name: vitest
  dependency-version: 4.0.16
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: vitest
- dependency-name: vitest
  dependency-version: 4.0.16
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: vitest
- dependency-name: "@vitest/coverage-v8"
  dependency-version: 4.0.16
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: vitest
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-22 00:23:05 +00:00
Nextcloud bot 5a1a0b4759 fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2025-12-22 00:13:29 +00:00
Ferdinand Thiessen 530efa6783 chore: extract new openAPI definitions
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
2025-12-22 01:02:22 +01:00
dependabot[bot] 0e5dd3d834 build(deps): bump nextcloud/openapi-extractor
Bumps [nextcloud/openapi-extractor](https://github.com/nextcloud-releases/openapi-extractor) from 1.8.6 to 1.8.7.
- [Changelog](https://github.com/nextcloud-releases/openapi-extractor/blob/main/CHANGELOG.md)
- [Commits](https://github.com/nextcloud-releases/openapi-extractor/compare/v1.8.6...v1.8.7)

---
updated-dependencies:
- dependency-name: nextcloud/openapi-extractor
  dependency-version: 1.8.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-22 01:01:30 +01:00
nextcloud-command ee04846dec chore(assets): Recompile assets
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
2025-12-21 23:58:50 +00:00
dependabot[bot] 2d6bd8b86a build(deps): Bump @nextcloud/dialogs from 7.1.0 to 7.2.0
Bumps [@nextcloud/dialogs](https://github.com/nextcloud-libraries/nextcloud-dialogs) from 7.1.0 to 7.2.0.
- [Release notes](https://github.com/nextcloud-libraries/nextcloud-dialogs/releases)
- [Changelog](https://github.com/nextcloud-libraries/nextcloud-dialogs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/nextcloud-libraries/nextcloud-dialogs/compare/v7.1.0...v7.2.0)

---
updated-dependencies:
- dependency-name: "@nextcloud/dialogs"
  dependency-version: 7.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-21 23:39:12 +00:00
Ferdinand Thiessen cc806fbd8e Merge pull request #57194 from nextcloud/dependabot/npm_and_yarn/vite-4fb37e91ba
build(deps-dev): Bump the vite group across 2 directories with 1 update
2025-12-22 00:37:20 +01:00
nextcloud-command a56e274140 chore(assets): Recompile assets
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
2025-12-21 21:55:31 +00:00
dependabot[bot] 3a20529708 build(deps-dev): Bump the vite group across 2 directories with 1 update
Bumps the vite group with 1 update in the / directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).
Bumps the vite group with 1 update in the /build/frontend-legacy directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).


Updates `vite` from 7.2.7 to 7.3.0
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v7.3.0/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.3.0/packages/vite)

Updates `vite` from 7.2.7 to 7.3.0
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v7.3.0/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.3.0/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 7.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: vite
- dependency-name: vite
  dependency-version: 7.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: vite
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-21 22:46:23 +01:00
github-actions[bot] 0d0264f057 Merge pull request #57198 from nextcloud/dependabot/npm_and_yarn/vue-3.5.26
build(deps): Bump vue from 3.5.25 to 3.5.26
2025-12-21 20:02:38 +00:00
nextcloud-command 36758db1bc chore(assets): Recompile assets
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
2025-12-21 19:46:43 +00:00
dependabot[bot] 869108de51 build(deps): Bump vue from 3.5.25 to 3.5.26
Bumps [vue](https://github.com/vuejs/core) from 3.5.25 to 3.5.26.
- [Release notes](https://github.com/vuejs/core/releases)
- [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vuejs/core/compare/v3.5.25...v3.5.26)

---
updated-dependencies:
- dependency-name: vue
  dependency-version: 3.5.26
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-21 20:29:59 +01:00
github-actions[bot] 7f7c1ed3bd Merge pull request #57208 from nextcloud/dependabot/npm_and_yarn/build/frontend-legacy/webpack-5.104.1
build(deps-dev): Bump webpack from 5.103.0 to 5.104.1 in /build/frontend-legacy
2025-12-21 19:29:02 +00:00
nextcloud-command a6a94fa45c chore(assets): Recompile assets
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
2025-12-21 19:06:40 +00:00
dependabot[bot] f937e10a08 build(deps-dev): Bump webpack in /build/frontend-legacy
Bumps [webpack](https://github.com/webpack/webpack) from 5.103.0 to 5.104.1.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Changelog](https://github.com/webpack/webpack/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack/compare/v5.103.0...v5.104.1)

---
updated-dependencies:
- dependency-name: webpack
  dependency-version: 5.104.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-21 19:58:39 +01:00
github-actions[bot] 9abcafb44c Merge pull request #57199 from nextcloud/dependabot/npm_and_yarn/sass-1.97.1
build(deps-dev): Bump sass from 1.95.1 to 1.97.1
2025-12-21 16:29:21 +00:00
Nextcloud bot e963d7e583 fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2025-12-21 00:13:27 +00:00
Git'Fellow 60cb5a3c90 Merge pull request #57179 from nextcloud/allowListAllUsers
feat(userList): Allow to list all users
2025-12-20 17:49:13 +01:00
github-actions[bot] febc130423 Merge pull request #57205 from nextcloud/dependabot/npm_and_yarn/build/frontend-legacy/sass-1.97.1
build(deps-dev): Bump sass from 1.95.1 to 1.97.1 in /build/frontend-legacy
2025-12-20 14:18:05 +01:00
Louis 531d4b08e7 Merge pull request #57174 from nextcloud/artonge/fix/inhibit_download
fix(files): Inhibit download for non downloadable nodes in all contexts
2025-12-20 10:18:04 +01:00
Louis 9019c56e70 Merge pull request #57079 from Pringels/enhancement/15632/persist-user-management-columns
feat(settings): persist user management column visibility
2025-12-20 10:02:38 +01:00
dependabot[bot] 7deca60136 build(deps-dev): Bump sass in /build/frontend-legacy
Bumps [sass](https://github.com/sass/dart-sass) from 1.95.1 to 1.97.1.
- [Release notes](https://github.com/sass/dart-sass/releases)
- [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/dart-sass/compare/1.95.1...1.97.1)

---
updated-dependencies:
- dependency-name: sass
  dependency-version: 1.97.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-20 02:20:54 +00:00
dependabot[bot] 34448d3410 build(deps-dev): Bump sass from 1.95.1 to 1.97.1
Bumps [sass](https://github.com/sass/dart-sass) from 1.95.1 to 1.97.1.
- [Release notes](https://github.com/sass/dart-sass/releases)
- [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/dart-sass/compare/1.95.1...1.97.1)

---
updated-dependencies:
- dependency-name: sass
  dependency-version: 1.97.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-20 02:19:34 +00:00
Nextcloud bot 294057e32f fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2025-12-20 00:13:30 +00:00
Ferdinand Thiessen 8d164db8e9 Merge pull request #56909 from nextcloud/fix/sharing-external-section
fix(files_sharing): ensure that external section is mounted
2025-12-19 17:49:35 +01:00
nextcloud-command 274ff3692d chore(assets): Recompile assets
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
2025-12-19 16:28:17 +00:00
github-actions[bot] 6d24abc06f Merge pull request #57190 from nextcloud/dependabot/npm_and_yarn/multi-801a3e5857
build(deps): Bump systeminformation and cypress
2025-12-19 16:26:08 +00:00
Ferdinand Thiessen ec617b6b3e fix(files_sharing): ensure that external section is mounted
Make sure the external section is mounted before trying to assign it the
node prop.

Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
2025-12-19 16:25:34 +00:00
dependabot[bot] e0bd85b067 build(deps): Bump systeminformation and cypress
Bumps [systeminformation](https://github.com/sebhildebrandt/systeminformation) to 5.27.14 and updates ancestor dependency [cypress](https://github.com/cypress-io/cypress). These dependencies need to be updated together.


Updates `systeminformation` from 5.27.7 to 5.27.14
- [Changelog](https://github.com/sebhildebrandt/systeminformation/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sebhildebrandt/systeminformation/compare/v5.27.7...v5.27.14)

Updates `cypress` from 15.7.0 to 15.8.1
- [Release notes](https://github.com/cypress-io/cypress/releases)
- [Changelog](https://github.com/cypress-io/cypress/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/cypress-io/cypress/compare/v15.7.0...v15.8.1)

---
updated-dependencies:
- dependency-name: systeminformation
  dependency-version: 5.27.14
  dependency-type: indirect
- dependency-name: cypress
  dependency-version: 15.8.1
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-19 15:39:38 +00:00
Joas Schilling aec12f5b51 Merge pull request #57116 from nextcloud/php/8.5
ci(PHP): Test against 8.5 on CI
2025-12-19 16:38:16 +01:00
Joas Schilling 226b7df65e fix(Hooks): Don't use offset null as it's deprecated (and not actually used)
Signed-off-by: Joas Schilling <coding@schilljs.com>
2025-12-19 15:58:05 +01:00
Joas Schilling c27db5fdad fix(GdImage): imagedestroy is noop since PHP 8.0
Signed-off-by: Joas Schilling <coding@schilljs.com>
2025-12-19 15:57:04 +01:00
Joas Schilling 56793fa5b8 fix(reflection): ReflectionMethod::setAccessible is noop since 8.1
Signed-off-by: Joas Schilling <coding@schilljs.com>
2025-12-19 15:57:04 +01:00
Joas Schilling 6bc73b0dab fix(PDO): Switch away from deprecated PDO parts
Signed-off-by: Joas Schilling <coding@schilljs.com>
2025-12-19 15:57:03 +01:00
Joas Schilling 121973d336 fix(logger): Fix calls to log normalizer
Signed-off-by: Joas Schilling <coding@schilljs.com>
2025-12-19 15:34:34 +01:00
Joas Schilling e863c3c500 ci(PHP): Test against 8.5 on CI
Signed-off-by: Joas Schilling <coding@schilljs.com>
2025-12-19 15:34:34 +01:00
nextcloud-command 16727bf781 chore(assets): Recompile assets
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
2025-12-19 13:59:48 +00:00
Louis Chmn 62fd47ee2c fix(files): Inhibit download for non downloadable nodes in all contexts
Signed-off-by: Louis Chmn <louis@chmn.me>
2025-12-19 13:57:18 +00:00
Peter Ringelmann 31605c7495 fix(settings): resolve Cypress crash on undefined showConfig
Signed-off-by: Peter Ringelmann <4850521+Pringels@users.noreply.github.com>
2025-12-19 13:42:36 +01:00
Peter Ringelmann 6a9be2e7f4 chore: fix Psalm rebase issue
Signed-off-by: Peter Ringelmann <4850521+Pringels@users.noreply.github.com>
2025-12-19 09:30:49 +01:00
Nextcloud bot e91840a61a fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2025-12-19 00:13:47 +00:00
Julius Knorr c1801b044a Merge pull request #57041 from nextcloud/feat/full-match-displayname
feat: Allow to block full matches on the display name
2025-12-18 20:41:44 +01:00
Joas Schilling 9d86b701ee Merge pull request #57180 from nextcloud/dependabot/composer/doctrine/dbal-3.10.4
build(deps): bump doctrine/dbal from 3.10.2 to 3.10.4
2025-12-18 16:39:03 +01:00
Joas Schilling 9dc11443a2 build(deps): bump doctrine/dbal from 3.10.2 to 3.10.4
Signed-off-by: Joas Schilling <coding@schilljs.com>
2025-12-18 15:43:54 +01:00
Joas Schilling 24de30d70f Merge pull request #57172 from nextcloud/dependabot/composer/symfony-32bc18790b
build(deps): bump the symfony group across 1 directory with 3 updates
2025-12-18 15:42:19 +01:00
nextcloud-command 9bbb6dedc3 chore(assets): Recompile assets
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
2025-12-18 14:11:47 +00:00
Maxence Lange 632ffba69d Merge pull request #57156 from nextcloud/fix/noid/ocm-fully-disable-signed-request
fix(ocm): fully disable signed request on config
2025-12-18 13:05:45 -01:00
Julius Knorr 7d5ffa50ae feat: Allow to block full matches on the display name
Signed-off-by: Julius Knorr <jus@bitgrid.net>
2025-12-18 14:04:46 +00:00
Peter Ringelmann c46510baba refactor(settings): Re-add user email key to lexicon
Signed-off-by: Peter Ringelmann <4850521+Pringels@users.noreply.github.com>
2025-12-18 14:40:08 +01:00
Peter Ringelmann 11eaa0479f refactor(settings): use ConfigLexicon for user list preferences
Signed-off-by: Peter Ringelmann <4850521+Pringels@users.noreply.github.com>
2025-12-18 14:40:08 +01:00
Peter Ringelmann e7aaaff69d feat(settings): persist user management column visibility
Previously, column visibility settings were stored in localStorage, causing them to be lost when logging out or switching browsers.
This change moves the persistence to the database as user preferences.
It also refactors the frontend to use clean `userList.*` keys for better consistency between the store and the API.

Signed-off-by: Peter Ringelmann <4850521+Pringels@users.noreply.github.com>
2025-12-18 14:40:08 +01:00
Joas Schilling 76e86fa920 build(deps): bump the symfony group across 1 directory with 3 updates
Signed-off-by: Joas Schilling <coding@schilljs.com>
2025-12-18 13:57:02 +01:00
Git'Fellow b585280534 feat(userList): Allow to list all users
Signed-off-by: Git'Fellow <12234510+solracsf@users.noreply.github.com>
2025-12-18 13:53:41 +01:00
Louis 75bed8535c Merge pull request #57176 from nextcloud/himehatsumi/master
[local] fix(login): Improve wording for login throttle warning
2025-12-18 13:49:41 +01:00
Joas Schilling 154f3597b4 Merge pull request #57160 from nextcloud/dependabot/composer/guzzlehttp/guzzle-7.10.0
build(deps): Bump guzzlehttp/guzzle from 7.9.3 to 7.10.0
2025-12-18 12:48:18 +01:00
Louis Chmn 637392c084 chore: Compile assets
Signed-off-by: Louis Chmn <louis@chmn.me>
2025-12-18 12:23:21 +01:00
himehatsumi 0677888291 fix(login): Improve wording for login throttle warning
Signed-off-by: himehatsumi <95652868+himehatsumi@users.noreply.github.com>
2025-12-18 12:22:09 +01:00
Côme Chilliet 9b1227749f Merge pull request #57133 from nextcloud/fix-template-headers-injection
fix(lib): include headers from OC\Template\Template as well in produced HTML
2025-12-18 11:59:09 +01:00
Joas Schilling 115c0e93a3 build(deps): Bump guzzlehttp/guzzle from 7.9.3 to 7.10.0
Signed-off-by: Joas Schilling <coding@schilljs.com>
2025-12-18 11:09:28 +01:00
Carl Schwan e594e9d0e7 Merge pull request #57155 from nextcloud/carl/fix-insert-preview-version
fix(preview): Correctly insert preview version
2025-12-18 10:34:38 +01:00
Nextcloud bot 0eca299ca8 fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2025-12-18 00:13:32 +00:00
Maxence Lange 4b684897ed fix(ocm): fully disable signed request on config
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
2025-12-17 18:55:14 -01:00
Joas Schilling 7c7010cdff Merge pull request #57149 from nextcloud/nickvbot/update-nextcloud-lognormalizer-300
build(deps): Bump nextcloud/lognormalizer from 2.0.0 to 3.0.0
2025-12-17 18:49:00 +01:00
Carl Schwan 06b6a5bc05 fix(preview): Correctly insert preview version
Use createNamedParameter otherwise values are not correctly escapted.

Signed-off-by: Carl Schwan <carl.schwan@nextcloud.com>
2025-12-17 18:23:53 +01:00
Joas Schilling 15cd533fcb build(deps): Bump nextcloud/lognormalizer from 2.0.0 to 3.0.0
Signed-off-by: Joas Schilling <coding@schilljs.com>
2025-12-17 17:22:17 +01:00
Ferdinand Thiessen cc23025c2a Merge pull request #57127 from nextcloud/addCheckBeforeBitwise
fix(IpNormalizer): Added `inet_pton()` check before bitwise operations
2025-12-17 16:28:37 +01:00
Louis 8406984336 Merge pull request #57078 from Pringels/fix/20685/limit-to-groups-persistence
fix(settings): reset limit to groups state when switching apps
2025-12-17 16:05:33 +01:00
Benjamin Gaussorgues 89fcefbfa0 Merge pull request #55369 from nextcloud/carl/cleanup-external-manager 2025-12-17 14:14:48 +01:00
Joas Schilling 01feb85809 Merge pull request #57137 from nextcloud/dependabot/composer/pimple/pimple-3.6.0
build(deps): Bump pimple/pimple from 3.5.0 to 3.6.0
2025-12-17 11:53:30 +01:00
Joas Schilling 99a2a31fa8 build(deps): Bump pimple/pimple from 3.5.0 to 3.6.0
Signed-off-by: Joas Schilling <coding@schilljs.com>
2025-12-17 10:52:25 +01:00
Carl Schwan 18964750f9 fix(openapi): Fix returned types from external share
We always been returning an int for for accepted, but since it was
returned as a mixed from the DB, psalm never complained about the fact
this was typed as a bool in the API doc.

Signed-off-by: Carl Schwan <carl.schwan@nextcloud.com>
2025-12-17 10:14:41 +01:00
Carl Schwan a011cb7780 refactor: Rename some variables in external share's manager
Signed-off-by: Carl Schwan <carl.schwan@nextcloud.com>
2025-12-17 10:14:40 +01:00
Carl Schwan bfb7e7dd8e refactor: Add more typing to integration context code
Signed-off-by: Carl Schwan <carl.schwan@nextcloud.com>
2025-12-17 10:14:40 +01:00
Carl Schwan df2f3a8422 refactor(integration): Refactor and fix federation integration tests
Signed-off-by: Carl Schwan <carl.schwan@nextcloud.com>
2025-12-17 10:14:35 +01:00
Nextcloud bot 5c7f52f40e fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2025-12-17 00:13:28 +00:00
Thomas Citharel 8482302e42 fix(lib): include headers from OC\Template\Template as well in produced HTML
Otherwise we only take those added through deprecated method C_Util::addHeader, not those of
OC\Template\Template::addHeader, which does nothing

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2025-12-16 23:01:38 +01:00
Daniel 61dc0bbff0 Merge pull request #56733 from nextcloud/3rdparty/sabre-vobject-rdate-patch
fix: Add sabre vobject rdate patch
2025-12-16 22:14:46 +01:00
SebastianKrupinski ce3f458ccc fix: Add sabre vobject rdate patch
Signed-off-by: SebastianKrupinski <krupinskis05@gmail.com>
2025-12-16 15:28:23 -05:00
Git'Fellow b9d55ba30c fix(IpNormalizer): Added inet_pton() check before bitwise operations
Signed-off-by: Git'Fellow <12234510+solracsf@users.noreply.github.com>
2025-12-16 15:06:59 +01:00
Carl Schwan 3183ea79d2 refactor(external-share): Port more code to string as type for the id
Signed-off-by: Carl Schwan <carl.schwan@nextcloud.com>
2025-12-16 10:40:09 +01:00
Carl Schwan 91d3c63222 fix: Remove auto increment from share_external
Signed-off-by: Carl Schwan <carl.schwan@nextcloud.com>
2025-12-16 10:40:09 +01:00
Carl Schwan 3bdb344224 perf(external-sharing): Port to Entity and SnowflakeId
This removes all the read after write and we don't need to queries all
the time the same share in the same request anymore.

Signed-off-by: Carl Schwan <carl.schwan@nextcloud.com>
2025-12-16 10:40:07 +01:00
Carl Schwan 93b258317d refactor: use DI-injected logger instead of Server::get
Signed-off-by: Carl Schwan <carl.schwan@nextcloud.com>
2025-12-16 10:38:30 +01:00
Carl Schwan aadf842039 fix: Revert change to the cloud integration
This might fixes the test.

Signed-off-by: Carl Schwan <carl.schwan@nextcloud.com>
2025-12-16 10:38:30 +01:00
Carl Schwan b573d8a58b fix(sharing): Adapt Hooks to new API
Signed-off-by: Carl Schwan <carl.schwan@nextcloud.com>
2025-12-16 10:38:30 +01:00
Carl Schwan 6945a030f5 refactor(OC_Helper): remove buildNotExistingFileNameForView
Move the functionality in the last place it is used OC\Files\Node\Folder

Signed-off-by: Carl Schwan <carl.schwan@nextcloud.com>
2025-12-16 10:38:29 +01:00
Carl Schwan 7b0f1c6dd0 refactor(external-share): Cleanup OCA\FIles_Sharing\External\Manager
- Port away from Files::buildNotExistingFileName
- Use IUser and IGroup instead of plain string

Signed-off-by: Carl Schwan <carl.schwan@nextcloud.com>
2025-12-16 10:38:29 +01:00
Peter Ringelmann bfd7138133 fix(settings): reset limit to groups state when switching apps
Signed-off-by: Peter Ringelmann <4850521+Pringels@users.noreply.github.com>
2025-12-15 19:00:46 +01:00
Josh b2bc785986 chore: make php-cs happy
Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-12-09 22:26:16 -05:00
Josh e476a22a50 fix(file/types): Preserve keys (including numeric-looking ones)
Replace array_merge with array_replace for definitions

Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-12-09 09:22:04 -05:00
Josh 50a94a35ee test(files/type): leading zero extension preservation
- adds a focused DetectionTest that ensures numeric-looking keys (e.g. "001") are preserved
- refactors filesystem tests to use an isolated temp dir with proper cleanup

Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-12-09 09:22:04 -05:00
Carl Schwan cc7655136c refactor(share): Remove code related to science mesh integration
The app was not updated for the past 2 years.

Signed-off-by: Carl Schwan <carl.schwan@nextcloud.com>
2025-12-03 14:11:58 +01:00
Josh 33fba8c084 chore(legacy): Remove deprecated getUserQuota method
Formally deprecated with 9.0.0 and we dropped final uses of it in #53045.

Signed-off-by: Josh <josh.t.richards@gmail.com>
2025-12-01 12:49:27 -05:00
1146 changed files with 17232 additions and 15221 deletions
+1 -1
View File
@@ -47,7 +47,7 @@ jobs:
strategy:
matrix:
php-versions: [ '8.2', '8.3', '8.4' ]
php-versions: [ '8.2', '8.3', '8.4', '8.5' ]
name: php-lint
+3 -1
View File
@@ -60,13 +60,15 @@ jobs:
fail-fast: false
matrix:
php-versions: ['8.2']
mariadb-versions: ['10.3', '10.6', '10.11', '11.4', '11.8']
mariadb-versions: ['10.6', '10.11', '11.4', '11.8']
include:
- php-versions: '8.3'
mariadb-versions: '10.11'
coverage: ${{ github.event_name != 'pull_request' }}
- php-versions: '8.4'
mariadb-versions: '11.8'
- php-versions: '8.5'
mariadb-versions: '11.8'
name: MariaDB ${{ matrix.mariadb-versions }} (PHP ${{ matrix.php-versions }}) - database tests
+1 -1
View File
@@ -56,7 +56,7 @@ jobs:
strategy:
fail-fast: false
matrix:
php-versions: ['8.3', '8.4']
php-versions: ['8.3', '8.4', '8.5']
include:
- php-versions: '8.2'
coverage: ${{ github.event_name != 'pull_request' }}
+2
View File
@@ -67,6 +67,8 @@ jobs:
coverage: ${{ github.event_name != 'pull_request' }}
- mysql-versions: '8.4'
php-versions: '8.4'
- mysql-versions: '8.4'
php-versions: '8.5'
name: MySQL ${{ matrix.mysql-versions }} (PHP ${{ matrix.php-versions }}) - database tests
+1 -1
View File
@@ -59,7 +59,7 @@ jobs:
strategy:
fail-fast: false
matrix:
php-versions: ['8.3', '8.4']
php-versions: ['8.3', '8.4', '8.5']
include:
- php-versions: '8.2'
coverage: ${{ github.event_name != 'pull_request' }}
+2
View File
@@ -69,6 +69,8 @@ jobs:
php-versions: '8.3'
- oracle-versions: '23'
php-versions: '8.4'
- oracle-versions: '23'
php-versions: '8.5'
name: Oracle ${{ matrix.oracle-versions }} (PHP ${{ matrix.php-versions }}) - database tests
+2
View File
@@ -68,6 +68,8 @@ jobs:
coverage: ${{ github.event_name != 'pull_request' }}
- php-versions: '8.4'
postgres-versions: '18'
- php-versions: '8.5'
postgres-versions: '18'
name: PostgreSQL ${{ matrix.postgres-versions }} (PHP ${{ matrix.php-versions }}) - database tests
+1 -1
View File
@@ -59,7 +59,7 @@ jobs:
strategy:
fail-fast: false
matrix:
php-versions: ['8.3', '8.4']
php-versions: ['8.3', '8.4', '8.5']
include:
- php-versions: '8.2'
coverage: ${{ github.event_name != 'pull_request' }}
@@ -148,18 +148,6 @@ class SharingEventListener extends Action implements IEventListener {
'id',
]
),
IShare::TYPE_SCIENCEMESH => $this->log(
'The %s "%s" with ID "%s" has been shared to the sciencemesh user "%s" with permissions "%s" (Share ID: %s)',
$params,
[
'itemType',
'path',
'itemSource',
'shareWith',
'permissions',
'id',
]
),
default => null
};
}
@@ -274,17 +262,6 @@ class SharingEventListener extends Action implements IEventListener {
'id',
]
),
IShare::TYPE_SCIENCEMESH => $this->log(
'The %s "%s" with ID "%s" has been unshared from the sciencemesh user "%s" (Share ID: %s)',
$params,
[
'itemType',
'fileTarget',
'itemSource',
'shareWith',
'id',
]
),
default => null
};
}
@@ -106,14 +106,16 @@ class RequestHandlerController extends Controller {
#[NoCSRFRequired]
#[BruteForceProtection(action: 'receiveFederatedShare')]
public function addShare($shareWith, $name, $description, $providerId, $owner, $ownerDisplayName, $sharedBy, $sharedByDisplayName, $protocol, $shareType, $resourceType) {
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();
$this->confirmSignedOrigin($signedRequest, 'owner', $owner);
} catch (IncomingRequestException $e) {
$this->logger->warning('incoming request exception', ['exception' => $e]);
return new JSONResponse(['message' => $e->getMessage(), 'validationErrors' => []], Http::STATUS_BAD_REQUEST);
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 not signed and host is known for not supporting signed request, no exception are thrown
$signedRequest = $this->getSignedRequest();
$this->confirmSignedOrigin($signedRequest, 'owner', $owner);
} catch (IncomingRequestException $e) {
$this->logger->warning('incoming request exception', ['exception' => $e]);
return new JSONResponse(['message' => $e->getMessage(), 'validationErrors' => []], Http::STATUS_BAD_REQUEST);
}
}
// check if all required parameters are set
@@ -354,14 +356,16 @@ 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();
$this->confirmNotificationIdentity($signedRequest, $resourceType, $notification);
} catch (IncomingRequestException $e) {
$this->logger->warning('incoming request exception', ['exception' => $e]);
return new JSONResponse(['message' => $e->getMessage(), 'validationErrors' => []], Http::STATUS_BAD_REQUEST);
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 not signed and host is known for not supporting signed request, no exception are thrown
$signedRequest = $this->getSignedRequest();
$this->confirmNotificationIdentity($signedRequest, $resourceType, $notification);
} catch (IncomingRequestException $e) {
$this->logger->warning('incoming request exception', ['exception' => $e]);
return new JSONResponse(['message' => $e->getMessage(), 'validationErrors' => []], Http::STATUS_BAD_REQUEST);
}
}
try {
@@ -500,7 +504,6 @@ class RequestHandlerController extends Controller {
*
* @param IIncomingSignedRequest|null $signedRequest
* @param string $resourceType
* @param string $sharedSecret
*
* @throws IncomingRequestException
* @throws BadRequestException
@@ -524,7 +527,7 @@ class RequestHandlerController extends Controller {
return;
}
} catch (\Exception $e) {
throw new IncomingRequestException($e->getMessage());
throw new IncomingRequestException($e->getMessage(), previous: $e);
}
$this->confirmNotificationEntry($signedRequest, $identity);
+1 -1
View File
@@ -252,7 +252,7 @@ OC.L10N.register(
"Completed on %s" : "Erledigt am %s",
"Due on %s by %s" : "Fällig am %s von %s",
"Due on %s" : "Fällig am %s",
"Welcome to Nextcloud Calendar!\n\nThis is a sample event - explore the flexibility of planning with Nextcloud Calendar by making any edits you want!\n\nWith Nextcloud Calendar, you can:\n- Create, edit, and manage events effortlessly.\n- Create multiple calendars and share them with teammates, friends, or family.\n- Check availability and display your busy times to others.\n- Seamlessly integrate with apps and devices via CalDAV.\n- Customize your experience: schedule recurring events, adjust notifications and other settings." : "Willkommen bei Nextcloud Calendar!\n\nDies ist ein Beispielereignis entdecke die Flexibilität der Planung mit Nextcloud Calendar und nimm beliebige Änderungen vor!\n\nMit Nextcloud Calendar kannst du:\n Ereignisse mühelos erstellen, bearbeiten und verwalten.\n Mehrere Kalender erstellen und mit Teamkollegen, Freunden oder der Familie teilen.\n Verfügbarkeit prüfen und Ihre Termine anderen anzeigen.\n Nahtlose Integration mit Apps und Geräten über CalDAV.\n Individuelle Gestaltung: Plane wiederkehrende Ereignisse, passe Benachrichtigungen und andere Einstellungen an.",
"Welcome to Nextcloud Calendar!\n\nThis is a sample event - explore the flexibility of planning with Nextcloud Calendar by making any edits you want!\n\nWith Nextcloud Calendar, you can:\n- Create, edit, and manage events effortlessly.\n- Create multiple calendars and share them with teammates, friends, or family.\n- Check availability and display your busy times to others.\n- Seamlessly integrate with apps and devices via CalDAV.\n- Customize your experience: schedule recurring events, adjust notifications and other settings." : "Willkommen bei Nextcloud Calendar!\n\nDies ist ein Beispielereignis entdecke die Flexibilität der Planung mit Nextcloud Calendar und nimm beliebige Änderungen vor!\n\nMit Nextcloud Calendar kannst du:\n Ereignisse mühelos erstellen, bearbeiten und verwalten.\n Mehrere Kalender erstellen und mit Teamkollegen, Freunden oder der Familie teilen.\n Verfügbarkeit prüfen und deine Termine anderen anzeigen.\n Nahtlose Integration mit Apps und Geräten über CalDAV.\n Individuelle Gestaltung: Plane wiederkehrende Ereignisse, passe Benachrichtigungen und andere Einstellungen an.",
"Example event - open me!" : "Beispielereignis öffne mich!",
"System Address Book" : "Systemadressbuch",
"The system address book contains contact information for all users in your instance." : "Das Systemadressbuch enthält Kontaktinformationen für alle Benutzer in dieser Instanz.",
+1 -1
View File
@@ -250,7 +250,7 @@
"Completed on %s" : "Erledigt am %s",
"Due on %s by %s" : "Fällig am %s von %s",
"Due on %s" : "Fällig am %s",
"Welcome to Nextcloud Calendar!\n\nThis is a sample event - explore the flexibility of planning with Nextcloud Calendar by making any edits you want!\n\nWith Nextcloud Calendar, you can:\n- Create, edit, and manage events effortlessly.\n- Create multiple calendars and share them with teammates, friends, or family.\n- Check availability and display your busy times to others.\n- Seamlessly integrate with apps and devices via CalDAV.\n- Customize your experience: schedule recurring events, adjust notifications and other settings." : "Willkommen bei Nextcloud Calendar!\n\nDies ist ein Beispielereignis entdecke die Flexibilität der Planung mit Nextcloud Calendar und nimm beliebige Änderungen vor!\n\nMit Nextcloud Calendar kannst du:\n Ereignisse mühelos erstellen, bearbeiten und verwalten.\n Mehrere Kalender erstellen und mit Teamkollegen, Freunden oder der Familie teilen.\n Verfügbarkeit prüfen und Ihre Termine anderen anzeigen.\n Nahtlose Integration mit Apps und Geräten über CalDAV.\n Individuelle Gestaltung: Plane wiederkehrende Ereignisse, passe Benachrichtigungen und andere Einstellungen an.",
"Welcome to Nextcloud Calendar!\n\nThis is a sample event - explore the flexibility of planning with Nextcloud Calendar by making any edits you want!\n\nWith Nextcloud Calendar, you can:\n- Create, edit, and manage events effortlessly.\n- Create multiple calendars and share them with teammates, friends, or family.\n- Check availability and display your busy times to others.\n- Seamlessly integrate with apps and devices via CalDAV.\n- Customize your experience: schedule recurring events, adjust notifications and other settings." : "Willkommen bei Nextcloud Calendar!\n\nDies ist ein Beispielereignis entdecke die Flexibilität der Planung mit Nextcloud Calendar und nimm beliebige Änderungen vor!\n\nMit Nextcloud Calendar kannst du:\n Ereignisse mühelos erstellen, bearbeiten und verwalten.\n Mehrere Kalender erstellen und mit Teamkollegen, Freunden oder der Familie teilen.\n Verfügbarkeit prüfen und deine Termine anderen anzeigen.\n Nahtlose Integration mit Apps und Geräten über CalDAV.\n Individuelle Gestaltung: Plane wiederkehrende Ereignisse, passe Benachrichtigungen und andere Einstellungen an.",
"Example event - open me!" : "Beispielereignis öffne mich!",
"System Address Book" : "Systemadressbuch",
"The system address book contains contact information for all users in your instance." : "Das Systemadressbuch enthält Kontaktinformationen für alle Benutzer in dieser Instanz.",
+30
View File
@@ -73,7 +73,19 @@ OC.L10N.register(
"Where: %s" : "قەيەردە: %s",
"%1$s via %2$s" : "%1$s ئارقىلىق %2$s",
"In the past on %1$s for the entire day" : "پۈتۈن كۈن ئۈچۈن ئۆتمۈشتىكى %1$s دا",
"_In %n minute on %1$s for the entire day_::_In %n minutes on %1$s for the entire day_" : ["%1$s دا پۈتۈن كۈندە %n مىنۇتتا","%1$s دا پۈتۈن كۈندە %n مىنۇتتا"],
"_In %n hour on %1$s for the entire day_::_In %n hours on %1$s for the entire day_" : ["%1$s دا پۈتۈن كۈندە %n سائەتتە","%1$s دا پۈتۈن كۈندە %n سائەتتە"],
"_In %n day on %1$s for the entire day_::_In %n days on %1$s for the entire day_" : ["%1$s دا پۈتۈن كۈندە %n كۈندە","%1$s دا پۈتۈن كۈندە %n كۈندە"],
"_In %n week on %1$s for the entire day_::_In %n weeks on %1$s for the entire day_" : ["%1$s دا پۈتۈن كۈندە %n ھەپتىدە","%1$s دا پۈتۈن كۈندە %n ھەپتىدە"],
"_In %n month on %1$s for the entire day_::_In %n months on %1$s for the entire day_" : ["%1$s دا پۈتۈن كۈندە %n ئايدا","%1$s دا پۈتۈن كۈندە %n ئايدا"],
"_In %n year on %1$s for the entire day_::_In %n years on %1$s for the entire day_" : ["%1$s دا پۈتۈن كۈندە %n يىلدا","%1$s دا پۈتۈن كۈندە %n يىلدا"],
"In the past on %1$s between %2$s - %3$s" : "ئۆتمۈشتىكى %1$s دە %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_" : ["%1$s دە %2$s - %3$s ئارلىقىدا %n مىنۇتتا","%1$s دە %2$s - %3$s ئارلىقىدا %n مىنۇتتا"],
"_In %n hour on %1$s between %2$s - %3$s_::_In %n hours on %1$s between %2$s - %3$s_" : ["%1$s دە %2$s - %3$s ئارلىقىدا %n سائەتتە","%1$s دە %2$s - %3$s ئارلىقىدا %n سائەتتە"],
"_In %n day on %1$s between %2$s - %3$s_::_In %n days on %1$s between %2$s - %3$s_" : ["%1$s دە %2$s - %3$s ئارلىقىدا %n كۈندە","%1$s دە %2$s - %3$s ئارلىقىدا %n كۈندە"],
"_In %n week on %1$s between %2$s - %3$s_::_In %n weeks on %1$s between %2$s - %3$s_" : ["%1$s دە %2$s - %3$s ئارلىقىدا %n ھەپتىدە","%1$s دە %2$s - %3$s ئارلىقىدا %n ھەپتىدە"],
"_In %n month on %1$s between %2$s - %3$s_::_In %n months on %1$s between %2$s - %3$s_" : ["%1$s دە %2$s - %3$s ئارلىقىدا %n ئايدا","%1$s دە %2$s - %3$s ئارلىقىدا %n ئايدا"],
"_In %n year on %1$s between %2$s - %3$s_::_In %n years on %1$s between %2$s - %3$s_" : ["%1$s دە %2$s - %3$s ئارلىقىدا %n يىلدا","%1$s دە %2$s - %3$s ئارلىقىدا %n يىلدا"],
"Could not generate when statement" : "بايان قىلغاندا ھاسىل قىلالمىدى",
"Every Day for the entire day" : "ھەر بىر كۈن پۈتۈن بىر كۈن",
"Every Day for the entire day until %1$s" : "ھەر بىر كۈن پۈتۈن كۈن %1$s غىچە",
@@ -111,8 +123,26 @@ OC.L10N.register(
"On specific dates for the entire day until %1$s" : "%1$s غىچە بەلگىلىك چېسلادا پۈتۈن كۈن",
"On specific dates between %1$s - %2$s until %3$s" : "%1$s - %2$s ئارلىقىدىكى %3$s غىچە بولغان بەلگىلىك چېسلادا",
"In the past on %1$s" : "ئۆتمۈشتە %1$s دا",
"_In %n minute on %1$s_::_In %n minutes on %1$s_" : ["%1$s دا %n مىنۇتتا","%1$s دا %n مىنۇتتا"],
"_In %n hour on %1$s_::_In %n hours on %1$s_" : ["%1$s دا %n سائەتتە","%1$s دا %n سائەتتە"],
"_In %n day on %1$s_::_In %n days on %1$s_" : ["%1$s دا %n كۈندە","%1$s دا %n كۈندە"],
"_In %n week on %1$s_::_In %n weeks on %1$s_" : ["%1$s دا %n ھەپتىدە","%1$s دا %n ھەپتىدە"],
"_In %n month on %1$s_::_In %n months on %1$s_" : ["%1$s دا %n ئايدا","%1$s دا %n ئايدا"],
"_In %n year on %1$s_::_In %n years on %1$s_" : ["%1$s دا %n يىلدا","%1$s دا %n يىلدا"],
"In the past on %1$s then on %2$s" : "ئۆتمۈشتە %1$s دە ئاندىن %2$s دا",
"_In %n minute on %1$s then on %2$s_::_In %n minutes on %1$s then on %2$s_" : ["%1$s دا %n مىنۇتتا ئاندىن %2$s دا","%1$s دا %n مىنۇتتا ئاندىن %2$s دا"],
"_In %n hour on %1$s then on %2$s_::_In %n hours on %1$s then on %2$s_" : ["%1$s دا %n سائەتتە ئاندىن %2$s دا","%1$s دا %n سائەتتە ئاندىن %2$s دا"],
"_In %n day on %1$s then on %2$s_::_In %n days on %1$s then on %2$s_" : ["%1$s دا %n كۈندە ئاندىن %2$s دا","%1$s دا %n كۈندە ئاندىن %2$s دا"],
"_In %n week on %1$s then on %2$s_::_In %n weeks on %1$s then on %2$s_" : ["%1$s دا %n ھەپتىدە ئاندىن %2$s دا","%1$s دا %n ھەپتىدە ئاندىن %2$s دا"],
"_In %n month on %1$s then on %2$s_::_In %n months on %1$s then on %2$s_" : ["%1$s دا %n ئايدا ئاندىن %2$s دا","%1$s دا %n ئايدا ئاندىن %2$s دا"],
"_In %n year on %1$s then on %2$s_::_In %n years on %1$s then on %2$s_" : ["%1$s دا %n يىلدا ئاندىن %2$s دا","%1$s دا %n يىلدا ئاندىن %2$s دا"],
"In the past on %1$s then on %2$s and %3$s" : "ئۆتمۈشتە %1$s دە ئاندىن %2$s بىلەن %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_" : ["%1$s دا %n مىنۇتتا ئاندىن كىيىن %2$s بىلەن %3$s دا","%1$s دا %n مىنۇتتا ئاندىن كىيىن %2$s بىلەن %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_" : ["%1$s دا %n سائەتتە ئاندىن كىيىن %2$s بىلەن %3$s دا","%1$s دا %n سائەتتە ئاندىن كىيىن %2$s بىلەن %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_" : ["%1$s دا %n كۈندە ئاندىن كىيىن %2$s بىلەن %3$s دا","%1$s دا %n كۈندە ئاندىن كىيىن %2$s بىلەن %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_" : ["%1$s دا %n ھەپتىدە ئاندىن كىيىن %2$s بىلەن %3$s دا","%1$s دا %n ھەپتىدە ئاندىن كىيىن %2$s بىلەن %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_" : ["%1$s دا %n ئايدا ئاندىن كىيىن %2$s بىلەن %3$s دا","%1$s دا %n ئايدا ئاندىن كىيىن %2$s بىلەن %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_" : ["%1$s دا %n يىلدا ئاندىن كىيىن %2$s بىلەن %3$s دا","%1$s دا %n يىلدا ئاندىن كىيىن %2$s بىلەن %3$s دا"],
"Could not generate next recurrence statement" : "كېيىنكى تەكرارلىنىش باياناتىنى ھاسىل قىلالمىدى",
"Cancelled: %1$s" : "ئەمەلدىن قالدۇرۇلدى: %1$s",
"\"%1$s\" has been canceled" : "\"%1$s\" ئەمەلدىن قالدۇرۇلدى",
+30
View File
@@ -71,7 +71,19 @@
"Where: %s" : "قەيەردە: %s",
"%1$s via %2$s" : "%1$s ئارقىلىق %2$s",
"In the past on %1$s for the entire day" : "پۈتۈن كۈن ئۈچۈن ئۆتمۈشتىكى %1$s دا",
"_In %n minute on %1$s for the entire day_::_In %n minutes on %1$s for the entire day_" : ["%1$s دا پۈتۈن كۈندە %n مىنۇتتا","%1$s دا پۈتۈن كۈندە %n مىنۇتتا"],
"_In %n hour on %1$s for the entire day_::_In %n hours on %1$s for the entire day_" : ["%1$s دا پۈتۈن كۈندە %n سائەتتە","%1$s دا پۈتۈن كۈندە %n سائەتتە"],
"_In %n day on %1$s for the entire day_::_In %n days on %1$s for the entire day_" : ["%1$s دا پۈتۈن كۈندە %n كۈندە","%1$s دا پۈتۈن كۈندە %n كۈندە"],
"_In %n week on %1$s for the entire day_::_In %n weeks on %1$s for the entire day_" : ["%1$s دا پۈتۈن كۈندە %n ھەپتىدە","%1$s دا پۈتۈن كۈندە %n ھەپتىدە"],
"_In %n month on %1$s for the entire day_::_In %n months on %1$s for the entire day_" : ["%1$s دا پۈتۈن كۈندە %n ئايدا","%1$s دا پۈتۈن كۈندە %n ئايدا"],
"_In %n year on %1$s for the entire day_::_In %n years on %1$s for the entire day_" : ["%1$s دا پۈتۈن كۈندە %n يىلدا","%1$s دا پۈتۈن كۈندە %n يىلدا"],
"In the past on %1$s between %2$s - %3$s" : "ئۆتمۈشتىكى %1$s دە %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_" : ["%1$s دە %2$s - %3$s ئارلىقىدا %n مىنۇتتا","%1$s دە %2$s - %3$s ئارلىقىدا %n مىنۇتتا"],
"_In %n hour on %1$s between %2$s - %3$s_::_In %n hours on %1$s between %2$s - %3$s_" : ["%1$s دە %2$s - %3$s ئارلىقىدا %n سائەتتە","%1$s دە %2$s - %3$s ئارلىقىدا %n سائەتتە"],
"_In %n day on %1$s between %2$s - %3$s_::_In %n days on %1$s between %2$s - %3$s_" : ["%1$s دە %2$s - %3$s ئارلىقىدا %n كۈندە","%1$s دە %2$s - %3$s ئارلىقىدا %n كۈندە"],
"_In %n week on %1$s between %2$s - %3$s_::_In %n weeks on %1$s between %2$s - %3$s_" : ["%1$s دە %2$s - %3$s ئارلىقىدا %n ھەپتىدە","%1$s دە %2$s - %3$s ئارلىقىدا %n ھەپتىدە"],
"_In %n month on %1$s between %2$s - %3$s_::_In %n months on %1$s between %2$s - %3$s_" : ["%1$s دە %2$s - %3$s ئارلىقىدا %n ئايدا","%1$s دە %2$s - %3$s ئارلىقىدا %n ئايدا"],
"_In %n year on %1$s between %2$s - %3$s_::_In %n years on %1$s between %2$s - %3$s_" : ["%1$s دە %2$s - %3$s ئارلىقىدا %n يىلدا","%1$s دە %2$s - %3$s ئارلىقىدا %n يىلدا"],
"Could not generate when statement" : "بايان قىلغاندا ھاسىل قىلالمىدى",
"Every Day for the entire day" : "ھەر بىر كۈن پۈتۈن بىر كۈن",
"Every Day for the entire day until %1$s" : "ھەر بىر كۈن پۈتۈن كۈن %1$s غىچە",
@@ -109,8 +121,26 @@
"On specific dates for the entire day until %1$s" : "%1$s غىچە بەلگىلىك چېسلادا پۈتۈن كۈن",
"On specific dates between %1$s - %2$s until %3$s" : "%1$s - %2$s ئارلىقىدىكى %3$s غىچە بولغان بەلگىلىك چېسلادا",
"In the past on %1$s" : "ئۆتمۈشتە %1$s دا",
"_In %n minute on %1$s_::_In %n minutes on %1$s_" : ["%1$s دا %n مىنۇتتا","%1$s دا %n مىنۇتتا"],
"_In %n hour on %1$s_::_In %n hours on %1$s_" : ["%1$s دا %n سائەتتە","%1$s دا %n سائەتتە"],
"_In %n day on %1$s_::_In %n days on %1$s_" : ["%1$s دا %n كۈندە","%1$s دا %n كۈندە"],
"_In %n week on %1$s_::_In %n weeks on %1$s_" : ["%1$s دا %n ھەپتىدە","%1$s دا %n ھەپتىدە"],
"_In %n month on %1$s_::_In %n months on %1$s_" : ["%1$s دا %n ئايدا","%1$s دا %n ئايدا"],
"_In %n year on %1$s_::_In %n years on %1$s_" : ["%1$s دا %n يىلدا","%1$s دا %n يىلدا"],
"In the past on %1$s then on %2$s" : "ئۆتمۈشتە %1$s دە ئاندىن %2$s دا",
"_In %n minute on %1$s then on %2$s_::_In %n minutes on %1$s then on %2$s_" : ["%1$s دا %n مىنۇتتا ئاندىن %2$s دا","%1$s دا %n مىنۇتتا ئاندىن %2$s دا"],
"_In %n hour on %1$s then on %2$s_::_In %n hours on %1$s then on %2$s_" : ["%1$s دا %n سائەتتە ئاندىن %2$s دا","%1$s دا %n سائەتتە ئاندىن %2$s دا"],
"_In %n day on %1$s then on %2$s_::_In %n days on %1$s then on %2$s_" : ["%1$s دا %n كۈندە ئاندىن %2$s دا","%1$s دا %n كۈندە ئاندىن %2$s دا"],
"_In %n week on %1$s then on %2$s_::_In %n weeks on %1$s then on %2$s_" : ["%1$s دا %n ھەپتىدە ئاندىن %2$s دا","%1$s دا %n ھەپتىدە ئاندىن %2$s دا"],
"_In %n month on %1$s then on %2$s_::_In %n months on %1$s then on %2$s_" : ["%1$s دا %n ئايدا ئاندىن %2$s دا","%1$s دا %n ئايدا ئاندىن %2$s دا"],
"_In %n year on %1$s then on %2$s_::_In %n years on %1$s then on %2$s_" : ["%1$s دا %n يىلدا ئاندىن %2$s دا","%1$s دا %n يىلدا ئاندىن %2$s دا"],
"In the past on %1$s then on %2$s and %3$s" : "ئۆتمۈشتە %1$s دە ئاندىن %2$s بىلەن %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_" : ["%1$s دا %n مىنۇتتا ئاندىن كىيىن %2$s بىلەن %3$s دا","%1$s دا %n مىنۇتتا ئاندىن كىيىن %2$s بىلەن %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_" : ["%1$s دا %n سائەتتە ئاندىن كىيىن %2$s بىلەن %3$s دا","%1$s دا %n سائەتتە ئاندىن كىيىن %2$s بىلەن %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_" : ["%1$s دا %n كۈندە ئاندىن كىيىن %2$s بىلەن %3$s دا","%1$s دا %n كۈندە ئاندىن كىيىن %2$s بىلەن %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_" : ["%1$s دا %n ھەپتىدە ئاندىن كىيىن %2$s بىلەن %3$s دا","%1$s دا %n ھەپتىدە ئاندىن كىيىن %2$s بىلەن %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_" : ["%1$s دا %n ئايدا ئاندىن كىيىن %2$s بىلەن %3$s دا","%1$s دا %n ئايدا ئاندىن كىيىن %2$s بىلەن %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_" : ["%1$s دا %n يىلدا ئاندىن كىيىن %2$s بىلەن %3$s دا","%1$s دا %n يىلدا ئاندىن كىيىن %2$s بىلەن %3$s دا"],
"Could not generate next recurrence statement" : "كېيىنكى تەكرارلىنىش باياناتىنى ھاسىل قىلالمىدى",
"Cancelled: %1$s" : "ئەمەلدىن قالدۇرۇلدى: %1$s",
"\"%1$s\" has been canceled" : "\"%1$s\" ئەمەلدىن قالدۇرۇلدى",
@@ -99,7 +99,6 @@ class SharesPlugin extends \Sabre\DAV\ServerPlugin {
IShare::TYPE_ROOM,
IShare::TYPE_CIRCLE,
IShare::TYPE_DECK,
IShare::TYPE_SCIENCEMESH,
];
foreach ($requestedShareTypes as $requestedShareType) {
+1 -2
View File
@@ -220,8 +220,7 @@
"schema": {
"type": "object",
"required": [
"fileId",
"expirationTime"
"fileId"
],
"properties": {
"fileId": {
@@ -253,7 +253,6 @@ class SharesPluginTest extends \Test\TestCase {
[[IShare::TYPE_REMOTE]],
[[IShare::TYPE_ROOM]],
[[IShare::TYPE_DECK]],
[[IShare::TYPE_SCIENCEMESH]],
[[IShare::TYPE_USER, IShare::TYPE_GROUP]],
[[IShare::TYPE_USER, IShare::TYPE_GROUP, IShare::TYPE_LINK]],
[[IShare::TYPE_USER, IShare::TYPE_LINK]],
@@ -7,9 +7,7 @@
*/
namespace OCA\FederatedFileSharing\Controller;
use OCA\FederatedFileSharing\AddressHandler;
use OCA\FederatedFileSharing\FederatedShareProvider;
use OCA\FederatedFileSharing\Notifications;
use OCP\App\IAppManager;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
@@ -29,7 +27,6 @@ use OCP\Federation\ICloudIdManager;
use OCP\HintException;
use OCP\IDBConnection;
use OCP\IRequest;
use OCP\IUserManager;
use OCP\Log\Audit\CriticalActionPerformedEvent;
use OCP\Server;
use OCP\Share;
@@ -44,10 +41,6 @@ class RequestHandlerController extends OCSController {
IRequest $request,
private FederatedShareProvider $federatedShareProvider,
private IDBConnection $connection,
private Share\IManager $shareManager,
private Notifications $notifications,
private AddressHandler $addressHandler,
private IUserManager $userManager,
private ICloudIdManager $cloudIdManager,
private LoggerInterface $logger,
private ICloudFederationFactory $cloudFederationFactory,
@@ -66,10 +59,10 @@ class RequestHandlerController extends OCSController {
* @param string|null $owner Display name of the receiver
* @param string|null $sharedBy Display name of the sender
* @param string|null $shareWith ID of the user that receives the share
* @param int|null $remoteId ID of the remote
* @param string|null $remoteId ID of the remote
* @param string|null $sharedByFederatedId Federated ID of the sender
* @param string|null $ownerFederatedId Federated ID of the receiver
* @return Http\DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @throws OCSException
*
* 200: Share created successfully
@@ -83,10 +76,10 @@ class RequestHandlerController extends OCSController {
?string $owner = null,
?string $sharedBy = null,
?string $shareWith = null,
?int $remoteId = null,
?string $remoteId = null,
?string $sharedByFederatedId = null,
?string $ownerFederatedId = null,
) {
): DataResponse {
if ($ownerFederatedId === null) {
$ownerFederatedId = $this->cloudIdManager->getCloudId($owner, $this->cleanupRemote($remote))->getId();
}
@@ -132,11 +125,11 @@ class RequestHandlerController extends OCSController {
/**
* create re-share on behalf of another user
*
* @param int $id ID of the share
* @param string $id ID of the share
* @param string|null $token Shared secret between servers
* @param string|null $shareWith ID of the user that receives the share
* @param int|null $remoteId ID of the remote
* @return Http\DataResponse<Http::STATUS_OK, array{token: string, remoteId: string}, array{}>
* @return DataResponse<Http::STATUS_OK, array{token: string, remoteId: string}, array{}>
* @throws OCSBadRequestException Re-sharing is not possible
* @throws OCSException
*
@@ -144,7 +137,7 @@ class RequestHandlerController extends OCSController {
*/
#[NoCSRFRequired]
#[PublicPage]
public function reShare(int $id, ?string $token = null, ?string $shareWith = null, ?int $remoteId = 0) {
public function reShare(string $id, ?string $token = null, ?string $shareWith = null, ?int $remoteId = 0): DataResponse {
if ($token === null
|| $shareWith === null
|| $remoteId === null
@@ -181,9 +174,9 @@ class RequestHandlerController extends OCSController {
/**
* accept server-to-server share
*
* @param int $id ID of the remote share
* @param string $id ID of the remote share
* @param string|null $token Shared secret between servers
* @return Http\DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @throws OCSException
* @throws ShareNotFound
* @throws HintException
@@ -192,7 +185,7 @@ class RequestHandlerController extends OCSController {
*/
#[NoCSRFRequired]
#[PublicPage]
public function acceptShare(int $id, ?string $token = null) {
public function acceptShare(string $id, ?string $token = null): DataResponse {
$notification = [
'sharedSecret' => $token,
'message' => 'Recipient accept the share'
@@ -216,16 +209,16 @@ class RequestHandlerController extends OCSController {
/**
* decline server-to-server share
*
* @param int $id ID of the remote share
* @param string $id ID of the remote share
* @param string|null $token Shared secret between servers
* @return Http\DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @throws OCSException
*
* 200: Share declined successfully
*/
#[NoCSRFRequired]
#[PublicPage]
public function declineShare(int $id, ?string $token = null) {
public function declineShare(string $id, ?string $token = null) {
$notification = [
'sharedSecret' => $token,
'message' => 'Recipient declined the share'
@@ -249,16 +242,16 @@ class RequestHandlerController extends OCSController {
/**
* remove server-to-server share if it was unshared by the owner
*
* @param int $id ID of the share
* @param string $id ID of the share
* @param string|null $token Shared secret between servers
* @return Http\DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @throws OCSException
*
* 200: Share unshared successfully
*/
#[NoCSRFRequired]
#[PublicPage]
public function unshare(int $id, ?string $token = null) {
public function unshare(string $id, ?string $token = null) {
if (!$this->isS2SEnabled()) {
throw new OCSException('Server does not support federated cloud sharing', 503);
}
@@ -275,7 +268,7 @@ class RequestHandlerController extends OCSController {
return new DataResponse();
}
private function cleanupRemote($remote) {
private function cleanupRemote(string $remote): string {
$remote = substr($remote, strpos($remote, '://') + 3);
return rtrim($remote, '/');
@@ -285,16 +278,16 @@ class RequestHandlerController extends OCSController {
/**
* federated share was revoked, either by the owner or the re-sharer
*
* @param int $id ID of the share
* @param string $id ID of the share
* @param string|null $token Shared secret between servers
* @return Http\DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @throws OCSBadRequestException Revoking the share is not possible
*
* 200: Share revoked successfully
*/
#[NoCSRFRequired]
#[PublicPage]
public function revoke(int $id, ?string $token = null) {
public function revoke(string $id, ?string $token = null) {
try {
$provider = $this->cloudFederationProviderManager->getCloudFederationProvider('file');
$notification = ['sharedSecret' => $token];
@@ -324,19 +317,19 @@ class RequestHandlerController extends OCSController {
}
/**
* update share information to keep federated re-shares in sync
* Update share information to keep federated re-shares in sync.
*
* @param int $id ID of the share
* @param string $id ID of the share
* @param string|null $token Shared secret between servers
* @param int|null $permissions New permissions
* @return Http\DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
* @throws OCSBadRequestException Updating permissions is not possible
*
* 200: Permissions updated successfully
*/
#[NoCSRFRequired]
#[PublicPage]
public function updatePermissions(int $id, ?string $token = null, ?int $permissions = null) {
public function updatePermissions(string $id, ?string $token = null, ?int $permissions = null) {
$ncPermissions = $permissions;
try {
@@ -385,7 +378,7 @@ class RequestHandlerController extends OCSController {
* @param string|null $token Shared secret between servers
* @param string|null $remote Address of the remote
* @param string|null $remote_id ID of the remote
* @return Http\DataResponse<Http::STATUS_OK, array{remote: string, owner: string}, array{}>
* @return DataResponse<Http::STATUS_OK, array{remote: string, owner: string}, array{}>
* @throws OCSBadRequestException Moving share is not possible
*
* 200: Share moved successfully
@@ -27,6 +27,7 @@ use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IShare;
use OCP\Share\IShareProvider;
use OCP\Share\IShareProviderSupportsAllSharesInFolder;
use Override;
use Psr\Log\LoggerInterface;
/**
@@ -62,24 +63,19 @@ class FederatedShareProvider implements IShareProvider, IShareProviderSupportsAl
) {
}
/**
* Return the identifier of this provider.
*
* @return string Containing only [a-zA-Z0-9]
*/
public function identifier() {
#[Override]
public function identifier(): string {
return 'ocFederatedSharing';
}
/**
* Share a path
*
* @param IShare $share
* @return IShare The share object
* @throws ShareNotFound
* @throws \Exception
*/
public function create(IShare $share) {
#[Override]
public function create(IShare $share): IShare {
$shareWith = $share->getSharedWith();
$itemSource = $share->getNodeId();
$itemType = $share->getNodeType();
@@ -168,14 +164,12 @@ class FederatedShareProvider implements IShareProvider, IShareProviderSupportsAl
}
/**
* create federated share and inform the recipient
* Create federated share and inform the recipient.
*
* @param IShare $share
* @return int
* @throws ShareNotFound
* @throws \Exception
*/
protected function createFederatedShare(IShare $share) {
protected function createFederatedShare(IShare $share): string {
$token = $this->tokenHandler->generateToken();
$shareId = $this->addShareToDB(
$share->getNodeId(),
@@ -293,9 +287,8 @@ class FederatedShareProvider implements IShareProvider, IShareProviderSupportsAl
* @param string $token
* @param int $shareType
* @param \DateTime $expirationDate
* @return int
*/
private function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $shareType, $expirationDate) {
private function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $shareType, $expirationDate): string {
$qb = $this->dbConnection->getQueryBuilder();
$qb->insert('share')
->setValue('share_type', $qb->createNamedParameter($shareType))
@@ -317,16 +310,13 @@ class FederatedShareProvider implements IShareProvider, IShareProviderSupportsAl
$qb->setValue('file_target', $qb->createNamedParameter(''));
$qb->executeStatement();
return $qb->getLastInsertId();
return (string)$qb->getLastInsertId();
}
/**
* Update a share
*
* @param IShare $share
* @return IShare The share object
* Update a share.
*/
public function update(IShare $share) {
public function update(IShare $share): IShare {
/*
* We allow updating the permissions of federated shares
*/
@@ -348,13 +338,12 @@ class FederatedShareProvider implements IShareProvider, IShareProviderSupportsAl
}
/**
* send the updated permission to the owner/initiator, if they are not the same
* Send the updated permission to the owner/initiator, if they are not the same.
*
* @param IShare $share
* @throws ShareNotFound
* @throws HintException
*/
protected function sendPermissionUpdate(IShare $share) {
protected function sendPermissionUpdate(IShare $share): void {
$remoteId = $this->getRemoteId($share);
// if the local user is the owner we send the permission change to the initiator
if ($this->userManager->userExists($share->getShareOwner())) {
@@ -367,12 +356,9 @@ class FederatedShareProvider implements IShareProvider, IShareProviderSupportsAl
/**
* update successful reShare with the correct token
*
* @param int $shareId
* @param string $token
* Update successful reShare with the correct token.
*/
protected function updateSuccessfulReShare($shareId, $token) {
protected function updateSuccessfulReShare(string $shareId, string $token): void {
$query = $this->dbConnection->getQueryBuilder();
$query->update('share')
->where($query->expr()->eq('id', $query->createNamedParameter($shareId)))
@@ -381,12 +367,9 @@ class FederatedShareProvider implements IShareProvider, IShareProviderSupportsAl
}
/**
* store remote ID in federated reShare table
*
* @param $shareId
* @param $remoteId
* Store remote ID in federated reShare table.
*/
public function storeRemoteId(int $shareId, string $remoteId): void {
public function storeRemoteId(string $shareId, string $remoteId): void {
$query = $this->dbConnection->getQueryBuilder();
$query->insert('federated_reshares')
->values(
@@ -399,10 +382,8 @@ class FederatedShareProvider implements IShareProvider, IShareProviderSupportsAl
}
/**
* get share ID on remote server for federated re-shares
* Get share ID on remote server for federated re-shares.
*
* @param IShare $share
* @return string
* @throws ShareNotFound
*/
public function getRemoteId(IShare $share): string {
@@ -512,11 +493,9 @@ class FederatedShareProvider implements IShareProvider, IShareProviderSupportsAl
}
/**
* remove share from table
*
* @param string $shareId
* Remove share from table.
*/
private function removeShareFromTableById($shareId) {
private function removeShareFromTableById(string $shareId): void {
$qb = $this->dbConnection->getQueryBuilder();
$qb->delete('share')
->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)))
@@ -748,14 +727,8 @@ class FederatedShareProvider implements IShareProvider, IShareProviderSupportsAl
return $shares;
}
/**
* Get a share by token
*
* @param string $token
* @return IShare
* @throws ShareNotFound
*/
public function getShareByToken($token) {
#[Override]
public function getShareByToken(string $token): IShare {
$qb = $this->dbConnection->getQueryBuilder();
$cursor = $qb->select('*')
@@ -812,9 +785,9 @@ class FederatedShareProvider implements IShareProvider, IShareProviderSupportsAl
* @throws InvalidShare
* @throws ShareNotFound
*/
private function createShareObject($data) {
private function createShareObject($data): IShare {
$share = new Share($this->rootFolder, $this->userManager);
$share->setId((int)$data['id'])
$share->setId((string)$data['id'])
->setShareType((int)$data['share_type'])
->setPermissions((int)$data['permissions'])
->setTarget($data['file_target'])
@@ -894,7 +867,7 @@ class FederatedShareProvider implements IShareProvider, IShareProviderSupportsAl
$qb = $this->dbConnection->getQueryBuilder();
$qb->delete('share_external')
->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_GROUP)))
->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_USER)))
->andWhere($qb->expr()->eq('user', $qb->createNamedParameter($uid)))
->executeStatement();
}
@@ -9,15 +9,18 @@ namespace OCA\FederatedFileSharing\OCM;
use NCU\Federation\ISignedCloudFederationProvider;
use OC\AppFramework\Http;
use OC\Files\Filesystem;
use OC\Files\SetupManager;
use OCA\FederatedFileSharing\AddressHandler;
use OCA\FederatedFileSharing\FederatedShareProvider;
use OCA\Federation\TrustedServers;
use OCA\Files_Sharing\Activity\Providers\RemoteShares;
use OCA\Files_Sharing\External\ExternalShare;
use OCA\Files_Sharing\External\ExternalShareMapper;
use OCA\Files_Sharing\External\Manager;
use OCA\GlobalSiteSelector\Service\SlaveService;
use OCA\Polls\Db\Share;
use OCP\Activity\IManager as IActivityManager;
use OCP\App\IAppManager;
use OCP\AppFramework\QueryException;
use OCP\Constants;
use OCP\Federation\Exceptions\ActionNotSupportedException;
use OCP\Federation\Exceptions\AuthenticationFailedException;
@@ -31,9 +34,9 @@ use OCP\Files\IFilenameValidator;
use OCP\Files\NotFoundException;
use OCP\HintException;
use OCP\IConfig;
use OCP\IDBConnection;
use OCP\IGroupManager;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\IUserManager;
use OCP\Notification\IManager as INotificationManager;
use OCP\Server;
@@ -41,55 +44,44 @@ 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;
use SensitiveParameter;
class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
/**
* CloudFederationProvider constructor.
*/
public function __construct(
private IAppManager $appManager,
private FederatedShareProvider $federatedShareProvider,
private AddressHandler $addressHandler,
private IUserManager $userManager,
private IManager $shareManager,
private ICloudIdManager $cloudIdManager,
private IActivityManager $activityManager,
private INotificationManager $notificationManager,
private IURLGenerator $urlGenerator,
private ICloudFederationFactory $cloudFederationFactory,
private ICloudFederationProviderManager $cloudFederationProviderManager,
private IDBConnection $connection,
private IGroupManager $groupManager,
private IConfig $config,
private Manager $externalShareManager,
private LoggerInterface $logger,
private IFilenameValidator $filenameValidator,
private readonly IAppManager $appManager,
private readonly FederatedShareProvider $federatedShareProvider,
private readonly AddressHandler $addressHandler,
private readonly IUserManager $userManager,
private readonly IManager $shareManager,
private readonly ICloudIdManager $cloudIdManager,
private readonly IActivityManager $activityManager,
private readonly INotificationManager $notificationManager,
private readonly IURLGenerator $urlGenerator,
private readonly ICloudFederationFactory $cloudFederationFactory,
private readonly ICloudFederationProviderManager $cloudFederationProviderManager,
private readonly IGroupManager $groupManager,
private readonly IConfig $config,
private readonly Manager $externalShareManager,
private readonly LoggerInterface $logger,
private readonly IFilenameValidator $filenameValidator,
private readonly IProviderFactory $shareProviderFactory,
private readonly SetupManager $setupManager,
private readonly IGenerator $snowflakeGenerator,
private readonly ExternalShareMapper $externalShareMapper,
) {
}
/**
* @return string
*/
public function getShareType() {
#[Override]
public function getShareType(): string {
return 'file';
}
/**
* share received from another server
*
* @param ICloudFederationShare $share
* @return string provider specific unique ID of the share
*
* @throws ProviderCouldNotAddShareException
* @throws QueryException
* @throws HintException
* @since 14.0.0
*/
public function shareReceived(ICloudFederationShare $share) {
#[Override]
public function shareReceived(ICloudFederationShare $share): string {
if (!$this->isS2SEnabled(true)) {
throw new ProviderCouldNotAddShareException('Server does not support federated cloud sharing', '', Http::STATUS_SERVICE_UNAVAILABLE);
}
@@ -99,7 +91,8 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
throw new ProviderCouldNotAddShareException('Unsupported protocol for data exchange.', '', Http::STATUS_NOT_IMPLEMENTED);
}
[$ownerUid, $remote] = $this->addressHandler->splitUserRemote($share->getOwner());
[, $remote] = $this->addressHandler->splitUserRemote($share->getOwner());
// for backward compatibility make sure that the remote url stored in the
// database ends with a trailing slash
if (!str_ends_with($remote, '/')) {
@@ -109,17 +102,15 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
$token = $share->getShareSecret();
$name = $share->getResourceName();
$owner = $share->getOwnerDisplayName() ?: $share->getOwner();
$sharedBy = $share->getSharedByDisplayName();
$shareWith = $share->getShareWith();
$remoteId = $share->getProviderId();
$sharedByFederatedId = $share->getSharedBy();
$ownerFederatedId = $share->getOwner();
$shareType = $this->mapShareTypeToNextcloud($share->getShareType());
// if no explicit information about the person who created the share was send
// if no explicit information about the person who created the share was sent
// we assume that the share comes from the owner
if ($sharedByFederatedId === null) {
$sharedBy = $owner;
$sharedByFederatedId = $ownerFederatedId;
}
@@ -128,7 +119,9 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
throw new ProviderCouldNotAddShareException('The mountpoint name contains invalid characters.', '', Http::STATUS_BAD_REQUEST);
}
// FIXME this should be a method in the user management instead
$user = null;
$group = null;
if ($shareType === IShare::TYPE_USER) {
$this->logger->debug('shareWith before, ' . $shareWith, ['app' => 'files_sharing']);
Util::emitHook(
@@ -138,20 +131,32 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
);
$this->logger->debug('shareWith after, ' . $shareWith, ['app' => 'files_sharing']);
if (!$this->userManager->userExists($shareWith)) {
$user = $this->userManager->get($shareWith);
if ($user === null) {
throw new ProviderCouldNotAddShareException('User does not exists', '', Http::STATUS_BAD_REQUEST);
}
\OC_Util::setupFS($shareWith);
$this->setupManager->setupForUser($user);
} else {
$group = $this->groupManager->get($shareWith);
if ($group === null) {
throw new ProviderCouldNotAddShareException('Group does not exists', '', Http::STATUS_BAD_REQUEST);
}
}
if ($shareType === IShare::TYPE_GROUP && !$this->groupManager->groupExists($shareWith)) {
throw new ProviderCouldNotAddShareException('Group does not exists', '', Http::STATUS_BAD_REQUEST);
}
$externalShare = new ExternalShare();
$externalShare->setId($this->snowflakeGenerator->nextId());
$externalShare->setRemote($remote);
$externalShare->setRemoteId($remoteId);
$externalShare->setShareToken($token);
$externalShare->setPassword('');
$externalShare->setName($name);
$externalShare->setOwner($owner);
$externalShare->setShareType($shareType);
$externalShare->setAccepted(IShare::STATUS_PENDING);
try {
$this->externalShareManager->addShare($remote, $token, '', $name, $owner, $shareType, false, $shareWith, $remoteId);
$shareId = Server::get(IDBConnection::class)->lastInsertId('*PREFIX*share_external');
$this->externalShareManager->addShare($externalShare, $user ?: $group);
// get DisplayName about the owner of the share
$ownerDisplayName = $this->getUserDisplayName($ownerFederatedId);
@@ -166,41 +171,40 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
}
}
if ($shareType === IShare::TYPE_USER) {
$event = $this->activityManager->generateEvent();
$event->setApp('files_sharing')
->setType('remote_share')
->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/'), $ownerDisplayName])
->setAffectedUser($shareWith)
->setObject('remote_share', $shareId, $name);
->setObject('remote_share', $externalShare->getId(), $name);
Server::get(IActivityManager::class)->publish($event);
$this->notifyAboutNewShare($shareWith, $shareId, $ownerFederatedId, $sharedByFederatedId, $name, $ownerDisplayName);
$this->notifyAboutNewShare($shareWith, $externalShare->getId(), $ownerFederatedId, $sharedByFederatedId, $name, $ownerDisplayName);
// If auto-accept is enabled, accept the share
if ($this->federatedShareProvider->isFederatedTrustedShareAutoAccept() && $trustedServers?->isTrustedServer($remote) === true) {
$this->externalShareManager->acceptShare($shareId, $shareWith);
$this->externalShareManager->acceptShare($externalShare, $user);
}
} else {
$groupMembers = $this->groupManager->get($shareWith)->getUsers();
$groupMembers = $group->getUsers();
foreach ($groupMembers as $user) {
$event = $this->activityManager->generateEvent();
$event->setApp('files_sharing')
->setType('remote_share')
->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/'), $ownerDisplayName])
->setAffectedUser($user->getUID())
->setObject('remote_share', $shareId, $name);
->setObject('remote_share', $externalShare->getId(), $name);
Server::get(IActivityManager::class)->publish($event);
$this->notifyAboutNewShare($user->getUID(), $shareId, $ownerFederatedId, $sharedByFederatedId, $name, $ownerDisplayName);
$this->notifyAboutNewShare($user->getUID(), $externalShare->getId(), $ownerFederatedId, $sharedByFederatedId, $name, $ownerDisplayName);
// If auto-accept is enabled, accept the share
if ($this->federatedShareProvider->isFederatedTrustedShareAutoAccept() && $trustedServers?->isTrustedServer($remote) === true) {
$this->externalShareManager->acceptShare($shareId, $user->getUID());
$this->externalShareManager->acceptShare($externalShare, $user);
}
}
}
return $shareId;
return $externalShare->getId();
} catch (\Exception $e) {
$this->logger->error('Server can not add remote share.', [
'app' => 'files_sharing',
@@ -213,56 +217,28 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
throw new ProviderCouldNotAddShareException('server can not add remote share, missing parameter', '', HTTP::STATUS_BAD_REQUEST);
}
/**
* notification received from another server
*
* @param string $notificationType (e.g. SHARE_ACCEPTED)
* @param string $providerId id of the share
* @param array $notification payload of the notification
* @return array<string> data send back to the sender
*
* @throws ActionNotSupportedException
* @throws AuthenticationFailedException
* @throws BadRequestException
* @throws HintException
* @since 14.0.0
*/
public function notificationReceived($notificationType, $providerId, array $notification) {
switch ($notificationType) {
case 'SHARE_ACCEPTED':
return $this->shareAccepted($providerId, $notification);
case 'SHARE_DECLINED':
return $this->shareDeclined($providerId, $notification);
case 'SHARE_UNSHARED':
return $this->unshare($providerId, $notification);
case 'REQUEST_RESHARE':
return $this->reshareRequested($providerId, $notification);
case 'RESHARE_UNDO':
return $this->undoReshare($providerId, $notification);
case 'RESHARE_CHANGE_PERMISSION':
return $this->updateResharePermissions($providerId, $notification);
}
throw new BadRequestException([$notificationType]);
#[Override]
public function notificationReceived(string $notificationType, string $providerId, array $notification): array {
return match ($notificationType) {
'SHARE_ACCEPTED' => $this->shareAccepted($providerId, $notification),
'SHARE_DECLINED' => $this->shareDeclined($providerId, $notification),
'SHARE_UNSHARED' => $this->unshare($providerId, $notification),
'REQUEST_RESHARE' => $this->reshareRequested($providerId, $notification),
'RESHARE_UNDO' => $this->undoReshare($providerId, $notification),
'RESHARE_CHANGE_PERMISSION' => $this->updateResharePermissions($providerId, $notification),
default => throw new BadRequestException([$notificationType]),
};
}
/**
* map OCM share type (strings) to Nextcloud internal share types (integer)
*
* @param string $shareType
* @return int
* Map OCM share type (strings) to Nextcloud internal share types (integer)
* @return IShare::TYPE_GROUP|IShare::TYPE_USER
*/
private function mapShareTypeToNextcloud($shareType) {
$result = IShare::TYPE_USER;
if ($shareType === 'group') {
$result = IShare::TYPE_GROUP;
}
return $result;
private function mapShareTypeToNextcloud(string $shareType): int {
return $shareType === 'group' ? IShare::TYPE_GROUP : IShare::TYPE_USER;
}
private function notifyAboutNewShare($shareWith, $shareId, $ownerFederatedId, $sharedByFederatedId, $name, $displayName): void {
private function notifyAboutNewShare(string $shareWith, string $shareId, $ownerFederatedId, $sharedByFederatedId, string $name, string $displayName): void {
$notification = $this->notificationManager->createNotification();
$notification->setApp('files_sharing')
->setUser($shareWith)
@@ -286,15 +262,14 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
/**
* process notification that the recipient accepted a share
*
* @param string $id
* @param array $notification
* @param array{sharedSecret?: string} $notification
* @return array<string>
* @throws ActionNotSupportedException
* @throws AuthenticationFailedException
* @throws BadRequestException
* @throws HintException
*/
private function shareAccepted($id, array $notification) {
private function shareAccepted(string $id, array $notification): array {
if (!$this->isS2SEnabled()) {
throw new ActionNotSupportedException('Server does not support federated cloud sharing');
}
@@ -333,21 +308,22 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
}
/**
* @param IShare $share
* @throws ShareNotFound
*/
protected function executeAcceptShare(IShare $share) {
protected function executeAcceptShare(IShare $share): void {
$user = $this->getCorrectUser($share);
try {
$fileId = (int)$share->getNode()->getId();
[$file, $link] = $this->getFile($this->getCorrectUid($share), $fileId);
} catch (\Exception $e) {
$fileId = $share->getNode()->getId();
[$file, $link] = $this->getFile($user, $fileId);
} catch (\Exception) {
throw new ShareNotFound();
}
$event = $this->activityManager->generateEvent();
$event->setApp('files_sharing')
->setType('remote_share')
->setAffectedUser($this->getCorrectUid($share))
->setAffectedUser($user->getUID())
->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_ACCEPTED, [$share->getSharedWith(), [$fileId => $file]])
->setObject('files', $fileId, $file)
->setLink($link);
@@ -357,8 +333,7 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
/**
* process notification that the recipient declined a share
*
* @param string $id
* @param array $notification
* @param array{sharedSecret?: string} $notification
* @return array<string>
* @throws ActionNotSupportedException
* @throws AuthenticationFailedException
@@ -367,7 +342,7 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
* @throws HintException
*
*/
protected function shareDeclined($id, array $notification) {
protected function shareDeclined(string $id, array $notification): array {
if (!$this->isS2SEnabled()) {
throw new ActionNotSupportedException('Server does not support federated cloud sharing');
}
@@ -394,7 +369,6 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
'sharedSecret' => $token,
'message' => 'Recipient declined the re-share'
]
);
$this->cloudFederationProviderManager->sendNotification($remote, $notification);
}
@@ -407,23 +381,24 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
/**
* delete declined share and create a activity
*
* @param IShare $share
* @throws ShareNotFound
*/
protected function executeDeclineShare(IShare $share) {
protected function executeDeclineShare(IShare $share): void {
$this->federatedShareProvider->removeShareFromTable($share);
$user = $this->getCorrectUser($share);
try {
$fileId = (int)$share->getNode()->getId();
[$file, $link] = $this->getFile($this->getCorrectUid($share), $fileId);
} catch (\Exception $e) {
$fileId = $share->getNode()->getId();
[$file, $link] = $this->getFile($user, $fileId);
} catch (\Exception) {
throw new ShareNotFound();
}
$event = $this->activityManager->generateEvent();
$event->setApp('files_sharing')
->setType('remote_share')
->setAffectedUser($this->getCorrectUid($share))
->setAffectedUser($user->getUID())
->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_DECLINED, [$share->getSharedWith(), [$fileId => $file]])
->setObject('files', $fileId, $file)
->setLink($link);
@@ -433,13 +408,12 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
/**
* received the notification that the owner unshared a file from you
*
* @param string $id
* @param array $notification
* @param array{sharedSecret?: string} $notification
* @return array<string>
* @throws AuthenticationFailedException
* @throws BadRequestException
*/
private function undoReshare($id, array $notification) {
private function undoReshare(string $id, array $notification): array {
if (!isset($notification['sharedSecret'])) {
throw new BadRequestException(['sharedSecret']);
}
@@ -455,13 +429,12 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
/**
* unshare file from self
*
* @param string $id
* @param array $notification
* @param array{sharedSecret?: string} $notification
* @return array<string>
* @throws ActionNotSupportedException
* @throws BadRequestException
*/
private function unshare($id, array $notification) {
private function unshare(string $id, array $notification): array {
if (!$this->isS2SEnabled(true)) {
throw new ActionNotSupportedException('incoming shares disabled!');
}
@@ -471,56 +444,29 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
}
$token = $notification['sharedSecret'];
$qb = $this->connection->getQueryBuilder();
$qb->select('*')
->from('share_external')
->where(
$qb->expr()->andX(
$qb->expr()->eq('remote_id', $qb->createNamedParameter($id)),
$qb->expr()->eq('share_token', $qb->createNamedParameter($token))
)
);
$share = $this->externalShareMapper->getShareByRemoteIdAndToken($id, $token);
$result = $qb->executeQuery();
$share = $result->fetchAssociative();
$result->closeCursor();
if ($token && $id && $share !== null) {
$remote = $this->cleanupRemote($share->getRemote());
if ($token && $id && !empty($share)) {
$remote = $this->cleanupRemote($share['remote']);
$owner = $this->cloudIdManager->getCloudId($share->getOwner(), $remote);
$mountpoint = $share->getMountpoint();
$user = $share->getUser();
$owner = $this->cloudIdManager->getCloudId($share['owner'], $remote);
$mountpoint = $share['mountpoint'];
$user = $share['user'];
$qb = $this->connection->getQueryBuilder();
$qb->delete('share_external')
->where(
$qb->expr()->andX(
$qb->expr()->eq('remote_id', $qb->createNamedParameter($id)),
$qb->expr()->eq('share_token', $qb->createNamedParameter($token))
)
);
$qb->executeStatement();
// delete all child in case of a group share
$qb = $this->connection->getQueryBuilder();
$qb->delete('share_external')
->where($qb->expr()->eq('parent', $qb->createNamedParameter((int)$share['id'])));
$qb->executeStatement();
$this->externalShareMapper->delete($share);
$ownerDisplayName = $this->getUserDisplayName($owner->getId());
if ((int)$share['share_type'] === IShare::TYPE_USER) {
if ($share['accepted']) {
if ($share->getShareType() === IShare::TYPE_USER) {
if ($share->getAccepted()) {
$path = trim($mountpoint, '/');
} else {
$path = trim($share['name'], '/');
$path = trim($share->getName(), '/');
}
$notification = $this->notificationManager->createNotification();
$notification->setApp('files_sharing')
->setUser($share['user'])
->setObject('remote_share', (string)$share['id']);
->setUser($share->getUser())
->setObject('remote_share', $share->getId());
$this->notificationManager->markProcessed($notification);
$event = $this->activityManager->generateEvent();
@@ -528,7 +474,7 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
->setType('remote_share')
->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_UNSHARED, [$owner->getId(), $path, $ownerDisplayName])
->setAffectedUser($user)
->setObject('remote_share', (int)$share['id'], $path);
->setObject('remote_share', $share->getId(), $path);
Server::get(IActivityManager::class)->publish($event);
}
}
@@ -536,7 +482,7 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
return [];
}
private function cleanupRemote($remote) {
private function cleanupRemote(string $remote): string {
$remote = substr($remote, strpos($remote, '://') + 3);
return rtrim($remote, '/');
@@ -545,15 +491,14 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
/**
* recipient of a share request to re-share the file with another user
*
* @param string $id
* @param array $notification
* @param array{sharedSecret?: string, shareWith?: string, senderId?: string} $notification
* @return array<string>
* @throws AuthenticationFailedException
* @throws BadRequestException
* @throws ProviderCouldNotAddShareException
* @throws ShareNotFound
*/
protected function reshareRequested($id, array $notification) {
protected function reshareRequested(string $id, array $notification) {
if (!isset($notification['sharedSecret'])) {
throw new BadRequestException(['sharedSecret']);
}
@@ -595,7 +540,7 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
$share->setSharedBy($share->getSharedWith());
$share->setSharedWith($shareWith);
$result = $this->federatedShareProvider->create($share);
$this->federatedShareProvider->storeRemoteId((int)$result->getId(), $senderId);
$this->federatedShareProvider->storeRemoteId($result->getId(), $senderId);
return ['token' => $result->getToken(), 'providerId' => $result->getId()];
} else {
throw new ProviderCouldNotAddShareException('resharing not allowed for share: ' . $id);
@@ -603,71 +548,22 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
}
/**
* update permission of a re-share so that the share dialog shows the right
* Update permission of a re-share so that the share dialog shows the right
* permission if the owner or the sender changes the permission
*
* @param string $id
* @param array $notification
* @return array<string>
* @return string[]
* @throws AuthenticationFailedException
* @throws BadRequestException
*/
protected function updateResharePermissions($id, array $notification) {
protected function updateResharePermissions(string $id, array $notification): array {
throw new HintException('Updating reshares not allowed');
}
/**
* translate OCM Permissions to Nextcloud permissions
*
* @param array $ocmPermissions
* @return int
* @throws BadRequestException
* @return list{?string, string} with internal path of the file and a absolute link to it
*/
protected function ocmPermissions2ncPermissions(array $ocmPermissions) {
$ncPermissions = 0;
foreach ($ocmPermissions as $permission) {
switch (strtolower($permission)) {
case 'read':
$ncPermissions += Constants::PERMISSION_READ;
break;
case 'write':
$ncPermissions += Constants::PERMISSION_CREATE + Constants::PERMISSION_UPDATE;
break;
case 'share':
$ncPermissions += Constants::PERMISSION_SHARE;
break;
default:
throw new BadRequestException(['permission']);
}
}
return $ncPermissions;
}
/**
* update permissions in database
*
* @param IShare $share
* @param int $permissions
*/
protected function updatePermissionsInDatabase(IShare $share, $permissions) {
$query = $this->connection->getQueryBuilder();
$query->update('share')
->where($query->expr()->eq('id', $query->createNamedParameter($share->getId())))
->set('permissions', $query->createNamedParameter($permissions))
->executeStatement();
}
/**
* get file
*
* @param string $user
* @param int $fileSource
* @return array with internal path of the file and a absolute link to it
*/
private function getFile($user, $fileSource) {
\OC_Util::setupFS($user);
private function getFile(IUser $user, int $fileSource): array {
$this->setupManager->setupForUser($user);
try {
$file = Filesystem::getPath($fileSource);
@@ -681,30 +577,26 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
}
/**
* check if we are the initiator or the owner of a re-share and return the correct UID
*
* @param IShare $share
* @return string
* Check if we are the initiator or the owner of a re-share and return the correct UID
*/
protected function getCorrectUid(IShare $share) {
if ($this->userManager->userExists($share->getShareOwner())) {
return $share->getShareOwner();
protected function getCorrectUser(IShare $share): IUser {
if ($user = $this->userManager->get($share->getShareOwner())) {
return $user;
}
return $share->getSharedBy();
$user = $this->userManager->get($share->getSharedBy());
if ($user === null) {
throw new \RuntimeException('Neither the share owner or the share initiator exist');
}
return $user;
}
/**
* check if we got the right share
*
* @param IShare $share
* @param string $token
* @return bool
* @throws AuthenticationFailedException
*/
protected function verifyShare(IShare $share, $token) {
protected function verifyShare(IShare $share, string $token): bool {
if (
$share->getShareType() === IShare::TYPE_REMOTE
&& $share->getToken() === $token
@@ -728,12 +620,9 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
/**
* check if server-to-server sharing is enabled
*
* @param bool $incoming
* @return bool
* Check if server-to-server sharing is enabled
*/
private function isS2SEnabled($incoming = false) {
private function isS2SEnabled(bool $incoming = false): bool {
$result = $this->appManager->isEnabledForUser('files_sharing');
if ($incoming) {
@@ -745,19 +634,11 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
return $result;
}
/**
* get the supported share types, e.g. "user", "group", etc.
*
* @return array
*
* @since 14.0.0
*/
public function getSupportedShareTypes() {
#[Override]
public function getSupportedShareTypes(): array {
return ['user', 'group'];
}
public function getUserDisplayName(string $userId): string {
// check if gss is enabled and available
if (!$this->appManager->isEnabledForAnyone('globalsiteselector')
@@ -768,7 +649,7 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
try {
$slaveService = Server::get(SlaveService::class);
} catch (\Throwable $e) {
Server::get(LoggerInterface::class)->error(
$this->logger->error(
$e->getMessage(),
['exception' => $e]
);
@@ -778,13 +659,7 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
return $slaveService->getUserDisplayName($this->cloudIdManager->removeProtocolFromUrl($userId), false);
}
/**
* @inheritDoc
*
* @param string $sharedSecret
* @param array $payload
* @return string
*/
#[Override]
public function getFederationIdFromSharedSecret(
#[SensitiveParameter]
string $sharedSecret,
@@ -800,7 +675,7 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
return '';
}
return $share['user'] . '@' . $share['remote'];
return $share->getUser() . '@' . $share->getRemote();
}
// if uid_owner is a local account, the request comes from the recipient
+8 -15
View File
@@ -192,8 +192,7 @@
"description": "ID of the user that receives the share"
},
"remoteId": {
"type": "integer",
"format": "int64",
"type": "string",
"nullable": true,
"default": null,
"description": "ID of the remote"
@@ -313,8 +312,7 @@
"description": "ID of the share",
"required": true,
"schema": {
"type": "integer",
"format": "int64"
"type": "string"
}
},
{
@@ -405,7 +403,7 @@
"/ocs/v2.php/cloud/shares/{id}/permissions": {
"post": {
"operationId": "request_handler-update-permissions",
"summary": "update share information to keep federated re-shares in sync",
"summary": "Update share information to keep federated re-shares in sync.",
"tags": [
"request_handler"
],
@@ -450,8 +448,7 @@
"description": "ID of the share",
"required": true,
"schema": {
"type": "integer",
"format": "int64"
"type": "string"
}
},
{
@@ -566,8 +563,7 @@
"description": "ID of the remote share",
"required": true,
"schema": {
"type": "integer",
"format": "int64"
"type": "string"
}
},
{
@@ -664,8 +660,7 @@
"description": "ID of the remote share",
"required": true,
"schema": {
"type": "integer",
"format": "int64"
"type": "string"
}
},
{
@@ -752,8 +747,7 @@
"description": "ID of the share",
"required": true,
"schema": {
"type": "integer",
"format": "int64"
"type": "string"
}
},
{
@@ -840,8 +834,7 @@
"description": "ID of the share",
"required": true,
"schema": {
"type": "integer",
"format": "int64"
"type": "string"
}
},
{
@@ -8,10 +8,8 @@ declare(strict_types=1);
*/
namespace OCA\FederatedFileSharing\Tests;
use OCA\FederatedFileSharing\AddressHandler;
use OCA\FederatedFileSharing\Controller\RequestHandlerController;
use OCA\FederatedFileSharing\FederatedShareProvider;
use OCA\FederatedFileSharing\Notifications;
use OCP\AppFramework\Http\DataResponse;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Federation\ICloudFederationFactory;
@@ -21,8 +19,6 @@ use OCP\Federation\ICloudFederationShare;
use OCP\Federation\ICloudIdManager;
use OCP\IDBConnection;
use OCP\IRequest;
use OCP\IUserManager;
use OCP\Share;
use OCP\Share\IShare;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Log\LoggerInterface;
@@ -42,15 +38,11 @@ class RequestHandlerControllerTest extends \Test\TestCase {
private RequestHandlerController $requestHandler;
private FederatedShareProvider&MockObject $federatedShareProvider;
private Notifications&MockObject $notifications;
private AddressHandler&MockObject $addressHandler;
private IUserManager&MockObject $userManager;
private IShare&MockObject $share;
private ICloudIdManager&MockObject $cloudIdManager;
private LoggerInterface&MockObject $logger;
private IRequest&MockObject $request;
private IDBConnection&MockObject $connection;
private Share\IManager&MockObject $shareManager;
private ICloudFederationFactory&MockObject $cloudFederationFactory;
private ICloudFederationProviderManager&MockObject $cloudFederationProviderManager;
private ICloudFederationProvider&MockObject $cloudFederationProvider;
@@ -67,13 +59,9 @@ class RequestHandlerControllerTest extends \Test\TestCase {
$this->federatedShareProvider->expects($this->any())->method('getShareById')
->willReturn($this->share);
$this->notifications = $this->createMock(Notifications::class);
$this->addressHandler = $this->createMock(AddressHandler::class);
$this->userManager = $this->createMock(IUserManager::class);
$this->cloudIdManager = $this->createMock(ICloudIdManager::class);
$this->request = $this->createMock(IRequest::class);
$this->connection = $this->createMock(IDBConnection::class);
$this->shareManager = $this->createMock(Share\IManager::class);
$this->cloudFederationFactory = $this->createMock(ICloudFederationFactory::class);
$this->cloudFederationProviderManager = $this->createMock(ICloudFederationProviderManager::class);
$this->cloudFederationProvider = $this->createMock(ICloudFederationProvider::class);
@@ -88,10 +76,6 @@ class RequestHandlerControllerTest extends \Test\TestCase {
$this->request,
$this->federatedShareProvider,
$this->connection,
$this->shareManager,
$this->notifications,
$this->addressHandler,
$this->userManager,
$this->cloudIdManager,
$this->logger,
$this->cloudFederationFactory,
@@ -106,7 +90,7 @@ class RequestHandlerControllerTest extends \Test\TestCase {
$this->user2,
'name',
'',
1,
'1',
$this->ownerCloudId,
$this->owner,
$this->user1CloudId,
@@ -125,13 +109,13 @@ class RequestHandlerControllerTest extends \Test\TestCase {
$this->cloudFederationProvider->expects($this->once())->method('shareReceived')
->with($this->cloudFederationShare);
$result = $this->requestHandler->createShare('localhost', 'token', 'name', $this->owner, $this->user1, $this->user2, 1, $this->user1CloudId, $this->ownerCloudId);
$result = $this->requestHandler->createShare('localhost', 'token', 'name', $this->owner, $this->user1, $this->user2, '1', $this->user1CloudId, $this->ownerCloudId);
$this->assertInstanceOf(DataResponse::class, $result);
}
public function testDeclineShare(): void {
$id = 42;
$id = '42';
$notification = [
'sharedSecret' => 'token',
@@ -154,7 +138,7 @@ class RequestHandlerControllerTest extends \Test\TestCase {
public function testAcceptShare(): void {
$id = 42;
$id = '42';
$notification = [
'sharedSecret' => 'token',
+1 -1
View File
@@ -309,7 +309,7 @@ OC.L10N.register(
"Move" : "Flyt",
"Move or copy operation failed" : "Flytte- eller kopioperationen fejlede",
"Move or copy" : "Flyt eller kopiér",
"Open folder" : "Åben mappe",
"Open folder" : "Åbn mappe",
"Open folder {displayName}" : "Åben mappe {displayName}",
"Open in Files" : "Åben i Filer",
"Open locally" : "Åben lokalt",
+1 -1
View File
@@ -307,7 +307,7 @@
"Move" : "Flyt",
"Move or copy operation failed" : "Flytte- eller kopioperationen fejlede",
"Move or copy" : "Flyt eller kopiér",
"Open folder" : "Åben mappe",
"Open folder" : "Åbn mappe",
"Open folder {displayName}" : "Åben mappe {displayName}",
"Open in Files" : "Åben i Filer",
"Open locally" : "Åben lokalt",
+1 -1
View File
@@ -183,7 +183,7 @@ OC.L10N.register(
"Preparing …" : "Bereite vor …",
"Refresh" : "Aktualisieren",
"All files have been santized for Windows filename support." : "Alle Dateien wurden für die Windows-Dateinamenunterstützung bereinigt.",
"Some files could not be sanitized, please check your logs." : "Einige Dateien konnten nicht bereinigt werden. Bitte überprüfen Sie Ihre Protokolle.",
"Some files could not be sanitized, please check your logs." : "Einige Dateien konnten nicht bereinigt werden. Bitte die Protokolle überprüfen.",
"Sanitization errors" : "Bereinigungsfehler",
"Not sanitized filenames" : "Nicht bereinigte Dateinamen",
"Windows filename support has been enabled." : "Windows Dateinamenunterstützung wurde aktiviert.",
+1 -1
View File
@@ -181,7 +181,7 @@
"Preparing …" : "Bereite vor …",
"Refresh" : "Aktualisieren",
"All files have been santized for Windows filename support." : "Alle Dateien wurden für die Windows-Dateinamenunterstützung bereinigt.",
"Some files could not be sanitized, please check your logs." : "Einige Dateien konnten nicht bereinigt werden. Bitte überprüfen Sie Ihre Protokolle.",
"Some files could not be sanitized, please check your logs." : "Einige Dateien konnten nicht bereinigt werden. Bitte die Protokolle überprüfen.",
"Sanitization errors" : "Bereinigungsfehler",
"Not sanitized filenames" : "Nicht bereinigte Dateinamen",
"Windows filename support has been enabled." : "Windows Dateinamenunterstützung wurde aktiviert.",
+80 -1
View File
@@ -51,6 +51,10 @@ OC.L10N.register(
"You do not have permission to create a file at the specified location" : "Nemáte oprávnenie vytvoriť súbor v zadanom umiestnení",
"The file could not be converted." : "Súbor nemohol byť skonvertovaný.",
"Could not get relative path to converted file" : "Nepodarilo sa získať relatícnu cestu ku skonvertovanému súboru",
"Limit must be a positive integer." : "Limit musí byť kladné celé číslo.",
"The replacement character may only be a single character." : "Zástupný znak môže byť iba jeden znak.",
"Filename sanitization already started." : "Sanitizácia názvu súboru bola už zahájená.",
"No filename sanitization in progress." : "Žiadna sanitácia názvu súboru neprebieha.",
"Favorite files" : "Obľúbené súbory",
"No favorites" : "Žiadne obľúbené",
"More favorites" : "Viac obľúbených",
@@ -91,6 +95,11 @@ OC.L10N.register(
"Renamed \"{oldName}\" to \"{newName}\"" : "Premenované z \"{oldName}\" na \"{newName}\"",
"Rename file" : "Premenovať súbor",
"Folder" : "Priečinok",
"Unknown file type" : "Neznámy typ súboru",
"{ext} image" : "{ext} obrázok",
"{ext} video" : "{ext} video",
"{ext} audio" : "{ext} zvuk",
"{ext} text" : "{ext} text",
"Pending" : "Čaká",
"Unknown date" : "Neznámy dátum",
"Clear filter" : "Vyčistiť filter",
@@ -101,10 +110,14 @@ OC.L10N.register(
"Remove filter" : "Odstrániť filter",
"Appearance" : "Vzhľad",
"Show hidden files" : "Zobraziť skryté súbory",
"Show file type column" : "Zobraziť stĺpec typu súboru",
"Show file extensions" : "Zobraziť prípony súborov",
"Crop image previews" : "Orezať náhľady obrázkov",
"General" : "Všeobecné",
"Sort favorites first" : "Zoradiť od najobľúbenejších",
"Sort folders before files" : "Zoradiť adresáre pred súbormi",
"Enable folder tree view" : "Povoliť zobrazenie stromu priečinkov",
"Default view" : "Predvolené zobrazenie",
"All files" : "Všetky súbory",
"Personal files" : "Osobné súbory",
"Additional settings" : "Ďalšie nastavenia",
@@ -113,16 +126,33 @@ OC.L10N.register(
"Selection" : "Výber",
"Select all files" : "Vybrať všetky súbory",
"Deselect all" : "Odznačiť všetko",
"Select or deselect" : "Vybrať alebo zrušiť výber",
"Select a range" : "Vybrať rozsah",
"Navigation" : "Navigácia",
"Go to parent folder" : "Prejsť do nadriadeného priečinka",
"Go to file above" : "Prejsť na súbor vyššie",
"Go to file below" : "Prejsť na súbor nižšie",
"Go left in grid" : "Prejsť doľava v mriežke",
"Go right in grid" : "Prejsť doprava v mriežke",
"View" : "Zobraziť",
"Toggle grid view" : "Prepnúť zobrazenie mriežky",
"Open file sidebar" : "Otvoriť bočný panel súboru",
"Show those shortcuts" : "Zobraziť klávesové skratky",
"Warnings" : "Upozornenia",
"Warn before changing a file extension" : "Upozorniť pred zmenou prípony súboru",
"Warn before deleting a file" : "Upozorniť pred vymazaním súboru",
"WebDAV URL" : "WebDAV URL",
"Create an app password" : "Vytvoriť heslo pre aplikáciu",
"Required for WebDAV authentication because Two-Factor Authentication is enabled for this account." : "Vyžaduje sa pre autentifikáciu WebDAV, pretože pre tento účet je povolená dvojfaktorová autentifikácia.",
"How to access files using WebDAV" : "Ako získať prístup k súborom pomocou WebDAV",
"Total rows summary" : "Súčet všetkých riadkov",
"Toggle selection for all files and folders" : "Prepnúť výber pre všetky súbory a adresáre",
"Name" : "Názov",
"File type" : "Typ súboru",
"Size" : "Veľkosť",
"{displayName}: failed on some elements" : "{displayName}: zlyhalo na niektorých prvkoch",
"{displayName}: done" : "{displayName}: hotovo",
"{displayName}: failed" : "{displayName}: zlyhalo",
"(selected)" : "(vybrané)",
"List of files and folders." : "Zoznam súborov a priečinkov.",
"You have used your space quota and cannot upload files anymore." : "Už ste využili kapacitu úložného priestoru a nie je možné nahrávať ďalšie súbory.",
@@ -130,6 +160,10 @@ OC.L10N.register(
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Tento zoznam nie je úplne vykreslený z dôvodov výkonu. Súbory budú vykreslené, keď budete prechádzať zoznamom.",
"File not found" : "Súbor nenájdený",
"_{count} selected_::_{count} selected_" : ["{count} vybraný","{count} vybrané","{count} vybraných","{count} vybraných"],
"Search everywhere …" : "Hľadať všade ...",
"Search here …" : "Hľadať tu …",
"Search scope options" : "Možnosti rozsahu vyhľadávania",
"Search here" : "Hľadať tu",
"{usedQuotaByte} used" : "{usedQuotaByte} použitých",
"{used} of {quota} used" : "použitých {used} z {quota}",
"{relative}% used" : "{relative}% použitých",
@@ -141,9 +175,27 @@ OC.L10N.register(
"Create new folder" : "Vytvoriť nový priečinok",
"This name is already in use." : "Toto meno je už používané.",
"Create" : "Vytvoriť",
"Files starting with a dot are hidden by default" : "Súbory, ktoré začínajú bodkou, sú predvolene skryté.",
"Failed to start filename sanitization." : "Nezískalo sa spustenie sanitizácie názvu súboru.",
"Failed to refresh filename sanitization status." : "Nepodarilo sa obnoviť stav sanitácie názvu súboru.",
"Filename sanitization in progress." : "Prebieha sanitácia názvu súboru.",
"Currently {processedUsers} of {totalUsers} accounts are already processed." : "Aktuálne je spracovaných {processedUsers} z {totalUsers} účtov.",
"Preparing …" : "Pripravuje sa …",
"Refresh" : "Obnoviť",
"All files have been santized for Windows filename support." : "Všetky súbory boli upravené na podporu názvov súborov vo Windows.",
"Some files could not be sanitized, please check your logs." : "Niektoré súbory nebolo možné upravené, prosím, skontrolujte svoje protokoly.",
"Sanitization errors" : "Chyby v sanitizácii",
"Not sanitized filenames" : "Nezabezpečené názvy súborov",
"Windows filename support has been enabled." : "Podpora názvov súborov vo Windows bola povolená.",
"While this blocks users from creating new files with unsupported filenames, existing files are not yet renamed and thus still may break sync on Windows." : "Kým toto blokuje používateľov v tvorbe nových súborov s nepodporovanými názvami, existujúce súbory ešte neboli premenované a teda môžu stále spôsobiť problémy so synchronizáciou na Windows.",
"You can trigger a rename of files with invalid filenames, this will be done in the background and may take some time." : "Môžete spustiť premenovanie súborov s neplatnými názvami, tento proces sa vykoná na pozadí a môže trvať nejaký čas.",
"Please note that this may cause high workload on the sync clients." : "Upozorňujeme, že to môže spôsobiť vysokú záťaž pre klientov synchronizácie.",
"Limit" : "Limit",
"This allows to configure how many users should be processed in one background job run." : "Toto umožňuje nastaviť, koľko používateľov by malo byť spracovaných v jednom spustení úlohy na pozadí.",
"Sanitize filenames" : "Vyčistiť názvy súborov",
"(starting)" : "(začína sa)",
"Fill template fields" : "Vyplňte položky šablóny",
"Submitting fields …" : "Odosielanie polí …",
"Submit" : "Odoslať",
"Choose a file or folder to transfer" : "Vyberte súbor alebo priečinok na prevod",
"Transfer" : "Prevod",
@@ -198,7 +250,11 @@ OC.L10N.register(
"Open in files" : "Otvoriť v súboroch",
"File cannot be accessed" : "Súbor nie je možné sprístupniť",
"The file could not be found or you do not have permissions to view it. Ask the sender to share it." : "Súbor sa nenašiel alebo nemáte oprávnenie na jeho zobrazenie. Požiadajte odosielateľa, aby ho sprístupnil.",
"No search results for “{query}”" : "Žiadne výsledky vyhľadávania pre „{query}“",
"Search for files" : "Vyhľadať súbory",
"Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "Povoliť obmedzenie názvov súborov, aby sa zabezpečila synchronizácia súborov so všetkými klientmi. V predvolenom nastavení sú povolené všetky názvy súborov platné pre POSIX (napr. Linux alebo macOS).",
"After enabling the Windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "Po povolení kompatibilných názvov súborov pre Windows už nie je možné upravovať existujúce súbory, ale ich vlastník ich môže premenovať na platné nové názvy.",
"Failed to toggle Windows filename support" : "Nepodarilo sa prepnúť podporu názvov súborov systému Windows",
"Files compatibility" : "Kompatibilita súborov",
"Enforce Windows compatibility" : "Vynútiť kompatibilitu s Windows",
"This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "Tým sa zablokujú názvy súborov, ktoré nie sú platné v systémoch Windows, ako napríklad používanie vyhradených názvov alebo špeciálnych znakov. To však nevynúti kompatibilitu rozlišovania malých a veľkých písmen.",
@@ -208,10 +264,16 @@ OC.L10N.register(
"Create a new file with the selected template" : "Vytvoriť nový súbor pomocou vybranej šablóny",
"Creating file" : "Vytvára sa súbor",
"Save as {displayName}" : "Uložiť ako {displayName}",
"Save as …" : "Uložiť ako ...",
"Converting files …" : "Konverzia súborov ...",
"Failed to convert files: {message}" : "Nepodarilo sa skonvertovať súbory: {message}",
"All files failed to be converted" : "Nepodarilo sa skonvertovať žiadne súbory",
"One file could not be converted: {message}" : "Jeden súbor sa nepodarilo skonvertovať: {message}",
"_%n file could not be converted_::_%n files could not be converted_" : ["%n súbor sa nepodarilo skonvertovať","%n súbory sa nepodarilo skonvertovať","%n súborov sa nepodarilo skonvertovať","%n súborov sa nepodarilo skonvertovať"],
"_%n file converted_::_%n files converted_" : ["%n prevedený súbor","%n prevedených súborov","%n prevedených súborov","%n prevedené súbory"],
"Files converted" : "Súbory boli konvertované",
"Failed to convert files" : "Konverzia súborov zlyhala",
"Converting file …" : "Konverzia súborov ...",
"File successfully converted" : "Súbor bol úspešne skonvertovaný",
"Failed to convert file: {message}" : "Nepodarilo sa skonvertovať súbor: {message}",
"Failed to convert file" : "Konverzia súboru zlyhala",
@@ -231,6 +293,11 @@ OC.L10N.register(
"Confirm deletion" : "Potvrdiť vymazanie",
"Cancel" : "Zrušiť",
"Download" : "Stiahnuť",
"The requested file is not available." : "Požadovaný súbor nie je k dispozícii.",
"The requested files are not available." : "Požadované súbory nie sú k dispozícii.",
"Add or remove favorite" : "Pridať alebo odstrániť obľúbené",
"Moving \"{source}\" to \"{destination}\" …" : "Presúvanie \"{source}\" do \"{destination}\" …",
"Copying \"{source}\" to \"{destination}\" …" : "Kopírovanie \"{source}\" do \"{destination}\" …",
"Destination is not a folder" : "Cieľ nie je priečinok",
"This file/folder is already in that directory" : "Tento súbor/priečinok sa už v danom adresári nachádza",
"You cannot move a file/folder onto itself or into a subfolder of itself" : "Nemôžete presunúť súbor/priečinok do seba alebo do jeho podpriečinka.",
@@ -277,6 +344,7 @@ OC.L10N.register(
"Templates" : "Šablóny",
"New template folder" : "Nový adresár šablóny",
"In folder" : "V adresári",
"Search in all files" : "Hľadať vo všetkých súboroch",
"Search in folder: {folder}" : "Hľadať v adresári: {folder}",
"One of the dropped files could not be processed" : "Jeden z vložených súborov nemohol byť spracovaný.",
"Your browser does not support the Filesystem API. Directories will not be uploaded" : "Váš prehliadač nepodporuje Filesystem API. Adresáre nebudú nahrané",
@@ -295,10 +363,12 @@ OC.L10N.register(
"The name \"{newName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Názov \"{newName}\" sa už používa v priečinku \"{dir}\". Vyberte prosím iný názov.",
"Could not rename \"{oldName}\"" : "Nebolo možné premenovať \"{oldName}\"",
"This operation is forbidden" : "Táto operácia je zakázaná",
"This folder is unavailable, please try again later or contact the administration" : "Táto zložka nie je k dispozícii, skúste to prosím neskôr alebo kontaktujte správu.",
"Storage is temporarily not available" : "Úložisko je dočasne nedostupné",
"Unexpected error: {error}" : "Neočakávaná chyba: {error}",
"_%n file_::_%n files_" : ["%n súbor","%n súbory","%n súborov","%n súborov"],
"_%n folder_::_%n folders_" : ["%n priečinok","%n priečinky","%n priečinkov","%n priečinkov"],
"_%n hidden_::_%n hidden_" : ["%n skrytý","%n skrytých","%n skrytých","%n sktyré"],
"Filename must not be empty." : "Názov súboru nesmie byť prázdny.",
"\"{char}\" is not allowed inside a filename." : "Znak \"{char}\" nie je povolený v názve súboru.",
"\"{segment}\" is a reserved name and not allowed for filenames." : "\"{segment}\" je rezervované slovo a nie je možné ho použiť v názvoch súborov.",
@@ -308,6 +378,7 @@ OC.L10N.register(
"No favorites yet" : "Zatiaľ žiadne obľúbené",
"Files and folders you mark as favorite will show up here" : "Súbory a priečinky označené ako obľúbené budú zobrazené tu",
"List of your files and folders." : "Zoznam vašich súborov a priečinkov.",
"Folder tree" : "Strom priečinkov",
"List of your files and folders that are not shared." : "Zoznam vašich súborov a priečinkov, ktoré nie sú zdieľané.",
"No personal files found" : "Žiadne osobné súbory nenájdené",
"Files that are not shared will show up here." : "Súbory, ktoré nie sú zdieľané, sa tu nezobrazia.",
@@ -316,11 +387,16 @@ OC.L10N.register(
"No recently modified files" : "Žiadne nedávno upravené súbory",
"Files and folders you recently modified will show up here." : "Súbory a priečinky, ktoré ste nedávno upravili sa zobrazia tu",
"Search" : "Hľadať",
"Search results within your files." : "Výsledky vyhľadávania vo vašich súboroch.",
"No entries found in this folder" : "V tomto priečinku nebolo nič nájdené",
"Select all" : "Vybrať všetko",
"Upload too large" : "Nahrávanie je príliš veľké",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Súbory, ktoré sa snažíte nahrať, presahujú maximálnu veľkosť pre nahratie súborov na tento server.",
"%1$s (renamed)" : "%1$s (premenovaný)",
"renamed file" : "premenovaný súbor",
"Upload (max. %s)" : "Nahrať (max. %s)",
"After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "Po povolení názvov súborov kompatibilných s Windows už nie je možné upravovať existujúce súbory, ale ich vlastník ich môže premenovať na platné nové názvy.",
"It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "Je tiež možné automaticky migrovať súbory po povolení tohto nastavenia, prosím, prečítajte si dokumentáciu o príkaze occ.",
"\"{displayName}\" failed on some elements" : "\"{displayName}\" zlyhalo na niektorých prvkoch.",
"\"{displayName}\" batch action executed successfully" : "Hromadná operácia \"{displayName}\" bola úspešne vykonaná",
"\"{displayName}\" action failed" : "\"{displayName}\" akcia zlýhala",
@@ -368,6 +444,9 @@ OC.L10N.register(
"Photos and images" : "Fotky a obrázky",
"New folder creation cancelled" : "Vytvorenie adresára bolo zrušené",
"This directory is unavailable, please check the logs or contact the administrator" : "Priečinok je nedostupný, skontrolujte prosím logy, alebo kontaktujte správcu",
"All folders" : "Všetky adresáre"
"All folders" : "Všetky adresáre",
"Search everywhere …" : "Hľadať všade ...",
"Search here …" : "Hľadať tu …",
"Preparing …" : "Pripravuje sa …"
},
"nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n >= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);");
+80 -1
View File
@@ -49,6 +49,10 @@
"You do not have permission to create a file at the specified location" : "Nemáte oprávnenie vytvoriť súbor v zadanom umiestnení",
"The file could not be converted." : "Súbor nemohol byť skonvertovaný.",
"Could not get relative path to converted file" : "Nepodarilo sa získať relatícnu cestu ku skonvertovanému súboru",
"Limit must be a positive integer." : "Limit musí byť kladné celé číslo.",
"The replacement character may only be a single character." : "Zástupný znak môže byť iba jeden znak.",
"Filename sanitization already started." : "Sanitizácia názvu súboru bola už zahájená.",
"No filename sanitization in progress." : "Žiadna sanitácia názvu súboru neprebieha.",
"Favorite files" : "Obľúbené súbory",
"No favorites" : "Žiadne obľúbené",
"More favorites" : "Viac obľúbených",
@@ -89,6 +93,11 @@
"Renamed \"{oldName}\" to \"{newName}\"" : "Premenované z \"{oldName}\" na \"{newName}\"",
"Rename file" : "Premenovať súbor",
"Folder" : "Priečinok",
"Unknown file type" : "Neznámy typ súboru",
"{ext} image" : "{ext} obrázok",
"{ext} video" : "{ext} video",
"{ext} audio" : "{ext} zvuk",
"{ext} text" : "{ext} text",
"Pending" : "Čaká",
"Unknown date" : "Neznámy dátum",
"Clear filter" : "Vyčistiť filter",
@@ -99,10 +108,14 @@
"Remove filter" : "Odstrániť filter",
"Appearance" : "Vzhľad",
"Show hidden files" : "Zobraziť skryté súbory",
"Show file type column" : "Zobraziť stĺpec typu súboru",
"Show file extensions" : "Zobraziť prípony súborov",
"Crop image previews" : "Orezať náhľady obrázkov",
"General" : "Všeobecné",
"Sort favorites first" : "Zoradiť od najobľúbenejších",
"Sort folders before files" : "Zoradiť adresáre pred súbormi",
"Enable folder tree view" : "Povoliť zobrazenie stromu priečinkov",
"Default view" : "Predvolené zobrazenie",
"All files" : "Všetky súbory",
"Personal files" : "Osobné súbory",
"Additional settings" : "Ďalšie nastavenia",
@@ -111,16 +124,33 @@
"Selection" : "Výber",
"Select all files" : "Vybrať všetky súbory",
"Deselect all" : "Odznačiť všetko",
"Select or deselect" : "Vybrať alebo zrušiť výber",
"Select a range" : "Vybrať rozsah",
"Navigation" : "Navigácia",
"Go to parent folder" : "Prejsť do nadriadeného priečinka",
"Go to file above" : "Prejsť na súbor vyššie",
"Go to file below" : "Prejsť na súbor nižšie",
"Go left in grid" : "Prejsť doľava v mriežke",
"Go right in grid" : "Prejsť doprava v mriežke",
"View" : "Zobraziť",
"Toggle grid view" : "Prepnúť zobrazenie mriežky",
"Open file sidebar" : "Otvoriť bočný panel súboru",
"Show those shortcuts" : "Zobraziť klávesové skratky",
"Warnings" : "Upozornenia",
"Warn before changing a file extension" : "Upozorniť pred zmenou prípony súboru",
"Warn before deleting a file" : "Upozorniť pred vymazaním súboru",
"WebDAV URL" : "WebDAV URL",
"Create an app password" : "Vytvoriť heslo pre aplikáciu",
"Required for WebDAV authentication because Two-Factor Authentication is enabled for this account." : "Vyžaduje sa pre autentifikáciu WebDAV, pretože pre tento účet je povolená dvojfaktorová autentifikácia.",
"How to access files using WebDAV" : "Ako získať prístup k súborom pomocou WebDAV",
"Total rows summary" : "Súčet všetkých riadkov",
"Toggle selection for all files and folders" : "Prepnúť výber pre všetky súbory a adresáre",
"Name" : "Názov",
"File type" : "Typ súboru",
"Size" : "Veľkosť",
"{displayName}: failed on some elements" : "{displayName}: zlyhalo na niektorých prvkoch",
"{displayName}: done" : "{displayName}: hotovo",
"{displayName}: failed" : "{displayName}: zlyhalo",
"(selected)" : "(vybrané)",
"List of files and folders." : "Zoznam súborov a priečinkov.",
"You have used your space quota and cannot upload files anymore." : "Už ste využili kapacitu úložného priestoru a nie je možné nahrávať ďalšie súbory.",
@@ -128,6 +158,10 @@
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Tento zoznam nie je úplne vykreslený z dôvodov výkonu. Súbory budú vykreslené, keď budete prechádzať zoznamom.",
"File not found" : "Súbor nenájdený",
"_{count} selected_::_{count} selected_" : ["{count} vybraný","{count} vybrané","{count} vybraných","{count} vybraných"],
"Search everywhere …" : "Hľadať všade ...",
"Search here …" : "Hľadať tu …",
"Search scope options" : "Možnosti rozsahu vyhľadávania",
"Search here" : "Hľadať tu",
"{usedQuotaByte} used" : "{usedQuotaByte} použitých",
"{used} of {quota} used" : "použitých {used} z {quota}",
"{relative}% used" : "{relative}% použitých",
@@ -139,9 +173,27 @@
"Create new folder" : "Vytvoriť nový priečinok",
"This name is already in use." : "Toto meno je už používané.",
"Create" : "Vytvoriť",
"Files starting with a dot are hidden by default" : "Súbory, ktoré začínajú bodkou, sú predvolene skryté.",
"Failed to start filename sanitization." : "Nezískalo sa spustenie sanitizácie názvu súboru.",
"Failed to refresh filename sanitization status." : "Nepodarilo sa obnoviť stav sanitácie názvu súboru.",
"Filename sanitization in progress." : "Prebieha sanitácia názvu súboru.",
"Currently {processedUsers} of {totalUsers} accounts are already processed." : "Aktuálne je spracovaných {processedUsers} z {totalUsers} účtov.",
"Preparing …" : "Pripravuje sa …",
"Refresh" : "Obnoviť",
"All files have been santized for Windows filename support." : "Všetky súbory boli upravené na podporu názvov súborov vo Windows.",
"Some files could not be sanitized, please check your logs." : "Niektoré súbory nebolo možné upravené, prosím, skontrolujte svoje protokoly.",
"Sanitization errors" : "Chyby v sanitizácii",
"Not sanitized filenames" : "Nezabezpečené názvy súborov",
"Windows filename support has been enabled." : "Podpora názvov súborov vo Windows bola povolená.",
"While this blocks users from creating new files with unsupported filenames, existing files are not yet renamed and thus still may break sync on Windows." : "Kým toto blokuje používateľov v tvorbe nových súborov s nepodporovanými názvami, existujúce súbory ešte neboli premenované a teda môžu stále spôsobiť problémy so synchronizáciou na Windows.",
"You can trigger a rename of files with invalid filenames, this will be done in the background and may take some time." : "Môžete spustiť premenovanie súborov s neplatnými názvami, tento proces sa vykoná na pozadí a môže trvať nejaký čas.",
"Please note that this may cause high workload on the sync clients." : "Upozorňujeme, že to môže spôsobiť vysokú záťaž pre klientov synchronizácie.",
"Limit" : "Limit",
"This allows to configure how many users should be processed in one background job run." : "Toto umožňuje nastaviť, koľko používateľov by malo byť spracovaných v jednom spustení úlohy na pozadí.",
"Sanitize filenames" : "Vyčistiť názvy súborov",
"(starting)" : "(začína sa)",
"Fill template fields" : "Vyplňte položky šablóny",
"Submitting fields …" : "Odosielanie polí …",
"Submit" : "Odoslať",
"Choose a file or folder to transfer" : "Vyberte súbor alebo priečinok na prevod",
"Transfer" : "Prevod",
@@ -196,7 +248,11 @@
"Open in files" : "Otvoriť v súboroch",
"File cannot be accessed" : "Súbor nie je možné sprístupniť",
"The file could not be found or you do not have permissions to view it. Ask the sender to share it." : "Súbor sa nenašiel alebo nemáte oprávnenie na jeho zobrazenie. Požiadajte odosielateľa, aby ho sprístupnil.",
"No search results for “{query}”" : "Žiadne výsledky vyhľadávania pre „{query}“",
"Search for files" : "Vyhľadať súbory",
"Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "Povoliť obmedzenie názvov súborov, aby sa zabezpečila synchronizácia súborov so všetkými klientmi. V predvolenom nastavení sú povolené všetky názvy súborov platné pre POSIX (napr. Linux alebo macOS).",
"After enabling the Windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "Po povolení kompatibilných názvov súborov pre Windows už nie je možné upravovať existujúce súbory, ale ich vlastník ich môže premenovať na platné nové názvy.",
"Failed to toggle Windows filename support" : "Nepodarilo sa prepnúť podporu názvov súborov systému Windows",
"Files compatibility" : "Kompatibilita súborov",
"Enforce Windows compatibility" : "Vynútiť kompatibilitu s Windows",
"This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "Tým sa zablokujú názvy súborov, ktoré nie sú platné v systémoch Windows, ako napríklad používanie vyhradených názvov alebo špeciálnych znakov. To však nevynúti kompatibilitu rozlišovania malých a veľkých písmen.",
@@ -206,10 +262,16 @@
"Create a new file with the selected template" : "Vytvoriť nový súbor pomocou vybranej šablóny",
"Creating file" : "Vytvára sa súbor",
"Save as {displayName}" : "Uložiť ako {displayName}",
"Save as …" : "Uložiť ako ...",
"Converting files …" : "Konverzia súborov ...",
"Failed to convert files: {message}" : "Nepodarilo sa skonvertovať súbory: {message}",
"All files failed to be converted" : "Nepodarilo sa skonvertovať žiadne súbory",
"One file could not be converted: {message}" : "Jeden súbor sa nepodarilo skonvertovať: {message}",
"_%n file could not be converted_::_%n files could not be converted_" : ["%n súbor sa nepodarilo skonvertovať","%n súbory sa nepodarilo skonvertovať","%n súborov sa nepodarilo skonvertovať","%n súborov sa nepodarilo skonvertovať"],
"_%n file converted_::_%n files converted_" : ["%n prevedený súbor","%n prevedených súborov","%n prevedených súborov","%n prevedené súbory"],
"Files converted" : "Súbory boli konvertované",
"Failed to convert files" : "Konverzia súborov zlyhala",
"Converting file …" : "Konverzia súborov ...",
"File successfully converted" : "Súbor bol úspešne skonvertovaný",
"Failed to convert file: {message}" : "Nepodarilo sa skonvertovať súbor: {message}",
"Failed to convert file" : "Konverzia súboru zlyhala",
@@ -229,6 +291,11 @@
"Confirm deletion" : "Potvrdiť vymazanie",
"Cancel" : "Zrušiť",
"Download" : "Stiahnuť",
"The requested file is not available." : "Požadovaný súbor nie je k dispozícii.",
"The requested files are not available." : "Požadované súbory nie sú k dispozícii.",
"Add or remove favorite" : "Pridať alebo odstrániť obľúbené",
"Moving \"{source}\" to \"{destination}\" …" : "Presúvanie \"{source}\" do \"{destination}\" …",
"Copying \"{source}\" to \"{destination}\" …" : "Kopírovanie \"{source}\" do \"{destination}\" …",
"Destination is not a folder" : "Cieľ nie je priečinok",
"This file/folder is already in that directory" : "Tento súbor/priečinok sa už v danom adresári nachádza",
"You cannot move a file/folder onto itself or into a subfolder of itself" : "Nemôžete presunúť súbor/priečinok do seba alebo do jeho podpriečinka.",
@@ -275,6 +342,7 @@
"Templates" : "Šablóny",
"New template folder" : "Nový adresár šablóny",
"In folder" : "V adresári",
"Search in all files" : "Hľadať vo všetkých súboroch",
"Search in folder: {folder}" : "Hľadať v adresári: {folder}",
"One of the dropped files could not be processed" : "Jeden z vložených súborov nemohol byť spracovaný.",
"Your browser does not support the Filesystem API. Directories will not be uploaded" : "Váš prehliadač nepodporuje Filesystem API. Adresáre nebudú nahrané",
@@ -293,10 +361,12 @@
"The name \"{newName}\" is already used in the folder \"{dir}\". Please choose a different name." : "Názov \"{newName}\" sa už používa v priečinku \"{dir}\". Vyberte prosím iný názov.",
"Could not rename \"{oldName}\"" : "Nebolo možné premenovať \"{oldName}\"",
"This operation is forbidden" : "Táto operácia je zakázaná",
"This folder is unavailable, please try again later or contact the administration" : "Táto zložka nie je k dispozícii, skúste to prosím neskôr alebo kontaktujte správu.",
"Storage is temporarily not available" : "Úložisko je dočasne nedostupné",
"Unexpected error: {error}" : "Neočakávaná chyba: {error}",
"_%n file_::_%n files_" : ["%n súbor","%n súbory","%n súborov","%n súborov"],
"_%n folder_::_%n folders_" : ["%n priečinok","%n priečinky","%n priečinkov","%n priečinkov"],
"_%n hidden_::_%n hidden_" : ["%n skrytý","%n skrytých","%n skrytých","%n sktyré"],
"Filename must not be empty." : "Názov súboru nesmie byť prázdny.",
"\"{char}\" is not allowed inside a filename." : "Znak \"{char}\" nie je povolený v názve súboru.",
"\"{segment}\" is a reserved name and not allowed for filenames." : "\"{segment}\" je rezervované slovo a nie je možné ho použiť v názvoch súborov.",
@@ -306,6 +376,7 @@
"No favorites yet" : "Zatiaľ žiadne obľúbené",
"Files and folders you mark as favorite will show up here" : "Súbory a priečinky označené ako obľúbené budú zobrazené tu",
"List of your files and folders." : "Zoznam vašich súborov a priečinkov.",
"Folder tree" : "Strom priečinkov",
"List of your files and folders that are not shared." : "Zoznam vašich súborov a priečinkov, ktoré nie sú zdieľané.",
"No personal files found" : "Žiadne osobné súbory nenájdené",
"Files that are not shared will show up here." : "Súbory, ktoré nie sú zdieľané, sa tu nezobrazia.",
@@ -314,11 +385,16 @@
"No recently modified files" : "Žiadne nedávno upravené súbory",
"Files and folders you recently modified will show up here." : "Súbory a priečinky, ktoré ste nedávno upravili sa zobrazia tu",
"Search" : "Hľadať",
"Search results within your files." : "Výsledky vyhľadávania vo vašich súboroch.",
"No entries found in this folder" : "V tomto priečinku nebolo nič nájdené",
"Select all" : "Vybrať všetko",
"Upload too large" : "Nahrávanie je príliš veľké",
"The files you are trying to upload exceed the maximum size for file uploads on this server." : "Súbory, ktoré sa snažíte nahrať, presahujú maximálnu veľkosť pre nahratie súborov na tento server.",
"%1$s (renamed)" : "%1$s (premenovaný)",
"renamed file" : "premenovaný súbor",
"Upload (max. %s)" : "Nahrať (max. %s)",
"After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "Po povolení názvov súborov kompatibilných s Windows už nie je možné upravovať existujúce súbory, ale ich vlastník ich môže premenovať na platné nové názvy.",
"It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "Je tiež možné automaticky migrovať súbory po povolení tohto nastavenia, prosím, prečítajte si dokumentáciu o príkaze occ.",
"\"{displayName}\" failed on some elements" : "\"{displayName}\" zlyhalo na niektorých prvkoch.",
"\"{displayName}\" batch action executed successfully" : "Hromadná operácia \"{displayName}\" bola úspešne vykonaná",
"\"{displayName}\" action failed" : "\"{displayName}\" akcia zlýhala",
@@ -366,6 +442,9 @@
"Photos and images" : "Fotky a obrázky",
"New folder creation cancelled" : "Vytvorenie adresára bolo zrušené",
"This directory is unavailable, please check the logs or contact the administrator" : "Priečinok je nedostupný, skontrolujte prosím logy, alebo kontaktujte správcu",
"All folders" : "Všetky adresáre"
"All folders" : "Všetky adresáre",
"Search everywhere …" : "Hľadať všade ...",
"Search here …" : "Hľadať tu …",
"Preparing …" : "Pripravuje sa …"
},"pluralForm" :"nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n >= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);"
}
+1 -1
View File
@@ -375,7 +375,7 @@ OC.L10N.register(
"\"{extension}\" is not an allowed filetype." : "\"{extension}\" не є дозволеним типом файлів.",
"Filenames must not end with \"{extension}\"." : "Імена файлів не мають закінчуватися на \"{extension}\".",
"List of favorite files and folders." : "Список файлів та каталогів із зірочкою.",
"No favorites yet" : "Поки немає нічого, позначеного зірочкою",
"No favorites yet" : "Відсутні файли чи каталоги, позначені зірочкою",
"Files and folders you mark as favorite will show up here" : "Файли та каталоги із зірочкою з’являться тут",
"List of your files and folders." : "Список ваших файлів та каталогів.",
"Folder tree" : "Дерево каталогів",
+1 -1
View File
@@ -373,7 +373,7 @@
"\"{extension}\" is not an allowed filetype." : "\"{extension}\" не є дозволеним типом файлів.",
"Filenames must not end with \"{extension}\"." : "Імена файлів не мають закінчуватися на \"{extension}\".",
"List of favorite files and folders." : "Список файлів та каталогів із зірочкою.",
"No favorites yet" : "Поки немає нічого, позначеного зірочкою",
"No favorites yet" : "Відсутні файли чи каталоги, позначені зірочкою",
"Files and folders you mark as favorite will show up here" : "Файли та каталоги із зірочкою з’являться тут",
"List of your files and folders." : "Список ваших файлів та каталогів.",
"Folder tree" : "Дерево каталогів",
@@ -198,7 +198,6 @@ class ApiController extends Controller {
IShare::TYPE_EMAIL,
IShare::TYPE_ROOM,
IShare::TYPE_DECK,
IShare::TYPE_SCIENCEMESH,
];
$shareTypes = [];
@@ -328,7 +328,6 @@ class OwnershipTransferService {
IShare::TYPE_EMAIL,
IShare::TYPE_CIRCLE,
IShare::TYPE_DECK,
IShare::TYPE_SCIENCEMESH,
];
foreach ($supportedShareTypes as $shareType) {
+1 -1
View File
@@ -367,7 +367,7 @@ export default defineComponent({
const metaKeyPressed = event.ctrlKey || event.metaKey || event.button === 1
if (metaKeyPressed || !this.defaultFileAction) {
// If no download permission, then we can not allow to download (direct link) the files
if (isPublicShare() && !isDownloadable(this.source)) {
if (!isDownloadable(this.source)) {
return
}
@@ -41,7 +41,7 @@ describe('Composables: useNavigation', () => {
it('should return already active navigation', async () => {
const view = new nextcloudFiles.View({ getContents: () => Promise.reject(new Error()), icon: '<svg></svg>', id: 'view-1', name: 'My View 1', order: 0 })
navigation.register(view)
navigation.setActive(view)
navigation.setActive(view.id)
// Now the navigation is already set it should take the active navigation
const wrapper = mount(TestComponent)
expect((wrapper.vm as unknown as { currentView: View | null }).currentView).toBe(view)
@@ -55,7 +55,7 @@ describe('Composables: useNavigation', () => {
// no active navigation
expect((wrapper.vm as unknown as { currentView: View | null }).currentView).toBe(null)
navigation.setActive(view)
navigation.setActive(view.id)
// Now the navigation is set it should take the active navigation
expect((wrapper.vm as unknown as { currentView: View | null }).currentView).toBe(view)
})
+3 -4
View File
@@ -10,10 +10,9 @@ import type { RootDirectory } from './DropServiceUtils.ts'
import { showError, showInfo, showSuccess, showWarning } from '@nextcloud/dialogs'
import { NodeStatus } from '@nextcloud/files'
import { getRootPath } from '@nextcloud/files/dav'
import { translate as t } from '@nextcloud/l10n'
import { joinPaths } from '@nextcloud/paths'
import { t } from '@nextcloud/l10n'
import { join } from '@nextcloud/paths'
import { getUploader, hasConflict } from '@nextcloud/upload'
import { join } from 'path'
import Vue from 'vue'
import { handleCopyMoveNodeTo } from '../actions/moveOrCopyAction.ts'
import { MoveCopyAction } from '../actions/moveOrCopyActionUtils.ts'
@@ -126,7 +125,7 @@ export async function onDropExternalFiles(root: RootDirectory, destination: Fold
// If the file is a directory, we need to create it first
// then browse its tree and upload its contents.
if (file instanceof Directory) {
const absolutePath = joinPaths(getRootPath(), destination.path, relativePath)
const absolutePath = join(getRootPath(), destination.path, relativePath)
try {
logger.debug('Processing directory', { relativePath })
await createDirectoryIfNotExists(absolutePath)
+31 -27
View File
@@ -1,45 +1,49 @@
/**
/*!
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import type { ContentsWithRoot } from '@nextcloud/files'
import { getCurrentUser } from '@nextcloud/auth'
import { Folder, Permission } from '@nextcloud/files'
import { getFavoriteNodes, getRemoteURL, getRootPath } from '@nextcloud/files/dav'
import { CancelablePromise } from 'cancelable-promise'
import logger from '../logger.ts'
import { getContents as filesContents } from './Files.ts'
import { client } from './WebdavClient.ts'
/**
* Get the contents for the favorites view
*
* @param path
* @param path - The path to get the contents for
* @param options - Additional options
* @param options.signal - Optional AbortSignal to cancel the request
* @return A promise resolving to the contents with root folder
*/
export function getContents(path = '/'): CancelablePromise<ContentsWithRoot> {
export async function getContents(path = '/', options: { signal: AbortSignal }): Promise<ContentsWithRoot> {
// We only filter root files for favorites, for subfolders we can simply reuse the files contents
if (path !== '/') {
return filesContents(path)
if (path && path !== '/') {
return filesContents(path, options)
}
return new CancelablePromise((resolve, reject, cancel) => {
const promise = getFavoriteNodes(client)
.catch(reject)
.then((contents) => {
if (!contents) {
reject()
return
}
resolve({
contents,
folder: new Folder({
id: 0,
source: `${getRemoteURL()}${getRootPath()}`,
root: getRootPath(),
owner: getCurrentUser()?.uid || null,
permissions: Permission.READ,
}),
})
})
cancel(() => promise.cancel())
})
try {
const contents = await getFavoriteNodes({ client, signal: options.signal })
return {
contents,
folder: new Folder({
id: 0,
source: `${getRemoteURL()}${getRootPath()}`,
root: getRootPath(),
owner: getCurrentUser()?.uid || null,
permissions: Permission.READ,
}),
}
} catch (error) {
if (options.signal.aborted) {
logger.debug('Favorite nodes request was aborted')
throw new DOMException('Aborted', 'AbortError')
}
logger.error('Failed to load favorite nodes via WebDAV', { error })
throw error
}
}
+33 -45
View File
@@ -6,7 +6,6 @@ import type { ContentsWithRoot, File, Folder } from '@nextcloud/files'
import type { FileStat, ResponseDataDetailed } from 'webdav'
import { getDefaultPropfind, getRootPath, resultToNode } from '@nextcloud/files/dav'
import { CancelablePromise } from 'cancelable-promise'
import { join } from 'path'
import logger from '../logger.ts'
import { useFilesStore } from '../store/files.ts'
@@ -20,66 +19,55 @@ import { searchNodes } from './WebDavSearch.ts'
* This also allows to fetch local search results when the user is currently filtering.
*
* @param path - The path to query
* @param options - Options
* @param options.signal - Abort signal to cancel the request
*/
export function getContents(path = '/'): CancelablePromise<ContentsWithRoot> {
const controller = new AbortController()
export async function getContents(path = '/', options?: { signal: AbortSignal }): Promise<ContentsWithRoot> {
const searchStore = useSearchStore(getPinia())
if (searchStore.query.length >= 3) {
return new CancelablePromise((resolve, reject, cancel) => {
cancel(() => controller.abort())
getLocalSearch(path, searchStore.query, controller.signal)
.then(resolve)
.catch(reject)
})
} else {
return defaultGetContents(path)
if (searchStore.query.length < 3) {
return await defaultGetContents(path, options)
}
return await getLocalSearch(path, searchStore.query, options?.signal)
}
/**
* Generic `getContents` implementation for the users files.
*
* @param path - The path to get the contents
* @param options - Options
* @param options.signal - Abort signal to cancel the request
*/
export function defaultGetContents(path: string): CancelablePromise<ContentsWithRoot> {
export async function defaultGetContents(path: string, options?: { signal: AbortSignal }): Promise<ContentsWithRoot> {
path = join(getRootPath(), path)
const controller = new AbortController()
const propfindPayload = getDefaultPropfind()
return new CancelablePromise(async (resolve, reject, onCancel) => {
onCancel(() => controller.abort())
const contentsResponse = await client.getDirectoryContents(path, {
details: true,
data: propfindPayload,
includeSelf: true,
signal: options?.signal,
}) as ResponseDataDetailed<FileStat[]>
try {
const contentsResponse = await client.getDirectoryContents(path, {
details: true,
data: propfindPayload,
includeSelf: true,
signal: controller.signal,
}) as ResponseDataDetailed<FileStat[]>
const root = contentsResponse.data[0]!
const contents = contentsResponse.data.slice(1)
if (root?.filename !== path && `${root?.filename}/` !== path) {
logger.debug(`Exepected "${path}" but got filename "${root.filename}" instead.`)
throw new Error('Root node does not match requested path')
}
const root = contentsResponse.data[0]
const contents = contentsResponse.data.slice(1)
if (root?.filename !== path && `${root?.filename}/` !== path) {
logger.debug(`Exepected "${path}" but got filename "${root.filename}" instead.`)
throw new Error('Root node does not match requested path')
return {
folder: resultToNode(root) as Folder,
contents: contents.map((result) => {
try {
return resultToNode(result)
} catch (error) {
logger.error(`Invalid node detected '${result.basename}'`, { error })
return null
}
resolve({
folder: resultToNode(root) as Folder,
contents: contents.map((result) => {
try {
return resultToNode(result)
} catch (error) {
logger.error(`Invalid node detected '${result.basename}'`, { error })
return null
}
}).filter(Boolean) as File[],
})
} catch (error) {
reject(error)
}
})
}).filter(Boolean) as File[],
}
}
/**
@@ -89,7 +77,7 @@ export function defaultGetContents(path: string): CancelablePromise<ContentsWith
* @param query - The current search query
* @param signal - The aboort signal
*/
async function getLocalSearch(path: string, query: string, signal: AbortSignal): Promise<ContentsWithRoot> {
async function getLocalSearch(path: string, query: string, signal?: AbortSignal): Promise<ContentsWithRoot> {
const filesStore = useFilesStore(getPinia())
let folder = filesStore.getDirectoryByPath('files', path)
if (!folder) {
+14 -11
View File
@@ -4,13 +4,12 @@
*/
import type { ContentsWithRoot } from '@nextcloud/files'
import type { CancelablePromise } from 'cancelable-promise'
import { getCurrentUser } from '@nextcloud/auth'
import axios from '@nextcloud/axios'
import { getRemoteURL } from '@nextcloud/files/dav'
import { getCanonicalLocale, getLanguage } from '@nextcloud/l10n'
import { dirname, encodePath, joinPaths } from '@nextcloud/paths'
import { dirname, encodePath, join } from '@nextcloud/paths'
import { generateOcsUrl } from '@nextcloud/router'
import { getContents as getFiles } from './Files.ts'
@@ -47,15 +46,16 @@ const collator = Intl.Collator(
const compareNodes = (a: TreeNodeData, b: TreeNodeData) => collator.compare(a.displayName ?? a.basename, b.displayName ?? b.basename)
/**
* Get all tree nodes recursively
*
* @param tree
* @param currentPath
* @param nodes
* @param tree - The tree to process
* @param currentPath - The current path
* @param nodes - The nodes collected so far
*/
function getTreeNodes(tree: Tree, currentPath: string = '/', nodes: TreeNode[] = []): TreeNode[] {
const sortedTree = tree.toSorted(compareNodes)
for (const { id, basename, displayName, children } of sortedTree) {
const path = joinPaths(currentPath, basename)
const path = join(currentPath, basename)
const source = `${sourceRoot}${path}`
const node: TreeNode = {
source,
@@ -76,9 +76,10 @@ function getTreeNodes(tree: Tree, currentPath: string = '/', nodes: TreeNode[] =
}
/**
* Get folder tree nodes
*
* @param path
* @param depth
* @param path - The path to get the tree from
* @param depth - The depth to fetch
*/
export async function getFolderTreeNodes(path: string = '/', depth: number = 1): Promise<TreeNode[]> {
const { data: tree } = await axios.get<Tree>(generateOcsUrl('/apps/files/api/v1/folder-tree'), {
@@ -88,11 +89,12 @@ export async function getFolderTreeNodes(path: string = '/', depth: number = 1):
return nodes
}
export const getContents = (path: string): CancelablePromise<ContentsWithRoot> => getFiles(path)
export const getContents = (path: string, options: { signal: AbortSignal }): Promise<ContentsWithRoot> => getFiles(path, options)
/**
* Encode source URL
*
* @param source
* @param source - The source URL
*/
export function encodeSource(source: string): string {
const { origin } = new URL(source)
@@ -100,8 +102,9 @@ export function encodeSource(source: string): string {
}
/**
* Get parent source URL
*
* @param source
* @param source - The source URL
*/
export function getSourceParent(source: string): string {
const parent = dirname(source)
+7 -4
View File
@@ -4,7 +4,6 @@
*/
import type { ContentsWithRoot, Node } from '@nextcloud/files'
import type { CancelablePromise } from 'cancelable-promise'
import { getCurrentUser } from '@nextcloud/auth'
import { getContents as getFiles } from './Files.ts'
@@ -31,13 +30,17 @@ export function isPersonalFile(node: Node): boolean {
}
/**
* Get personal files from a given path
*
* @param path
* @param path - The path to get the personal files from
* @param options - Options
* @param options.signal - Abort signal to cancel the request
* @return A promise that resolves to the personal files
*/
export function getContents(path: string = '/'): CancelablePromise<ContentsWithRoot> {
export function getContents(path: string = '/', options: { signal: AbortSignal }): Promise<ContentsWithRoot> {
// get all the files from the current path as a cancellable promise
// then filter the files that the user does not own, or has shared / is a group folder
return getFiles(path)
return getFiles(path, options)
.then((content) => {
content.contents = content.contents.filter(isPersonalFile)
return content
+13 -10
View File
@@ -8,7 +8,7 @@ import type { ResponseDataDetailed, SearchResult } from 'webdav'
import { getCurrentUser } from '@nextcloud/auth'
import { Folder, Permission } from '@nextcloud/files'
import { getRecentSearch, getRemoteURL, getRootPath, resultToNode } from '@nextcloud/files/dav'
import { CancelablePromise } from 'cancelable-promise'
import logger from '../logger.ts'
import { getPinia } from '../store/index.ts'
import { useUserConfigStore } from '../store/userconfig.ts'
import { client } from './WebdavClient.ts'
@@ -22,8 +22,10 @@ const lastTwoWeeksTimestamp = Math.round((Date.now() / 1000) - (60 * 60 * 24 * 1
* If hidden files are not shown, then also recently changed files *in* hidden directories are filtered.
*
* @param path Path to search for recent changes
* @param options Options including abort signal
* @param options.signal Abort signal to cancel the request
*/
export function getContents(path = '/'): CancelablePromise<ContentsWithRoot> {
export async function getContents(path = '/', options: { signal: AbortSignal }): Promise<ContentsWithRoot> {
const store = useUserConfigStore(getPinia())
/**
@@ -35,10 +37,9 @@ export function getContents(path = '/'): CancelablePromise<ContentsWithRoot> {
|| store.userConfig.show_hidden // If configured to show hidden files we can early return
|| !node.dirname.split('/').some((dir) => dir.startsWith('.')) // otherwise only include the file if non of the parent directories is hidden
const controller = new AbortController()
const handler = async () => {
try {
const contentsResponse = await client.search('/', {
signal: controller.signal,
signal: options.signal,
details: true,
data: getRecentSearch(lastTwoWeeksTimestamp),
}) as ResponseDataDetailed<SearchResult>
@@ -61,10 +62,12 @@ export function getContents(path = '/'): CancelablePromise<ContentsWithRoot> {
}),
contents,
}
} catch (error) {
if (options.signal.aborted) {
logger.info('Fetching recent files aborted')
throw new DOMException('Aborted', 'AbortError')
}
logger.error('Failed to fetch recent files', { error })
throw error
}
return new CancelablePromise(async (resolve, reject, cancel) => {
cancel(() => controller.abort())
resolve(handler())
})
}
+5 -4
View File
@@ -35,12 +35,12 @@ describe('Search service', () => {
searchNodes.mockImplementationOnce(() => {
throw new Error('expected error')
})
expect(getContents).rejects.toThrow('expected error')
expect(() => getContents('', { signal: new AbortController().signal })).rejects.toThrow('expected error')
})
it('returns the search results and a fake root', async () => {
searchNodes.mockImplementationOnce(() => [fakeFolder])
const { contents, folder } = await getContents()
const { contents, folder } = await getContents('', { signal: new AbortController().signal })
expect(searchNodes).toHaveBeenCalledOnce()
expect(contents).toHaveLength(1)
@@ -57,8 +57,9 @@ describe('Search service', () => {
return []
})
const content = getContents()
content.cancel()
const controller = new AbortController()
getContents('', { signal: controller.signal })
controller.abort()
// its cancelled thus the promise returns the event
const event = await promise
+24 -22
View File
@@ -8,7 +8,6 @@ import type { ContentsWithRoot } from '@nextcloud/files'
import { getCurrentUser } from '@nextcloud/auth'
import { Folder, Permission } from '@nextcloud/files'
import { defaultRemoteURL, getRootPath } from '@nextcloud/files/dav'
import { CancelablePromise } from 'cancelable-promise'
import logger from '../logger.ts'
import { getPinia } from '../store/index.ts'
import { useSearchStore } from '../store/search.ts'
@@ -16,29 +15,32 @@ import { searchNodes } from './WebDavSearch.ts'
/**
* Get the contents for a search view
*
* @param path - (not used)
* @param options - Options including abort signal
* @param options.signal - Abort signal to cancel the request
*/
export function getContents(): CancelablePromise<ContentsWithRoot> {
const controller = new AbortController()
export async function getContents(path, options: { signal: AbortSignal }): Promise<ContentsWithRoot> {
const searchStore = useSearchStore(getPinia())
return new CancelablePromise<ContentsWithRoot>(async (resolve, reject, cancel) => {
cancel(() => controller.abort())
try {
const contents = await searchNodes(searchStore.query, { signal: controller.signal })
resolve({
contents,
folder: new Folder({
id: 0,
source: `${defaultRemoteURL}${getRootPath()}}#search`,
owner: getCurrentUser()!.uid,
permissions: Permission.READ,
root: getRootPath(),
}),
})
} catch (error) {
logger.error('Failed to fetch search results', { error })
reject(error)
try {
const contents = await searchNodes(searchStore.query, { signal: options.signal })
return {
contents,
folder: new Folder({
id: 0,
source: `${defaultRemoteURL}${getRootPath()}}#search`,
owner: getCurrentUser()!.uid,
permissions: Permission.READ,
root: getRootPath(),
}),
}
})
} catch (error) {
if (options.signal.aborted) {
logger.info('Fetching search results aborted')
throw new DOMException('Aborted', 'AbortError')
}
logger.error('Failed to fetch search results', { error })
throw error
}
}
+2 -2
View File
@@ -8,8 +8,8 @@ import axios, { isAxiosError } from '@nextcloud/axios'
import { emit, subscribe } from '@nextcloud/event-bus'
import { FileType, NodeStatus } from '@nextcloud/files'
import { t } from '@nextcloud/l10n'
import { basename, dirname, extname } from '@nextcloud/paths'
import { spawnDialog } from '@nextcloud/vue/functions/dialog'
import { basename, dirname, extname } from 'path'
import { defineStore } from 'pinia'
import Vue, { defineAsyncComponent, ref } from 'vue'
import logger from '../logger.ts'
@@ -36,7 +36,7 @@ export const useRenamingStore = defineStore('renaming', () => {
* This will rename the node set as `renamingNode` to the configured new name `newName`.
*
* @return true if success, false if skipped (e.g. new and old name are the same)
* @throws Error if renaming fails, details are set in the error message
* @throws {Error} if renaming fails, details are set in the error message
*/
async function rename(): Promise<boolean> {
if (renamingNode.value === undefined) {
+8 -6
View File
@@ -161,7 +161,6 @@
<script lang="ts">
import type { ContentsWithRoot, FileListAction, INode, Node } from '@nextcloud/files'
import type { Upload } from '@nextcloud/upload'
import type { CancelablePromise } from 'cancelable-promise'
import type { ComponentPublicInstance } from 'vue'
import type { Route } from 'vue-router'
import type { UserConfig } from '../types.ts'
@@ -174,10 +173,11 @@ import { Folder, getFileListActions, Permission, sortNodes } from '@nextcloud/fi
import { getRemoteURL, getRootPath } from '@nextcloud/files/dav'
import { loadState } from '@nextcloud/initial-state'
import { translate as t } from '@nextcloud/l10n'
import { dirname, join } from '@nextcloud/paths'
import { ShareType } from '@nextcloud/sharing'
import { UploadPicker, UploadStatus } from '@nextcloud/upload'
import { useThrottleFn } from '@vueuse/core'
import { dirname, join, normalize, relative } from 'path'
import { normalize, relative } from 'path'
import { defineComponent } from 'vue'
import NcActionButton from '@nextcloud/vue/components/NcActionButton'
import NcActions from '@nextcloud/vue/components/NcActions'
@@ -294,7 +294,8 @@ export default defineComponent({
loading: true,
loadingAction: null as string | null,
error: null as string | null,
promise: null as CancelablePromise<ContentsWithRoot> | Promise<ContentsWithRoot> | null,
controller: new AbortController(),
promise: null as Promise<ContentsWithRoot> | null,
dirContentsFiltered: [] as INode[],
}
@@ -639,13 +640,14 @@ export default defineComponent({
logger.debug('Fetching contents for directory', { dir, currentView })
// If we have a cancellable promise ongoing, cancel it
if (this.promise && 'cancel' in this.promise) {
this.promise.cancel()
if (this.promise) {
this.controller.abort()
logger.debug('Cancelled previous ongoing fetch')
}
// Fetch the current dir contents
this.promise = currentView.getContents(dir) as Promise<ContentsWithRoot>
this.controller = new AbortController()
this.promise = currentView.getContents(dir, { signal: this.controller.signal })
try {
const { folder, contents } = await this.promise
logger.debug('Fetched contents', { dir, folder, contents })
+1 -1
View File
@@ -178,7 +178,7 @@ export default defineComponent({
showView(view: View) {
// Closing any opened sidebar
window.OCA?.Files?.Sidebar?.close?.()
getNavigation().setActive(view)
getNavigation().setActive(view.id)
emit('files:navigation:changed', view)
},
+20 -22
View File
@@ -3,12 +3,11 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import type { Folder as CFolder, Navigation } from '@nextcloud/files'
import type { Navigation, Folder as NcFolder } from '@nextcloud/files'
import * as eventBus from '@nextcloud/event-bus'
import * as filesUtils from '@nextcloud/files'
import * as filesDavUtils from '@nextcloud/files/dav'
import { CancelablePromise } from 'cancelable-promise'
import { basename } from 'path'
import { beforeEach, describe, expect, test, vi } from 'vitest'
import { action } from '../actions/favoriteAction.ts'
@@ -42,8 +41,8 @@ describe('Favorites view definition', () => {
test('Default empty favorite view', async () => {
vi.spyOn(eventBus, 'subscribe')
vi.spyOn(filesDavUtils, 'getFavoriteNodes').mockReturnValue(CancelablePromise.resolve([]))
vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as CFolder, contents: [] }))
vi.spyOn(filesDavUtils, 'getFavoriteNodes').mockReturnValue(Promise.resolve([]))
vi.spyOn(favoritesService, 'getContents').mockReturnValue(Promise.resolve({ folder: {} as NcFolder, contents: [] }))
await registerFavoritesView()
const favoritesView = Navigation.views.find((view) => view.id === 'favorites')
@@ -95,8 +94,8 @@ describe('Favorites view definition', () => {
owner: 'admin',
}),
]
vi.spyOn(filesDavUtils, 'getFavoriteNodes').mockReturnValue(CancelablePromise.resolve(favoriteFolders))
vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as CFolder, contents: [] }))
vi.spyOn(filesDavUtils, 'getFavoriteNodes').mockReturnValue(Promise.resolve(favoriteFolders))
vi.spyOn(favoritesService, 'getContents').mockReturnValue(Promise.resolve({ folder: {} as NcFolder, contents: favoriteFolders }))
await registerFavoritesView()
const favoritesView = Navigation.views.find((view) => view.id === 'favorites')
@@ -140,8 +139,8 @@ describe('Dynamic update of favorite folders', () => {
test('Add a favorite folder creates a new entry in the navigation', async () => {
vi.spyOn(eventBus, 'emit')
vi.spyOn(filesDavUtils, 'getFavoriteNodes').mockReturnValue(CancelablePromise.resolve([]))
vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as CFolder, contents: [] }))
vi.spyOn(filesDavUtils, 'getFavoriteNodes').mockReturnValue(Promise.resolve([]))
vi.spyOn(favoritesService, 'getContents').mockReturnValue(Promise.resolve({ folder: {} as NcFolder, contents: [] }))
await registerFavoritesView()
const favoritesView = Navigation.views.find((view) => view.id === 'favorites')
@@ -164,7 +163,7 @@ describe('Dynamic update of favorite folders', () => {
await action.exec({
nodes: [folder],
view: favoritesView,
folder: {} as CFolder,
folder: {} as NcFolder,
contents: [],
})
@@ -173,16 +172,15 @@ describe('Dynamic update of favorite folders', () => {
})
test('Remove a favorite folder remove the entry from the navigation column', async () => {
const favoriteFolders = [new Folder({
id: 42,
root: '/files/admin',
source: 'http://nextcloud.local/remote.php/dav/files/admin/Foo/Bar',
owner: 'admin',
})]
vi.spyOn(eventBus, 'emit')
vi.spyOn(filesDavUtils, 'getFavoriteNodes').mockReturnValue(CancelablePromise.resolve([
new Folder({
id: 42,
root: '/files/admin',
source: 'http://nextcloud.local/remote.php/dav/files/admin/Foo/Bar',
owner: 'admin',
}),
]))
vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as CFolder, contents: [] }))
vi.spyOn(filesDavUtils, 'getFavoriteNodes').mockReturnValue(Promise.resolve(favoriteFolders))
vi.spyOn(favoritesService, 'getContents').mockReturnValue(Promise.resolve({ folder: {} as NcFolder, contents: favoriteFolders }))
await registerFavoritesView()
let favoritesView = Navigation.views.find((view) => view.id === 'favorites')
@@ -211,7 +209,7 @@ describe('Dynamic update of favorite folders', () => {
await action.exec({
nodes: [folder],
view: favoritesView,
folder: {} as CFolder,
folder: {} as NcFolder,
contents: [],
})
@@ -230,8 +228,8 @@ describe('Dynamic update of favorite folders', () => {
test('Renaming a favorite folder updates the navigation', async () => {
vi.spyOn(eventBus, 'emit')
vi.spyOn(filesDavUtils, 'getFavoriteNodes').mockReturnValue(CancelablePromise.resolve([]))
vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as CFolder, contents: [] }))
vi.spyOn(filesDavUtils, 'getFavoriteNodes').mockReturnValue(Promise.resolve([]))
vi.spyOn(favoritesService, 'getContents').mockReturnValue(Promise.resolve({ folder: {} as NcFolder, contents: [] }))
await registerFavoritesView()
const favoritesView = Navigation.views.find((view) => view.id === 'favorites')
@@ -256,7 +254,7 @@ describe('Dynamic update of favorite folders', () => {
await action.exec({
nodes: [folder],
view: favoritesView,
folder: {} as CFolder,
folder: {} as NcFolder,
contents: [],
})
expect(eventBus.emit).toHaveBeenNthCalledWith(1, 'files:favorites:added', folder)
+15 -12
View File
@@ -1,4 +1,4 @@
/**
/*!
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
@@ -9,17 +9,16 @@ import FolderSvg from '@mdi/svg/svg/folder-outline.svg?raw'
import StarSvg from '@mdi/svg/svg/star-outline.svg?raw'
import { subscribe } from '@nextcloud/event-bus'
import { FileType, getNavigation, View } from '@nextcloud/files'
import { getFavoriteNodes } from '@nextcloud/files/dav'
import { getCanonicalLocale, getLanguage, t } from '@nextcloud/l10n'
import logger from '../logger.ts'
import { getContents } from '../services/Favorites.ts'
import { client } from '../services/WebdavClient.ts'
import { hashCode } from '../utils/hashUtils.ts'
/**
* Generate a favorite folder view
*
* @param folder
* @param index
* @param folder - The folder to generate the view for
* @param index - The order index
*/
function generateFavoriteFolderView(folder: Folder, index = 0): View {
return new View({
@@ -44,15 +43,16 @@ function generateFavoriteFolderView(folder: Folder, index = 0): View {
}
/**
* Generate a unique id from the folder path
*
* @param path
* @param path - The folder path
*/
function generateIdFromPath(path: string): string {
return `favorite-${hashCode(path)}`
}
/**
*
* Register the favorites view and setup event listeners to update it
*/
export async function registerFavoritesView() {
const Navigation = getNavigation()
@@ -72,8 +72,11 @@ export async function registerFavoritesView() {
getContents,
}))
const favoriteFolders = (await getFavoriteNodes(client)).filter((node) => node.type === FileType.Folder) as Folder[]
const favoriteFoldersViews = favoriteFolders.map((folder, index) => generateFavoriteFolderView(folder, index)) as View[]
const controller = new AbortController()
const favoriteFolders = (await getContents('', { signal: controller.signal })).contents
.filter((node) => node.type === FileType.Folder) as Folder[]
const favoriteFoldersViews = favoriteFolders
.map((folder, index) => generateFavoriteFolderView(folder, index)) as View[]
logger.debug('Generating favorites view', { favoriteFolders })
favoriteFoldersViews.forEach((view) => Navigation.register(view))
@@ -143,7 +146,7 @@ export async function registerFavoritesView() {
/**
* Add a folder to the favorites paths array and update the views
*
* @param node
* @param node - The folder node
*/
function addToFavorites(node: Folder) {
const view = generateFavoriteFolderView(node)
@@ -165,7 +168,7 @@ export async function registerFavoritesView() {
/**
* Remove a folder from the favorites paths array and update the views
*
* @param path
* @param path - The folder path
*/
function removePathFromFavorites(path: string) {
const id = generateIdFromPath(path)
@@ -188,7 +191,7 @@ export async function registerFavoritesView() {
/**
* Update a folder from the favorites paths array and update the views
*
* @param node
* @param node - The updated folder node
*/
function updateNodeFromFavorites(node: Folder) {
const favoriteFolder = favoriteFolders.find((folder) => folder.fileid === node.fileid)
+1
View File
@@ -130,6 +130,7 @@ OC.L10N.register(
"Delete storage?" : "저장소를 삭제하시겠습니까?",
"Click to recheck the configuration" : "설정을 다시 확인하려면 클릭",
"Saved" : "저장됨",
"Saving …" : "저장 중 …",
"Save" : "저장",
"No external storage configured or you don't have the permission to configure them" : "외부 저장소가 구성되지 않았거나 외부 저장소를 구성할 권한이 없습니다.",
"Open documentation" : "문서 열기",
+1
View File
@@ -128,6 +128,7 @@
"Delete storage?" : "저장소를 삭제하시겠습니까?",
"Click to recheck the configuration" : "설정을 다시 확인하려면 클릭",
"Saved" : "저장됨",
"Saving …" : "저장 중 …",
"Save" : "저장",
"No external storage configured or you don't have the permission to configure them" : "외부 저장소가 구성되지 않았거나 외부 저장소를 구성할 권한이 없습니다.",
"Open documentation" : "문서 열기",
+1
View File
@@ -49,6 +49,7 @@ OC.L10N.register(
"Kerberos default realm, defaults to \"WORKGROUP\"" : "Kerberos standardområde sätts som standard till \"WORKGROUP\"",
"Kerberos ticket Apache mode" : "Kerberos-biljett Apache-läge",
"Kerberos ticket" : "Kerberos-biljett",
"S3 Storage" : "S3-lagring",
"Bucket" : "Bucket",
"Hostname" : "Värdnamn",
"Port" : "Port",
+1
View File
@@ -47,6 +47,7 @@
"Kerberos default realm, defaults to \"WORKGROUP\"" : "Kerberos standardområde sätts som standard till \"WORKGROUP\"",
"Kerberos ticket Apache mode" : "Kerberos-biljett Apache-läge",
"Kerberos ticket" : "Kerberos-biljett",
"S3 Storage" : "S3-lagring",
"Bucket" : "Bucket",
"Hostname" : "Värdnamn",
"Port" : "Port",
+1
View File
@@ -49,6 +49,7 @@ OC.L10N.register(
"Kerberos default realm, defaults to \"WORKGROUP\"" : "Kerberos سۈكۈتتىكى رايون ، «WORKGROUP» غا سۈكۈت قىلىدۇ",
"Kerberos ticket Apache mode" : "Kerberos بېلەت Apache ھالىتى",
"Kerberos ticket" : "Kerberos بېلەت",
"S3 Storage" : "S3 ساقلىغۇچ",
"Bucket" : "چېلەك",
"Hostname" : "ساھىبجامال",
"Port" : "ئېغىز",
+1
View File
@@ -47,6 +47,7 @@
"Kerberos default realm, defaults to \"WORKGROUP\"" : "Kerberos سۈكۈتتىكى رايون ، «WORKGROUP» غا سۈكۈت قىلىدۇ",
"Kerberos ticket Apache mode" : "Kerberos بېلەت Apache ھالىتى",
"Kerberos ticket" : "Kerberos بېلەت",
"S3 Storage" : "S3 ساقلىغۇچ",
"Bucket" : "چېلەك",
"Hostname" : "ساھىبجامال",
"Port" : "ئېغىز",
@@ -14,9 +14,11 @@ use OCP\IUserManager;
use OCP\IUserSession;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IManager;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\MockObject;
use Test\TestCase;
class UserPlaceholderHandlerTest extends \Test\TestCase {
class UserPlaceholderHandlerTest extends TestCase {
protected IUser&MockObject $user;
protected IUserSession&MockObject $session;
protected IManager&MockObject $shareManager;
@@ -34,6 +36,9 @@ class UserPlaceholderHandlerTest extends \Test\TestCase {
$this->session = $this->createMock(IUserSession::class);
$this->shareManager = $this->createMock(IManager::class);
$this->request = $this->createMock(IRequest::class);
$this->request->method('getParam')
->with('token')
->willReturn('foo');
$this->userManager = $this->createMock(IUserManager::class);
$this->handler = new UserPlaceholderHandler($this->session, $this->shareManager, $this->request, $this->userManager);
@@ -53,16 +58,17 @@ class UserPlaceholderHandlerTest extends \Test\TestCase {
];
}
#[\PHPUnit\Framework\Attributes\DataProvider('optionProvider')]
#[DataProvider('optionProvider')]
public function testHandle(string|array $option, string|array $expected): void {
$this->setUser();
$this->assertSame($expected, $this->handler->handle($option));
}
#[\PHPUnit\Framework\Attributes\DataProvider('optionProvider')]
#[DataProvider('optionProvider')]
public function testHandleNoUser(string|array $option): void {
$this->shareManager->expects($this->once())
->method('getShareByToken')
->with('foo')
->willThrowException(new ShareNotFound());
$this->assertSame($option, $this->handler->handle($option));
}
+1
View File
@@ -20,6 +20,7 @@ OC.L10N.register(
"Cancel" : "Avbryt",
"Clear reminder" : "Rensa påminnelse",
"Set reminder" : "Ställ in påminnelse",
"Set reminder for " : "Ställ in påminnelse för",
"Reminder set" : "Påminnelse inställd",
"Custom reminder" : "Anpassad påminnelse",
"Later today" : "Senare idag",
+1
View File
@@ -18,6 +18,7 @@
"Cancel" : "Avbryt",
"Clear reminder" : "Rensa påminnelse",
"Set reminder" : "Ställ in påminnelse",
"Set reminder for " : "Ställ in påminnelse för",
"Reminder set" : "Påminnelse inställd",
"Custom reminder" : "Anpassad påminnelse",
"Later today" : "Senare idag",
@@ -50,6 +50,8 @@ return array(
'OCA\\Files_Sharing\\Exceptions\\SharingRightsException' => $baseDir . '/../lib/Exceptions/SharingRightsException.php',
'OCA\\Files_Sharing\\ExpireSharesJob' => $baseDir . '/../lib/ExpireSharesJob.php',
'OCA\\Files_Sharing\\External\\Cache' => $baseDir . '/../lib/External/Cache.php',
'OCA\\Files_Sharing\\External\\ExternalShare' => $baseDir . '/../lib/External/ExternalShare.php',
'OCA\\Files_Sharing\\External\\ExternalShareMapper' => $baseDir . '/../lib/External/ExternalShareMapper.php',
'OCA\\Files_Sharing\\External\\Manager' => $baseDir . '/../lib/External/Manager.php',
'OCA\\Files_Sharing\\External\\Mount' => $baseDir . '/../lib/External/Mount.php',
'OCA\\Files_Sharing\\External\\MountProvider' => $baseDir . '/../lib/External/MountProvider.php',
@@ -82,6 +84,7 @@ return array(
'OCA\\Files_Sharing\\Migration\\Version24000Date20220404142216' => $baseDir . '/../lib/Migration/Version24000Date20220404142216.php',
'OCA\\Files_Sharing\\Migration\\Version31000Date20240821142813' => $baseDir . '/../lib/Migration/Version31000Date20240821142813.php',
'OCA\\Files_Sharing\\Migration\\Version32000Date20251017081948' => $baseDir . '/../lib/Migration/Version32000Date20251017081948.php',
'OCA\\Files_Sharing\\Migration\\Version33000Date20251030081948' => $baseDir . '/../lib/Migration/Version33000Date20251030081948.php',
'OCA\\Files_Sharing\\MountProvider' => $baseDir . '/../lib/MountProvider.php',
'OCA\\Files_Sharing\\Notification\\Listener' => $baseDir . '/../lib/Notification/Listener.php',
'OCA\\Files_Sharing\\Notification\\Notifier' => $baseDir . '/../lib/Notification/Notifier.php',
@@ -65,6 +65,8 @@ class ComposerStaticInitFiles_Sharing
'OCA\\Files_Sharing\\Exceptions\\SharingRightsException' => __DIR__ . '/..' . '/../lib/Exceptions/SharingRightsException.php',
'OCA\\Files_Sharing\\ExpireSharesJob' => __DIR__ . '/..' . '/../lib/ExpireSharesJob.php',
'OCA\\Files_Sharing\\External\\Cache' => __DIR__ . '/..' . '/../lib/External/Cache.php',
'OCA\\Files_Sharing\\External\\ExternalShare' => __DIR__ . '/..' . '/../lib/External/ExternalShare.php',
'OCA\\Files_Sharing\\External\\ExternalShareMapper' => __DIR__ . '/..' . '/../lib/External/ExternalShareMapper.php',
'OCA\\Files_Sharing\\External\\Manager' => __DIR__ . '/..' . '/../lib/External/Manager.php',
'OCA\\Files_Sharing\\External\\Mount' => __DIR__ . '/..' . '/../lib/External/Mount.php',
'OCA\\Files_Sharing\\External\\MountProvider' => __DIR__ . '/..' . '/../lib/External/MountProvider.php',
@@ -97,6 +99,7 @@ class ComposerStaticInitFiles_Sharing
'OCA\\Files_Sharing\\Migration\\Version24000Date20220404142216' => __DIR__ . '/..' . '/../lib/Migration/Version24000Date20220404142216.php',
'OCA\\Files_Sharing\\Migration\\Version31000Date20240821142813' => __DIR__ . '/..' . '/../lib/Migration/Version31000Date20240821142813.php',
'OCA\\Files_Sharing\\Migration\\Version32000Date20251017081948' => __DIR__ . '/..' . '/../lib/Migration/Version32000Date20251017081948.php',
'OCA\\Files_Sharing\\Migration\\Version33000Date20251030081948' => __DIR__ . '/..' . '/../lib/Migration/Version33000Date20251030081948.php',
'OCA\\Files_Sharing\\MountProvider' => __DIR__ . '/..' . '/../lib/MountProvider.php',
'OCA\\Files_Sharing\\Notification\\Listener' => __DIR__ . '/..' . '/../lib/Notification/Listener.php',
'OCA\\Files_Sharing\\Notification\\Notifier' => __DIR__ . '/..' . '/../lib/Notification/Notifier.php',
+1 -1
View File
@@ -77,7 +77,6 @@ OC.L10N.register(
"You cannot share to a Team if the app is not enabled" : "لا يمكنك المشاركة مع فريق إذا لم يكن التطبيق مُمكّناً",
"Please specify a valid team" : "من فضلك، قم بتحديد فريق صحيح",
"Sharing %s failed because the back end does not support room shares" : "فشلت مشاركة %s لأن الخلفية back end لا تدعم مشاركات الغُرَف room shares",
"Sharing %s failed because the back end does not support ScienceMesh shares" : " المشاركة %s فشلت بسبب أن الخادم لا يدعم مشاركات ScienceMesh",
"Unknown share type" : "نوع مشاركة غير معروف",
"Not a directory" : "ليس مُجلّداً صحيحاً",
"Could not lock node" : "تعذّر قَفْل lock النقطة node",
@@ -373,6 +372,7 @@ OC.L10N.register(
"Share not found" : "مشاركة غير موجودة",
"Back to %s" : "عودة إلى %s",
"Add to your Nextcloud" : "إضافة إلى حسابك على نكست كلاود",
"Sharing %s failed because the back end does not support ScienceMesh shares" : " المشاركة %s فشلت بسبب أن الخادم لا يدعم مشاركات ScienceMesh",
"Link copied to clipboard" : "تمّ نسخ الرابط إلى الحافظة",
"Copy to clipboard" : "نسخ الرابط إلى الحافظة",
"Copy internal link to clipboard" : "إنسَخ رابطاً داخليّاً إلى الحافظة",
+1 -1
View File
@@ -75,7 +75,6 @@
"You cannot share to a Team if the app is not enabled" : "لا يمكنك المشاركة مع فريق إذا لم يكن التطبيق مُمكّناً",
"Please specify a valid team" : "من فضلك، قم بتحديد فريق صحيح",
"Sharing %s failed because the back end does not support room shares" : "فشلت مشاركة %s لأن الخلفية back end لا تدعم مشاركات الغُرَف room shares",
"Sharing %s failed because the back end does not support ScienceMesh shares" : " المشاركة %s فشلت بسبب أن الخادم لا يدعم مشاركات ScienceMesh",
"Unknown share type" : "نوع مشاركة غير معروف",
"Not a directory" : "ليس مُجلّداً صحيحاً",
"Could not lock node" : "تعذّر قَفْل lock النقطة node",
@@ -371,6 +370,7 @@
"Share not found" : "مشاركة غير موجودة",
"Back to %s" : "عودة إلى %s",
"Add to your Nextcloud" : "إضافة إلى حسابك على نكست كلاود",
"Sharing %s failed because the back end does not support ScienceMesh shares" : " المشاركة %s فشلت بسبب أن الخادم لا يدعم مشاركات ScienceMesh",
"Link copied to clipboard" : "تمّ نسخ الرابط إلى الحافظة",
"Copy to clipboard" : "نسخ الرابط إلى الحافظة",
"Copy internal link to clipboard" : "إنسَخ رابطاً داخليّاً إلى الحافظة",
+1 -1
View File
@@ -73,7 +73,6 @@ OC.L10N.register(
"Please specify a valid federated account ID" : "Especifica una ID de cuenta federada válida",
"Please specify a valid federated group ID" : "Especifica una ID de grupu federáu válida",
"Sharing %s failed because the back end does not support room shares" : "Nun se pudo compartir «%s» porque'l backend nun ye compatible coles comparticiones con sales",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Nun se pudo compartir «%s» porque nun ye compatible coles comparticiones de ScienceMesh",
"Unknown share type" : "Tipu de compartición desconocida",
"Not a directory" : "Nun ye un direutoriu",
"Could not lock node" : "Nun se pudo bloquiar el noyu",
@@ -269,6 +268,7 @@ OC.L10N.register(
"Share not found" : "Nun s'atopó la compartición",
"Back to %s" : "Volver a «%s»",
"Add to your Nextcloud" : "Amestar a Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Nun se pudo compartir «%s» porque nun ye compatible coles comparticiones de ScienceMesh",
"Link copied to clipboard" : "L'enllaz copióse nel cartafueyu",
"Copy to clipboard" : "Copiar nel cartafueyu",
"Copy internal link to clipboard" : "Copiar l'enllaz internu nel cartafueyu",
+1 -1
View File
@@ -71,7 +71,6 @@
"Please specify a valid federated account ID" : "Especifica una ID de cuenta federada válida",
"Please specify a valid federated group ID" : "Especifica una ID de grupu federáu válida",
"Sharing %s failed because the back end does not support room shares" : "Nun se pudo compartir «%s» porque'l backend nun ye compatible coles comparticiones con sales",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Nun se pudo compartir «%s» porque nun ye compatible coles comparticiones de ScienceMesh",
"Unknown share type" : "Tipu de compartición desconocida",
"Not a directory" : "Nun ye un direutoriu",
"Could not lock node" : "Nun se pudo bloquiar el noyu",
@@ -267,6 +266,7 @@
"Share not found" : "Nun s'atopó la compartición",
"Back to %s" : "Volver a «%s»",
"Add to your Nextcloud" : "Amestar a Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Nun se pudo compartir «%s» porque nun ye compatible coles comparticiones de ScienceMesh",
"Link copied to clipboard" : "L'enllaz copióse nel cartafueyu",
"Copy to clipboard" : "Copiar nel cartafueyu",
"Copy internal link to clipboard" : "Copiar l'enllaz internu nel cartafueyu",
+1 -1
View File
@@ -71,7 +71,6 @@ OC.L10N.register(
"Sharing %1$s failed because the back end does not allow shares from type %2$s" : "Споделянето %1$s не бе успешно, защото вътрешния сървър не позволява споделяния от тип %2$s",
"Please specify a valid federated group ID" : "Моля, посочете валиден идентификатор на федерирана група",
"Sharing %s failed because the back end does not support room shares" : "Споделянето %s не бе успешно, защото вътрешния сървър не позволява споделяния на стаите",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Споделянето %s не бе успешно, защото вътрешния сървър не позволява споделяния на приложението ScienceMesh",
"Unknown share type" : "Неизвестен тип споделяне",
"Not a directory" : "Не е директория",
"Could not lock node" : "Възелът не можа да се заключи",
@@ -224,6 +223,7 @@ OC.L10N.register(
"Share not found" : "Споделянето не е открито",
"Back to %s" : "Обратно към %s",
"Add to your Nextcloud" : "Добавете към Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Споделянето %s не бе успешно, защото вътрешния сървър не позволява споделяния на приложението ScienceMesh",
"Link copied to clipboard" : "Връзката е копирана в клипборда",
"Copy to clipboard" : "Копиране в клипборда",
"Copy internal link to clipboard" : "Копиране на вътрешна връзката в клипборда",
+1 -1
View File
@@ -69,7 +69,6 @@
"Sharing %1$s failed because the back end does not allow shares from type %2$s" : "Споделянето %1$s не бе успешно, защото вътрешния сървър не позволява споделяния от тип %2$s",
"Please specify a valid federated group ID" : "Моля, посочете валиден идентификатор на федерирана група",
"Sharing %s failed because the back end does not support room shares" : "Споделянето %s не бе успешно, защото вътрешния сървър не позволява споделяния на стаите",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Споделянето %s не бе успешно, защото вътрешния сървър не позволява споделяния на приложението ScienceMesh",
"Unknown share type" : "Неизвестен тип споделяне",
"Not a directory" : "Не е директория",
"Could not lock node" : "Възелът не можа да се заключи",
@@ -222,6 +221,7 @@
"Share not found" : "Споделянето не е открито",
"Back to %s" : "Обратно към %s",
"Add to your Nextcloud" : "Добавете към Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Споделянето %s не бе успешно, защото вътрешния сървър не позволява споделяния на приложението ScienceMesh",
"Link copied to clipboard" : "Връзката е копирана в клипборда",
"Copy to clipboard" : "Копиране в клипборда",
"Copy internal link to clipboard" : "Копиране на вътрешна връзката в клипборда",
+1 -1
View File
@@ -77,7 +77,6 @@ OC.L10N.register(
"You cannot share to a Team if the app is not enabled" : "No podeu compartir amb un Equip si l'aplicació no està habilitada",
"Please specify a valid team" : "Especifiqueu un equip vàlid",
"Sharing %s failed because the back end does not support room shares" : "No s'ha pogut compartir %s perquè el rerefons no permet l'ús sales compartides",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "No s'ha pogut compartir %s perquè el rerefons no permet elements compartits de ScienceMesh",
"Unknown share type" : "Tipus d'element compartit desconegut",
"Not a directory" : "No és una carpeta",
"Could not lock node" : "No s'ha pogut blocar el node",
@@ -375,6 +374,7 @@ OC.L10N.register(
"Share not found" : "No s'ha trobat la compartició",
"Back to %s" : "Torna a %s",
"Add to your Nextcloud" : "Afegeix al Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "No s'ha pogut compartir %s perquè el rerefons no permet elements compartits de ScienceMesh",
"Link copied to clipboard" : "Enllaç copiat al porta-retalls",
"Copy to clipboard" : "Copia-ho al porta-retalls",
"Copy internal link to clipboard" : "Copia l'enllaç intern al porta-retalls",
+1 -1
View File
@@ -75,7 +75,6 @@
"You cannot share to a Team if the app is not enabled" : "No podeu compartir amb un Equip si l'aplicació no està habilitada",
"Please specify a valid team" : "Especifiqueu un equip vàlid",
"Sharing %s failed because the back end does not support room shares" : "No s'ha pogut compartir %s perquè el rerefons no permet l'ús sales compartides",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "No s'ha pogut compartir %s perquè el rerefons no permet elements compartits de ScienceMesh",
"Unknown share type" : "Tipus d'element compartit desconegut",
"Not a directory" : "No és una carpeta",
"Could not lock node" : "No s'ha pogut blocar el node",
@@ -373,6 +372,7 @@
"Share not found" : "No s'ha trobat la compartició",
"Back to %s" : "Torna a %s",
"Add to your Nextcloud" : "Afegeix al Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "No s'ha pogut compartir %s perquè el rerefons no permet elements compartits de ScienceMesh",
"Link copied to clipboard" : "Enllaç copiat al porta-retalls",
"Copy to clipboard" : "Copia-ho al porta-retalls",
"Copy internal link to clipboard" : "Copia l'enllaç intern al porta-retalls",
+1 -1
View File
@@ -77,7 +77,6 @@ OC.L10N.register(
"You cannot share to a Team if the app is not enabled" : "Týmu nemůžete sdílet, pokud není příslušná aplikace zapnutá",
"Please specify a valid team" : "Zadejte platný tým",
"Sharing %s failed because the back end does not support room shares" : "Sdílení %s se nezdařilo protože podpůrná vrstva nepodporuje sdílení místností",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Sdílení %s se nezdařilo protože podpůrná vrstva nepodporuje ScienceMesh sdílení",
"Unknown share type" : "Neznámý typ sdílení",
"Not a directory" : "Není adresář",
"Could not lock node" : "Uzel se nedaří uzamknout",
@@ -404,6 +403,7 @@ OC.L10N.register(
"Share not found" : "Sdílení nenalezeno",
"Back to %s" : "Zpět na %s",
"Add to your Nextcloud" : "Přidat do Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Sdílení %s se nezdařilo protože podpůrná vrstva nepodporuje ScienceMesh sdílení",
"Link copied to clipboard" : "Odkaz zkopírován do schánky",
"Copy to clipboard" : "Zkopírovat do schránky",
"Copy internal link to clipboard" : "Zkopírovat interní odkaz do schránky",
+1 -1
View File
@@ -75,7 +75,6 @@
"You cannot share to a Team if the app is not enabled" : "Týmu nemůžete sdílet, pokud není příslušná aplikace zapnutá",
"Please specify a valid team" : "Zadejte platný tým",
"Sharing %s failed because the back end does not support room shares" : "Sdílení %s se nezdařilo protože podpůrná vrstva nepodporuje sdílení místností",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Sdílení %s se nezdařilo protože podpůrná vrstva nepodporuje ScienceMesh sdílení",
"Unknown share type" : "Neznámý typ sdílení",
"Not a directory" : "Není adresář",
"Could not lock node" : "Uzel se nedaří uzamknout",
@@ -402,6 +401,7 @@
"Share not found" : "Sdílení nenalezeno",
"Back to %s" : "Zpět na %s",
"Add to your Nextcloud" : "Přidat do Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Sdílení %s se nezdařilo protože podpůrná vrstva nepodporuje ScienceMesh sdílení",
"Link copied to clipboard" : "Odkaz zkopírován do schánky",
"Copy to clipboard" : "Zkopírovat do schránky",
"Copy internal link to clipboard" : "Zkopírovat interní odkaz do schránky",
+1 -1
View File
@@ -77,7 +77,6 @@ OC.L10N.register(
"You cannot share to a Team if the app is not enabled" : "Du kan ikke dele til et Team, hvis app'en ikke er aktiveret",
"Please specify a valid team" : "Angiv venligst et gyldigt team",
"Sharing %s failed because the back end does not support room shares" : "Deling af %s mislykkedes fordi backenden ikke tillader delinger af rumdeling",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Kunne ikke dele %s fordi backenden ikke understøtter deling af ScienceMesh",
"Unknown share type" : "Ukendt deletype",
"Not a directory" : "Ikke en mappe",
"Could not lock node" : "Kunne ikke låse node",
@@ -404,6 +403,7 @@ OC.L10N.register(
"Share not found" : "Delt fil ikke fundet",
"Back to %s" : "Tilbage til %s",
"Add to your Nextcloud" : "Tilføj til din Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Kunne ikke dele %s fordi backenden ikke understøtter deling af ScienceMesh",
"Link copied to clipboard" : "Link kopieret til udklipsholder",
"Copy to clipboard" : "Kopier til udklipsholder",
"Copy internal link to clipboard" : "Kopier internt link til klippebord",
+1 -1
View File
@@ -75,7 +75,6 @@
"You cannot share to a Team if the app is not enabled" : "Du kan ikke dele til et Team, hvis app'en ikke er aktiveret",
"Please specify a valid team" : "Angiv venligst et gyldigt team",
"Sharing %s failed because the back end does not support room shares" : "Deling af %s mislykkedes fordi backenden ikke tillader delinger af rumdeling",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Kunne ikke dele %s fordi backenden ikke understøtter deling af ScienceMesh",
"Unknown share type" : "Ukendt deletype",
"Not a directory" : "Ikke en mappe",
"Could not lock node" : "Kunne ikke låse node",
@@ -402,6 +401,7 @@
"Share not found" : "Delt fil ikke fundet",
"Back to %s" : "Tilbage til %s",
"Add to your Nextcloud" : "Tilføj til din Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Kunne ikke dele %s fordi backenden ikke understøtter deling af ScienceMesh",
"Link copied to clipboard" : "Link kopieret til udklipsholder",
"Copy to clipboard" : "Kopier til udklipsholder",
"Copy internal link to clipboard" : "Kopier internt link til klippebord",
+3 -3
View File
@@ -77,7 +77,6 @@ OC.L10N.register(
"You cannot share to a Team if the app is not enabled" : "Du kannst nichts mit einem Team teilen, wenn die App nicht aktiviert ist",
"Please specify a valid team" : "Bitte ein gültiges Team angeben",
"Sharing %s failed because the back end does not support room shares" : "Freigabe von %s fehlgeschlagen, da das Backend die Freigabe von Räumen nicht unterstützt",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Freigabe von %s fehlgeschlagen, da das Backend keine ScienceMesh-Freigaben unterstützt",
"Unknown share type" : "Unbekannter Freigabetyp",
"Not a directory" : "Kein Verzeichnis",
"Could not lock node" : "Node konnte nicht gesperrt werden",
@@ -305,8 +304,8 @@ OC.L10N.register(
"Unable to fetch inherited shares" : "Vererbte Freigaben konnten nicht geladen werden",
"Link shares" : "Freigaben teilen",
"Shares" : "Freigaben",
"Share files within your organization. Recipients who can already view the file can also use this link for easy access." : "Dateien innerhalb Ihrer Organisation teilen. Auch Empfänger, die auf die Datei bereits zugreifen können, können diesen Link für einen einfachen Zugriff nutzen.",
"Share files with others outside your organization via public links and email addresses. You can also share to {productName} accounts on other instances using their federated cloud ID." : "Dateien über öffentliche Links und E-Mail-Adressen mit anderen außerhalb Ihrer Organisation teilen. Sie können {productName}-Konten auch auf anderen Instanzen mithilfe ihrer Federated-Cloud-ID teilen.",
"Share files within your organization. Recipients who can already view the file can also use this link for easy access." : "Dateien innerhalb deiner Organisation teilen. Auch Empfänger, die auf die Datei bereits zugreifen können, können diesen Link für einen einfachen Zugriff nutzen.",
"Share files with others outside your organization via public links and email addresses. You can also share to {productName} accounts on other instances using their federated cloud ID." : "Dateien über öffentliche Links und E-Mail-Adressen mit anderen außerhalb deiner Organisation teilen. Du kannst {productName}-Konten auch auf anderen Instanzen mithilfe deiner Federated-Cloud-ID teilen.",
"Shares from apps or other sources which are not included in internal or external shares." : "Freigaben aus Apps oder anderen Quellen, die nicht in internen oder externen Freigaben enthalten sind.",
"Type names, teams, federated cloud IDs" : "Namen, Teams oder Federated-Cloud-IDs eingeben",
"Type names or teams" : "Namen oder Federated-Cloud-IDs eingeben",
@@ -404,6 +403,7 @@ OC.L10N.register(
"Share not found" : "Freigabe nicht gefunden",
"Back to %s" : "Zurück zu %s",
"Add to your Nextcloud" : "Zu deiner Nextcloud hinzufügen",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Freigabe von %s fehlgeschlagen, da das Backend keine ScienceMesh-Freigaben unterstützt",
"Link copied to clipboard" : "Link wurde in die Zwischenablage kopiert",
"Copy to clipboard" : "In die Zwischenablage kopieren",
"Copy internal link to clipboard" : "Internen Link in die Zwischenablage kopieren",
+3 -3
View File
@@ -75,7 +75,6 @@
"You cannot share to a Team if the app is not enabled" : "Du kannst nichts mit einem Team teilen, wenn die App nicht aktiviert ist",
"Please specify a valid team" : "Bitte ein gültiges Team angeben",
"Sharing %s failed because the back end does not support room shares" : "Freigabe von %s fehlgeschlagen, da das Backend die Freigabe von Räumen nicht unterstützt",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Freigabe von %s fehlgeschlagen, da das Backend keine ScienceMesh-Freigaben unterstützt",
"Unknown share type" : "Unbekannter Freigabetyp",
"Not a directory" : "Kein Verzeichnis",
"Could not lock node" : "Node konnte nicht gesperrt werden",
@@ -303,8 +302,8 @@
"Unable to fetch inherited shares" : "Vererbte Freigaben konnten nicht geladen werden",
"Link shares" : "Freigaben teilen",
"Shares" : "Freigaben",
"Share files within your organization. Recipients who can already view the file can also use this link for easy access." : "Dateien innerhalb Ihrer Organisation teilen. Auch Empfänger, die auf die Datei bereits zugreifen können, können diesen Link für einen einfachen Zugriff nutzen.",
"Share files with others outside your organization via public links and email addresses. You can also share to {productName} accounts on other instances using their federated cloud ID." : "Dateien über öffentliche Links und E-Mail-Adressen mit anderen außerhalb Ihrer Organisation teilen. Sie können {productName}-Konten auch auf anderen Instanzen mithilfe ihrer Federated-Cloud-ID teilen.",
"Share files within your organization. Recipients who can already view the file can also use this link for easy access." : "Dateien innerhalb deiner Organisation teilen. Auch Empfänger, die auf die Datei bereits zugreifen können, können diesen Link für einen einfachen Zugriff nutzen.",
"Share files with others outside your organization via public links and email addresses. You can also share to {productName} accounts on other instances using their federated cloud ID." : "Dateien über öffentliche Links und E-Mail-Adressen mit anderen außerhalb deiner Organisation teilen. Du kannst {productName}-Konten auch auf anderen Instanzen mithilfe deiner Federated-Cloud-ID teilen.",
"Shares from apps or other sources which are not included in internal or external shares." : "Freigaben aus Apps oder anderen Quellen, die nicht in internen oder externen Freigaben enthalten sind.",
"Type names, teams, federated cloud IDs" : "Namen, Teams oder Federated-Cloud-IDs eingeben",
"Type names or teams" : "Namen oder Federated-Cloud-IDs eingeben",
@@ -402,6 +401,7 @@
"Share not found" : "Freigabe nicht gefunden",
"Back to %s" : "Zurück zu %s",
"Add to your Nextcloud" : "Zu deiner Nextcloud hinzufügen",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Freigabe von %s fehlgeschlagen, da das Backend keine ScienceMesh-Freigaben unterstützt",
"Link copied to clipboard" : "Link wurde in die Zwischenablage kopiert",
"Copy to clipboard" : "In die Zwischenablage kopieren",
"Copy internal link to clipboard" : "Internen Link in die Zwischenablage kopieren",
+1 -1
View File
@@ -77,7 +77,6 @@ OC.L10N.register(
"You cannot share to a Team if the app is not enabled" : "Sie können nichts mit einem Team teilen, wenn die App nicht aktiviert ist",
"Please specify a valid team" : "Bitte ein gültiges Team angeben",
"Sharing %s failed because the back end does not support room shares" : "Freigabe von %s fehlgeschlagen, da das Backend die Freigabe von Räumen nicht unterstützt",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Freigabe von %s fehlgeschlagen, da das Backend keine ScienceMesh-Freigaben unterstützt",
"Unknown share type" : "Unbekannter Freigabetyp",
"Not a directory" : "Kein Verzeichnis",
"Could not lock node" : "Knotenpunkt konnte nicht gesperrt werden",
@@ -404,6 +403,7 @@ OC.L10N.register(
"Share not found" : "Freigabe nicht gefunden",
"Back to %s" : "Zurück zu %s",
"Add to your Nextcloud" : "Zu Ihrer Nextcloud hinzufügen",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Freigabe von %s fehlgeschlagen, da das Backend keine ScienceMesh-Freigaben unterstützt",
"Link copied to clipboard" : "Link wurde in die Zwischenablage kopiert",
"Copy to clipboard" : "In die Zwischenablage kopieren",
"Copy internal link to clipboard" : "Internen Link in die Zwischenablage kopieren",
+1 -1
View File
@@ -75,7 +75,6 @@
"You cannot share to a Team if the app is not enabled" : "Sie können nichts mit einem Team teilen, wenn die App nicht aktiviert ist",
"Please specify a valid team" : "Bitte ein gültiges Team angeben",
"Sharing %s failed because the back end does not support room shares" : "Freigabe von %s fehlgeschlagen, da das Backend die Freigabe von Räumen nicht unterstützt",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Freigabe von %s fehlgeschlagen, da das Backend keine ScienceMesh-Freigaben unterstützt",
"Unknown share type" : "Unbekannter Freigabetyp",
"Not a directory" : "Kein Verzeichnis",
"Could not lock node" : "Knotenpunkt konnte nicht gesperrt werden",
@@ -402,6 +401,7 @@
"Share not found" : "Freigabe nicht gefunden",
"Back to %s" : "Zurück zu %s",
"Add to your Nextcloud" : "Zu Ihrer Nextcloud hinzufügen",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Freigabe von %s fehlgeschlagen, da das Backend keine ScienceMesh-Freigaben unterstützt",
"Link copied to clipboard" : "Link wurde in die Zwischenablage kopiert",
"Copy to clipboard" : "In die Zwischenablage kopieren",
"Copy internal link to clipboard" : "Internen Link in die Zwischenablage kopieren",
+1 -1
View File
@@ -77,7 +77,6 @@ OC.L10N.register(
"You cannot share to a Team if the app is not enabled" : "Δεν μπορείτε να διαμοιραστείτε σε Ομάδα εάν η εφαρμογή δεν είναι ενεργοποιημένη",
"Please specify a valid team" : "Παρακαλώ καθορίστε μια έγκυρη ομάδα",
"Sharing %s failed because the back end does not support room shares" : "Διαμοιρασμός %s απέτυχε επειδή ο εξυπηρετητής δεν επιτρέπει διαμοιρασμούς δωματίων",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Ο διαμοιρασμός %s απέτυχε επειδή το σύστημα υποστήριξης δεν υποστηρίζει μετοχές ScienceMesh",
"Unknown share type" : "Άγνωστος τύπος διαμοιρασμού",
"Not a directory" : "Δεν είναι κατάλογος",
"Could not lock node" : "Δεν ήταν δυνατό να κλειδώσει ο κόμβος",
@@ -402,6 +401,7 @@ OC.L10N.register(
"Share not found" : "Δεν βρέθηκε το κονόχρηστο",
"Back to %s" : "Πίσω στο %s",
"Add to your Nextcloud" : "Προσθήκη στο Nextcloud σου",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Ο διαμοιρασμός %s απέτυχε επειδή το σύστημα υποστήριξης δεν υποστηρίζει μετοχές ScienceMesh",
"Link copied to clipboard" : "Ο σύνδεσμος αντιγράφηκε στο πρόχειρο",
"Copy to clipboard" : "Αντιγραφή στο πρόχειρο",
"Copy internal link to clipboard" : "Αντιγραφή εσωτερικού συνδέσμου στο πρόχειρο",
+1 -1
View File
@@ -75,7 +75,6 @@
"You cannot share to a Team if the app is not enabled" : "Δεν μπορείτε να διαμοιραστείτε σε Ομάδα εάν η εφαρμογή δεν είναι ενεργοποιημένη",
"Please specify a valid team" : "Παρακαλώ καθορίστε μια έγκυρη ομάδα",
"Sharing %s failed because the back end does not support room shares" : "Διαμοιρασμός %s απέτυχε επειδή ο εξυπηρετητής δεν επιτρέπει διαμοιρασμούς δωματίων",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Ο διαμοιρασμός %s απέτυχε επειδή το σύστημα υποστήριξης δεν υποστηρίζει μετοχές ScienceMesh",
"Unknown share type" : "Άγνωστος τύπος διαμοιρασμού",
"Not a directory" : "Δεν είναι κατάλογος",
"Could not lock node" : "Δεν ήταν δυνατό να κλειδώσει ο κόμβος",
@@ -400,6 +399,7 @@
"Share not found" : "Δεν βρέθηκε το κονόχρηστο",
"Back to %s" : "Πίσω στο %s",
"Add to your Nextcloud" : "Προσθήκη στο Nextcloud σου",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Ο διαμοιρασμός %s απέτυχε επειδή το σύστημα υποστήριξης δεν υποστηρίζει μετοχές ScienceMesh",
"Link copied to clipboard" : "Ο σύνδεσμος αντιγράφηκε στο πρόχειρο",
"Copy to clipboard" : "Αντιγραφή στο πρόχειρο",
"Copy internal link to clipboard" : "Αντιγραφή εσωτερικού συνδέσμου στο πρόχειρο",
+1 -1
View File
@@ -77,7 +77,6 @@ OC.L10N.register(
"You cannot share to a Team if the app is not enabled" : "You cannot share to a Team if the app is not enabled",
"Please specify a valid team" : "Please specify a valid team",
"Sharing %s failed because the back end does not support room shares" : "Sharing %s failed because the back end does not support room shares",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Sharing %s failed because the back end does not support ScienceMesh shares",
"Unknown share type" : "Unknown share type",
"Not a directory" : "Not a directory",
"Could not lock node" : "Could not lock node",
@@ -404,6 +403,7 @@ OC.L10N.register(
"Share not found" : "Share not found",
"Back to %s" : "Back to %s",
"Add to your Nextcloud" : "Add to your Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Sharing %s failed because the back end does not support ScienceMesh shares",
"Link copied to clipboard" : "Link copied to clipboard",
"Copy to clipboard" : "Copy to clipboard",
"Copy internal link to clipboard" : "Copy internal link to clipboard",
+1 -1
View File
@@ -75,7 +75,6 @@
"You cannot share to a Team if the app is not enabled" : "You cannot share to a Team if the app is not enabled",
"Please specify a valid team" : "Please specify a valid team",
"Sharing %s failed because the back end does not support room shares" : "Sharing %s failed because the back end does not support room shares",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Sharing %s failed because the back end does not support ScienceMesh shares",
"Unknown share type" : "Unknown share type",
"Not a directory" : "Not a directory",
"Could not lock node" : "Could not lock node",
@@ -402,6 +401,7 @@
"Share not found" : "Share not found",
"Back to %s" : "Back to %s",
"Add to your Nextcloud" : "Add to your Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Sharing %s failed because the back end does not support ScienceMesh shares",
"Link copied to clipboard" : "Link copied to clipboard",
"Copy to clipboard" : "Copy to clipboard",
"Copy internal link to clipboard" : "Copy internal link to clipboard",
+1 -1
View File
@@ -77,7 +77,6 @@ OC.L10N.register(
"You cannot share to a Team if the app is not enabled" : "No puede compartir a un equipo si la aplicación no está habilitada",
"Please specify a valid team" : "Por favor, especifique un equipo válido",
"Sharing %s failed because the back end does not support room shares" : "Compartir %s ha fallado porque el backend no soporta habitaciones compartidas",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Compartir %s ha fallado porque el backend no soporta recursos compartidos de ScienceMesh",
"Unknown share type" : "Tipo de recurso compartido desconocido",
"Not a directory" : "No es un directorio",
"Could not lock node" : "No se ha podido bloquear el nodo",
@@ -402,6 +401,7 @@ OC.L10N.register(
"Share not found" : "Recurso compartido no encontrado",
"Back to %s" : "Volver a %s",
"Add to your Nextcloud" : "Añadir a tu Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Compartir %s ha fallado porque el backend no soporta recursos compartidos de ScienceMesh",
"Link copied to clipboard" : "Enlace copiado al portapapeles",
"Copy to clipboard" : "Copiar al portapapeles",
"Copy internal link to clipboard" : "Copiar enlace interno al portapapeles",
+1 -1
View File
@@ -75,7 +75,6 @@
"You cannot share to a Team if the app is not enabled" : "No puede compartir a un equipo si la aplicación no está habilitada",
"Please specify a valid team" : "Por favor, especifique un equipo válido",
"Sharing %s failed because the back end does not support room shares" : "Compartir %s ha fallado porque el backend no soporta habitaciones compartidas",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Compartir %s ha fallado porque el backend no soporta recursos compartidos de ScienceMesh",
"Unknown share type" : "Tipo de recurso compartido desconocido",
"Not a directory" : "No es un directorio",
"Could not lock node" : "No se ha podido bloquear el nodo",
@@ -400,6 +399,7 @@
"Share not found" : "Recurso compartido no encontrado",
"Back to %s" : "Volver a %s",
"Add to your Nextcloud" : "Añadir a tu Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Compartir %s ha fallado porque el backend no soporta recursos compartidos de ScienceMesh",
"Link copied to clipboard" : "Enlace copiado al portapapeles",
"Copy to clipboard" : "Copiar al portapapeles",
"Copy internal link to clipboard" : "Copiar enlace interno al portapapeles",
+1 -1
View File
@@ -71,7 +71,6 @@ OC.L10N.register(
"Sharing %1$s failed because the back end does not allow shares from type %2$s" : "Error al compartir %1$s porque el servidor no permite comparticiones del tipo %2$s",
"Please specify a valid federated group ID" : "Por favor, especifica un ID de grupo federado válido",
"Sharing %s failed because the back end does not support room shares" : "Error al compartir %s porque el servidor no admite comparticiones de salas",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Error al compartir %s porque el servidor no admite comparticiones de ScienceMesh",
"Unknown share type" : "Tipo de elemento compartido desconocido",
"Not a directory" : "No es una carpeta",
"Could not lock node" : "No se pudo bloquear el nodo",
@@ -225,6 +224,7 @@ OC.L10N.register(
"Share not found" : "No se encontró el elemento compartido",
"Back to %s" : "Volver a %s",
"Add to your Nextcloud" : "Agregar a tu Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Error al compartir %s porque el servidor no admite comparticiones de ScienceMesh",
"Link copied to clipboard" : "Enlace copiado al portapapeles",
"Copy to clipboard" : "Copiar al portapapeles",
"Copy internal link to clipboard" : "Copiar enlace interno al portapapeles",
+1 -1
View File
@@ -69,7 +69,6 @@
"Sharing %1$s failed because the back end does not allow shares from type %2$s" : "Error al compartir %1$s porque el servidor no permite comparticiones del tipo %2$s",
"Please specify a valid federated group ID" : "Por favor, especifica un ID de grupo federado válido",
"Sharing %s failed because the back end does not support room shares" : "Error al compartir %s porque el servidor no admite comparticiones de salas",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Error al compartir %s porque el servidor no admite comparticiones de ScienceMesh",
"Unknown share type" : "Tipo de elemento compartido desconocido",
"Not a directory" : "No es una carpeta",
"Could not lock node" : "No se pudo bloquear el nodo",
@@ -223,6 +222,7 @@
"Share not found" : "No se encontró el elemento compartido",
"Back to %s" : "Volver a %s",
"Add to your Nextcloud" : "Agregar a tu Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Error al compartir %s porque el servidor no admite comparticiones de ScienceMesh",
"Link copied to clipboard" : "Enlace copiado al portapapeles",
"Copy to clipboard" : "Copiar al portapapeles",
"Copy internal link to clipboard" : "Copiar enlace interno al portapapeles",
+1 -1
View File
@@ -77,7 +77,6 @@ OC.L10N.register(
"You cannot share to a Team if the app is not enabled" : "No puede compartir a un equipo si la aplicación no está habilitada",
"Please specify a valid team" : "Por favor, especifique un equipo válido",
"Sharing %s failed because the back end does not support room shares" : "Compartir %s falló porque el servidor no soporta salas compartidas",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Compartir %s falló porque el servidor no soporta recursos compartidos de ScienceMesh",
"Unknown share type" : "Tipo de elemento compartido desconocido",
"Not a directory" : "No es una carpeta",
"Could not lock node" : "No se pudo bloquear el nodo",
@@ -321,6 +320,7 @@ OC.L10N.register(
"Share not found" : "No se encontró el elemento compartido",
"Back to %s" : "Volver a %s",
"Add to your Nextcloud" : "Agregar a tu Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Compartir %s falló porque el servidor no soporta recursos compartidos de ScienceMesh",
"Link copied to clipboard" : "Enlace copiado al portapapeles",
"Copy to clipboard" : "Copiar al portapapeles",
"Copy internal link to clipboard" : "Copiar enlace interno al portapapeles",
+1 -1
View File
@@ -75,7 +75,6 @@
"You cannot share to a Team if the app is not enabled" : "No puede compartir a un equipo si la aplicación no está habilitada",
"Please specify a valid team" : "Por favor, especifique un equipo válido",
"Sharing %s failed because the back end does not support room shares" : "Compartir %s falló porque el servidor no soporta salas compartidas",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Compartir %s falló porque el servidor no soporta recursos compartidos de ScienceMesh",
"Unknown share type" : "Tipo de elemento compartido desconocido",
"Not a directory" : "No es una carpeta",
"Could not lock node" : "No se pudo bloquear el nodo",
@@ -319,6 +318,7 @@
"Share not found" : "No se encontró el elemento compartido",
"Back to %s" : "Volver a %s",
"Add to your Nextcloud" : "Agregar a tu Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Compartir %s falló porque el servidor no soporta recursos compartidos de ScienceMesh",
"Link copied to clipboard" : "Enlace copiado al portapapeles",
"Copy to clipboard" : "Copiar al portapapeles",
"Copy internal link to clipboard" : "Copiar enlace interno al portapapeles",
+1 -1
View File
@@ -77,7 +77,6 @@ OC.L10N.register(
"You cannot share to a Team if the app is not enabled" : "Sa ei saa jagada tiimiga, kui see rakendus pole lubatud",
"Please specify a valid team" : "Palun määratle korrektne tiim",
"Sharing %s failed because the back end does not support room shares" : "„%s“ jagamine ei õnnestunud, sest taustateenus ei toeta jututubadesse jagamist",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "„%s“ jagamine ei õnnestunud, sest taustateenus ei toeta ScienceMeshi meedia jagamist",
"Unknown share type" : "Tundmatu jagamise tüüp",
"Not a directory" : "Ei ole kaust",
"Could not lock node" : "Sõlme lukustamine ei õnnestunud",
@@ -404,6 +403,7 @@ OC.L10N.register(
"Share not found" : "Jagamist ei leidu",
"Back to %s" : "Tagasi siia: %s",
"Add to your Nextcloud" : "Lisa oma Nextcloudi",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "„%s“ jagamine ei õnnestunud, sest taustateenus ei toeta ScienceMeshi meedia jagamist",
"Link copied to clipboard" : "Link on lõikelauale kopeeritud",
"Copy to clipboard" : "Kopeeri lõikepuhvrisse",
"Copy internal link to clipboard" : "Kopeeri sisemine link lõikelauale",
+1 -1
View File
@@ -75,7 +75,6 @@
"You cannot share to a Team if the app is not enabled" : "Sa ei saa jagada tiimiga, kui see rakendus pole lubatud",
"Please specify a valid team" : "Palun määratle korrektne tiim",
"Sharing %s failed because the back end does not support room shares" : "„%s“ jagamine ei õnnestunud, sest taustateenus ei toeta jututubadesse jagamist",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "„%s“ jagamine ei õnnestunud, sest taustateenus ei toeta ScienceMeshi meedia jagamist",
"Unknown share type" : "Tundmatu jagamise tüüp",
"Not a directory" : "Ei ole kaust",
"Could not lock node" : "Sõlme lukustamine ei õnnestunud",
@@ -402,6 +401,7 @@
"Share not found" : "Jagamist ei leidu",
"Back to %s" : "Tagasi siia: %s",
"Add to your Nextcloud" : "Lisa oma Nextcloudi",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "„%s“ jagamine ei õnnestunud, sest taustateenus ei toeta ScienceMeshi meedia jagamist",
"Link copied to clipboard" : "Link on lõikelauale kopeeritud",
"Copy to clipboard" : "Kopeeri lõikepuhvrisse",
"Copy internal link to clipboard" : "Kopeeri sisemine link lõikelauale",
+1 -1
View File
@@ -77,7 +77,6 @@ OC.L10N.register(
"You cannot share to a Team if the app is not enabled" : "Ezin duzu talde batekin partekatu aplikazioa gaituta ez badago",
"Please specify a valid team" : "Zehaztu baliozko lantalde bat",
"Sharing %s failed because the back end does not support room shares" : "%s partekatzeak huts egin du, atzealdeak ez duelako gelak partekatzea onartzen",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "%s partekatzeak huts egin du atzealdeak ez dituelako ScienceMesh parteatzeak onartzen",
"Unknown share type" : "Partekatze mota ezezaguna",
"Not a directory" : "Ez da direktorio bat",
"Could not lock node" : "Ezin izan da nodoa blokeatu",
@@ -400,6 +399,7 @@ OC.L10N.register(
"Share not found" : "Partekatzea ez da aurkitu",
"Back to %s" : "Itzuli %s(e)ra",
"Add to your Nextcloud" : "Gehitu zure Nextclouden",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "%s partekatzeak huts egin du atzealdeak ez dituelako ScienceMesh parteatzeak onartzen",
"Link copied to clipboard" : "Arbelara kopiatutako esteka",
"Copy to clipboard" : "Kopiatu arbelera",
"Copy internal link to clipboard" : "Kopiatu barne esteka arbelera",
+1 -1
View File
@@ -75,7 +75,6 @@
"You cannot share to a Team if the app is not enabled" : "Ezin duzu talde batekin partekatu aplikazioa gaituta ez badago",
"Please specify a valid team" : "Zehaztu baliozko lantalde bat",
"Sharing %s failed because the back end does not support room shares" : "%s partekatzeak huts egin du, atzealdeak ez duelako gelak partekatzea onartzen",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "%s partekatzeak huts egin du atzealdeak ez dituelako ScienceMesh parteatzeak onartzen",
"Unknown share type" : "Partekatze mota ezezaguna",
"Not a directory" : "Ez da direktorio bat",
"Could not lock node" : "Ezin izan da nodoa blokeatu",
@@ -398,6 +397,7 @@
"Share not found" : "Partekatzea ez da aurkitu",
"Back to %s" : "Itzuli %s(e)ra",
"Add to your Nextcloud" : "Gehitu zure Nextclouden",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "%s partekatzeak huts egin du atzealdeak ez dituelako ScienceMesh parteatzeak onartzen",
"Link copied to clipboard" : "Arbelara kopiatutako esteka",
"Copy to clipboard" : "Kopiatu arbelera",
"Copy internal link to clipboard" : "Kopiatu barne esteka arbelera",
+1 -1
View File
@@ -77,7 +77,6 @@ OC.L10N.register(
"You cannot share to a Team if the app is not enabled" : "اگر برنامه فعال نباشد، نمی‌توانید آن را با یک تیم به اشتراک بگذارید",
"Please specify a valid team" : "لطفا یک تیم معتبر معرفی کنید",
"Sharing %s failed because the back end does not support room shares" : "اشتراک گذاری %sانجام نشد زیرا قسمت پشتی سهام اتاق را پشتیبانی نمی کند",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Sharing %s failed because the back end does not support ScienceMesh shares",
"Unknown share type" : "نوع اشتراک ناشناخته",
"Not a directory" : "این یک پوشه نیست",
"Could not lock node" : "گره را نمی توان قفل کرد",
@@ -404,6 +403,7 @@ OC.L10N.register(
"Share not found" : "اشتراک گذاری یافت نشد",
"Back to %s" : "بازگشت به %s",
"Add to your Nextcloud" : "به نکست‌کلود خود اضافه کنید",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Sharing %s failed because the back end does not support ScienceMesh shares",
"Link copied to clipboard" : "پیوند در حافظه موقت کپی شده",
"Copy to clipboard" : "کپی به کلیپ بورد",
"Copy internal link to clipboard" : "کپی کردن لینک داخلی در کلیپ بورد",
+1 -1
View File
@@ -75,7 +75,6 @@
"You cannot share to a Team if the app is not enabled" : "اگر برنامه فعال نباشد، نمی‌توانید آن را با یک تیم به اشتراک بگذارید",
"Please specify a valid team" : "لطفا یک تیم معتبر معرفی کنید",
"Sharing %s failed because the back end does not support room shares" : "اشتراک گذاری %sانجام نشد زیرا قسمت پشتی سهام اتاق را پشتیبانی نمی کند",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Sharing %s failed because the back end does not support ScienceMesh shares",
"Unknown share type" : "نوع اشتراک ناشناخته",
"Not a directory" : "این یک پوشه نیست",
"Could not lock node" : "گره را نمی توان قفل کرد",
@@ -402,6 +401,7 @@
"Share not found" : "اشتراک گذاری یافت نشد",
"Back to %s" : "بازگشت به %s",
"Add to your Nextcloud" : "به نکست‌کلود خود اضافه کنید",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Sharing %s failed because the back end does not support ScienceMesh shares",
"Link copied to clipboard" : "پیوند در حافظه موقت کپی شده",
"Copy to clipboard" : "کپی به کلیپ بورد",
"Copy internal link to clipboard" : "کپی کردن لینک داخلی در کلیپ بورد",
+1 -1
View File
@@ -77,7 +77,6 @@ OC.L10N.register(
"You cannot share to a Team if the app is not enabled" : "Vous ne pouvez pas partager à une équipe si l'application n'est pas activée",
"Please specify a valid team" : "Merci de spécifier un équipe valide",
"Sharing %s failed because the back end does not support room shares" : "Le partage %s a échoué parce que l'arrière-plan ne prend pas en charge les partages.",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Le partage de %s a échoué car le serveur ne supporte pas les partages ScienceMesh",
"Unknown share type" : "Type de partage inconnu",
"Not a directory" : "N'est pas un dossier",
"Could not lock node" : "Impossible de verrouiller le nœud",
@@ -404,6 +403,7 @@ OC.L10N.register(
"Share not found" : "Partage non trouvé",
"Back to %s" : "Retourner à %s",
"Add to your Nextcloud" : "Ajouter à votre Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Le partage de %s a échoué car le serveur ne supporte pas les partages ScienceMesh",
"Link copied to clipboard" : "Lien copié dans le presse-papier",
"Copy to clipboard" : "Copier dans le presse-papiers",
"Copy internal link to clipboard" : "Copier le lien interne dans le presse-papiers",
+1 -1
View File
@@ -75,7 +75,6 @@
"You cannot share to a Team if the app is not enabled" : "Vous ne pouvez pas partager à une équipe si l'application n'est pas activée",
"Please specify a valid team" : "Merci de spécifier un équipe valide",
"Sharing %s failed because the back end does not support room shares" : "Le partage %s a échoué parce que l'arrière-plan ne prend pas en charge les partages.",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Le partage de %s a échoué car le serveur ne supporte pas les partages ScienceMesh",
"Unknown share type" : "Type de partage inconnu",
"Not a directory" : "N'est pas un dossier",
"Could not lock node" : "Impossible de verrouiller le nœud",
@@ -402,6 +401,7 @@
"Share not found" : "Partage non trouvé",
"Back to %s" : "Retourner à %s",
"Add to your Nextcloud" : "Ajouter à votre Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Le partage de %s a échoué car le serveur ne supporte pas les partages ScienceMesh",
"Link copied to clipboard" : "Lien copié dans le presse-papier",
"Copy to clipboard" : "Copier dans le presse-papiers",
"Copy internal link to clipboard" : "Copier le lien interne dans le presse-papiers",
+1 -1
View File
@@ -77,7 +77,6 @@ OC.L10N.register(
"You cannot share to a Team if the app is not enabled" : "Ní féidir leat a roinnt le foireann mura bhfuil an feidhmchlár cumasaithe",
"Please specify a valid team" : "Sonraigh foireann bhailí le do thoil",
"Sharing %s failed because the back end does not support room shares" : "Theip ar chomhroinnt %s toisc nach dtacaíonn an ceann cúil le comhroinnt seomra",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Theip ar chomhroinnt %s toisc nach dtacaíonn an cúlcheann le scaireanna ScienceMesh",
"Unknown share type" : "Cineál scaire anaithnid",
"Not a directory" : "Ní eolaire",
"Could not lock node" : "Níorbh fhéidir nód a ghlasáil",
@@ -404,6 +403,7 @@ OC.L10N.register(
"Share not found" : "Ní bhfuarthas an sciar",
"Back to %s" : "Ar ais go dtí %s",
"Add to your Nextcloud" : "Cuir le do Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Theip ar chomhroinnt %s toisc nach dtacaíonn an cúlcheann le scaireanna ScienceMesh",
"Link copied to clipboard" : "Cóipeáladh an nasc chuig an ngearrthaisce",
"Copy to clipboard" : "Cóipeáil chuig an ngearrthaisce",
"Copy internal link to clipboard" : "Cóipeáil nasc inmheánach chuig an ngearrthaisce",
+1 -1
View File
@@ -75,7 +75,6 @@
"You cannot share to a Team if the app is not enabled" : "Ní féidir leat a roinnt le foireann mura bhfuil an feidhmchlár cumasaithe",
"Please specify a valid team" : "Sonraigh foireann bhailí le do thoil",
"Sharing %s failed because the back end does not support room shares" : "Theip ar chomhroinnt %s toisc nach dtacaíonn an ceann cúil le comhroinnt seomra",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Theip ar chomhroinnt %s toisc nach dtacaíonn an cúlcheann le scaireanna ScienceMesh",
"Unknown share type" : "Cineál scaire anaithnid",
"Not a directory" : "Ní eolaire",
"Could not lock node" : "Níorbh fhéidir nód a ghlasáil",
@@ -402,6 +401,7 @@
"Share not found" : "Ní bhfuarthas an sciar",
"Back to %s" : "Ar ais go dtí %s",
"Add to your Nextcloud" : "Cuir le do Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Theip ar chomhroinnt %s toisc nach dtacaíonn an cúlcheann le scaireanna ScienceMesh",
"Link copied to clipboard" : "Cóipeáladh an nasc chuig an ngearrthaisce",
"Copy to clipboard" : "Cóipeáil chuig an ngearrthaisce",
"Copy internal link to clipboard" : "Cóipeáil nasc inmheánach chuig an ngearrthaisce",
+1 -1
View File
@@ -77,7 +77,6 @@ OC.L10N.register(
"You cannot share to a Team if the app is not enabled" : "Vde. non pode compartir cun equipo se a aplicación non está activada",
"Please specify a valid team" : "Especifique un equipo correcto",
"Sharing %s failed because the back end does not support room shares" : "Fallou a compartición de %s, xa que a infraestrutura non admite salas compartidas",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Produciuse un erro ao compartir %s porque a infraestrutura non admite comparticións de ScienceMesh",
"Unknown share type" : "Tipo descoñecido de compartición",
"Not a directory" : "Non é un directorio",
"Could not lock node" : "Non foi posíbel bloquear o nodo",
@@ -404,6 +403,7 @@ OC.L10N.register(
"Share not found" : "Non se atopou a compartición",
"Back to %s" : "Volver a %s",
"Add to your Nextcloud" : "Engadir ao seu Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Produciuse un erro ao compartir %s porque a infraestrutura non admite comparticións de ScienceMesh",
"Link copied to clipboard" : "A ligazón foi copiada no portapapeis",
"Copy to clipboard" : "Copiar no portapapeis",
"Copy internal link to clipboard" : "Copiar a ligazón interna ao portapapeis",
+1 -1
View File
@@ -75,7 +75,6 @@
"You cannot share to a Team if the app is not enabled" : "Vde. non pode compartir cun equipo se a aplicación non está activada",
"Please specify a valid team" : "Especifique un equipo correcto",
"Sharing %s failed because the back end does not support room shares" : "Fallou a compartición de %s, xa que a infraestrutura non admite salas compartidas",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Produciuse un erro ao compartir %s porque a infraestrutura non admite comparticións de ScienceMesh",
"Unknown share type" : "Tipo descoñecido de compartición",
"Not a directory" : "Non é un directorio",
"Could not lock node" : "Non foi posíbel bloquear o nodo",
@@ -402,6 +401,7 @@
"Share not found" : "Non se atopou a compartición",
"Back to %s" : "Volver a %s",
"Add to your Nextcloud" : "Engadir ao seu Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Produciuse un erro ao compartir %s porque a infraestrutura non admite comparticións de ScienceMesh",
"Link copied to clipboard" : "A ligazón foi copiada no portapapeis",
"Copy to clipboard" : "Copiar no portapapeis",
"Copy internal link to clipboard" : "Copiar a ligazón interna ao portapapeis",
+1 -1
View File
@@ -76,7 +76,6 @@ OC.L10N.register(
"You cannot share to a Team if the app is not enabled" : "Nem tudja megosztani egy Csapat számára, ha az alkalmazás nem engedélyezett",
"Please specify a valid team" : "Adjon meg egy érvényes csapatot",
"Sharing %s failed because the back end does not support room shares" : "A(z) %s megosztása sikertelen, mert a háttérprogram nem támogatja a szobamegosztásokat",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "A(z) %s megosztása sikertelen, mert a háttérprogram nem támogatja a ScienceMesh megosztásokat",
"Unknown share type" : "Ismeretlen megosztástípus",
"Not a directory" : "Nem könyvtár",
"Could not lock node" : "Nem sikerült zárolni a csomópontot",
@@ -281,6 +280,7 @@ OC.L10N.register(
"Share not found" : "A megosztás nem található",
"Back to %s" : "Vissza ide: %s",
"Add to your Nextcloud" : "Hozzáadás a Nextcloudjához",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "A(z) %s megosztása sikertelen, mert a háttérprogram nem támogatja a ScienceMesh megosztásokat",
"Link copied to clipboard" : "Hivatkozás a vágólapra másolva",
"Copy to clipboard" : "Másolás a vágólapra",
"Copy internal link to clipboard" : "Belső hivatkozás másolása a vágólapra",
+1 -1
View File
@@ -74,7 +74,6 @@
"You cannot share to a Team if the app is not enabled" : "Nem tudja megosztani egy Csapat számára, ha az alkalmazás nem engedélyezett",
"Please specify a valid team" : "Adjon meg egy érvényes csapatot",
"Sharing %s failed because the back end does not support room shares" : "A(z) %s megosztása sikertelen, mert a háttérprogram nem támogatja a szobamegosztásokat",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "A(z) %s megosztása sikertelen, mert a háttérprogram nem támogatja a ScienceMesh megosztásokat",
"Unknown share type" : "Ismeretlen megosztástípus",
"Not a directory" : "Nem könyvtár",
"Could not lock node" : "Nem sikerült zárolni a csomópontot",
@@ -279,6 +278,7 @@
"Share not found" : "A megosztás nem található",
"Back to %s" : "Vissza ide: %s",
"Add to your Nextcloud" : "Hozzáadás a Nextcloudjához",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "A(z) %s megosztása sikertelen, mert a háttérprogram nem támogatja a ScienceMesh megosztásokat",
"Link copied to clipboard" : "Hivatkozás a vágólapra másolva",
"Copy to clipboard" : "Másolás a vágólapra",
"Copy internal link to clipboard" : "Belső hivatkozás másolása a vágólapra",
+1 -1
View File
@@ -76,7 +76,6 @@ OC.L10N.register(
"You cannot share to a Team if the app is not enabled" : "Þú getur ekki deilt með teymi ef forritið er ekki virkt",
"Please specify a valid team" : "Settu inn gilt teymi",
"Sharing %s failed because the back end does not support room shares" : "Deiling %s mistókst því bakvinnslukerfið leyfir ekki spjallsvæðasameignir",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Deiling %s mistókst því bakvinnslukerfið leyfir ekki ScienceMesh-sameignir",
"Unknown share type" : "Óþekkt tegund sameignar",
"Not a directory" : "Er ekki mappa",
"Could not lock node" : "Gat ekki læst hnút",
@@ -350,6 +349,7 @@ OC.L10N.register(
"Share not found" : "Sameign fannst ekki",
"Back to %s" : "Til baka í %s",
"Add to your Nextcloud" : "Bæta í þitt eigið Nextcloud",
"Sharing %s failed because the back end does not support ScienceMesh shares" : "Deiling %s mistókst því bakvinnslukerfið leyfir ekki ScienceMesh-sameignir",
"Link copied to clipboard" : "Tengill afritaður á klippispjald",
"Copy to clipboard" : "Afrita á klippispjald",
"Copy internal link to clipboard" : "Afrita innri tengil á klippispjald",

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