Compare commits

..

395 Commits

Author SHA1 Message Date
grnd-alt
93307bb247 Merge pull request #6520 from nextcloud/backport/6518/stable24
[stable24] fix: Detect end of the activity responses (fix #3395)
2024-11-19 11:33:56 +01:00
Julius Härtl
45f2eedafe fix: Detect end of the activity responses (fix #3395)
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-11-19 10:24:54 +00:00
Arthur Schiwon
6fb0f6209c Merge pull request #5706 from nextcloud/backport/5703/stable24
[stable24] fix: Avoid conflicts on deck attachments folder name
2024-05-24 10:27:45 +02:00
Julius Härtl
043327dc09 fix: Compatibility with php 7.4
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-03-28 10:15:56 +01:00
Julius Härtl
05aafd9ddb ci: Update base query count
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-03-27 15:02:29 +00:00
Julius Härtl
5f789962b4 fix: Avoid conflicts on deck attachments folder name
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-03-27 15:02:28 +00:00
Julius Härtl
ff2c11c796 chore(release): Bump version to 1.7.5
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-01-16 17:37:35 +01:00
Julius Härtl
3dee8587b7 Merge pull request #5449 from nextcloud/backport/5444/stable24
[stable24] Fix deleted card/board issues
2024-01-12 09:30:35 +01:00
Julius Härtl
86751c4b89 test: Adapt unit tests
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-01-12 09:17:25 +01:00
Julius Härtl
f70b31c449 ci: Remove unused test
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-01-12 08:42:15 +01:00
Julius Härtl
52c5020ba4 chore: update actions
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-01-12 08:42:15 +01:00
Julius Härtl
1f71d1ab78 fix: PHP 7.4 compatibility
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-01-12 08:42:15 +01:00
Julius Härtl
9119017ce8 tests: Fix missing behat context methods
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-01-09 23:06:21 +01:00
Julius Härtl
0c0bb40515 chore: Fix ci setup for activity
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-01-09 23:06:21 +01:00
Julius Härtl
0954d4d8a0 fix: Limit card activities for deleted cards
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-01-09 23:06:21 +01:00
Julius Härtl
272da5406a fix: Further limit updating cards
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-01-09 23:06:19 +01:00
Julius Härtl
aef06d833d fix: limit to non-deleted cards
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-01-09 23:05:43 +01:00
Julius Härtl
71948d670e fix: Consider a deleted board inaccessible to share recipients
Only the owner can delete/undo a board deletion so there is no reason
other users should have any permission on a board marked as deleted

Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-01-09 23:05:10 +01:00
Julius Härtl
22a3efe445 tests: Add integration tests for deleted boards/cards
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-01-09 23:05:09 +01:00
Julius Härtl
6aca034222 Merge pull request #5446 from nextcloud/backport/5440/stable24
[stable24] Fix small issues around delete/undo
2024-01-09 22:52:18 +01:00
Julius Härtl
b37ba6a409 ci: Update actions
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-01-09 22:15:17 +01:00
Julius Härtl
ffb99b8010 ci: Bump setup-php
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-01-09 19:38:33 +01:00
Julius Härtl
7e33f38b4c fix: Psalm and CI
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-01-09 19:38:09 +01:00
Julius Härtl
5391689eb0 ci: Update phpunit github action
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-01-09 19:38:09 +01:00
Julius Härtl
e289e05c98 fix: Only query boards not marked for deletion unless we want to undo
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-01-09 19:38:06 +01:00
Julius Härtl
efb0bef5e1 Merge pull request #5278 from nextcloud/automated/noid/stable24-fix-npm-audit 2023-11-12 09:06:49 +01:00
nextcloud-command
1825ae4711 chore(deps): fix npm audit
Signed-off-by: GitHub <noreply@github.com>
2023-11-12 04:06:39 +00:00
Julius Härtl
c4bdffbce5 Merge pull request #5247 from nextcloud/automated/noid/stable24-fix-npm-audit 2023-10-29 20:29:37 +01:00
nextcloud-command
7eb57b0ed1 chore(deps): fix npm audit
Signed-off-by: GitHub <noreply@github.com>
2023-10-29 03:37:32 +00:00
Julius Härtl
3516e7a9c2 Merge pull request #5230 from nextcloud/automated/noid/stable24-fix-npm-audit 2023-10-23 08:35:52 +02:00
nextcloud-command
5a5ee3cd4f chore(deps): fix npm audit
Signed-off-by: GitHub <noreply@github.com>
2023-10-22 03:22:47 +00:00
Julius Härtl
574aa325a0 Merge pull request #5199 from nextcloud/dependabot/npm_and_yarn/stable24/babel/runtime-7.23.2
Chore(deps): Bump @babel/runtime from 7.22.15 to 7.23.2
2023-10-16 23:00:28 +02:00
dependabot[bot]
933e0b097e Chore(deps): Bump @babel/runtime from 7.22.15 to 7.23.2
Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.22.15 to 7.23.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-runtime)

---
updated-dependencies:
- dependency-name: "@babel/runtime"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-14 01:17:32 +00:00
Julius Härtl
2a6023cf86 Merge pull request #5194 from nextcloud/automated/noid/stable24-fix-npm-audit 2023-10-09 12:30:17 +02:00
nextcloud-command
b1ee1ae156 chore(deps): fix npm audit
Signed-off-by: GitHub <noreply@github.com>
2023-10-08 03:43:35 +00:00
Julius Härtl
892727fed0 Merge pull request #5112 from nextcloud/dependabot/npm_and_yarn/stable24/url-search-params-polyfill-8.2.5 2023-09-09 09:38:07 +02:00
Julius Härtl
cced84af3d Merge pull request #5113 from nextcloud/dependabot/npm_and_yarn/stable24/babel/runtime-7.22.15 2023-09-09 09:08:01 +02:00
dependabot[bot]
f33477fe1a Chore(deps): Bump @babel/runtime from 7.22.11 to 7.22.15
Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.22.11 to 7.22.15.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.22.15/packages/babel-runtime)

---
updated-dependencies:
- dependency-name: "@babel/runtime"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-09 01:51:23 +00:00
dependabot[bot]
bafc3e5221 Chore(deps): Bump url-search-params-polyfill from 8.2.4 to 8.2.5
Bumps [url-search-params-polyfill](https://github.com/jerrybendy/url-search-params-polyfill) from 8.2.4 to 8.2.5.
- [Release notes](https://github.com/jerrybendy/url-search-params-polyfill/releases)
- [Commits](https://github.com/jerrybendy/url-search-params-polyfill/commits)

---
updated-dependencies:
- dependency-name: url-search-params-polyfill
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-09 01:51:10 +00:00
Julius Härtl
67ecf24d86 Merge pull request #5074 from nextcloud/backport/4810/stable24 2023-08-30 19:44:31 +02:00
Max
10bda7253e Fix(occ): set user id for permission sevice from board service
Fixes #4010.

Signed-off-by: Max <max@nextcloud.com>
2023-08-30 08:51:09 +00:00
Julius Härtl
1713343dd4 Merge pull request #5063 from nextcloud/dependabot/npm_and_yarn/stable24/babel/runtime-7.22.11 2023-08-28 08:30:34 +02:00
dependabot[bot]
c2cf3feb25 Chore(deps): Bump @babel/runtime from 7.22.10 to 7.22.11
Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.22.10 to 7.22.11.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.22.11/packages/babel-runtime)

---
updated-dependencies:
- dependency-name: "@babel/runtime"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-26 01:24:10 +00:00
Julius Härtl
56792e048a Merge pull request #5020 from nextcloud/dependabot/npm_and_yarn/stable24/babel/runtime-7.22.10 2023-08-12 10:02:13 +02:00
dependabot[bot]
dae3144c25 Chore(deps): Bump @babel/runtime from 7.22.6 to 7.22.10
Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.22.6 to 7.22.10.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.22.10/packages/babel-runtime)

---
updated-dependencies:
- dependency-name: "@babel/runtime"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-12 02:19:24 +00:00
Julius Härtl
31b73fe6bb Merge pull request #4983 from nextcloud/dependabot/npm_and_yarn/stable24/dompurify-2.4.7 2023-08-06 22:10:53 +02:00
dependabot[bot]
ef686bef34 Chore(deps): Bump dompurify from 2.4.5 to 2.4.7
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 2.4.5 to 2.4.7.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/2.4.5...2.4.7)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-05 02:19:00 +00:00
Julius Härtl
50609944bc Merge pull request #4959 from nextcloud/automated/noid/stable24-fix-npm-audit 2023-07-24 08:25:32 +02:00
nextcloud-command
21727cfb3a chore(deps): fix npm audit
Signed-off-by: GitHub <noreply@github.com>
2023-07-23 03:20:18 +00:00
Julius Härtl
a93b874b89 Merge pull request #4872 from nextcloud/automated/noid/stable24-fix-npm-audit 2023-07-10 12:31:24 +02:00
Julius Härtl
c573c33926 Merge pull request #4888 from nextcloud/dependabot/npm_and_yarn/stable24/babel/runtime-7.22.6 2023-07-10 07:30:05 +02:00
Julius Härtl
9ff9858e9e Merge pull request #4889 from nextcloud/dependabot/npm_and_yarn/stable24/url-search-params-polyfill-8.2.4 2023-07-10 07:29:54 +02:00
nextcloud-command
aa3c80e8d0 chore(deps): fix npm audit
Signed-off-by: GitHub <noreply@github.com>
2023-07-09 03:53:19 +00:00
dependabot[bot]
56c4d45712 Chore(deps): Bump url-search-params-polyfill from 8.2.2 to 8.2.4
Bumps [url-search-params-polyfill](https://github.com/jerrybendy/url-search-params-polyfill) from 8.2.2 to 8.2.4.
- [Release notes](https://github.com/jerrybendy/url-search-params-polyfill/releases)
- [Commits](https://github.com/jerrybendy/url-search-params-polyfill/commits/v8.2.4)

---
updated-dependencies:
- dependency-name: url-search-params-polyfill
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-08 01:27:33 +00:00
dependabot[bot]
4f67d2fe60 Chore(deps): Bump @babel/runtime from 7.22.5 to 7.22.6
Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.22.5 to 7.22.6.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.22.6/packages/babel-runtime)

---
updated-dependencies:
- dependency-name: "@babel/runtime"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-08 01:27:25 +00:00
Julius Härtl
875ac0d6e9 Merge pull request #4851 from nextcloud/automated/noid/stable24-fix-npm-audit 2023-06-26 16:29:47 +02:00
nextcloud-command
741df20b49 chore(deps): fix npm audit
Signed-off-by: GitHub <noreply@github.com>
2023-06-25 03:57:37 +00:00
Julius Härtl
0ac494df9d Merge pull request #4795 from nextcloud/dependabot/npm_and_yarn/stable24/vue/test-utils-1.3.6 2023-06-10 12:47:17 +02:00
Julius Härtl
a8ce89d487 Merge pull request #4793 from nextcloud/dependabot/npm_and_yarn/stable24/babel/runtime-7.22.5 2023-06-10 12:47:08 +02:00
dependabot[bot]
2fcbbbbc23 Chore(deps-dev): Bump @vue/test-utils from 1.3.5 to 1.3.6
Bumps [@vue/test-utils](https://github.com/vuejs/test-utils) from 1.3.5 to 1.3.6.
- [Release notes](https://github.com/vuejs/test-utils/releases)
- [Commits](https://github.com/vuejs/test-utils/commits)

---
updated-dependencies:
- dependency-name: "@vue/test-utils"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-10 03:40:27 +00:00
dependabot[bot]
4f673fe598 Chore(deps): Bump @babel/runtime from 7.22.3 to 7.22.5
Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.22.3 to 7.22.5.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.22.5/packages/babel-runtime)

---
updated-dependencies:
- dependency-name: "@babel/runtime"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-10 03:30:15 +00:00
Julius Härtl
02ba8f85ce Merge pull request #4759 from nextcloud/dependabot/npm_and_yarn/stable24/babel/runtime-7.22.3 2023-06-05 07:45:41 +02:00
Julius Härtl
f88d53d7f1 Merge pull request #4762 from nextcloud/dependabot/npm_and_yarn/stable24/url-search-params-polyfill-8.2.2 2023-06-05 07:45:09 +02:00
dependabot[bot]
6a5eecea76 Chore(deps): Bump url-search-params-polyfill from 8.1.1 to 8.2.2
Bumps [url-search-params-polyfill](https://github.com/jerrybendy/url-search-params-polyfill) from 8.1.1 to 8.2.2.
- [Release notes](https://github.com/jerrybendy/url-search-params-polyfill/releases)
- [Commits](https://github.com/jerrybendy/url-search-params-polyfill/commits)

---
updated-dependencies:
- dependency-name: url-search-params-polyfill
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-03 03:39:30 +00:00
dependabot[bot]
b61667c90b Chore(deps): Bump @babel/runtime from 7.22.0 to 7.22.3
Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.22.0 to 7.22.3.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.22.3/packages/babel-runtime)

---
updated-dependencies:
- dependency-name: "@babel/runtime"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-03 03:07:49 +00:00
Julius Härtl
6864846d84 Merge pull request #4745 from nextcloud/dependabot/npm_and_yarn/stable24/babel/runtime-7.22.0 2023-05-30 10:55:23 +02:00
dependabot[bot]
962256acb0 Chore(deps): Bump @babel/runtime from 7.21.5 to 7.22.0
Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.21.5 to 7.22.0.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.22.0/packages/babel-runtime)

---
updated-dependencies:
- dependency-name: "@babel/runtime"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-27 03:33:27 +00:00
Nextcloud bot
9db8c9af80 Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-05-21 00:29:12 +00:00
Nextcloud bot
88bd868e76 Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-05-18 00:29:48 +00:00
Julius Härtl
3c88551ad5 Merge pull request #4681 from nextcloud/automated/noid/stable24-fix-npm-audit 2023-05-15 08:25:09 +02:00
nextcloud-command
0872b1b606 chore(deps): fix npm audit
Signed-off-by: GitHub <noreply@github.com>
2023-05-14 03:09:57 +00:00
Nextcloud bot
65242c2b6c Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-05-12 02:43:23 +00:00
Julius Härtl
a3527542f9 Bump version to 1.7.4
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2023-05-10 15:41:56 +02:00
Nextcloud bot
28e4b12428 Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-05-08 02:40:24 +00:00
Julius Härtl
628cd333f1 Merge pull request #4646 from nextcloud/backport/4643/stable24
[stable24] fix: Append datetime picker to body to avoid cut off
2023-05-03 13:32:01 +02:00
Julius Härtl
ccfaa4886a fix: z-index of datepicker in modal
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2023-05-03 13:10:40 +02:00
Julius Härtl
0ef238da0e Merge pull request #4639 from nextcloud/automated/noid/stable24-fix-npm-audit
[stable24] Fix npm audit
2023-05-03 12:45:05 +02:00
Julius Härtl
333b904335 fix: Append datetime picker to body to avoid cut off
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2023-05-03 10:41:52 +00:00
nextcloud-command
32a956af02 chore(deps): fix npm audit
Signed-off-by: GitHub <noreply@github.com>
2023-05-03 08:12:52 +00:00
Julius Härtl
b7dad3134d Merge pull request #4629 from nextcloud/dependabot/npm_and_yarn/stable24/nextcloud/webpack-vue-config-5.5.1 2023-05-02 10:31:28 +02:00
Julius Härtl
42f76117f2 Merge pull request #4631 from nextcloud/dependabot/npm_and_yarn/stable24/babel/runtime-7.21.5 2023-05-02 10:31:15 +02:00
dependabot[bot]
be1c646bd7 Chore(deps): Bump @babel/runtime from 7.21.0 to 7.21.5
Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.21.0 to 7.21.5.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.21.5/packages/babel-runtime)

---
updated-dependencies:
- dependency-name: "@babel/runtime"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-29 01:58:38 +00:00
dependabot[bot]
137fece0b8 Chore(deps-dev): Bump @nextcloud/webpack-vue-config from 5.5.0 to 5.5.1
Bumps [@nextcloud/webpack-vue-config](https://github.com/nextcloud/webpack-vue-config) from 5.5.0 to 5.5.1.
- [Release notes](https://github.com/nextcloud/webpack-vue-config/releases)
- [Changelog](https://github.com/nextcloud/webpack-vue-config/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nextcloud/webpack-vue-config/compare/v5.5.0...v5.5.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-29 01:58:09 +00:00
Nextcloud bot
81e5922dfd Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-04-28 02:40:36 +00:00
Nextcloud bot
ccc216d388 Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-04-27 02:40:52 +00:00
Julius Härtl
3f7ab93df9 Update appbuild.yml
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2023-04-25 08:28:20 +02:00
Julius Härtl
a621aacac0 Update phpunit.yml
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2023-04-24 12:52:14 +02:00
Julius Härtl
bb7ed1bc31 Merge pull request #4595 from nextcloud/dependabot/npm_and_yarn/stable24/vue/test-utils-1.3.5 2023-04-24 12:26:08 +02:00
Nextcloud bot
4d0f7ddef3 Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-04-23 02:40:59 +00:00
Nextcloud bot
bd13cc09d8 Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-04-19 02:40:51 +00:00
Nextcloud bot
cb3925faeb Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-04-16 02:39:55 +00:00
dependabot[bot]
ac11571a7d Chore(deps-dev): Bump @vue/test-utils from 1.3.4 to 1.3.5
Bumps [@vue/test-utils](https://github.com/vuejs/test-utils) from 1.3.4 to 1.3.5.
- [Release notes](https://github.com/vuejs/test-utils/releases)
- [Commits](https://github.com/vuejs/test-utils/commits)

---
updated-dependencies:
- dependency-name: "@vue/test-utils"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-15 01:57:50 +00:00
Nextcloud bot
fd4564450b Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-04-09 02:42:15 +00:00
Nextcloud bot
acbd42d6a4 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-04-06 02:41:16 +00:00
Nextcloud bot
458831dfc7 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-04-05 02:42:40 +00:00
Jonas
8a5098951c Merge pull request #4569 from nextcloud/backport/4566/stable24
[stable24] Gracefully handle not found card for a share
2023-03-29 11:17:55 +02:00
Jonas
99260ae966 Gracefully handle not found card for a share
Fixes: #3464
Fixes: #4565

Signed-off-by: Jonas <jonas@freesources.org>
2023-03-29 09:01:10 +00:00
Nextcloud bot
ea592251f9 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-28 02:31:42 +00:00
Julius Härtl
6c80674ce0 Merge pull request #4541 from nextcloud/backport/4487/stable24 2023-03-20 07:16:14 +01:00
Julius Härtl
060e8cd7db Merge pull request #4551 from nextcloud/automated/noid/stable24-update-nextcloud-ocp
[stable24] Update nextcloud/ocp dependency
2023-03-20 07:15:33 +01:00
nextcloud-command
f05bd86be9 chore(dev-deps): Bump nextcloud/ocp package
Signed-off-by: GitHub <noreply@github.com>
2023-03-19 03:09:00 +00:00
dependabot[bot]
1ce7856cae Merge pull request #4549 from nextcloud/dependabot/npm_and_yarn/stable24/nextcloud/webpack-vue-config-5.5.0 2023-03-18 05:23:13 +00:00
dependabot[bot]
678e4c9569 Chore(deps-dev): Bump @nextcloud/webpack-vue-config from 5.4.0 to 5.5.0
Bumps [@nextcloud/webpack-vue-config](https://github.com/nextcloud/webpack-vue-config) from 5.4.0 to 5.5.0.
- [Release notes](https://github.com/nextcloud/webpack-vue-config/releases)
- [Changelog](https://github.com/nextcloud/webpack-vue-config/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nextcloud/webpack-vue-config/compare/v5.4.0...v5.5.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-18 04:11:24 +00:00
Nextcloud bot
4fe4216cb5 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-18 02:39:40 +00:00
Julius Härtl
85e7305d8d fix: Use passed userid when getting attachment folder
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2023-03-17 14:05:15 +00:00
Nextcloud bot
090378580c Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-17 02:39:10 +00:00
Nextcloud bot
3f8efb5368 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-16 02:40:49 +00:00
Julius Härtl
c1f2fd452b Merge pull request #4538 from nextcloud/backport/4535/stable24 2023-03-15 15:32:42 +01:00
Jérôme Herbinet
576c47bdef Fix : Overlapping expiry dates on tags
Signed-off-by: Jérôme Herbinet <33763786+Jerome-Herbinet@users.noreply.github.com>

Signed-off-by: Jérôme Herbinet <33763786+Jerome-Herbinet@users.noreply.github.com>
2023-03-15 12:50:37 +00:00
Nextcloud bot
e907aeb8c0 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-15 02:38:47 +00:00
Nextcloud bot
c51119d051 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-10 02:40:09 +00:00
Nextcloud bot
ee72cb4660 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-06 02:39:16 +00:00
dependabot[bot]
d4f2ed263f Merge pull request #4501 from nextcloud/dependabot/npm_and_yarn/stable24/dompurify-2.4.5 2023-03-04 04:06:06 +00:00
dependabot[bot]
e6f8796b63 Chore(deps): Bump dompurify from 2.4.4 to 2.4.5
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 2.4.4 to 2.4.5.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/2.4.4...2.4.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-04 02:57:56 +00:00
Nextcloud bot
846443d003 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-03-04 02:40:29 +00:00
dependabot[bot]
144c27d403 Merge pull request #4475 from nextcloud/dependabot/npm_and_yarn/stable24/babel/runtime-7.21.0 2023-02-25 04:26:43 +00:00
dependabot[bot]
f374084989 chore(deps): bump @babel/runtime from 7.20.13 to 7.21.0
Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.20.13 to 7.21.0.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.21.0/packages/babel-runtime)

---
updated-dependencies:
- dependency-name: "@babel/runtime"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-25 02:57:54 +00:00
Nextcloud bot
0656e53508 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-02-24 02:42:13 +00:00
Nextcloud bot
7506126ef7 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-02-22 02:34:22 +00:00
Nextcloud bot
5214721875 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-02-21 02:33:48 +00:00
Julius Härtl
34f7b726cd Merge pull request #4465 from nextcloud/automated/noid/stable24-update-nextcloud-ocp 2023-02-20 14:57:17 +01:00
nextcloud-command
ea5baa5339 chore(dev-deps): Bump nextcloud/ocp package
Signed-off-by: GitHub <noreply@github.com>
2023-02-19 03:33:35 +00:00
Nextcloud bot
7c3aa301ac Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-02-19 02:34:29 +00:00
dependabot[bot]
313bc90ce9 Merge pull request #4462 from nextcloud/dependabot/npm_and_yarn/stable24/dompurify-2.4.4 2023-02-18 05:31:36 +00:00
dependabot[bot]
be06c7ab70 Chore(deps): Bump dompurify from 2.4.3 to 2.4.4
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 2.4.3 to 2.4.4.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/2.4.3...2.4.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-18 04:46:30 +00:00
Nextcloud bot
5964da382e Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-02-18 02:34:50 +00:00
Nextcloud bot
eaa2facc29 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-02-17 02:33:47 +00:00
Nextcloud bot
13e836760a Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-02-16 02:33:30 +00:00
Nextcloud bot
73815827e1 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-02-15 02:33:45 +00:00
Nextcloud bot
34107ad06f Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-02-14 02:33:25 +00:00
Nextcloud bot
90535b3c30 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-02-13 02:32:44 +00:00
Nextcloud bot
312376e596 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-02-12 02:33:25 +00:00
Nextcloud bot
04dbe45f29 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-02-11 02:33:40 +00:00
Nextcloud bot
bc38340daf Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-02-10 02:34:53 +00:00
Nextcloud bot
9b89897d74 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-02-07 02:33:12 +00:00
Nextcloud bot
f411181dcf Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-02-05 02:32:16 +00:00
Nextcloud bot
080465d48a Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-02-04 02:32:52 +00:00
Nextcloud bot
2358645037 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-02-01 02:32:45 +00:00
Nextcloud bot
c6545c7c00 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-01-31 02:33:59 +00:00
Nextcloud bot
3baa2fc1a0 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-01-30 02:34:13 +00:00
Julius Härtl
fd297dc92e Merge pull request #4416 from nextcloud/automated/noid/stable24-update-nextcloud-ocp 2023-01-29 08:41:17 +01:00
nextcloud-command
4608e4b77b chore(dev-deps): Bump nextcloud/ocp package
Signed-off-by: GitHub <noreply@github.com>
2023-01-29 02:56:09 +00:00
dependabot[bot]
524b8ba90e Merge pull request #4413 from nextcloud/dependabot/npm_and_yarn/stable24/vue/test-utils-1.3.4 2023-01-28 06:50:48 +00:00
dependabot[bot]
569e568136 Merge pull request #4403 from nextcloud/dependabot/npm_and_yarn/stable24/babel/runtime-7.20.13 2023-01-28 05:17:01 +00:00
dependabot[bot]
d9c563d5bf Chore(deps-dev): Bump @vue/test-utils from 1.3.3 to 1.3.4
Bumps [@vue/test-utils](https://github.com/vuejs/test-utils) from 1.3.3 to 1.3.4.
- [Release notes](https://github.com/vuejs/test-utils/releases)
- [Commits](https://github.com/vuejs/test-utils/commits)

---
updated-dependencies:
- dependency-name: "@vue/test-utils"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-28 03:28:46 +00:00
Nextcloud bot
f51956891e Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-01-28 02:33:42 +00:00
dependabot[bot]
053ecdacee Chore(deps): Bump @babel/runtime from 7.20.7 to 7.20.13
Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.20.7 to 7.20.13.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.20.13/packages/babel-runtime)

---
updated-dependencies:
- dependency-name: "@babel/runtime"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-28 02:01:56 +00:00
Nextcloud bot
8f755ee3eb Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-01-25 02:51:31 +00:00
Nextcloud bot
fa6d819409 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-01-24 02:32:51 +00:00
Nextcloud bot
fa17dfac3a Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-01-23 02:33:00 +00:00
Nextcloud bot
92b20efa89 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-01-22 02:32:42 +00:00
Nextcloud bot
2849177998 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-01-21 02:32:35 +00:00
Nextcloud bot
0bbeedb7e3 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-01-17 02:34:22 +00:00
Nextcloud bot
918f22f7a6 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-01-16 02:32:13 +00:00
Nextcloud bot
ecac9b772b Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-01-14 02:33:55 +00:00
Nextcloud bot
f0a4469be5 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-01-13 02:33:55 +00:00
Nextcloud bot
f47f4983d9 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-01-11 02:32:12 +00:00
Nextcloud bot
c9b8735804 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-01-10 02:33:45 +00:00
Julius Härtl
c9d7647200 Merge pull request #4370 from nextcloud/automated/noid/stable24-update-nextcloud-ocp 2023-01-09 16:38:03 +01:00
Nextcloud bot
4a8410f0fc Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-01-09 02:32:10 +00:00
nextcloud-command
4fbb383c0f Update psalm baseline
Signed-off-by: GitHub <noreply@github.com>
2023-01-08 02:51:52 +00:00
dependabot[bot]
98361ff096 Merge pull request #4364 from nextcloud/dependabot/npm_and_yarn/stable24/dompurify-2.4.3 2023-01-07 03:45:56 +00:00
Nextcloud bot
31f2ca49d5 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-01-07 02:32:16 +00:00
dependabot[bot]
e0e6f86801 Bump dompurify from 2.4.1 to 2.4.3
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 2.4.1 to 2.4.3.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/2.4.1...2.4.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-07 02:02:47 +00:00
Nextcloud bot
0bc4e1fa7b Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-01-05 02:32:03 +00:00
Nextcloud bot
0d137a372c Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-01-04 02:25:31 +00:00
Nextcloud bot
2d1ad75f35 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-01-03 02:47:16 +00:00
Nextcloud bot
e381e021d6 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-01-02 03:17:23 +00:00
Nextcloud bot
59f0813aa5 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2023-01-01 03:01:30 +00:00
Nextcloud bot
90d14c544f Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-12-31 03:20:24 +00:00
dependabot[bot]
02ca7acf4f Merge pull request #4346 from nextcloud/dependabot/npm_and_yarn/stable24/nextcloud/router-2.0.1 2022-12-30 13:32:22 +00:00
dependabot[bot]
0725b55773 Bump @nextcloud/router from 2.0.0 to 2.0.1
Bumps [@nextcloud/router](https://github.com/nextcloud/nextcloud-router) from 2.0.0 to 2.0.1.
- [Release notes](https://github.com/nextcloud/nextcloud-router/releases)
- [Changelog](https://github.com/nextcloud/nextcloud-router/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nextcloud/nextcloud-router/commits)

---
updated-dependencies:
- dependency-name: "@nextcloud/router"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-30 13:17:49 +00:00
Nextcloud bot
1219c0aed0 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-12-27 03:13:49 +00:00
dependabot[bot]
da57b9c7e1 Merge pull request #4336 from nextcloud/dependabot/npm_and_yarn/stable24/babel/runtime-7.20.7 2022-12-24 04:46:16 +00:00
Nextcloud bot
e67822167b Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-12-24 03:40:01 +00:00
dependabot[bot]
20e3729b86 Bump @babel/runtime from 7.20.6 to 7.20.7
Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.20.6 to 7.20.7.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.20.7/packages/babel-runtime)

---
updated-dependencies:
- dependency-name: "@babel/runtime"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-24 02:01:47 +00:00
Nextcloud bot
5c3d88dae0 Fix(l10n): 🔠 Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-12-21 02:38:12 +00:00
Nextcloud bot
2fb86b11ec [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-12-18 02:27:11 +00:00
Nextcloud bot
5d9c504842 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-12-16 02:27:05 +00:00
Nextcloud bot
1610968ed7 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-12-14 02:29:30 +00:00
Nextcloud bot
aad4aafc03 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-12-13 02:40:06 +00:00
Marcel Klehr
40e3987ae6 Merge pull request #4302 from nextcloud/backport/4194/stable24 2022-12-09 16:04:50 +01:00
Michal Polacik
d3a77e4a11 Permanently delete deck cards marked as deleted after 5 min in a cron job
Limit deleted cards in one cron job run to 500

Converted spaces to tabs

Added missing import for CardMapper class

Added another missing import for CardMapper class

Fixed response object in findToDelete method + fixed 2 misspellings in API.md

Fixed invalid parameter type

Fix DeleteCronTest

Signed-off-by: Marcel Klehr <mklehr@gmx.net>

Fix lint errors

Signed-off-by: Marcel Klehr <mklehr@gmx.net>
2022-12-09 14:38:59 +00:00
Nextcloud bot
c93189ff9a [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-12-04 02:22:13 +00:00
dependabot[bot]
bca7b3386c Merge pull request #4283 from nextcloud/dependabot/npm_and_yarn/stable24/babel/runtime-7.20.6 2022-12-03 03:47:27 +00:00
dependabot[bot]
3c7cc0b09c Bump @babel/runtime from 7.20.1 to 7.20.6
Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.20.1 to 7.20.6.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.20.6/packages/babel-runtime)

---
updated-dependencies:
- dependency-name: "@babel/runtime"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-03 02:02:26 +00:00
Nextcloud bot
8e35b67a0d [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-12-01 02:23:05 +00:00
Nextcloud bot
bfb292c54d [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-11-30 02:23:28 +00:00
Nextcloud bot
ab6c775f5c [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-11-23 02:26:02 +00:00
Nextcloud bot
e3e9e4596a [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-11-22 02:26:48 +00:00
Nextcloud bot
fefe77c245 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-11-21 02:22:57 +00:00
Nextcloud bot
42108cb223 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-11-20 02:24:07 +00:00
dependabot[bot]
72d7a245d2 Merge pull request #4271 from nextcloud/dependabot/npm_and_yarn/stable24/nextcloud/webpack-vue-config-5.4.0 2022-11-19 08:38:43 +00:00
Nextcloud bot
e187a665d5 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-11-19 02:25:09 +00:00
dependabot[bot]
01ab23dc82 Bump @nextcloud/webpack-vue-config from 5.0.0 to 5.4.0
Bumps [@nextcloud/webpack-vue-config](https://github.com/nextcloud/webpack-vue-config) from 5.0.0 to 5.4.0.
- [Release notes](https://github.com/nextcloud/webpack-vue-config/releases)
- [Changelog](https://github.com/nextcloud/webpack-vue-config/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nextcloud/webpack-vue-config/compare/v5.0.0...v5.4.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-19 01:53:18 +00:00
dependabot[bot]
004814ace7 Merge pull request #4267 from nextcloud/dependabot/npm_and_yarn/stable24/vue-2.7.14 2022-11-19 01:52:04 +00:00
dependabot[bot]
326a38557b Merge pull request #4264 from nextcloud/dependabot/npm_and_yarn/stable24/relative-ci/agent-3.1.3 2022-11-19 01:50:28 +00:00
dependabot[bot]
6e43ed5fce Merge pull request #4245 from nextcloud/dependabot/npm_and_yarn/stable24/moment-2.29.4 2022-11-18 23:41:59 +00:00
dependabot[bot]
8b92610f67 Merge pull request #4243 from nextcloud/dependabot/npm_and_yarn/stable24/nextcloud/moment-1.2.1 2022-11-18 23:36:56 +00:00
dependabot[bot]
6cc919b62d Bump vue from 2.6.14 to 2.7.14
Bumps [vue](https://github.com/vuejs/core) from 2.6.14 to 2.7.14.
- [Release notes](https://github.com/vuejs/core/releases)
- [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vuejs/core/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-18 22:30:17 +00:00
dependabot[bot]
3ff47580ad Bump @relative-ci/agent from 3.1.2 to 3.1.3
Bumps [@relative-ci/agent](https://github.com/relative-ci/agent) from 3.1.2 to 3.1.3.
- [Release notes](https://github.com/relative-ci/agent/releases)
- [Commits](https://github.com/relative-ci/agent/compare/v3.1.2...v3.1.3)

---
updated-dependencies:
- dependency-name: "@relative-ci/agent"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-18 22:29:42 +00:00
dependabot[bot]
a1a2120d43 Merge pull request #4270 from nextcloud/dependabot/npm_and_yarn/stable24/nextcloud/vue-5.4.0 2022-11-18 22:29:17 +00:00
dependabot[bot]
273222bb21 Merge pull request #4269 from nextcloud/dependabot/npm_and_yarn/stable24/vue-router-3.6.5 2022-11-18 22:29:12 +00:00
dependabot[bot]
1255e5a6c9 Merge pull request #4268 from nextcloud/dependabot/npm_and_yarn/stable24/vue/test-utils-1.3.3 2022-11-18 22:27:26 +00:00
dependabot[bot]
dace366b6c Merge pull request #4260 from nextcloud/dependabot/npm_and_yarn/stable24/nextcloud/browserslist-config-2.3.0 2022-11-18 21:49:06 +00:00
dependabot[bot]
a2f5414c48 Merge pull request #4257 from nextcloud/dependabot/npm_and_yarn/stable24/nextcloud/dialogs-3.2.0 2022-11-18 21:47:15 +00:00
dependabot[bot]
1887527197 Merge pull request #4254 from nextcloud/dependabot/npm_and_yarn/stable24/babel/runtime-7.20.1 2022-11-18 21:25:07 +00:00
dependabot[bot]
6d35c2f1c1 Merge pull request #4252 from nextcloud/dependabot/npm_and_yarn/stable24/dompurify-2.4.1 2022-11-18 21:18:01 +00:00
dependabot[bot]
51626698c4 Merge pull request #4266 from nextcloud/dependabot/npm_and_yarn/stable24/vue-at-2.5.1 2022-11-18 21:06:31 +00:00
dependabot[bot]
5ed2b23f76 Merge pull request #4265 from nextcloud/dependabot/npm_and_yarn/stable24/nextcloud/axios-1.11.0 2022-11-18 21:03:26 +00:00
dependabot[bot]
502b5acb69 Merge pull request #4261 from nextcloud/dependabot/npm_and_yarn/stable24/markdown-it-link-attributes-4.0.1 2022-11-18 20:46:28 +00:00
dependabot[bot]
03b5257fea Bump moment from 2.29.2 to 2.29.4
Bumps [moment](https://github.com/moment/moment) from 2.29.2 to 2.29.4.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.29.2...2.29.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-18 20:20:50 +00:00
dependabot[bot]
39b158f92d Bump @nextcloud/moment from 1.2.0 to 1.2.1
Bumps [@nextcloud/moment](https://github.com/nextcloud/nextcloud-moment) from 1.2.0 to 1.2.1.
- [Release notes](https://github.com/nextcloud/nextcloud-moment/releases)
- [Changelog](https://github.com/nextcloud/nextcloud-moment/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nextcloud/nextcloud-moment/compare/v1.2.0...v1.2.1)

---
updated-dependencies:
- dependency-name: "@nextcloud/moment"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-18 20:20:49 +00:00
dependabot[bot]
3163136b73 Merge pull request #4248 from nextcloud/dependabot/npm_and_yarn/stable24/nextcloud/l10n-1.6.0 2022-11-18 20:19:42 +00:00
dependabot[bot]
9791444167 Bump @nextcloud/vue from 5.3.1 to 5.4.0
Bumps [@nextcloud/vue](https://github.com/nextcloud/nextcloud-vue) from 5.3.1 to 5.4.0.
- [Release notes](https://github.com/nextcloud/nextcloud-vue/releases)
- [Changelog](https://github.com/nextcloud/nextcloud-vue/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nextcloud/nextcloud-vue/compare/v5.3.1...v5.4.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-18 17:35:27 +00:00
dependabot[bot]
77acf95106 Bump vue-router from 3.5.3 to 3.6.5
Bumps [vue-router](https://github.com/vuejs/router) from 3.5.3 to 3.6.5.
- [Release notes](https://github.com/vuejs/router/releases)
- [Commits](https://github.com/vuejs/router/commits)

---
updated-dependencies:
- dependency-name: vue-router
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-18 17:35:11 +00:00
dependabot[bot]
6505cc99ce Bump @vue/test-utils from 1.3.0 to 1.3.3
Bumps [@vue/test-utils](https://github.com/vuejs/test-utils) from 1.3.0 to 1.3.3.
- [Release notes](https://github.com/vuejs/test-utils/releases)
- [Commits](https://github.com/vuejs/test-utils/commits)

---
updated-dependencies:
- dependency-name: "@vue/test-utils"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-18 17:35:01 +00:00
dependabot[bot]
54d1a40eeb Bump vue-at from 2.5.0-beta.2 to 2.5.1
Bumps [vue-at](https://github.com/fritx/vue-at) from 2.5.0-beta.2 to 2.5.1.
- [Release notes](https://github.com/fritx/vue-at/releases)
- [Commits](https://github.com/fritx/vue-at/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-18 17:32:26 +00:00
dependabot[bot]
ab577a95eb Bump @nextcloud/axios from 1.9.0 to 1.11.0
Bumps [@nextcloud/axios](https://github.com/nextcloud/nextcloud-axios) from 1.9.0 to 1.11.0.
- [Release notes](https://github.com/nextcloud/nextcloud-axios/releases)
- [Changelog](https://github.com/nextcloud/nextcloud-axios/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nextcloud/nextcloud-axios/compare/v1.9.0...v1.11.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-18 17:32:14 +00:00
dependabot[bot]
8537d4acef Bump markdown-it-link-attributes from 4.0.0 to 4.0.1
Bumps [markdown-it-link-attributes](https://github.com/crookedneighbor/markdown-it-link-attributes) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/crookedneighbor/markdown-it-link-attributes/releases)
- [Changelog](https://github.com/crookedneighbor/markdown-it-link-attributes/blob/main/CHANGELOG.md)
- [Commits](https://github.com/crookedneighbor/markdown-it-link-attributes/compare/v4.0.0...v4.0.1)

---
updated-dependencies:
- dependency-name: markdown-it-link-attributes
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-18 17:31:22 +00:00
dependabot[bot]
d0fda8a546 Bump @nextcloud/browserslist-config from 2.2.0 to 2.3.0
Bumps [@nextcloud/browserslist-config](https://github.com/nextcloud/browserslist-config) from 2.2.0 to 2.3.0.
- [Release notes](https://github.com/nextcloud/browserslist-config/releases)
- [Commits](https://github.com/nextcloud/browserslist-config/compare/v2.2.0...v2.3.0)

---
updated-dependencies:
- dependency-name: "@nextcloud/browserslist-config"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-18 17:31:12 +00:00
dependabot[bot]
031f69523d Bump @nextcloud/dialogs from 3.1.2 to 3.2.0
Bumps [@nextcloud/dialogs](https://github.com/nextcloud/nextcloud-dialogs) from 3.1.2 to 3.2.0.
- [Release notes](https://github.com/nextcloud/nextcloud-dialogs/releases)
- [Changelog](https://github.com/nextcloud/nextcloud-dialogs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nextcloud/nextcloud-dialogs/compare/v3.1.2...v3.2.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-18 17:31:00 +00:00
dependabot[bot]
3864f29bbd Bump @babel/runtime from 7.17.9 to 7.20.1
Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.17.9 to 7.20.1.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.20.1/packages/babel-runtime)

---
updated-dependencies:
- dependency-name: "@babel/runtime"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-18 17:30:49 +00:00
dependabot[bot]
ee1b32fcd7 Bump dompurify from 2.3.6 to 2.4.1
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 2.3.6 to 2.4.1.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/2.3.6...2.4.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-18 17:30:38 +00:00
dependabot[bot]
6ad6b1680f Bump @nextcloud/l10n from 1.4.1 to 1.6.0
Bumps [@nextcloud/l10n](https://github.com/nextcloud/nextcloud-l10n) from 1.4.1 to 1.6.0.
- [Release notes](https://github.com/nextcloud/nextcloud-l10n/releases)
- [Changelog](https://github.com/nextcloud/nextcloud-l10n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nextcloud/nextcloud-l10n/compare/v1.4.1...v1.6.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-18 17:30:24 +00:00
Julius Härtl
b158d79403 Bump version to 1.7.3
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-11-18 16:29:52 +01:00
Nextcloud bot
2d823e3321 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-11-17 02:21:30 +00:00
Julius Härtl
9a153356c2 Merge pull request #4207 from nextcloud/automated/noid/stable24-update-nextcloud-ocp 2022-11-13 16:55:55 +01:00
nextcloud-command
eaf5e6ff29 Update psalm baseline
Signed-off-by: GitHub <noreply@github.com>
2022-11-13 03:36:07 +00:00
Nextcloud bot
585a02a3d2 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-11-12 02:22:17 +00:00
Julius Härtl
30acd27c94 Merge pull request #4202 from nextcloud/backport/4180/stable24 2022-11-11 14:59:23 +01:00
Nextcloud bot
71db398e9a [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-11-11 02:21:22 +00:00
Johannes Szeibert
d8f44e2c94 minor style fixes
Signed-off-by: Johannes Szeibert <johannes@szeibert.de>
2022-11-10 08:31:48 +00:00
Nextcloud bot
20c8cb12e3 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-11-10 02:23:00 +00:00
Nextcloud bot
60eadb7035 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-11-09 02:21:47 +00:00
Julius Härtl
17e71c5c9a Merge pull request #4188 from nextcloud/automated/noid/stable24-update-nextcloud-ocp 2022-11-07 08:26:43 +01:00
nextcloud-command
289c0f72dd Update psalm baseline
Signed-off-by: GitHub <noreply@github.com>
2022-11-06 03:33:40 +00:00
Nextcloud bot
c2a326d538 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-11-05 02:22:34 +00:00
Nextcloud bot
438bb8cb0d [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-11-04 02:21:19 +00:00
Julius Härtl
b98f8e3b07 Merge pull request #4178 from nextcloud/backport/4173/stable24 2022-11-03 21:47:23 +01:00
Julius Härtl
333206c549 Fix validation of attachment data
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-11-03 20:43:47 +01:00
Julius Härtl
5359ec34ef Unify getting the share for attachments
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-11-03 20:43:45 +01:00
Julius Härtl
ab7da85964 Add integration test for attachment handling on cards
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-11-03 20:43:45 +01:00
Marcel Klehr
7ecb215957 Merge pull request #4182 from nextcloud/backport/4101/stable24 2022-11-03 18:54:37 +01:00
mokkin
df89839b51 disables autocomplete on card creation
solves https://github.com/nextcloud/deck/issues/4083

Signed-off-by: mokkin <markus@haybach.com>
2022-11-03 18:25:22 +01:00
Nextcloud bot
03ed40df67 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-11-03 02:21:17 +00:00
Nextcloud bot
ad1429b4a2 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-11-02 02:21:35 +00:00
Nextcloud bot
eb03cd6814 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-11-01 02:21:41 +00:00
Julius Härtl
566846fe4d Merge pull request #4176 from nextcloud/backport/4059/stable24 2022-10-31 21:17:49 +01:00
Julius Härtl
f4c09fefd9 Add some tests for parameter validation
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-10-31 14:22:23 +01:00
Luka Trovic
bd6e632055 feat: add validators to check values in services
Signed-off-by: Luka Trovic <luka@nextcloud.com>
2022-10-31 14:22:20 +01:00
Nextcloud bot
75ddc058b8 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-10-31 02:21:06 +00:00
Julius Härtl
8558ce432a Merge pull request #4171 from nextcloud/automated/noid/stable24-update-nextcloud-ocp
[stable24] Update nextcloud/ocp dependency
2022-10-30 08:40:38 +01:00
nextcloud-command
7586084980 Update psalm baseline
Signed-off-by: GitHub <noreply@github.com>
2022-10-30 03:57:06 +00:00
Nextcloud bot
863de715a4 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-10-30 02:24:11 +00:00
Nextcloud bot
04abf47653 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-10-29 02:23:25 +00:00
Marcel Klehr
45c9a8ba27 Merge pull request #4158 from nextcloud/release/1.7.2 2022-10-27 11:47:09 +02:00
Nextcloud bot
3d10521524 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-10-27 02:21:17 +00:00
Marcel Klehr
ef616f37bd v1.7.2
Signed-off-by: Marcel Klehr <mklehr@gmx.net>
2022-10-26 16:15:54 +02:00
Nextcloud bot
e64c36ffce [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-10-25 02:26:18 +00:00
Nextcloud bot
837d925536 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-10-24 02:21:56 +00:00
Julius Härtl
feaeb90f76 Merge pull request #4132 from nextcloud/backport/4065/stable24 2022-10-18 19:22:08 +02:00
Julius Härtl
2ea94a12ad Cache user membership for circles
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-10-18 11:35:19 +02:00
Julius Härtl
c8cf8238b8 Pin postgres to 14
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-10-18 11:29:51 +02:00
Julius Härtl
16f41f74b3 Merge pull request #4118 from nextcloud/backport/3439/stable24 2022-10-18 11:26:27 +02:00
Nextcloud bot
3a78eea105 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-10-18 02:21:41 +00:00
Julius Härtl
8e158972f4 Activity: Set event link also for notifications that get emitted from activity
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-10-14 10:51:06 +00:00
Nextcloud bot
b12a1306eb [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-10-13 02:22:23 +00:00
Julius Härtl
1175c8b605 Merge pull request #4103 from nextcloud/fix/24-no-card-menu-without-description 2022-10-11 14:53:35 +02:00
Nextcloud bot
4b06ef3ac0 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-10-08 02:21:52 +00:00
Marcel Klehr
5f59f485f2 Merge pull request #4019 from nextcloud/backport/4014/stable24 2022-10-07 12:07:41 +02:00
Marcel Klehr
2f28015b91 Fix Card menu not displaying when description is not set
Signed-off-by: Marcel Klehr <mklehr@gmx.net>
2022-10-07 11:40:31 +02:00
Nextcloud bot
675aff612d [tx-robot] Update transifex configuration
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-10-07 02:21:55 +00:00
Nextcloud bot
9ad65af60e [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-10-06 02:26:16 +00:00
Nextcloud bot
2210c05e28 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-10-05 02:21:23 +00:00
Côme Chilliet
a189139a04 Merge pull request #4093 from nextcloud/migrate-stable24-christophwurst-package
Migrate to nextcloud/OCP package in stable24
2022-10-02 10:39:09 +02:00
Joas Schilling
c6a209c63a Migrate to nextcloud/OCP package in stable24
Signed-off-by: Joas Schilling <coding@schilljs.com>
2022-10-02 09:18:23 +02:00
Nextcloud bot
1968d8493b [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-10-01 02:24:38 +00:00
Nextcloud bot
a94eb0cd31 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-09-30 03:23:40 +00:00
Nextcloud bot
b2bbf31f46 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-09-28 02:46:17 +00:00
Nextcloud bot
2b959c10dd [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-09-26 02:47:18 +00:00
Nextcloud bot
81669635c5 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-09-24 02:47:23 +00:00
Nextcloud bot
7350a2a811 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-09-23 02:42:09 +00:00
Nextcloud bot
e677cbcdac [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-09-22 02:45:48 +00:00
Nextcloud bot
6d7461d0d1 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-09-20 02:45:57 +00:00
Nextcloud bot
86d94166f0 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-09-17 02:45:14 +00:00
Nextcloud bot
a664545ebf [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-09-16 02:39:38 +00:00
Nextcloud bot
360bd4192b [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-09-15 02:45:09 +00:00
Nextcloud bot
da3f2b8ee4 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-09-14 02:39:54 +00:00
Nextcloud bot
78aa411e09 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-09-13 02:40:41 +00:00
Nextcloud bot
2d318c0ac1 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-09-12 02:39:42 +00:00
Nextcloud bot
b58f598044 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-09-09 02:40:41 +00:00
Julien Veyssier
bad2a19be6 Merge pull request #4037 from nextcloud/backport/4036/stable24
[stable24] Fix attachment creator name: show display name
2022-09-08 12:23:00 +02:00
Julien Veyssier
a89bdab5e3 fix tests
Signed-off-by: Julien Veyssier <eneiluj@posteo.net>
2022-09-08 12:09:23 +02:00
Julien Veyssier
5b2c03f733 refs #4035 fix attachment creator name: show display name instead of user id
Signed-off-by: Julien Veyssier <eneiluj@posteo.net>
2022-09-08 12:09:23 +02:00
Nextcloud bot
552e10d79d [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-09-08 02:40:32 +00:00
Nextcloud bot
40f39fa21a [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-09-07 02:40:01 +00:00
Nextcloud bot
d5c1833638 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-09-06 02:39:38 +00:00
Nextcloud bot
36dd98c93e [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-09-05 02:38:59 +00:00
Nextcloud bot
ccbec7f5ac [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-09-04 02:38:02 +00:00
Nextcloud bot
0359e89b22 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-09-03 02:44:35 +00:00
Robin Appelman
e9f8634334 disable Create card button while no stack is chosen
make the `isBoardAndStackChoosen` method do what it says

Signed-off-by: Robin Appelman <robin@icewind.nl>
2022-09-02 11:12:41 +00:00
Nextcloud bot
1889c0c4f9 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-09-01 02:50:07 +00:00
Nextcloud bot
1ac501db79 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-08-28 02:36:32 +00:00
Nextcloud bot
c9ddd4f997 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-08-27 02:36:44 +00:00
Julius Härtl
e8a0d7c47c Merge pull request #3997 from nextcloud/backport/3980/stable24 2022-08-26 10:50:27 +02:00
Julius Härtl
8ace53bfe2 Make CappedMemoryCache usage compatible with older releases
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-08-26 10:07:59 +02:00
Raul Ferreira Fuentes
89c3490015 Merge pull request #3995 from nextcloud/backport/3982/stable24
[stable24] Improve CalDAV integration performance
2022-08-25 12:13:48 +00:00
Julius Härtl
72bc2f438a Use capped memory cache for board permissions
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-08-25 10:47:40 +00:00
Julius Härtl
1183459608 Avoid fetching archived cards for calendars
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-08-25 10:47:32 +00:00
Julius Härtl
a4e6c7b746 Avoid querying each card when getting the calendars only
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-08-25 10:47:32 +00:00
Nextcloud bot
b99fb6e8f6 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-08-24 02:39:41 +00:00
Nextcloud bot
f613a60f7c [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-08-22 02:37:15 +00:00
Nextcloud bot
7c77cde669 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-08-21 02:36:35 +00:00
Nextcloud bot
9a7bde4cbd [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-08-20 02:36:58 +00:00
Nextcloud bot
b807a71f1f [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-08-13 02:37:50 +00:00
Nextcloud bot
33942236f0 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-08-12 02:36:56 +00:00
Nextcloud bot
3dd3301ffc [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-08-09 02:36:37 +00:00
Julius Härtl
0d310d317e Merge pull request #3959 from nextcloud/backport/3952/stable24 2022-08-08 09:32:39 +02:00
Julius Härtl
82515e5731 Fetch attachment folder for the correct user during cron job
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-08-08 07:00:52 +00:00
Nextcloud bot
4cd4707559 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-08-07 02:40:59 +00:00
Nextcloud bot
90c14861c4 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-08-06 02:37:35 +00:00
Nextcloud bot
17a51501ec [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-08-05 02:13:42 +00:00
Nextcloud bot
86707f18dd [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-08-03 02:13:43 +00:00
Julius Härtl
a28cd746f1 Merge pull request #3925 from nextcloud/backport/3898/stable24
[stable24] Switch to 'markdown-it-task-checkbox' for rendering of task lists
2022-08-01 22:06:14 +02:00
Nextcloud bot
10ad995cd0 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-07-29 02:13:34 +00:00
Nextcloud bot
856c5f50c4 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-07-28 02:13:40 +00:00
Nextcloud bot
0a9d96d964 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-07-27 02:13:38 +00:00
Nextcloud bot
1d15921a57 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-07-25 02:39:10 +00:00
Nextcloud bot
b9826cb29f [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-07-24 02:40:48 +00:00
Nextcloud bot
94c13bbbdb [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-07-23 02:38:35 +00:00
Nextcloud bot
549f9c9045 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-07-21 02:38:53 +00:00
q-wertz
ac16521404 Switch to 'markdown-it-task-checkbox' for rendering of task lists
Signed-off-by: q-wertz <clemens.sonnleitner@web.de>
2022-07-19 09:33:39 +02:00
Nextcloud bot
4be298f537 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-07-19 02:38:00 +00:00
Nextcloud bot
10dead9d9f [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-07-18 02:37:16 +00:00
Nextcloud bot
f9cb601a99 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-07-14 02:37:44 +00:00
Julius Härtl
efdd3b0056 Merge pull request #3917 from nextcloud/backport/3916/stable24
[stable24] Prevent opening card and applyLabelFilter on card drag end
2022-07-12 16:37:01 +02:00
Julien Veyssier
a18f550dc1 refs #2594 prevent opening card and applyLabelFilter on card drag end
Signed-off-by: Julien Veyssier <eneiluj@posteo.net>
2022-07-12 11:57:22 +00:00
Nextcloud bot
d808b9fef7 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-07-08 02:37:16 +00:00
Nextcloud bot
f4742259f2 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-07-06 02:35:55 +00:00
Julius Härtl
3fe5da0ee1 Merge pull request #3901 from nextcloud/backport/3833/stable24
[stable24] Fix for issue #3637
2022-07-05 14:30:09 +02:00
Thomas Flummer
17ae3a9a39 Fix for issue #3637
Added padding on nested ul, to compensate for the negative margin on the containing li

Signed-off-by: Thomas Flummer <tf@flummer.net>
2022-07-05 10:41:38 +00:00
Nextcloud bot
1ff588a15a [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-07-04 02:35:49 +00:00
Nextcloud bot
2bb04ef298 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-07-02 02:37:23 +00:00
Raul Ferreira Fuentes
055dda909e Merge pull request #3885 from nextcloud/backport/3884/stable24
[stable24] Fix z-index for deck sidebar
2022-06-28 15:26:18 +02:00
Raul
f364709318 Fix z-index for deck sidebar
The sidebar would previously render above the user menu (logout, settings, etc)

Signed-off-by: Raul <r.ferreira.fuentes@gmail.com>
2022-06-28 12:40:36 +00:00
Nextcloud bot
84de1c0198 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-06-22 02:40:26 +00:00
Nextcloud bot
413017d333 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-06-14 02:41:52 +00:00
Nextcloud bot
5c069e5413 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-06-12 02:41:04 +00:00
Nextcloud bot
9d9cdb0f95 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-06-09 02:45:32 +00:00
Nextcloud bot
74f45e2e54 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-06-07 02:44:07 +00:00
Nextcloud bot
f82c48ad29 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-06-03 02:47:52 +00:00
Nextcloud bot
ece052a20d [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-06-02 02:47:09 +00:00
Luka Trovic
8a9a36ed10 Merge pull request #3847 from nextcloud/release/1.7.1
release/1.7.1
2022-06-01 13:36:59 +02:00
Luka Trovic
82f2a2c363 changes for 1.7.1
Signed-off-by: Luka Trovic <luka@nextcloud.com>
2022-05-30 08:21:03 +02:00
Nextcloud bot
3016659c81 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-05-29 02:46:53 +00:00
Nextcloud bot
b9ab0f14ab [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-05-28 02:43:24 +00:00
Nextcloud bot
2d90ed7414 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-05-26 02:44:17 +00:00
Nextcloud bot
5d87f05994 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-05-24 02:47:12 +00:00
Nextcloud bot
9ef183bcaa [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-05-23 02:43:45 +00:00
Nextcloud bot
34f18fbd7d [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-05-22 02:43:40 +00:00
Nextcloud bot
27fa2bbc54 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-05-21 02:47:13 +00:00
Nextcloud bot
03a88327a5 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-05-20 02:46:27 +00:00
Julius Härtl
67ac21e688 Merge pull request #3815 from nextcloud/backport/3811/stable24
[stable24] Align Duedate-delete icon properly - fixes nextcloud/deck#3791
2022-05-13 09:34:37 +02:00
Nextcloud bot
e90f32ca32 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-05-13 02:41:48 +00:00
ben
b21e65027c Align Duedate-delete icon properly - fixes nextcloud/deck#3791
Signed-off-by: ben <ben@ro.tt>
2022-05-12 14:54:17 +00:00
Julius Härtl
b628532def Merge pull request #3804 from nextcloud/backport/3682/stable24
[stable24] Increase file count after sharing
2022-05-12 09:18:37 +02:00
Julius Härtl
e0b2755b7c Fix php-cs-fixer failure
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-05-12 09:09:20 +02:00
Julius Härtl
9e1fbb9852 Move all caching to helper
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-05-11 14:43:32 +00:00
Luka Trovic
047ca3e203 fix: move shares count cache logic to the DeckShareProvider
Signed-off-by: Luka Trovic <luka@nextcloud.com>

fix: conflicts

Signed-off-by: Luka Trovic <luka@nextcloud.com>

fix: conflicts and test issues

Signed-off-by: Luka Trovic <luka@nextcloud.com>
2022-05-11 14:43:31 +00:00
Luka Trovic
bfcd5357e3 fix: update attachments count when sharing
Signed-off-by: Luka Trovic <luka@nextcloud.com>
2022-05-11 14:43:30 +00:00
Luka Trovic
461ed6b81f fix: increase file count after sharing
Signed-off-by: Luka Trovic <luka@nextcloud.com>
2022-05-11 14:43:29 +00:00
Nextcloud bot
ee2969fc5b [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-05-06 02:41:15 +00:00
Nextcloud bot
ca32ebd9cb [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-05-05 02:41:05 +00:00
Julius Härtl
4a29617fed Merge pull request #3779 from nextcloud/backport/3777/stable24
[stable24] Fetch full board data after cloning
2022-05-04 17:17:07 +02:00
Julius Härtl
8eab97a92a Fetch full board data after cloning
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-05-04 10:29:18 +00:00
Nextcloud bot
f453f69cce [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-05-04 02:42:57 +00:00
Nextcloud bot
8ca84147e8 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2022-05-03 02:41:23 +00:00
Julius Härtl
5e3ddd83fc Bump version to 1.7.0
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-05-02 16:43:48 +02:00
Julius Härtl
6b985463d8 Merge pull request #3769 from nextcloud/bugfix/noid/stable24-psalm
Handle qb mapper exception messages properly
2022-04-29 17:28:20 +02:00
Julius Härtl
25e0ae2670 Bump version to 1.7.0-rc.1
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-04-29 16:17:24 +02:00
Julius Härtl
614c6fbdba Handle qb mapper exception messages properly
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-04-29 15:45:07 +02:00
Julius Härtl
8efe415558 Merge pull request #3765 from nextcloud/backport/3761/stable24
[stable24] Fix text selection in dark mode and modal view
2022-04-29 15:41:06 +02:00
Julius Härtl
f3ad2a3709 Fix text selection in dark mode and modal view
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-04-29 09:33:06 +00:00
Julius Härtl
25dd71ba04 Merge pull request #3764 from nextcloud/backport/3762/stable24
[stable24] Adapt the card modal to upstream changes
2022-04-29 11:09:08 +02:00
Julius Härtl
a514e6e168 Adapt modal size to viewer upstream changes
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-04-29 08:47:21 +00:00
Julius Härtl
cb5553ea94 Merge pull request #3754 from nextcloud/backport/3745/stable24
[stable24] Add missing indices
2022-04-28 10:10:31 +02:00
Julius Härtl
335ee31c7c Add missing indices
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2022-04-26 16:26:17 +00:00
Julius Härtl
9b4379727d Merge pull request #3736 from nextcloud/backport/3681/stable24
[stable24] Show cards after moving into another list
2022-04-20 18:14:34 +02:00
Julius Härtl
a5fe2f59be Merge pull request #3733 from nextcloud/backport/3692/stable24
[stable24] Fix hidden attachment icon on archived cards
2022-04-20 18:14:13 +02:00
Luka Trovic
1b58f7854e fix: feedback
Signed-off-by: Luka Trovic <luka@nextcloud.com>
2022-04-20 14:24:24 +00:00
Luka Trovic
b6effa468f fix: show card after moving into another list
Signed-off-by: Luka Trovic <luka@nextcloud.com>
2022-04-20 14:24:24 +00:00
Luka Trovic
2b512b88c4 fix: hidden attachment icon on archived cards
Signed-off-by: Luka Trovic <luka@nextcloud.com>
2022-04-20 14:22:23 +00:00
Julius Härtl
5cb61cba90 Merge pull request #3723 from nextcloud/update-stable24-target-versions
Update stable24 target versions
2022-04-19 15:38:37 +02:00
Joas Schilling
0657efe239 Update stable24 target versions
Signed-off-by: Joas Schilling <coding@schilljs.com>
2022-04-14 22:09:00 +02:00
181 changed files with 9999 additions and 15151 deletions

View File

@@ -3,10 +3,7 @@ root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = tab
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true
[*.{js,vue}]
indent_style = tab

View File

@@ -1,5 +1,4 @@
module.exports = {
root: true,
extends: [
'@nextcloud',
],
@@ -8,7 +7,6 @@ module.exports = {
'jsdoc/require-param-type': ['off'],
'jsdoc/check-param-names': ['off'],
'jsdoc/no-undefined-types': ['off'],
'jsdoc/require-property-description': ['off'],
'import/no-named-as-default-member': ['off']
'jsdoc/require-property-description' : ['off']
},
}

View File

@@ -1,43 +0,0 @@
name: Package build
on:
push:
branches:
- main
- master
- stable*
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: Set up npm7
run: npm i -g npm@7
- name: Setup PHP
uses: shivammathur/setup-php@2.21.2
with:
php-version: '7.4'
tools: composer
- name: install dependencies
run: |
wget https://github.com/ChristophWurst/krankerl/releases/download/v0.12.2/krankerl_0.12.2_amd64.deb
sudo dpkg -i krankerl_0.12.2_amd64.deb
- name: package
run: |
uname -a
RUST_BACKTRACE=1 krankerl --version
RUST_BACKTRACE=1 krankerl package
- uses: actions/upload-artifact@v3
with:
name: Deck app tarball
path: build/artifacts/deck.tar.gz

View File

@@ -66,7 +66,7 @@ jobs:
run: npm i -g npm@"${{ steps.versions.outputs.npmVersion }}"
- name: Set up php ${{ env.PHP_VERSION }}
uses: shivammathur/setup-php@2.21.2
uses: shivammathur/setup-php@2.18.0
with:
php-version: ${{ env.PHP_VERSION }}
coverage: none

View File

@@ -9,14 +9,9 @@ on:
issue_comment:
types: created
permissions:
contents: read
jobs:
rebase:
runs-on: ubuntu-latest
permissions:
contents: none
# On pull requests and if the comment starts with `/rebase`
if: github.event.issue.pull_request != '' && startsWith(github.event.comment.body, '/rebase')
@@ -37,7 +32,7 @@ jobs:
token: ${{ secrets.COMMAND_BOT_PAT }}
- name: Automatic Rebase
uses: cirrus-actions/rebase@1.7
uses: cirrus-actions/rebase@1.5
env:
GITHUB_TOKEN: ${{ secrets.COMMAND_BOT_PAT }}

View File

@@ -1,112 +0,0 @@
name: Cypress
on:
pull_request:
push:
branches:
- master
- stable*
env:
APP_NAME: deck
CYPRESS_baseUrl: http://localhost:8081/index.php
jobs:
cypress:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version: [14.x]
# containers: [1, 2, 3]
php-versions: [ '7.4' ]
databases: [ 'sqlite' ]
server-versions: [ 'stable25' ]
steps:
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: Set up npm7
run: npm i -g npm@7
- name: Checkout server
uses: actions/checkout@v3
with:
repository: nextcloud/server
ref: ${{ matrix.server-versions }}
- name: Checkout submodules
shell: bash
run: |
auth_header="$(git config --local --get http.https://github.com/.extraheader)"
git submodule sync --recursive
git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1
- name: Checkout ${{ env.APP_NAME }}
uses: actions/checkout@v3
with:
path: apps/${{ env.APP_NAME }}
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@2.21.2
with:
php-version: ${{ matrix.php-versions }}
extensions: mbstring, iconv, fileinfo, intl, sqlite, pdo_sqlite, zip, gd, apcu
ini-values:
apc.enable_cli=on
coverage: none
- name: Set up Nextcloud
env:
DB_PORT: 4444
PHP_CLI_SERVER_WORKERS: 10
run: |
mkdir data
php occ maintenance:install --verbose --database=${{ matrix.databases }} --database-name=nextcloud --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
php occ config:system:set memcache.local --value="\\OC\\Memcache\\APCu"
php occ config:system:set debug --value=true --type=boolean
php -f index.php
php -S 0.0.0.0:8081 &
export OC_PASS=1234561
php occ user:add --password-from-env user1
php occ user:add --password-from-env user2
php occ app:enable deck
php occ app:list
cd apps/deck
composer install --no-dev
npm ci
npm run build
cd ../../
curl -v http://localhost:8081/index.php/login
- name: Cypress run
uses: cypress-io/github-action@v4
with:
record: true
parallel: false
wait-on: '${{ env.CYPRESS_baseUrl }}'
working-directory: 'apps/${{ env.APP_NAME }}'
config: defaultCommandTimeout=10000,video=false
env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
npm_package_name: ${{ env.APP_NAME }}
- name: Upload test failure screenshots
uses: actions/upload-artifact@v2
if: failure()
with:
name: Upload screenshots
path: apps/${{ env.APP_NAME }}/cypress/screenshots/
retention-days: 5
- name: Upload nextcloud logs
uses: actions/upload-artifact@v2
if: failure()
with:
name: Upload nextcloud log
path: data/nextcloud.log
retention-days: 5

View File

@@ -8,20 +8,13 @@ name: Dependabot
on:
pull_request_target:
branches:
- main
- master
- stable*
permissions:
contents: read
jobs:
auto-approve-merge:
if: github.actor == 'dependabot[bot]'
runs-on: ubuntu-latest
permissions:
# for hmarr/auto-approve-action to approve PRs
pull-requests: write
steps:
# Github actions bot approve

View File

@@ -3,18 +3,31 @@
# https://github.com/nextcloud/.github
# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
name: Pull request checks
name: Block fixup and squash commits
on: pull_request
on:
pull_request:
types: [opened, ready_for_review, reopened, synchronize]
permissions:
contents: read
concurrency:
group: fixup-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
commit-message-check:
if: github.event.pull_request.draft == false
permissions:
pull-requests: write
name: Block fixup and squash commits
runs-on: ubuntu-latest
steps:
- name: Run check
uses: xt0rted/block-autosquash-commits-action@v2
uses: skjnldsv/block-fixup-merge-action@42d26e1b536ce61e5cf467d65fb76caf4aa85acf # v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -2,14 +2,6 @@ name: Integration tests
on:
pull_request:
paths:
- '.github/workflows/integration.yml'
- 'appinfo/**'
- 'lib/**'
- 'templates/**'
- 'tests/**'
- 'composer.json'
- 'composer.lock'
push:
branches:
- master
@@ -27,7 +19,7 @@ jobs:
matrix:
php-versions: ['7.4']
databases: ['sqlite', 'mysql', 'pgsql']
server-versions: ['stable25']
server-versions: ['stable24']
name: php${{ matrix.php-versions }}-${{ matrix.databases }}-${{ matrix.server-versions }}
@@ -62,24 +54,32 @@ jobs:
auth_header="$(git config --local --get http.https://github.com/.extraheader)"
git submodule sync --recursive
git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1
cd build/integration && composer require --dev phpunit/phpunit:~9
cd build/integration && composer require --dev phpunit/phpunit:~8
- name: Checkout app
uses: actions/checkout@v3
with:
path: apps/${{ env.APP_NAME }}
- name: Checkout activity
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
with:
repository: nextcloud/activity
ref: ${{ matrix.server-versions }}
path: apps/activity
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@2.21.2
uses: shivammathur/setup-php@2.25.4
with:
php-version: ${{ matrix.php-versions }}
tools: phpunit
extensions: mbstring, iconv, fileinfo, intl, sqlite, pdo_sqlite, mysql, pdo_mysql, pgsql, pdo_pgsql,
extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite, mysql, pdo_mysql, pgsql, pdo_pgsql, apcu
ini-values:
apc.enable_cli=on
coverage: none
- name: Set up PHPUnit
- name: Set up dependencies
working-directory: apps/${{ env.APP_NAME }}
run: composer i
run: composer i --no-dev
- name: Set up Nextcloud
run: |

View File

@@ -19,7 +19,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up php${{ matrix.php-versions }}
uses: shivammathur/setup-php@2.21.2
uses: shivammathur/setup-php@2.18.0
with:
php-version: ${{ matrix.php-versions }}
coverage: none
@@ -33,7 +33,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
- name: Set up php
uses: shivammathur/setup-php@2.21.2
uses: shivammathur/setup-php@2.18.0
with:
php-version: 7.4
coverage: none

View File

@@ -25,7 +25,7 @@ jobs:
- name: Set up npm7
run: npm i -g npm@7
- name: Setup PHP
uses: shivammathur/setup-php@2.21.2
uses: shivammathur/setup-php@2.18.0
with:
php-version: '7.4'
tools: composer

View File

@@ -2,14 +2,6 @@ name: PHPUnit
on:
pull_request:
paths:
- '.github/workflows/phpunit.yml'
- 'appinfo/**'
- 'lib/**'
- 'templates/**'
- 'tests/**'
- 'composer.json'
- 'composer.lock'
push:
branches:
- master
@@ -26,9 +18,9 @@ jobs:
strategy:
fail-fast: false
matrix:
php-versions: ['7.4', '8.0', '8.1']
php-versions: ['7.4', '8.0']
databases: ['sqlite', 'mysql', 'pgsql']
server-versions: ['stable25']
server-versions: ['stable24']
name: php${{ matrix.php-versions }}-${{ matrix.databases }}-${{ matrix.server-versions }}
@@ -70,11 +62,12 @@ jobs:
path: apps/${{ env.APP_NAME }}
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@2.21.2
uses: shivammathur/setup-php@2.24.0
with:
php-version: ${{ matrix.php-versions }}
tools: phpunit
extensions: zip, gd, mbstring, iconv, fileinfo, intl, sqlite, pdo_sqlite, mysql, pdo_mysql, pgsql, pdo_pgsql
ini-file: development
coverage: none
- name: Set up PHPUnit

View File

@@ -1,106 +1,59 @@
# Changelog
All notable changes to this project will be documented in this file.
## 1.8.5
## 1.7.5
### Fixed
- fix: Properly overwrite z-index of datepicker above modal [#4667](https://github.com/nextcloud/deck/pull/4667)
- Fix(occ): set user id for permission sevice from board service [#5074](https://github.com/nextcloud/deck/pull/5074)
- Fix small issues around delete/undo @juliushaertl [#5446](https://github.com/nextcloud/deck/pull/5446)
- Fix deleted card/board issues @juliushaertl [#5449](https://github.com/nextcloud/deck/pull/5449)
## 1.8.4
## 1.7.4
### Fixed
- fix: Use passed userid when getting attachment folder [#4540](https://github.com/nextcloud/deck/pull/4540)
- fix: Adapt NcEmptyContent usages to new slots [#4563](https://github.com/nextcloud/deck/pull/4563)
- Gracefully handle not found card for a share [#4568](https://github.com/nextcloud/deck/pull/4568)
- allow user to toggle visibility of the calendar for a deck board [#4626](https://github.com/nextcloud/deck/pull/4626)
- fix: Append datetime picker to body to avoid cut off [#4645](https://github.com/nextcloud/deck/pull/4645)
- Fix : Overlapping expiry dates on tags [#4536](https://github.com/nextcloud/deck/pull/4536)
- Better display of card dates (creation and change dates) [#4620](https://github.com/nextcloud/deck/pull/4620)
- Dependency updates
- Gracefully handle not found card for a share [#4569](https://github.com/nextcloud/deck/pull/4569)
- fix: Use passed userid when getting attachment folder [#4541](https://github.com/nextcloud/deck/pull/4541)
- fix: Append datetime picker to body to avoid cut off [#4646](https://github.com/nextcloud/deck/pull/4646)
- Permanently delete deck cards marked as deleted after 5 min in a cron job [#4302](https://github.com/nextcloud/deck/pull/4302)
- Fix : Overlapping expiry dates on tags [#4538](https://github.com/nextcloud/deck/pull/4538)
- Update dependencies
## 1.8.3
## 1.7.3
### Fixed
- Fix component renaming so that acl works on shares again [#4328](https://github.com/nextcloud/deck/pull/4328)
- Permanently delete deck cards marked as deleted after 5 min in a cron job [#4301](https://github.com/nextcloud/deck/pull/4301)
- Dependency updates
- feat: add validators to check values in services @juliushaertl [#4176](https://github.com/nextcloud/deck/pull/4176)
- Add integration test for attachment handling on cards [#4178](https://github.com/nextcloud/deck/pull/4178)
- disables autocomplete on card creation @juliushaertl [#4182](https://github.com/nextcloud/deck/pull/4182)
- minor style fixes [#4202](https://github.com/nextcloud/deck/pull/4202)
## 1.8.2
## 1.7.2
### Fixed
- minor style fixes [#4201](https://github.com/nextcloud/deck/pull/4201)
- feat: add validators to check values in services [#4174](https://github.com/nextcloud/deck/pull/4174)
- Add integration test for attachment handling on cards [#4179](https://github.com/nextcloud/deck/pull/4179)
- Add missing userId property [#4198](https://github.com/nextcloud/deck/pull/4198)
- Cache user membership for circles [#4132](https://github.com/nextcloud/deck/pull/4132)
- Set event link also for notifications that get emitted from activities [#4118](https://github.com/nextcloud/deck/pull/4118)
- Fix Card menu not displaying when description is not set [#4103](https://github.com/nextcloud/deck/pull/4103)
- disable Create card button while no stack is chosen [#4019](https://github.com/nextcloud/deck/pull/4019)
- to nextcloud/OCP package in stable24 [#4093](https://github.com/nextcloud/deck/pull/4093)
- Fix attachment creator name: show display name [#4037](https://github.com/nextcloud/deck/pull/4037)
- Use capped memory cache for board permissions [#3997](https://github.com/nextcloud/deck/pull/3997)
- Improve CalDAV integration performance [#3995](https://github.com/nextcloud/deck/pull/3995)
- Fetch attachment folder for the correct user during cron job [#3959](https://github.com/nextcloud/deck/pull/3959)
- Switch to 'markdown-it-task-checkbox' for rendering of task lists [#3925](https://github.com/nextcloud/deck/pull/3925)
- Prevent opening card and applyLabelFilter on card drag end [#3917](https://github.com/nextcloud/deck/pull/3917)
- Fix for issue #3637 [#3901](https://github.com/nextcloud/deck/pull/3901)
- Fix z-index for deck sidebar [#3885](https://github.com/nextcloud/deck/pull/3885)
## 1.8.1
## 1.7.1
### Fixed
- Fix Duedate activity @nickvergessen [#4155](https://github.com/nextcloud/deck/pull/4155)
## 1.8.0
### Added
- Nextcloud 25 compatibility
- Performance improvements
- Use capped memory cache for board permissions @juliushaertl [#3980](https://github.com/nextcloud/deck/pull/3980)
- Improve CalDAV integration performance @juliushaertl [#3982](https://github.com/nextcloud/deck/pull/3982)
- Simpify query for getting shared files @juliushaertl [#3983](https://github.com/nextcloud/deck/pull/3983)
- Accessibility improvements
- Add a11y label for sidebar button @marcelklehr [#3986](https://github.com/nextcloud/deck/pull/3986)
- Improve filter popover accessibility @juliushaertl [#3820](https://github.com/nextcloud/deck/pull/3820)
- Set ids to skip to content/navigation @juliushaertl [#3924](https://github.com/nextcloud/deck/pull/3924)
- Invert icons properly in dark mode @juliushaertl [#3939](https://github.com/nextcloud/deck/pull/3939)
- Implement card reference widget @eneiluj [#4031](https://github.com/nextcloud/deck/pull/4031)
- Implement new dashboard widget interfaces @eneiluj [#4033](https://github.com/nextcloud/deck/pull/4033)
- Add related resources panel to board sharing tab sidebar @Pytal [#4000](https://github.com/nextcloud/deck/pull/4000)
### Fixed
- Fix sorting stacks [#4116](https://github.com/nextcloud/deck/pull/4116)
- Fix issue with duedate format [#4140](https://github.com/nextcloud/deck/pull/4140)
- Fix missing icon for activity rendering [#4090](https://github.com/nextcloud/deck/pull/4090)
- disables autocomplete on card creation [#4142](https://github.com/nextcloud/deck/pull/4142)
- Set event link also for notifications that get emitted from activities [#4117](https://github.com/nextcloud/deck/pull/4117)
- Fix attachment creator name: show display name @eneiluj [#4036](https://github.com/nextcloud/deck/pull/4036)
- Fix reference provider when caching @eneiluj [#4056](https://github.com/nextcloud/deck/pull/4056)
- Use global import for nextcloud-vue [#4072](https://github.com/nextcloud/deck/pull/4072)
- Disable Create card button while no stack is chosen @icewind1991 [#4014](https://github.com/nextcloud/deck/pull/4014)
- Adjust testing matrix for Nextcloud 25 on stable25 @nickvergessen [#4068](https://github.com/nextcloud/deck/pull/4068)
- Fix Card menu not displaying when description is not set @marcelklehr [#4105](https://github.com/nextcloud/deck/pull/4105)
- Reference widget adjustments for Text [#4075](https://github.com/nextcloud/deck/pull/4075)
- use OCP\Collaboration\Reference\Reference [#4078](https://github.com/nextcloud/deck/pull/4078)
- Cache user membership for circles [#4141](https://github.com/nextcloud/deck/pull/4141)
- set last modified when the card was found. Fixes #3763 @ylebre [#3796](https://github.com/nextcloud/deck/pull/3796)
- Increase file count after sharing @luka-nextcloud [#3682](https://github.com/nextcloud/deck/pull/3682)
- Align Duedate-delete icon properly - fixes nextcloud/deck#3791 @Ben-Ro [#3811](https://github.com/nextcloud/deck/pull/3811)
- Fix for issue #3637 @flummer [#3833](https://github.com/nextcloud/deck/pull/3833)
- Switch to 'markdown-it-task-checkbox' for rendering of task lists @q-wertz [#3898](https://github.com/nextcloud/deck/pull/3898)
- Make rename functions accessibly by keyboard navigation @juliushaertl [#3813](https://github.com/nextcloud/deck/pull/3813)
- Prevent opening card and applyLabelFilter on card drag end @eneiluj [#3916](https://github.com/nextcloud/deck/pull/3916)
- Inserted required property in the rename list field, to prevent the l… @mstolf [#3862](https://github.com/nextcloud/deck/pull/3862)
- Fix share provider for master changes @nickvergessen [#3942](https://github.com/nextcloud/deck/pull/3942)
- Fetch attachment folder for the correct user during cron job @juliushaertl [#3952](https://github.com/nextcloud/deck/pull/3952)
- Fix z-index for deck sidebar @Raudius [#3884](https://github.com/nextcloud/deck/pull/3884)
### Other
- Switch from OC::$server->get to OCP\Server::get @CarlSchwan [#3801](https://github.com/nextcloud/deck/pull/3801)
- Add performance section in README @eneiluj [#3830](https://github.com/nextcloud/deck/pull/3830)
- Fix static analysis by stubbing more circle methods @juliushaertl [#3900](https://github.com/nextcloud/deck/pull/3900)
- fix(docs): fix links to JSON schemas for Trello @wiktor2200 [#3872](https://github.com/nextcloud/deck/pull/3872)
- Move to OCP\Collaboration\Resources\LoadAdditionalScriptsEvent @juliushaertl [#3818](https://github.com/nextcloud/deck/pull/3818)
- Rename settings to deck settings @PVince81 [#3928](https://github.com/nextcloud/deck/pull/3928)
- SCSS cleanup @juliushaertl [#3803](https://github.com/nextcloud/deck/pull/3803)
- Hide deprecated projects in sidebar and card details by default @Pytal [#3984](https://github.com/nextcloud/deck/pull/3984)
- Align Duedate-delete icon properly - fixes nextcloud/deck#3791 [#3817](https://github.com/nextcloud/deck/pull/3817)
- Increase file count after sharing [#3806](https://github.com/nextcloud/deck/pull/3806)
- Fetch full board data after cloning [#3781](https://github.com/nextcloud/deck/pull/3781)
## 1.7.0
@@ -152,7 +105,7 @@ All notable changes to this project will be documented in this file.
- Adapt the card modal to upstream changes [#3764](https://github.com/nextcloud/deck/pull/3764)
- Fix text selection in dark mode and modal view [#3765](https://github.com/nextcloud/deck/pull/3765)
- Add missing indices [#3754](https://github.com/nextcloud/deck/pull/3754)
- Handle qb mapper exception messages properly @juliushaertl [#3769](https://github.com/nextcloud/deck/pull/3769)
## 1.6.0-beta1
@@ -523,7 +476,7 @@ Android app team for helping to improve our REST API:
- Fix comment activities on Nextcloud 15
- Fix issues with Edge
- API: Fix numeric types that were returned as strings
- API: Fix If-Modified-Since header parsing
- API: Fix If-Modified-Since header parsing
## 0.5.1 - 2018-12-05
@@ -650,7 +603,7 @@ Android app team for helping to improve our REST API:
### Fixed
- Various frontend fixes
- Fix sidebar drag issues
- Improvements for IE11
- Improvements for IE11
- Fix bug when draging a card to an empty stack
## 0.2.1 - 2017-07-04
@@ -724,7 +677,7 @@ Android app team for helping to improve our REST API:
### Fixed
- Various styling improvements
- Fix problems with MySQL and PostgreSQL
- Fix problems with MySQL and PostgreSQL
- Select first color by default when creating boards
- Fix error when changing board permissions
@@ -732,9 +685,9 @@ Android app team for helping to improve our REST API:
### Added
- Sharing boards with other users
- Create and manage boards
- Create and manage boards
- Sort cards on stacks by drag-and-drop
- Assign labels
- Markdown notes for each card
- Archive cards
- Archive cards

View File

@@ -24,9 +24,9 @@ Deck is a kanban style organization tool aimed at personal planning and project
### 3rd-Party Integrations
- [trello-to-deck](https://github.com/maxammann/trello-to-deck) - Migrates cards from Trello
- [mail2deck](https://github.com/newroco/mail2deck) - Provides an "email in" solution
- [mail2deck](https://github.com/newroco/mail2deck) - Provides an "email in" solution
- [A-deck](https://github.com/leoossa/A-deck) - Chrome Extension that allows to create new card in selected stack based on current tab
## Installation/Update
This app is supposed to work on the two latest Nextcloud versions.
@@ -52,17 +52,6 @@ Please make sure you have installed the following dependencies: `make, which, ta
Instead of setting everything up manually, you can just [download the nightly build](https://github.com/nextcloud/deck/releases/tag/nightly) instead. These builds are updated every 24 hours, and are pre-configured with all the needed dependencies.
## Performance limitations
Deck is not yet ready for intensive usage.
A lot of database queries are generated when the number of boards, cards and attachments is high.
For example, a user having access to 13 boards, with each board having on average 100 cards,
and each card having on average 5 attachments,
would generate 6500 database queries when doing the file related queries
which would increase the page loading time significantly.
Improvements on Nextcloud server and Deck itself will improve the situation.
## Developing
### PHP
@@ -71,8 +60,6 @@ Nothing to prepare, just dig into the code.
### JavaScript
This requires at least Node 14 and npm 7 to be installed.
Deck requires running a `make build-js` to install npm dependencies and build the JavaScript code using webpack. While developing you can also use `make watch` to rebuild everytime the code changes.
#### Hot reloading

View File

@@ -16,7 +16,7 @@
- 🚀 Get your project organized
</description>
<version>1.8.5</version>
<version>1.7.5</version>
<licence>agpl</licence>
<author>Julius Härtl</author>
<namespace>Deck</namespace>
@@ -34,7 +34,7 @@
<database min-version="9.4">pgsql</database>
<database>sqlite</database>
<database min-version="8.0">mysql</database>
<nextcloud min-version="25" max-version="25"/>
<nextcloud min-version="24" max-version="24"/>
</dependencies>
<background-jobs>
<job>OCA\Deck\Cron\DeleteCron</job>

View File

@@ -19,7 +19,7 @@
"symfony/event-dispatcher": "^4.0",
"vimeo/psalm": "^4.3",
"php-parallel-lint/php-parallel-lint": "^1.2",
"nextcloud/ocp": "dev-stable25"
"nextcloud/ocp": "dev-stable24"
},
"config": {
"optimize-autoloader": true,
@@ -36,14 +36,14 @@
"cs:check": "php-cs-fixer fix --dry-run --diff",
"cs:fix": "php-cs-fixer fix",
"psalm": "psalm",
"psalm:update-baseline": "psalm --update-baseline",
"psalm:fix": "psalm --alter --issues=InvalidReturnType,InvalidNullableReturnType,MismatchingDocblockParamType,MismatchingDocblockReturnType,MissingParamType,InvalidFalsableReturnType",
"test": [
"@test:unit",
"@test:integration"
],
"test:unit": "phpunit -c tests/phpunit.xml",
"test:integration": "phpunit -c tests/phpunit.integration.xml && cd tests/integration && ./run.sh"
"test:integration": "phpunit -c tests/phpunit.integration.xml",
"test:api": "cd tests/integration && ./run.sh"
},
"autoload-dev": {
"psr-4": {

369
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "445858d371d9a1c7057d0603c566966a",
"content-hash": "fdd039ec52f9c829403494423b527e10",
"packages": [
{
"name": "cogpowered/finediff",
@@ -63,16 +63,16 @@
},
{
"name": "justinrainbow/json-schema",
"version": "5.2.12",
"version": "5.2.11",
"source": {
"type": "git",
"url": "https://github.com/justinrainbow/json-schema.git",
"reference": "ad87d5a5ca981228e0e205c2bc7dfb8e24559b60"
"reference": "2ab6744b7296ded80f8cc4f9509abbff393399aa"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/ad87d5a5ca981228e0e205c2bc7dfb8e24559b60",
"reference": "ad87d5a5ca981228e0e205c2bc7dfb8e24559b60",
"url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/2ab6744b7296ded80f8cc4f9509abbff393399aa",
"reference": "2ab6744b7296ded80f8cc4f9509abbff393399aa",
"shasum": ""
},
"require": {
@@ -127,9 +127,9 @@
],
"support": {
"issues": "https://github.com/justinrainbow/json-schema/issues",
"source": "https://github.com/justinrainbow/json-schema/tree/5.2.12"
"source": "https://github.com/justinrainbow/json-schema/tree/5.2.11"
},
"time": "2022-04-13T08:02:27+00:00"
"time": "2021-07-22T09:24:00+00:00"
}
],
"packages-dev": [
@@ -445,16 +445,16 @@
},
{
"name": "composer/semver",
"version": "3.3.2",
"version": "3.2.9",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9"
"reference": "a951f614bd64dcd26137bc9b7b2637ddcfc57649"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9",
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9",
"url": "https://api.github.com/repos/composer/semver/zipball/a951f614bd64dcd26137bc9b7b2637ddcfc57649",
"reference": "a951f614bd64dcd26137bc9b7b2637ddcfc57649",
"shasum": ""
},
"require": {
@@ -506,7 +506,7 @@
"support": {
"irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/semver/issues",
"source": "https://github.com/composer/semver/tree/3.3.2"
"source": "https://github.com/composer/semver/tree/3.2.9"
},
"funding": [
{
@@ -522,7 +522,7 @@
"type": "tidelift"
}
],
"time": "2022-04-01T19:23:25+00:00"
"time": "2022-02-04T13:58:43+00:00"
},
{
"name": "composer/xdebug-handler",
@@ -896,16 +896,16 @@
},
{
"name": "felixfbecker/language-server-protocol",
"version": "v1.5.2",
"version": "1.5.1",
"source": {
"type": "git",
"url": "https://github.com/felixfbecker/php-language-server-protocol.git",
"reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842"
"reference": "9d846d1f5cf101deee7a61c8ba7caa0a975cd730"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/6e82196ffd7c62f7794d778ca52b69feec9f2842",
"reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842",
"url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/9d846d1f5cf101deee7a61c8ba7caa0a975cd730",
"reference": "9d846d1f5cf101deee7a61c8ba7caa0a975cd730",
"shasum": ""
},
"require": {
@@ -946,9 +946,9 @@
],
"support": {
"issues": "https://github.com/felixfbecker/php-language-server-protocol/issues",
"source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.5.2"
"source": "https://github.com/felixfbecker/php-language-server-protocol/tree/1.5.1"
},
"time": "2022-03-02T22:36:06+00:00"
"time": "2021-02-22T14:02:09+00:00"
},
{
"name": "friendsofphp/php-cs-fixer",
@@ -1192,16 +1192,16 @@
},
{
"name": "nextcloud/ocp",
"version": "dev-stable25",
"version": "dev-stable24",
"source": {
"type": "git",
"url": "https://github.com/nextcloud-deps/ocp.git",
"reference": "1e34a80be034fe9a58057d2e756913363675bddb"
"reference": "0b89697ba1146d48506132c452cf548adb2a9cb8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/1e34a80be034fe9a58057d2e756913363675bddb",
"reference": "1e34a80be034fe9a58057d2e756913363675bddb",
"url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/0b89697ba1146d48506132c452cf548adb2a9cb8",
"reference": "0b89697ba1146d48506132c452cf548adb2a9cb8",
"shasum": ""
},
"require": {
@@ -1213,7 +1213,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "26.0.0-dev"
"dev-master": "24.0.0-dev"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -1229,22 +1229,22 @@
"description": "Composer package containing Nextcloud's public API (classes, interfaces)",
"support": {
"issues": "https://github.com/nextcloud-deps/ocp/issues",
"source": "https://github.com/nextcloud-deps/ocp/tree/stable25"
"source": "https://github.com/nextcloud-deps/ocp/tree/stable24"
},
"time": "2023-05-13T00:33:04+00:00"
"time": "2023-03-16T00:40:04+00:00"
},
{
"name": "nikic/php-parser",
"version": "v4.14.0",
"version": "v4.13.2",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "34bea19b6e03d8153165d8f30bba4c3be86184c1"
"reference": "210577fe3cf7badcc5814d99455df46564f3c077"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/34bea19b6e03d8153165d8f30bba4c3be86184c1",
"reference": "34bea19b6e03d8153165d8f30bba4c3be86184c1",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077",
"reference": "210577fe3cf7badcc5814d99455df46564f3c077",
"shasum": ""
},
"require": {
@@ -1285,9 +1285,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.14.0"
"source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2"
},
"time": "2022-05-31T20:59:12+00:00"
"time": "2021-11-30T19:35:32+00:00"
},
{
"name": "openlss/lib-array2xml",
@@ -1723,24 +1723,91 @@
"time": "2022-03-15T21:29:03+00:00"
},
{
"name": "phpunit/php-code-coverage",
"version": "9.2.17",
"name": "phpspec/prophecy",
"version": "v1.15.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "aa94dc41e8661fe90c7316849907cba3007b10d8"
"url": "https://github.com/phpspec/prophecy.git",
"reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/aa94dc41e8661fe90c7316849907cba3007b10d8",
"reference": "aa94dc41e8661fe90c7316849907cba3007b10d8",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/bbcd7380b0ebf3961ee21409db7b38bc31d69a13",
"reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.2",
"php": "^7.2 || ~8.0, <8.2",
"phpdocumentor/reflection-docblock": "^5.2",
"sebastian/comparator": "^3.0 || ^4.0",
"sebastian/recursion-context": "^3.0 || ^4.0"
},
"require-dev": {
"phpspec/phpspec": "^6.0 || ^7.0",
"phpunit/phpunit": "^8.0 || ^9.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Prophecy\\": "src/Prophecy"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Konstantin Kudryashov",
"email": "ever.zet@gmail.com",
"homepage": "http://everzet.com"
},
{
"name": "Marcello Duarte",
"email": "marcello.duarte@gmail.com"
}
],
"description": "Highly opinionated mocking framework for PHP 5.3+",
"homepage": "https://github.com/phpspec/prophecy",
"keywords": [
"Double",
"Dummy",
"fake",
"mock",
"spy",
"stub"
],
"support": {
"issues": "https://github.com/phpspec/prophecy/issues",
"source": "https://github.com/phpspec/prophecy/tree/v1.15.0"
},
"time": "2021-12-08T12:19:24+00:00"
},
{
"name": "phpunit/php-code-coverage",
"version": "9.2.15",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "2e9da11878c4202f97915c1cb4bb1ca318a63f5f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2e9da11878c4202f97915c1cb4bb1ca318a63f5f",
"reference": "2e9da11878c4202f97915c1cb4bb1ca318a63f5f",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-libxml": "*",
"ext-xmlwriter": "*",
"nikic/php-parser": "^4.14",
"nikic/php-parser": "^4.13.0",
"php": ">=7.3",
"phpunit/php-file-iterator": "^3.0.3",
"phpunit/php-text-template": "^2.0.2",
@@ -1789,7 +1856,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.17"
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.15"
},
"funding": [
{
@@ -1797,7 +1864,7 @@
"type": "github"
}
],
"time": "2022-08-30T12:24:04+00:00"
"time": "2022-03-07T09:28:20+00:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -2042,16 +2109,16 @@
},
{
"name": "phpunit/phpunit",
"version": "9.5.24",
"version": "9.5.20",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "d0aa6097bef9fd42458a9b3c49da32c6ce6129c5"
"reference": "12bc8879fb65aef2138b26fc633cb1e3620cffba"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d0aa6097bef9fd42458a9b3c49da32c6ce6129c5",
"reference": "d0aa6097bef9fd42458a9b3c49da32c6ce6129c5",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/12bc8879fb65aef2138b26fc633cb1e3620cffba",
"reference": "12bc8879fb65aef2138b26fc633cb1e3620cffba",
"shasum": ""
},
"require": {
@@ -2066,6 +2133,7 @@
"phar-io/manifest": "^2.0.3",
"phar-io/version": "^3.0.2",
"php": ">=7.3",
"phpspec/prophecy": "^1.12.1",
"phpunit/php-code-coverage": "^9.2.13",
"phpunit/php-file-iterator": "^3.0.5",
"phpunit/php-invoker": "^3.1.1",
@@ -2080,9 +2148,13 @@
"sebastian/global-state": "^5.0.1",
"sebastian/object-enumerator": "^4.0.3",
"sebastian/resource-operations": "^3.0.3",
"sebastian/type": "^3.1",
"sebastian/type": "^3.0",
"sebastian/version": "^3.0.2"
},
"require-dev": {
"ext-pdo": "*",
"phpspec/prophecy-phpunit": "^2.0.1"
},
"suggest": {
"ext-soap": "*",
"ext-xdebug": "*"
@@ -2124,7 +2196,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.24"
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.20"
},
"funding": [
{
@@ -2136,7 +2208,7 @@
"type": "github"
}
],
"time": "2022-08-30T07:42:16+00:00"
"time": "2022-04-01T12:37:26+00:00"
},
{
"name": "psr/cache",
@@ -3133,16 +3205,16 @@
},
{
"name": "sebastian/environment",
"version": "5.1.4",
"version": "5.1.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
"reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7"
"reference": "388b6ced16caa751030f6a69e588299fa09200ac"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/1b5dff7bb151a4db11d49d90e5408e4e938270f7",
"reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/388b6ced16caa751030f6a69e588299fa09200ac",
"reference": "388b6ced16caa751030f6a69e588299fa09200ac",
"shasum": ""
},
"require": {
@@ -3184,7 +3256,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/environment/issues",
"source": "https://github.com/sebastianbergmann/environment/tree/5.1.4"
"source": "https://github.com/sebastianbergmann/environment/tree/5.1.3"
},
"funding": [
{
@@ -3192,7 +3264,7 @@
"type": "github"
}
],
"time": "2022-04-03T09:37:03+00:00"
"time": "2020-09-28T05:52:38+00:00"
},
{
"name": "sebastian/exporter",
@@ -3624,16 +3696,16 @@
},
{
"name": "sebastian/type",
"version": "3.1.0",
"version": "3.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/type.git",
"reference": "fb44e1cc6e557418387ad815780360057e40753e"
"reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/fb44e1cc6e557418387ad815780360057e40753e",
"reference": "fb44e1cc6e557418387ad815780360057e40753e",
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b233b84bc4465aff7b57cf1c4bc75c86d00d6dad",
"reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad",
"shasum": ""
},
"require": {
@@ -3645,7 +3717,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
"dev-master": "3.0-dev"
}
},
"autoload": {
@@ -3668,7 +3740,7 @@
"homepage": "https://github.com/sebastianbergmann/type",
"support": {
"issues": "https://github.com/sebastianbergmann/type/issues",
"source": "https://github.com/sebastianbergmann/type/tree/3.1.0"
"source": "https://github.com/sebastianbergmann/type/tree/3.0.0"
},
"funding": [
{
@@ -3676,7 +3748,7 @@
"type": "github"
}
],
"time": "2022-08-29T06:55:37+00:00"
"time": "2022-03-15T09:54:48+00:00"
},
{
"name": "sebastian/version",
@@ -3733,16 +3805,16 @@
},
{
"name": "symfony/console",
"version": "v5.4.12",
"version": "v5.4.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "c072aa8f724c3af64e2c7a96b796a4863d24dba1"
"reference": "d8111acc99876953f52fe16d4c50eb60940d49ad"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/c072aa8f724c3af64e2c7a96b796a4863d24dba1",
"reference": "c072aa8f724c3af64e2c7a96b796a4863d24dba1",
"url": "https://api.github.com/repos/symfony/console/zipball/d8111acc99876953f52fe16d4c50eb60940d49ad",
"reference": "d8111acc99876953f52fe16d4c50eb60940d49ad",
"shasum": ""
},
"require": {
@@ -3812,7 +3884,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v5.4.12"
"source": "https://github.com/symfony/console/tree/v5.4.5"
},
"funding": [
{
@@ -3828,20 +3900,20 @@
"type": "tidelift"
}
],
"time": "2022-08-17T13:18:05+00:00"
"time": "2022-02-24T12:45:35+00:00"
},
{
"name": "symfony/deprecation-contracts",
"version": "v2.5.2",
"version": "v2.5.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66"
"reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
"reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/6f981ee24cf69ee7ce9736146d1c57c2780598a8",
"reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8",
"shasum": ""
},
"require": {
@@ -3879,7 +3951,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2"
"source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.0"
},
"funding": [
{
@@ -3895,7 +3967,7 @@
"type": "tidelift"
}
],
"time": "2022-01-02T09:53:40+00:00"
"time": "2021-07-12T14:48:14+00:00"
},
{
"name": "symfony/event-dispatcher",
@@ -3983,16 +4055,16 @@
},
{
"name": "symfony/event-dispatcher-contracts",
"version": "v1.1.13",
"version": "v1.1.11",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher-contracts.git",
"reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e"
"reference": "01e9a4efac0ee33a05dfdf93b346f62e7d0e998c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/1d5cd762abaa6b2a4169d3e77610193a7157129e",
"reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e",
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/01e9a4efac0ee33a05dfdf93b346f62e7d0e998c",
"reference": "01e9a4efac0ee33a05dfdf93b346f62e7d0e998c",
"shasum": ""
},
"require": {
@@ -4042,7 +4114,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.13"
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.11"
},
"funding": [
{
@@ -4058,7 +4130,7 @@
"type": "tidelift"
}
],
"time": "2022-01-02T09:41:36+00:00"
"time": "2021-03-23T15:25:38+00:00"
},
{
"name": "symfony/filesystem",
@@ -4258,16 +4330,16 @@
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.26.0",
"version": "v1.25.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4"
"reference": "30885182c981ab175d4d034db0f6f469898070ab"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
"reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab",
"reference": "30885182c981ab175d4d034db0f6f469898070ab",
"shasum": ""
},
"require": {
@@ -4282,7 +4354,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -4320,7 +4392,7 @@
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0"
},
"funding": [
{
@@ -4336,20 +4408,20 @@
"type": "tidelift"
}
],
"time": "2022-05-24T11:49:31+00:00"
"time": "2021-10-20T20:35:02+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
"version": "v1.26.0",
"version": "v1.25.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
"reference": "433d05519ce6990bf3530fba6957499d327395c2"
"reference": "81b86b50cf841a64252b439e738e97f4a34e2783"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/433d05519ce6990bf3530fba6957499d327395c2",
"reference": "433d05519ce6990bf3530fba6957499d327395c2",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/81b86b50cf841a64252b439e738e97f4a34e2783",
"reference": "81b86b50cf841a64252b439e738e97f4a34e2783",
"shasum": ""
},
"require": {
@@ -4361,7 +4433,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -4401,7 +4473,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.25.0"
},
"funding": [
{
@@ -4417,20 +4489,20 @@
"type": "tidelift"
}
],
"time": "2022-05-24T11:49:31+00:00"
"time": "2021-11-23T21:10:46+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.26.0",
"version": "v1.25.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "219aa369ceff116e673852dce47c3a41794c14bd"
"reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd",
"reference": "219aa369ceff116e673852dce47c3a41794c14bd",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8",
"reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8",
"shasum": ""
},
"require": {
@@ -4442,7 +4514,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -4485,7 +4557,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.25.0"
},
"funding": [
{
@@ -4501,20 +4573,20 @@
"type": "tidelift"
}
],
"time": "2022-05-24T11:49:31+00:00"
"time": "2021-02-19T12:13:01+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.26.0",
"version": "v1.25.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e"
"reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
"reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825",
"reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825",
"shasum": ""
},
"require": {
@@ -4529,7 +4601,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -4568,7 +4640,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0"
},
"funding": [
{
@@ -4584,20 +4656,20 @@
"type": "tidelift"
}
],
"time": "2022-05-24T11:49:31+00:00"
"time": "2021-11-30T18:21:41+00:00"
},
{
"name": "symfony/polyfill-php73",
"version": "v1.26.0",
"version": "v1.25.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php73.git",
"reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85"
"reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/e440d35fa0286f77fb45b79a03fedbeda9307e85",
"reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85",
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/cc5db0e22b3cb4111010e48785a97f670b350ca5",
"reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5",
"shasum": ""
},
"require": {
@@ -4606,7 +4678,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -4647,7 +4719,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php73/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-php73/tree/v1.25.0"
},
"funding": [
{
@@ -4663,20 +4735,20 @@
"type": "tidelift"
}
],
"time": "2022-05-24T11:49:31+00:00"
"time": "2021-06-05T21:20:04+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.26.0",
"version": "v1.25.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace"
"reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace",
"reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4407588e0d3f1f52efb65fbe92babe41f37fe50c",
"reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c",
"shasum": ""
},
"require": {
@@ -4685,7 +4757,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -4730,7 +4802,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-php80/tree/v1.25.0"
},
"funding": [
{
@@ -4746,7 +4818,7 @@
"type": "tidelift"
}
],
"time": "2022-05-10T07:21:04+00:00"
"time": "2022-03-04T08:16:47+00:00"
},
{
"name": "symfony/polyfill-php81",
@@ -4891,22 +4963,22 @@
},
{
"name": "symfony/service-contracts",
"version": "v2.5.2",
"version": "v2.5.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c"
"reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
"reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc",
"reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"psr/container": "^1.1",
"symfony/deprecation-contracts": "^2.1|^3"
"symfony/deprecation-contracts": "^2.1"
},
"conflict": {
"ext-psr": "<1.1|>=2"
@@ -4954,7 +5026,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/service-contracts/tree/v2.5.2"
"source": "https://github.com/symfony/service-contracts/tree/v2.5.0"
},
"funding": [
{
@@ -4970,7 +5042,7 @@
"type": "tidelift"
}
],
"time": "2022-05-30T19:17:29+00:00"
"time": "2021-11-04T16:48:04+00:00"
},
{
"name": "symfony/stopwatch",
@@ -5036,16 +5108,16 @@
},
{
"name": "symfony/string",
"version": "v5.4.12",
"version": "v5.4.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "2fc515e512d721bf31ea76bd02fe23ada4640058"
"reference": "92043b7d8383e48104e411bc9434b260dbeb5a10"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/2fc515e512d721bf31ea76bd02fe23ada4640058",
"reference": "2fc515e512d721bf31ea76bd02fe23ada4640058",
"url": "https://api.github.com/repos/symfony/string/zipball/92043b7d8383e48104e411bc9434b260dbeb5a10",
"reference": "92043b7d8383e48104e411bc9434b260dbeb5a10",
"shasum": ""
},
"require": {
@@ -5102,7 +5174,7 @@
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v5.4.12"
"source": "https://github.com/symfony/string/tree/v5.4.3"
},
"funding": [
{
@@ -5118,7 +5190,7 @@
"type": "tidelift"
}
],
"time": "2022-08-12T17:03:11+00:00"
"time": "2022-01-02T09:53:40+00:00"
},
{
"name": "theseer/tokenizer",
@@ -5172,16 +5244,16 @@
},
{
"name": "vimeo/psalm",
"version": "4.27.0",
"version": "4.22.0",
"source": {
"type": "git",
"url": "https://github.com/vimeo/psalm.git",
"reference": "faf106e717c37b8c81721845dba9de3d8deed8ff"
"reference": "fc2c6ab4d5fa5d644d8617089f012f3bb84b8703"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/vimeo/psalm/zipball/faf106e717c37b8c81721845dba9de3d8deed8ff",
"reference": "faf106e717c37b8c81721845dba9de3d8deed8ff",
"url": "https://api.github.com/repos/vimeo/psalm/zipball/fc2c6ab4d5fa5d644d8617089f012f3bb84b8703",
"reference": "fc2c6ab4d5fa5d644d8617089f012f3bb84b8703",
"shasum": ""
},
"require": {
@@ -5206,7 +5278,6 @@
"php": "^7.1|^8",
"sebastian/diff": "^3.0 || ^4.0",
"symfony/console": "^3.4.17 || ^4.1.6 || ^5.0 || ^6.0",
"symfony/polyfill-php80": "^1.25",
"webmozart/path-util": "^2.3"
},
"provide": {
@@ -5273,27 +5344,27 @@
],
"support": {
"issues": "https://github.com/vimeo/psalm/issues",
"source": "https://github.com/vimeo/psalm/tree/4.27.0"
"source": "https://github.com/vimeo/psalm/tree/4.22.0"
},
"time": "2022-08-31T13:47:09+00:00"
"time": "2022-02-24T20:34:05+00:00"
},
{
"name": "webmozart/assert",
"version": "1.11.0",
"version": "1.10.0",
"source": {
"type": "git",
"url": "https://github.com/webmozarts/assert.git",
"reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991"
"reference": "6964c76c7804814a842473e0c8fd15bab0f18e25"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991",
"reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991",
"url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25",
"reference": "6964c76c7804814a842473e0c8fd15bab0f18e25",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"php": "^7.2 || ^8.0"
"php": "^7.2 || ^8.0",
"symfony/polyfill-ctype": "^1.8"
},
"conflict": {
"phpstan/phpstan": "<0.12.20",
@@ -5331,9 +5402,9 @@
],
"support": {
"issues": "https://github.com/webmozarts/assert/issues",
"source": "https://github.com/webmozarts/assert/tree/1.11.0"
"source": "https://github.com/webmozarts/assert/tree/1.10.0"
},
"time": "2022-06-03T18:03:27+00:00"
"time": "2021-03-09T10:59:23+00:00"
},
{
"name": "webmozart/path-util",

View File

@@ -1,9 +0,0 @@
.icon-deck {
background-image: url(../img/deck-dark.svg);
filter: var(--background-invert-if-dark);
}
.icon-deck-white, .icon-deck.icon-white {
background-image: url(../img/deck.svg);
filter: var(--background-invert-if-dark);
}

1
css/deck.scss Normal file
View File

@@ -0,0 +1 @@
@include icon-black-white('deck', 'deck', 1);

View File

@@ -1,8 +1,11 @@
<?php
/**
* @copyright Copyright (c) 2022 Raul Ferreira Fuentes <raul@nextcloud.com>
/*
* @copyright Copyright (c) 2016 Julius Härtl <jus@bitgrid.net>
*
* @author Raul Ferreira Fuentes <raul@nextcloud.com>
* @author Julius Härtl <jus@bitgrid.net>
* @author Artem Anufrij <artem.anufrij@live.de>
* @author Marin Treselj <marin@pixelipo.com>
* @author Oskar Kurz <oskar.kurz@gmail.com>
* @author Ryan Fletcher <ryan.fletcher@codepassion.ca>
*
* @license GNU AGPL version 3 or any later version
*
@@ -20,26 +23,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Deck\Model;
use OCA\Deck\Db\Board;
class BoardSummary extends Board {
private Board $board;
public function __construct(Board $board) {
parent::__construct();
$this->board = $board;
}
public function jsonSerialize(): array {
return [
'id' => $this->getId(),
'title' => $this->getTitle()
];
}
public function __call($name, $arguments) {
return $this->board->__call($name, $arguments);
}
}
@import 'icons';
@import 'print';

41
css/icons.scss Normal file
View File

@@ -0,0 +1,41 @@
/**
* Custom icons
*/
@include icon-black-white('deck', 'deck', 1);
@include icon-black-white('archive', 'deck', 1);
@include icon-black-white('circles', 'deck', 1);
@include icon-black-white('clone', 'deck', 1);
@include icon-black-white('filter', 'deck', 1);
@include icon-black-white('filter_set', 'deck', 1);
@include icon-black-white('attach', 'deck', 1);
@include icon-black-white('reply', 'deck', 1);
@include icon-black-white('notifications-dark', 'deck', 1);
@include icon-black-white('description', 'deck', 1);
.icon-toggle-compact-collapsed {
@include icon-color('toggle-view-expand', 'deck', $color-black);
}
.icon-toggle-compact-expanded {
@include icon-color('toggle-view-collapse', 'deck', $color-black);
}
.icon-activity {
@include icon-color('activity-dark', 'activity', $color-black);
}
.icon-comment--unread {
@include icon-color('comment', 'actions', $color-primary, 1, true);
}
.avatardiv.circles {
background: var(--color-primary);
}
.icon-circles {
opacity: 1;
background-size: 20px;
background-position: center center;
}
.icon-colorpicker {
background-image: url('../img/color_picker.svg');
}

View File

@@ -1,17 +0,0 @@
const { defineConfig } = require('cypress')
module.exports = defineConfig({
projectId: '1s7wkc',
viewportWidth: 1280,
viewportHeight: 720,
e2e: {
// We've imported your old cypress plugins here.
// You may want to clean this up later by importing these.
setupNodeEvents(on, config) {
return require('./cypress/plugins/index.js')(on, config)
},
baseUrl: 'http://nextcloud.local/index.php',
experimentalSessionAndOrigin: true,
specPattern: 'cypress/e2e/**/*.{js,jsx,ts,tsx}',
},
})

View File

@@ -1,41 +0,0 @@
import { randHash } from '../utils'
const randUser = randHash()
describe('Board', function() {
const password = 'pass123'
before(function() {
cy.nextcloudCreateUser(randUser, password)
})
beforeEach(function() {
cy.login(randUser, password)
})
it('Can create a board', function() {
const board = 'TestBoard'
cy.intercept({
method: 'POST',
url: '/index.php/apps/deck/boards',
}).as('createBoardRequest')
// Click "Add board"
cy.openLeftSidebar()
cy.get('#app-navigation-vue .app-navigation__list .app-navigation-entry')
.eq(3).find('a').first().click({ force: true })
// Type the board title
cy.get('.board-create form input[type=text]')
.type(board, { force: true })
// Submit
cy.get('.board-create form input[type=submit]')
.first().click({ force: true })
cy.wait('@createBoardRequest').its('response.statusCode').should('equal', 200)
cy.get('.app-navigation__list .app-navigation-entry__children .app-navigation-entry')
.contains(board).should('be.visible')
})
})

View File

@@ -1,67 +0,0 @@
import { randHash } from '../utils'
const randUser = randHash()
const testBoardData = {
title: 'MyBoardTest',
color: '00ff00',
stacks: [
{
title: 'TestList',
cards: [
{
title: 'Hello world',
},
],
},
],
}
describe('Card', function() {
before(function() {
cy.nextcloudCreateUser(randUser, randUser)
cy.createExampleBoard({
user: randUser,
password: randUser,
board: testBoardData,
})
})
beforeEach(function() {
cy.login(randUser, randUser)
})
it('Can show card details modal', function() {
cy.openLeftSidebar()
cy.getNavigationEntry(testBoardData.title)
.first().click({ force: true })
cy.get('.board .stack').eq(0).within(() => {
cy.get('.card:contains("Hello world")').should('be.visible').click()
})
cy.get('.modal__card').should('be.visible')
cy.get('.app-sidebar-header__maintitle').contains('Hello world')
})
it('Can add a card', function() {
const newCardTitle = 'Write some cypress tests'
cy.openLeftSidebar()
cy.getNavigationEntry(testBoardData.title)
.first().click({ force: true })
cy.get('.board .stack').eq(0).within(() => {
cy.get('.card:contains("Hello world")').should('be.visible')
cy.get('.button-vue[aria-label*="Add card"]')
.first().click()
cy.get('.stack__card-add form input#new-stack-input-main')
.type(newCardTitle)
cy.get('.stack__card-add form input[type=submit]')
.first().click()
cy.get(`.card:contains("${newCardTitle}")`).should('be.visible')
})
})
})

View File

@@ -1,31 +0,0 @@
import { randHash } from '../utils'
const randUser = randHash()
describe('Deck dashboard', function() {
const password = 'pass123'
before(function() {
cy.nextcloudCreateUser(randUser, password)
})
beforeEach(function() {
cy.login(randUser, password)
})
it('Can show the right title on the dashboard', function() {
cy.get('.board-title h2')
.should('have.length', 1).first()
.should('have.text', 'Upcoming cards')
})
it('Can see the default "Personal Board" created for user by default', function() {
const defaultBoard = 'Personal'
cy.openLeftSidebar()
cy.get('.app-navigation-entry-wrapper[icon=icon-deck]')
.find('ul.app-navigation-entry__children .app-navigation-entry:contains(' + defaultBoard + ')')
.first()
.contains(defaultBoard)
.should('be.visible')
})
})

View File

@@ -1,30 +0,0 @@
import { randHash } from '../utils'
const randUser = randHash()
describe('Stack', function() {
const board = 'TestBoard'
const password = 'pass123'
const stack = 'List 1'
before(function() {
cy.nextcloudCreateUser(randUser, password)
cy.deckCreateBoard({ user: randUser, password }, board)
})
beforeEach(function() {
cy.logout()
cy.login(randUser, password)
})
it('Can create a stack', function() {
cy.openLeftSidebar()
cy.getNavigationEntry(board)
.click({ force: true })
cy.get('#stack-add button').first().click()
cy.get('#stack-add form input#new-stack-input-main').type(stack)
cy.get('#stack-add form input[type=submit]').first().click()
cy.get('.board .stack').eq(0).contains(stack).should('be.visible')
})
})

View File

@@ -1,5 +0,0 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

View File

@@ -1,22 +0,0 @@
/// <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
/**
* @type {Cypress.PluginConfig}
*/
// eslint-disable-next-line no-unused-vars
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
}

View File

@@ -1,159 +0,0 @@
/**
* @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
const url = Cypress.config('baseUrl').replace(/\/index.php\/?$/g, '')
Cypress.env('baseUrl', url)
Cypress.Commands.add('login', (user, password, route = '/apps/deck/') => {
const session = `${user}-${Date.now()}`
cy.session(session, function() {
cy.visit(route)
cy.get('input[name=user]').type(user)
cy.get('input[name=password]').type(password)
cy.get('form[name=login] [type=submit]').click()
cy.url().should('include', route)
})
cy.visit(route)
})
Cypress.Commands.add('logout', (route = '/') => {
cy.session('_guest', function() {})
})
Cypress.Commands.add('nextcloudCreateUser', (user, password) => {
cy.clearCookies()
cy.request({
method: 'POST',
url: `${Cypress.env('baseUrl')}/ocs/v1.php/cloud/users?format=json`,
form: true,
body: {
userid: user,
password,
},
auth: { user: 'admin', pass: 'admin' },
headers: {
'OCS-ApiRequest': 'true',
'Content-Type': 'application/x-www-form-urlencoded',
},
}).then((response) => {
cy.log(`Created user ${user}`, response.status)
})
})
Cypress.Commands.add('nextcloudUpdateUser', (user, password, key, value) => {
cy.request({
method: 'PUT',
url: `${Cypress.env('baseUrl')}/ocs/v2.php/cloud/users/${user}`,
form: true,
body: { key, value },
auth: { user, pass: password },
headers: {
'OCS-ApiRequest': 'true',
'Content-Type': 'application/x-www-form-urlencoded',
},
}).then((response) => {
cy.log(`Updated user ${user} ${key} to ${value}`, response.status)
})
})
Cypress.Commands.add('openLeftSidebar', () => {
cy.get('.app-navigation button.app-navigation-toggle').click()
})
Cypress.Commands.add('deckCreateBoard', ({ user, password }, title) => {
cy.login(user, password)
cy.get('.app-navigation button.app-navigation-toggle').click()
cy.get('#app-navigation-vue .app-navigation__list .app-navigation-entry')
.eq(3)
.find('a')
.first()
.click({ force: true })
cy.get('.board-create form input[type=text]').type(title, { force: true })
cy.get('.board-create form input[type=submit]')
.first()
.click({ force: true })
})
Cypress.Commands.add('deckCreateList', ({ user, password }, title) => {
cy.login(user, password)
cy.get('.app-navigation button.app-navigation-toggle').click()
cy.get('#app-navigation-vue .app-navigation__list .app-navigation-entry')
.eq(3)
.find('a.app-navigation-entry-link')
.first()
.click({ force: true })
cy.get('#stack-add button').first().click()
cy.get('#stack-add form input#new-stack-input-main').type(title)
cy.get('#stack-add form input[type=submit]').first().click()
})
Cypress.Commands.add('createExampleBoard', ({ user, password, board }) => {
cy.request({
method: 'POST',
url: `${Cypress.env('baseUrl')}/index.php/apps/deck/api/v1.0/boards`,
auth: {
user,
password,
},
body: { title: board.title, color: board.color ?? 'ff0000' },
}).then((boardResponse) => {
expect(boardResponse.status).to.eq(200)
const boardData = boardResponse.body
for (const stackIndex in board.stacks) {
const stack = board.stacks[stackIndex]
cy.request({
method: 'POST',
url: `${Cypress.env('baseUrl')}/index.php/apps/deck/api/v1.0/boards/${boardData.id}/stacks`,
auth: {
user,
password,
},
body: { title: stack.title, order: 0 },
}).then((stackResponse) => {
const stackData = stackResponse.body
for (const cardIndex in stack.cards) {
const card = stack.cards[cardIndex]
cy.request({
method: 'POST',
url: `${Cypress.env('baseUrl')}/index.php/apps/deck/api/v1.0/boards/${boardData.id}/stacks/${stackData.id}/cards`,
auth: {
user,
password,
},
body: { title: card.title },
})
}
})
}
})
})
Cypress.Commands.add('getNavigationEntry', (boardTitle) => {
return cy.get('.app-navigation-entry-wrapper[icon=icon-deck]')
.find('ul.app-navigation-entry__children .app-navigation-entry:contains(' + boardTitle + ')')
.find('a.app-navigation-entry-link')
})

View File

@@ -1,20 +0,0 @@
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands'
// Alternatively you can use CommonJS syntax:
// require('./commands')

View File

@@ -1 +0,0 @@
export const randHash = () => Math.random().toString(36).replace(/[^a-z]+/g, '').slice(0, 10)

View File

@@ -90,7 +90,7 @@ Steps:
* Create the configuration file
* Execute the import informing the import file path, data file and source as `Trello JSON`
Create the configuration file respecting the [JSON Schema](https://github.com/nextcloud/deck/blob/master/lib/Service/Importer/fixtures/config-trelloJson-schema.json) for import `Trello JSON`
Create the configuration file respecting the [JSON Schema](https://github.com/nextcloud/deck/blob/master/lib/Service/fixtures/config-trelloJson-schema.json) for import `Trello JSON`
Example configuration file:
```json
@@ -120,7 +120,7 @@ https://api.trello.com/1/members/me/boards?key={yourKey}&token={yourToken}&field
This ID you will use in the configuration file in the `board` property
* Create the configuration file
Create the configuration file respecting the [JSON Schema](https://github.com/nextcloud/deck/blob/master/lib/Service/Importer/fixtures/config-trelloApi-schema.json) for import `Trello JSON`
Create the configuration file respecting the [JSON Schema](https://github.com/nextcloud/deck/blob/master/lib/Service/fixtures/config-trelloApi-schema.json) for import `Trello JSON`
Example configuration file:
```json

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" height="32" width="32" version="1.0" viewbox="0 0 32 32">
<path d="m16 1-10 18h11l-1 12 10-18h-11z"/>
</svg>

Before

Width:  |  Height:  |  Size: 205 B

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" height="32" width="32" version="1.0" viewBox="0 0 32 32">
<path d="m16 1-10 18h11l-1 12 10-18h-11z" fill="#FFF"/>
</svg>

Before

Width:  |  Height:  |  Size: 217 B

1
img/archive-white.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><g transform="translate(0 -1036.362)" fill="#fff"><path d="M1.93 1041.296c-.185 0-.336.138-.336.31v9.842c0 .172.15.313.336.313h12.517c.185 0 .333-.14.333-.313v-9.842c0-.172-.148-.31-.333-.31H1.93zm4.124 1.507h4.223c.39 0 .705.314.705.704v.43c0 .39-.315.705-.705.705H6.054a.703.703 0 0 1-.705-.705v-.43c0-.39.314-.704.705-.704z"/><rect width="15.742" height="2.296" x=".136" y="1037.543" ry="0"/></g></svg>

After

Width:  |  Height:  |  Size: 488 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 58 58" width="512" height="512"><g fill="#000"><path d="M54.319 37.839C54.762 35.918 55 33.96 55 32c0-9.095-4.631-17.377-12.389-22.153a1 1 0 1 0-1.049 1.703C48.724 15.96 53 23.604 53 32c0 1.726-.2 3.451-.573 5.147A6.992 6.992 0 0 0 51 37c-3.86 0-7 3.141-7 7s3.14 7 7 7 7-3.141 7-7a7.006 7.006 0 0 0-3.681-6.161zM38.171 54.182A23.867 23.867 0 0 1 29 56a24.047 24.047 0 0 1-17.017-7.092A6.974 6.974 0 0 0 14 44c0-3.859-3.14-7-7-7s-7 3.141-7 7 3.14 7 7 7a6.952 6.952 0 0 0 3.381-.875C15.26 55.136 21.994 58 29 58c3.435 0 6.778-.663 9.936-1.971.51-.211.753-.796.542-1.307a1.001 1.001 0 0 0-1.307-.54zM4 31.213a1 1 0 0 0 1.068-.927c.712-10.089 7.586-18.52 17.22-21.314C23.142 11.874 25.825 14 29 14c3.86 0 7-3.141 7-7s-3.14-7-7-7c-3.851 0-6.985 3.127-6.999 6.975C11.42 9.922 3.851 19.12 3.073 30.146A.999.999 0 0 0 4 31.213z"/></g></svg>

Before

Width:  |  Height:  |  Size: 885 B

View File

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 58 58" width="512" height="512"><g fill="#fff"><path d="M54.319 37.839C54.762 35.918 55 33.96 55 32c0-9.095-4.631-17.377-12.389-22.153a1 1 0 1 0-1.049 1.703C48.724 15.96 53 23.604 53 32c0 1.726-.2 3.451-.573 5.147A6.992 6.992 0 0 0 51 37c-3.86 0-7 3.141-7 7s3.14 7 7 7 7-3.141 7-7a7.006 7.006 0 0 0-3.681-6.161zM38.171 54.182A23.867 23.867 0 0 1 29 56a24.047 24.047 0 0 1-17.017-7.092A6.974 6.974 0 0 0 14 44c0-3.859-3.14-7-7-7s-7 3.141-7 7 3.14 7 7 7a6.952 6.952 0 0 0 3.381-.875C15.26 55.136 21.994 58 29 58c3.435 0 6.778-.663 9.936-1.971.51-.211.753-.796.542-1.307a1.001 1.001 0 0 0-1.307-.54zM4 31.213a1 1 0 0 0 1.068-.927c.712-10.089 7.586-18.52 17.22-21.314C23.142 11.874 25.825 14 29 14c3.86 0 7-3.141 7-7s-3.14-7-7-7c-3.851 0-6.985 3.127-6.999 6.975C11.42 9.922 3.851 19.12 3.073 30.146A.999.999 0 0 0 4 31.213z"/></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 58 58" width="512" height="512"><g fill="#000"><path d="M54.319 37.839C54.762 35.918 55 33.96 55 32c0-9.095-4.631-17.377-12.389-22.153a1 1 0 1 0-1.049 1.703C48.724 15.96 53 23.604 53 32c0 1.726-.2 3.451-.573 5.147A6.992 6.992 0 0 0 51 37c-3.86 0-7 3.141-7 7s3.14 7 7 7 7-3.141 7-7a7.006 7.006 0 0 0-3.681-6.161zM38.171 54.182A23.867 23.867 0 0 1 29 56a24.047 24.047 0 0 1-17.017-7.092A6.974 6.974 0 0 0 14 44c0-3.859-3.14-7-7-7s-7 3.141-7 7 3.14 7 7 7a6.952 6.952 0 0 0 3.381-.875C15.26 55.136 21.994 58 29 58c3.435 0 6.778-.663 9.936-1.971.51-.211.753-.796.542-1.307a1.001 1.001 0 0 0-1.307-.54zM4 31.213a1 1 0 0 0 1.068-.927c.712-10.089 7.586-18.52 17.22-21.314C23.142 11.874 25.825 14 29 14c3.86 0 7-3.141 7-7s-3.14-7-7-7c-3.851 0-6.985 3.127-6.999 6.975C11.42 9.922 3.851 19.12 3.073 30.146A.999.999 0 0 0 4 31.213z"/></g></svg>

Before

Width:  |  Height:  |  Size: 885 B

After

Width:  |  Height:  |  Size: 885 B

1
img/clone.svg Normal file
View File

@@ -0,0 +1 @@
<svg width="16" height="16" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M11.8 13.8H2.2V4.2h9.6m1.2 0c0-.67-.53-1.2-1.2-1.2H2.2C1.53 3 1 3.53 1 4.2v9.6c0 .67.53 1.2 1.2 1.2h9.6c.67 0 1.2-.53 1.2-1.2"/><path d="m4.2 1c-0.67 0-1.2 0.54-1.2 1.2h10.8v10.8c0.67 0 1.2-0.53 1.2-1.2v-9.6c0-0.67-0.53-1.2-1.2-1.2z"/></svg>

After

Width:  |  Height:  |  Size: 327 B

1
img/reply.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16"><path d="M15 15s-.4-7.8-7-10V1L1 8l7 7v-4c5.1 0 7 4 7 4z"/></svg>

After

Width:  |  Height:  |  Size: 128 B

View File

@@ -38,6 +38,7 @@ use OCA\Deck\Db\CardMapper;
use OCA\Deck\Db\Label;
use OCA\Deck\Db\Stack;
use OCA\Deck\Db\StackMapper;
use OCA\Deck\NoPermissionException;
use OCA\Deck\Service\PermissionService;
use OCP\Activity\IEvent;
use OCP\Activity\IManager;
@@ -45,9 +46,7 @@ use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\Comments\IComment;
use OCP\IUser;
use OCP\Server;
use OCP\L10N\IFactory;
use Psr\Log\LoggerInterface;
class ActivityManager {
public const DECK_NOAUTHOR_COMMENT_SYSTEM_ENFORCED = 'DECK_NOAUTHOR_COMMENT_SYSTEM_ENFORCED';
@@ -55,14 +54,14 @@ class ActivityManager {
public const SUBJECT_PARAMS_MAX_LENGTH = 4000;
public const SHORTENED_DESCRIPTION_MAX_LENGTH = 2000;
private IManager $manager;
private ?string $userId;
private PermissionService $permissionService;
private BoardMapper $boardMapper;
private CardMapper $cardMapper;
private AclMapper $aclMapper;
private StackMapper $stackMapper;
private IFactory $l10nFactory;
private $manager;
private $userId;
private $permissionService;
private $boardMapper;
private $cardMapper;
private $aclMapper;
private $stackMapper;
private $l10nFactory;
public const DECK_OBJECT_BOARD = 'deck_board';
public const DECK_OBJECT_CARD = 'deck_card';
@@ -116,7 +115,7 @@ class ActivityManager {
StackMapper $stackMapper,
AclMapper $aclMapper,
IFactory $l10nFactory,
?string $userId
$userId
) {
$this->manager = $manager;
$this->permissionService = $permissionsService;
@@ -312,10 +311,10 @@ class ActivityManager {
try {
$object = $this->findObjectForEntity($objectType, $entity);
} catch (DoesNotExistException $e) {
Server::get(LoggerInterface::class)->error('Could not create activity entry for ' . $subject . '. Entity not found.', (array)$entity);
\OC::$server->getLogger()->error('Could not create activity entry for ' . $subject . '. Entity not found.', (array)$entity);
return null;
} catch (MultipleObjectsReturnedException $e) {
Server::get(LoggerInterface::class)->error('Could not create activity entry for ' . $subject . '. Entity not found.', (array)$entity);
\OC::$server->getLogger()->error('Could not create activity entry for ' . $subject . '. Entity not found.', (array)$entity);
return null;
}
@@ -367,15 +366,7 @@ class ActivityManager {
case self::SUBJECT_CARD_USER_ASSIGN:
case self::SUBJECT_CARD_USER_UNASSIGN:
$subjectParams = $this->findDetailsForCard($entity->getId(), $subject);
if (isset($additionalParams['after']) && $additionalParams['after'] instanceof \DateTimeInterface) {
$additionalParams['after'] = $additionalParams['after']->format('c');
}
if (isset($additionalParams['before']) && $additionalParams['before'] instanceof \DateTimeInterface) {
$additionalParams['before'] = $additionalParams['before']->format('c');
}
break;
break;
case self::SUBJECT_ATTACHMENT_CREATE:
case self::SUBJECT_ATTACHMENT_UPDATE:
case self::SUBJECT_ATTACHMENT_DELETE:
@@ -559,4 +550,24 @@ class ActivityManager {
'board' => $board
];
}
public function canSeeCardActivity(int $cardId): bool {
try {
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ);
$card = $this->cardMapper->find($cardId);
return $card->getDeletedAt() === 0;
} catch (NoPermissionException $e) {
return false;
}
}
public function canSeeBoardActivity(int $boardId): bool {
try {
$this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_READ);
$board = $this->boardMapper->find($boardId);
return $board->getDeletedAt() === 0;
} catch (NoPermissionException $e) {
return false;
}
}
}

View File

@@ -111,6 +111,9 @@ class DeckProvider implements IProvider {
$event->setAuthor($author);
}
if ($event->getObjectType() === ActivityManager::DECK_OBJECT_BOARD) {
if (!$this->activityManager->canSeeBoardActivity($event->getObjectId())) {
throw new \InvalidArgumentException();
}
if (isset($subjectParams['board']) && $event->getObjectName() === '') {
$event->setObject($event->getObjectType(), $event->getObjectId(), $subjectParams['board']['title']);
}
@@ -125,6 +128,9 @@ class DeckProvider implements IProvider {
}
if (isset($subjectParams['card']) && $event->getObjectType() === ActivityManager::DECK_OBJECT_CARD) {
if (!$this->activityManager->canSeeCardActivity($event->getObjectId())) {
throw new \InvalidArgumentException();
}
if ($event->getObjectName() === '') {
$event->setObject($event->getObjectType(), $event->getObjectId(), $subjectParams['card']['title']);
}
@@ -312,19 +318,12 @@ class DeckProvider implements IProvider {
$userLanguage = $this->config->getUserValue($event->getAuthor(), 'core', 'lang', $this->l10nFactory->findLanguage());
$userLocale = $this->config->getUserValue($event->getAuthor(), 'core', 'locale', $this->l10nFactory->findLocale());
$l10n = $this->l10nFactory->get('deck', $userLanguage, $userLocale);
if (is_array($subjectParams['after'])) {
// Unluckily there was a time when we stored jsonSerialized date objects in the database
// Broken in 1.8.0 and fixed again in 1.8.1
$date = new \DateTime($subjectParams['after']['date']);
$date->setTimezone(new \DateTimeZone(\date_default_timezone_get()));
} else {
$date = new \DateTime($subjectParams['after']);
$date->setTimezone(new \DateTimeZone(\date_default_timezone_get()));
}
$date = new \DateTime($subjectParams['after']);
$date->setTimezone(new \DateTimeZone(\date_default_timezone_get()));
$params['after'] = [
'type' => 'highlight',
'id' => 'dt:' . $subjectParams['after'],
'name' => $l10n->l('datetime', $date),
'name' => $l10n->l('datetime', $date)
];
}
return $params;

View File

@@ -47,7 +47,6 @@ use OCA\Deck\Listeners\FullTextSearchEventListener;
use OCA\Deck\Middleware\DefaultBoardMiddleware;
use OCA\Deck\Middleware\ExceptionMiddleware;
use OCA\Deck\Notification\Notifier;
use OCA\Deck\Reference\CardReferenceProvider;
use OCA\Deck\Search\CardCommentProvider;
use OCA\Deck\Search\DeckProvider;
use OCA\Deck\Service\PermissionService;
@@ -58,22 +57,20 @@ use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent;
use OCP\Collaboration\Reference\RenderReferenceEvent;
use OCP\Collaboration\Resources\IProviderManager;
use OCP\Comments\CommentsEntityEvent;
use OCP\Comments\ICommentsManager;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Group\Events\GroupDeletedEvent;
use OCP\IConfig;
use OCP\IDBConnection;
use OCP\IGroup;
use OCP\IGroupManager;
use OCP\IRequest;
use OCP\Server;
use OCP\IServerContainer;
use OCP\IUser;
use OCP\IUserManager;
use OCP\Notification\IManager as NotificationManager;
use OCP\Share\IManager;
use OCP\User\Events\UserDeletedEvent;
use OCP\Util;
use Psr\Container\ContainerInterface;
@@ -82,16 +79,13 @@ class Application extends App implements IBootstrap {
public const COMMENT_ENTITY_TYPE = 'deckCard';
/** @var IServerContainer */
private $server;
public function __construct(array $urlParams = []) {
parent::__construct(self::APP_ID, $urlParams);
// TODO move this back to ::register after fixing the autoload issue
// (and use a listener class)
$container = $this->getContainer();
$eventDispatcher = $container->get(IEventDispatcher::class);
$eventDispatcher->addListener(RenderReferenceEvent::class, function () {
Util::addScript(self::APP_ID, self::APP_ID . '-card-reference');
});
$this->server = \OC::$server;
}
public function boot(IBootContext $context): void {
@@ -130,12 +124,8 @@ class Application extends App implements IBootstrap {
$context->registerSearchProvider(CardCommentProvider::class);
$context->registerDashboardWidget(DeckWidget::class);
// reference widget
$context->registerReferenceProvider(CardReferenceProvider::class);
// $context->registerEventListener(RenderReferenceEvent::class, CardReferenceListener::class);
$context->registerEventListener(BeforeTemplateRenderedEvent::class, BeforeTemplateRenderedListener::class);
// Event listening for full text search indexing
$context->registerEventListener(CardCreatedEvent::class, FullTextSearchEventListener::class);
$context->registerEventListener(CardUpdatedEvent::class, FullTextSearchEventListener::class);
@@ -151,43 +141,33 @@ class Application extends App implements IBootstrap {
private function registerUserGroupHooks(IUserManager $userManager, IGroupManager $groupManager): void {
$container = $this->getContainer();
/** @var IEventDispatcher $eventDispatcher */
$eventDispatcher = $container->get(IEventDispatcher::class);
// Delete user/group acl entries when they get deleted
$eventDispatcher->addListener(UserDeletedEvent::class, static function (Event $event) use ($container): void {
if (!($event instanceof UserDeletedEvent)) {
return;
}
$user = $event->getUser();
$userManager->listen('\OC\User', 'postDelete', static function (IUser $user) use ($container) {
// delete existing acl entries for deleted user
/** @var AclMapper $aclMapper */
$aclMapper = $container->get(AclMapper::class);
$aclMapper = $container->query(AclMapper::class);
$acls = $aclMapper->findByParticipant(Acl::PERMISSION_TYPE_USER, $user->getUID());
foreach ($acls as $acl) {
$aclMapper->delete($acl);
}
// delete existing user assignments
$assignmentMapper = $container->get(AssignmentMapper::class);
$assignmentMapper = $container->query(AssignmentMapper::class);
$assignments = $assignmentMapper->findByParticipant($user->getUID());
foreach ($assignments as $assignment) {
$assignmentMapper->delete($assignment);
}
/** @var BoardMapper $boardMapper */
$boardMapper = $container->get(BoardMapper::class);
$boardMapper = $container->query(BoardMapper::class);
$boards = $boardMapper->findAllByOwner($user->getUID());
foreach ($boards as $board) {
$boardMapper->delete($board);
}
});
$eventDispatcher->addListener(GroupDeletedEvent::class, static function (Event $event) use ($container): void {
if (!($event instanceof GroupDeletedEvent)) {
return;
}
$group = $event->getGroup();
$groupManager->listen('\OC\Group', 'postDelete', static function (IGroup $group) use ($container) {
/** @var AclMapper $aclMapper */
$aclMapper = $container->get(AclMapper::class);
$aclMapper = $container->query(AclMapper::class);
$aclMapper->findByParticipant(Acl::PERMISSION_TYPE_GROUP, $group->getGID());
$acls = $aclMapper->findByParticipant(Acl::PERMISSION_TYPE_GROUP, $group->getGID());
foreach ($acls as $acl) {
@@ -201,7 +181,6 @@ class Application extends App implements IBootstrap {
$event->addEntityCollection(self::COMMENT_ENTITY_TYPE, function ($name) {
/** @var CardMapper */
$cardMapper = $this->getContainer()->get(CardMapper::class);
/** @var PermissionService $permissionService */
$permissionService = $this->getContainer()->get(PermissionService::class);
try {
@@ -224,7 +203,7 @@ class Application extends App implements IBootstrap {
$resourceManager->registerResourceProvider(ResourceProviderCard::class);
$symfonyAdapter->addListener('\OCP\Collaboration\Resources::loadAdditionalScripts', static function () {
if (strpos(Server::get(IRequest::class)->getPathInfo(), '/call/') === 0) {
if (strpos(\OC::$server->getRequest()->getPathInfo(), '/call/') === 0) {
// Talk integration has its own entrypoint which already includes collections handling
return;
}

View File

@@ -32,23 +32,20 @@ use OCP\AppFramework\QueryException;
use OCP\Collaboration\Resources\IManager;
use OCP\Collaboration\Resources\IProvider;
use OCP\Collaboration\Resources\IResource;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\Server;
class ResourceProvider implements IProvider {
public const RESOURCE_TYPE = 'deck';
private BoardMapper $boardMapper;
private PermissionService $permissionService;
private IURLGenerator $urlGenerator;
private $boardMapper;
private $permissionService;
protected array $nodes = [];
/** @var array */
protected $nodes = [];
public function __construct(BoardMapper $boardMapper, PermissionService $permissionService, IURLGenerator $urlGenerator) {
public function __construct(BoardMapper $boardMapper, PermissionService $permissionService) {
$this->boardMapper = $boardMapper;
$this->permissionService = $permissionService;
$this->urlGenerator = $urlGenerator;
}
/**
@@ -73,14 +70,14 @@ class ResourceProvider implements IProvider {
*/
public function getResourceRichObject(IResource $resource): array {
$board = $this->getBoard($resource);
$link = $this->urlGenerator->linkToRoute('deck.page.index') . '#/board/' . $resource->getId();
$link = \OC::$server->getURLGenerator()->linkToRoute('deck.page.index') . '#/board/' . $resource->getId();
return [
'type' => self::RESOURCE_TYPE,
'id' => $resource->getId(),
'name' => $board->getTitle(),
'link' => $link,
'iconUrl' => $this->urlGenerator->imagePath('deck', 'deck-dark.svg')
'iconUrl' => \OC::$server->getURLGenerator()->imagePath('deck', 'deck-dark.svg')
];
}
@@ -111,7 +108,7 @@ class ResourceProvider implements IProvider {
private function getBoard(IResource $resource) {
try {
return $this->boardMapper->find($resource->getId(), false, true);
return $this->boardMapper->find((int)$resource->getId(), false, true);
} catch (DoesNotExistException $e) {
} catch (MultipleObjectsReturnedException $e) {
return null;
@@ -121,7 +118,7 @@ class ResourceProvider implements IProvider {
public function invalidateAccessCache($boardId = null) {
try {
/** @var IManager $resourceManager */
$resourceManager = Server::get(IManager::class);
$resourceManager = \OC::$server->query(IManager::class);
} catch (QueryException $e) {
}
if ($boardId !== null) {

View File

@@ -37,16 +37,24 @@ use OCP\Collaboration\Resources\IResource;
use OCP\Collaboration\Resources\ResourceException;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\Server;
class ResourceProviderCard implements IProvider {
public const RESOURCE_TYPE = 'deck-card';
private CardMapper $cardMapper;
private BoardMapper $boardMapper;
private PermissionService $permissionService;
private IURLGenerator $urlGenerator;
protected array $nodes = [];
/** @var CardMapper */
private $cardMapper;
/** @var BoardMapper */
private $boardMapper;
/** @var PermissionService */
private $permissionService;
/** @var IURLGenerator */
private $urlGenerator;
/** @var array */
protected $nodes = [];
public function __construct(CardMapper $cardMapper, BoardMapper $boardMapper, PermissionService $permissionService, IURLGenerator $urlGenerator) {
$this->cardMapper = $cardMapper;
@@ -139,7 +147,7 @@ class ResourceProviderCard implements IProvider {
public function invalidateAccessCache($cardId = null) {
try {
/** @var IManager $resourceManager */
$resourceManager = Server::get(IManager::class);
$resourceManager = \OC::$server->query(IManager::class);
} catch (QueryException $e) {
}
if ($cardId !== null) {

View File

@@ -30,7 +30,8 @@ use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class BoardImport extends Command {
private BoardImportCommandService $boardImportCommandService;
/** @var BoardImportCommandService */
private $boardImportCommandService;
public function __construct(
BoardImportCommandService $boardImportCommandService

View File

@@ -27,7 +27,6 @@ use OCA\Deck\Db\AssignmentMapper;
use OCA\Deck\Db\BoardMapper;
use OCA\Deck\Db\CardMapper;
use OCA\Deck\Db\StackMapper;
use OCA\Deck\Model\CardDetails;
use OCA\Deck\Service\BoardService;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
@@ -102,9 +101,7 @@ class UserExport extends Command {
$fullCard = $this->cardMapper->find($card->getId());
$assignedUsers = $this->assignedUsersMapper->findAll($card->getId());
$fullCard->setAssignedUsers($assignedUsers);
$cardDetails = new CardDetails($fullCard, $fullBoard);
$data[$board->getId()]['stacks'][$stack->getId()]['cards'][] = $cardDetails->jsonSerialize();
$data[$board->getId()]['stacks'][$stack->getId()]['cards'][] = (array)$fullCard->jsonSerialize();
}
}
}

View File

@@ -29,9 +29,7 @@ use OCA\Deck\Service\PermissionService;
use OCA\Files\Event\LoadSidebar;
use OCA\Viewer\Event\LoadViewer;
use OCP\AppFramework\Http\ContentSecurityPolicy;
use OCP\Collaboration\Resources\LoadAdditionalScriptsEvent as CollaborationResourcesEvent;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IConfig;
use OCP\IInitialStateService;
use OCP\IRequest;
use OCP\AppFramework\Http\TemplateResponse;
@@ -43,17 +41,16 @@ use OCA\Deck\Db\Acl;
use OCA\Deck\Service\CardService;
class PageController extends Controller {
private PermissionService $permissionService;
private IInitialStateService $initialState;
private ConfigService $configService;
private IEventDispatcher $eventDispatcher;
private CardMapper $cardMapper;
private IURLGenerator $urlGenerator;
private CardService $cardService;
private IConfig $config;
private $permissionService;
private $initialState;
private $configService;
private $eventDispatcher;
private $cardMapper;
private $urlGenerator;
private $cardService;
public function __construct(
string $AppName,
$AppName,
IRequest $request,
PermissionService $permissionService,
IInitialStateService $initialStateService,
@@ -61,8 +58,7 @@ class PageController extends Controller {
IEventDispatcher $eventDispatcher,
CardMapper $cardMapper,
IURLGenerator $urlGenerator,
CardService $cardService,
IConfig $config
CardService $cardService
) {
parent::__construct($AppName, $request);
@@ -73,7 +69,6 @@ class PageController extends Controller {
$this->cardMapper = $cardMapper;
$this->urlGenerator = $urlGenerator;
$this->cardService = $cardService;
$this->config = $config;
}
/**
@@ -89,17 +84,13 @@ class PageController extends Controller {
$this->initialState->provideInitialState(Application::APP_ID, 'config', $this->configService->getAll());
$this->eventDispatcher->dispatchTyped(new LoadSidebar());
$this->eventDispatcher->dispatchTyped(new CollaborationResourcesEvent());
if (class_exists(LoadViewer::class)) {
$this->eventDispatcher->dispatchTyped(new LoadViewer());
}
$response = new TemplateResponse('deck', 'main', [
'id-app-content' => '#app-content-vue',
'id-app-navigation' => '#app-navigation-vue',
]);
$response = new TemplateResponse('deck', 'main');
if ($this->config->getSystemValueBool('debug', false)) {
if (\OC::$server->getConfig()->getSystemValueBool('debug', false)) {
$csp = new ContentSecurityPolicy();
$csp->addAllowedConnectDomain('*');
$csp->addAllowedScriptDomain('*');

View File

@@ -27,7 +27,6 @@ declare(strict_types=1);
namespace OCA\Deck\Controller;
use OCA\Deck\Db\Card;
use OCA\Deck\Model\CardDetails;
use OCA\Deck\Service\SearchService;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
@@ -51,12 +50,9 @@ class SearchController extends OCSController {
public function search(string $term, ?int $limit = null, ?int $cursor = null): DataResponse {
$cards = $this->searchService->searchCards($term, $limit, $cursor);
return new DataResponse(array_map(function (Card $card) {
$board = $card->getRelatedBoard();
$json = (new CardDetails($card, $board))->jsonSerialize();
$json['relatedBoard'] = $board;
$json = $card->jsonSerialize();
$json['relatedStack'] = $card->getRelatedStack();
$json['relatedBoard'] = $card->getRelatedBoard();
return $json;
}, $cards));
}

View File

@@ -59,21 +59,20 @@ class Calendar extends ExternalCalendar {
}
public function getACL() {
// the calendar should always have the read and the write-properties permissions
// write-properties is needed to allow the user to toggle the visibility of shared deck calendars
$acl = [
[
'privilege' => '{DAV:}read',
'principal' => $this->getOwner(),
'protected' => true,
],
[
]
];
if ($this->backend->checkBoardPermission($this->board->getId(), Acl::PERMISSION_MANAGE)) {
$acl[] = [
'privilege' => '{DAV:}write-properties',
'principal' => $this->getOwner(),
'protected' => true,
]
];
];
}
return $acl;
}
@@ -188,18 +187,12 @@ class Calendar extends ExternalCalendar {
foreach ($properties as $key => $value) {
switch ($key) {
case '{DAV:}displayname':
if (!$this->backend->checkBoardPermission($this->board->getId(), Acl::PERMISSION_MANAGE)) {
throw new Forbidden('no permission to change the displayname');
}
if (mb_strpos($value, 'Deck: ') === 0) {
$value = mb_substr($value, strlen('Deck: '));
}
$this->board->setTitle($value);
break;
case '{http://apple.com/ns/ical/}calendar-color':
if (!$this->backend->checkBoardPermission($this->board->getId(), Acl::PERMISSION_MANAGE)) {
throw new Forbidden('no permission to change the calendar color');
}
$color = substr($value, 1, 6);
if (!preg_match('/[a-f0-9]{6}/i', $color)) {
throw new InvalidDataException('No valid color provided');

View File

@@ -26,34 +26,18 @@ declare(strict_types=1);
namespace OCA\Deck\Dashboard;
use DateTime;
use OCA\Deck\AppInfo\Application;
use OCA\Deck\Db\Label;
use OCA\Deck\Service\OverviewService;
use OCP\Dashboard\IAPIWidget;
use OCP\Dashboard\IButtonWidget;
use OCP\Dashboard\IIconWidget;
use OCP\Dashboard\Model\WidgetButton;
use OCP\Dashboard\Model\WidgetItem;
use OCP\IDateTimeFormatter;
use OCP\Dashboard\IWidget;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\Util;
class DeckWidget implements IAPIWidget, IButtonWidget, IIconWidget {
private IL10N $l10n;
private OverviewService $dashboardService;
private IURLGenerator $urlGenerator;
private IDateTimeFormatter $dateTimeFormatter;
class DeckWidget implements IWidget {
public function __construct(IL10N $l10n,
OverviewService $dashboardService,
IDateTimeFormatter $dateTimeFormatter,
IURLGenerator $urlGenerator) {
/**
* @var IL10N
*/
private $l10n;
public function __construct(IL10N $l10n) {
$this->l10n = $l10n;
$this->dashboardService = $dashboardService;
$this->urlGenerator = $urlGenerator;
$this->dateTimeFormatter = $dateTimeFormatter;
}
/**
@@ -84,88 +68,17 @@ class DeckWidget implements IAPIWidget, IButtonWidget, IIconWidget {
return 'icon-deck';
}
/**
* @inheritDoc
*/
public function getIconUrl(): string {
return $this->urlGenerator->getAbsoluteURL(
$this->urlGenerator->imagePath(Application::APP_ID, 'deck-dark.svg')
);
}
/**
* @inheritDoc
*/
public function getUrl(): ?string {
return $this->urlGenerator->getAbsoluteURL(
$this->urlGenerator->linkToRoute(Application::APP_ID . '.page.index')
);
return null;
}
/**
* @inheritDoc
*/
public function load(): void {
Util::addScript('deck', 'deck-dashboard');
}
/**
* @inheritDoc
*/
public function getItems(string $userId, ?string $since = null, int $limit = 7): array {
$upcomingCards = $this->dashboardService->findUpcomingCards($userId);
$nowTimestamp = (new Datetime())->getTimestamp();
$sinceTimestamp = $since !== null ? (new Datetime($since))->getTimestamp() : null;
$upcomingCards = array_filter($upcomingCards, static function (array $card) use ($nowTimestamp, $sinceTimestamp) {
if ($card['duedate']) {
$ts = (new Datetime($card['duedate']))->getTimestamp();
return $ts > $nowTimestamp && ($sinceTimestamp === null || $ts > $sinceTimestamp);
}
return false;
});
usort($upcomingCards, static function ($a, $b) {
$a = new Datetime($a['duedate']);
$ta = $a->getTimestamp();
$b = new Datetime($b['duedate']);
$tb = $b->getTimestamp();
return ($ta > $tb) ? 1 : -1;
});
$upcomingCards = array_slice($upcomingCards, 0, $limit);
$urlGenerator = $this->urlGenerator;
$dateTimeFormatter = $this->dateTimeFormatter;
return array_map(static function (array $card) use ($urlGenerator, $dateTimeFormatter) {
$formattedDueDate = $dateTimeFormatter->formatDateTime(new DateTime($card['duedate']));
return new WidgetItem(
$card['title'] . ' (' . $formattedDueDate . ')',
implode(
', ',
array_map(static function (Label $label) {
return $label->jsonSerialize()['title'];
}, $card['labels'])
),
$urlGenerator->getAbsoluteURL(
$urlGenerator->linkToRoute(Application::APP_ID . '.page.redirectToCard', ['cardId' => $card['id']])
),
$urlGenerator->getAbsoluteURL(
$urlGenerator->imagePath(Application::APP_ID, 'deck-dark.svg')
),
$card['duedate']
);
}, $upcomingCards);
}
/**
* @inheritDoc
*/
public function getWidgetButtons(string $userId): array {
return [
new WidgetButton(
WidgetButton::TYPE_MORE,
$this->urlGenerator->getAbsoluteURL(
$this->urlGenerator->linkToRoute(Application::APP_ID . '.page.index')
),
$this->l10n->t('Load more')
),
];
\OCP\Util::addScript('deck', 'deck-dashboard');
}
}

View File

@@ -33,46 +33,18 @@ class AclMapper extends DeckMapper implements IPermissionMapper {
parent::__construct($db, 'deck_board_acl', Acl::class);
}
/**
* @param numeric $boardId
* @param int|null $limit
* @param int|null $offset
* @return Acl[]
* @throws \OCP\DB\Exception
*/
public function findAll($boardId, $limit = null, $offset = null) {
$qb = $this->db->getQueryBuilder();
$qb->select('id', 'board_id', 'type', 'participant', 'permission_edit', 'permission_share', 'permission_manage')
->from('deck_board_acl')
->where($qb->expr()->eq('board_id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
->setMaxResults($limit)
->setFirstResult($offset);
return $this->findEntities($qb);
$sql = 'SELECT id, board_id, type, participant, permission_edit, permission_share, permission_manage FROM `*PREFIX*deck_board_acl` WHERE `board_id` = ? ';
return $this->findEntities($sql, [$boardId], $limit, $offset);
}
/**
* @param numeric $userId
* @param numeric $id
* @return bool
* @throws \OCP\DB\Exception
*/
public function isOwner($userId, $id): bool {
$aclId = $id;
$qb = $this->db->getQueryBuilder();
$qb->select('acl.id')
->from($this->getTableName(), 'acl')
->innerJoin('acl', 'deck_boards', 'b', 'acl.board_id = b.id')
->where($qb->expr()->eq('owner', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)))
->andWhere($qb->expr()->eq('acl.id', $qb->createNamedParameter($aclId, IQueryBuilder::PARAM_INT)));
return count($qb->executeQuery()->fetchAll()) > 0;
public function isOwner($userId, $aclId): bool {
$sql = 'SELECT owner FROM `*PREFIX*deck_boards` WHERE `id` IN (SELECT board_id FROM `*PREFIX*deck_board_acl` WHERE id = ?)';
$stmt = $this->execute($sql, [$aclId]);
$row = $stmt->fetch();
return ($row['owner'] === $userId);
}
/**
* @param numeric $id
* @return int|null
*/
public function findBoardId($id): ?int {
try {
$entity = $this->find($id);
@@ -82,21 +54,9 @@ class AclMapper extends DeckMapper implements IPermissionMapper {
return null;
}
/**
* @param int $type
* @param string $participant
* @return Acl[]
* @throws \OCP\DB\Exception
*/
public function findByParticipant($type, $participant): array {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->getTableName())
->where($qb->expr()->eq('type', $qb->createNamedParameter($type, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->eq('participant', $qb->createNamedParameter($participant, IQueryBuilder::PARAM_STR)));
return $this->findEntities($qb);
$sql = 'SELECT * from *PREFIX*deck_board_acl WHERE type = ? AND participant = ?';
return $this->findEntities($sql, [$type, $participant]);
}
/**

View File

@@ -55,6 +55,9 @@ class AssignmentMapper extends QBMapper implements IPermissionMapper {
$this->circleService = $circleService;
}
/**
* @return Assignment[]
*/
public function findAll(int $cardId): array {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
@@ -77,8 +80,8 @@ class AssignmentMapper extends QBMapper implements IPermissionMapper {
}
public function isOwner($userId, $id): bool {
return $this->cardMapper->isOwner($userId, $id);
public function isOwner($userId, $cardId): bool {
return $this->cardMapper->isOwner($userId, $cardId);
}
public function findBoardId($id): ?int {

View File

@@ -30,6 +30,7 @@ use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
use OCP\IUserManager;
use PDO;
class AttachmentMapper extends DeckMapper implements IPermissionMapper {
private $cardMapper;
@@ -51,53 +52,70 @@ class AttachmentMapper extends DeckMapper implements IPermissionMapper {
}
/**
* @param int $id
* @return Attachment
* @throws DoesNotExistException
* @throws MultipleObjectsReturnedException
* @throws \OCP\DB\Exception
* @param $id
* @return Entity|Attachment
* @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
*/
public function find($id) {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->getTableName())
->from('deck_attachment')
->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)));
return $this->findEntity($qb);
$cursor = $qb->execute();
$row = $cursor->fetch(PDO::FETCH_ASSOC);
if ($row === false) {
$cursor->closeCursor();
throw new DoesNotExistException('Did expect one result but found none when executing query: ' . $qb->getSQL());
}
$row2 = $cursor->fetch();
$cursor->closeCursor();
if ($row2 !== false) {
throw new MultipleObjectsReturnedException('Did not expect more than one result when executing query: ' . $qb->getSQL());
}
return $this->mapRowToEntity($row);
}
/**
* @param int $cardId
* @param string $data
* @return Attachment
* @throws DoesNotExistException
* @throws MultipleObjectsReturnedException
* @throws \OCP\DB\Exception
*/
public function findByData($cardId, $data) {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->getTableName())
->from('deck_attachment')
->where($qb->expr()->eq('card_id', $qb->createNamedParameter($cardId, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->eq('data', $qb->createNamedParameter($data, IQueryBuilder::PARAM_STR)));
return $this->findEntity($qb);
$cursor = $qb->execute();
$row = $cursor->fetch(PDO::FETCH_ASSOC);
if ($row === false) {
$cursor->closeCursor();
throw new DoesNotExistException('Did expect one result but found none when executing query: ' . $qb->getSQL());
}
$cursor->closeCursor();
return $this->mapRowToEntity($row);
}
/**
* Find all attachments for a card
*
* @param $cardId
* @return Entity[]
* @throws \OCP\DB\Exception
* @return array
*/
public function findAll($cardId) {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->getTableName())
->from('deck_attachment')
->where($qb->expr()->eq('card_id', $qb->createNamedParameter($cardId, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->eq('deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)));
return $this->findEntities($qb);
$entities = [];
$cursor = $qb->execute();
while ($row = $cursor->fetch()) {
$entities[] = $this->mapRowToEntity($row);
}
$cursor->closeCursor();
return $entities;
}
/**
@@ -110,7 +128,7 @@ class AttachmentMapper extends DeckMapper implements IPermissionMapper {
$timeLimit = time() - (60 * 5);
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->getTableName())
->from('deck_attachment')
->where($qb->expr()->gt('deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)));
if ($withOffset) {
$qb
@@ -121,7 +139,13 @@ class AttachmentMapper extends DeckMapper implements IPermissionMapper {
->andWhere($qb->expr()->eq('card_id', $qb->createNamedParameter($cardId, IQueryBuilder::PARAM_INT)));
}
return $this->findEntities($qb);
$entities = [];
$cursor = $qb->execute();
while ($row = $cursor->fetch()) {
$entities[] = $this->mapRowToEntity($row);
}
$cursor->closeCursor();
return $entities;
}

View File

@@ -23,14 +23,6 @@
namespace OCA\Deck\Db;
/**
* @method int getId()
* @method string getTitle()
* @method int getShared()
* @method bool getArchived()
* @method int getDeletedAt()
* @method int getLastModified()
*/
class Board extends RelationalEntity {
protected $title;
protected $owner;

View File

@@ -42,9 +42,9 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
private $circlesService;
private $logger;
/** @var CappedMemoryCache<Board[]> */
/** @var CappedMemoryCache */
private $userBoardCache;
/** @var CappedMemoryCache<Board> */
/** @var CappedMemoryCache */
private $boardCache;
public function __construct(
@@ -79,12 +79,14 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws DoesNotExistException
*/
public function find($id, $withLabels = false, $withAcl = false): Board {
public function find(int $id, bool $withLabels = false, bool $withAcl = false, bool $allowDeleted = false): Board {
if (!isset($this->boardCache[$id])) {
$qb = $this->db->getQueryBuilder();
$deletedWhere = $allowDeleted ? $qb->expr()->gte('deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)) : $qb->expr()->eq('deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT));
$qb->select('*')
->from('deck_boards')
->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)))
->andWhere($deletedWhere)
->orderBy('id');
$this->boardCache[$id] = $this->findEntity($qb);
}
@@ -107,47 +109,6 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
return $this->boardCache[$id];
}
public function findBoardIds(string $userId): array {
$qb = $this->db->getQueryBuilder();
$qb->selectDistinct('b.id')
->from($this->getTableName(), 'b')
->leftJoin('b', 'deck_board_acl', 'acl', $qb->expr()->eq('b.id', 'acl.board_id'));
// Owned by the user
$qb->where($qb->expr()->andX(
$qb->expr()->eq('owner', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)),
));
// Shared to the user
$qb->orWhere($qb->expr()->andX(
$qb->expr()->eq('acl.participant', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)),
$qb->expr()->eq('acl.type', $qb->createNamedParameter(Acl::PERMISSION_TYPE_USER, IQueryBuilder::PARAM_INT)),
));
// Shared to user groups of the user
$groupIds = $this->groupManager->getUserGroupIds($this->userManager->get($userId));
if (count($groupIds) !== 0) {
$qb->orWhere($qb->expr()->andX(
$qb->expr()->in('acl.participant', $qb->createNamedParameter($groupIds, IQueryBuilder::PARAM_STR_ARRAY)),
$qb->expr()->eq('acl.type', $qb->createNamedParameter(Acl::PERMISSION_TYPE_GROUP, IQueryBuilder::PARAM_INT)),
));
}
// Shared to circles of the user
$circles = $this->circlesService->getUserCircles($userId);
if (count($circles) !== 0) {
$qb->orWhere($qb->expr()->andX(
$qb->expr()->in('acl.participant', $qb->createNamedParameter($circles, IQueryBuilder::PARAM_STR_ARRAY)),
$qb->expr()->eq('acl.type', $qb->createNamedParameter(Acl::PERMISSION_TYPE_CIRCLE, IQueryBuilder::PARAM_INT)),
));
}
$result = $qb->executeQuery();
return array_map(function (string $id) {
return (int)$id;
}, $result->fetchAll(\PDO::FETCH_COLUMN));
}
public function findAllForUser(string $userId, ?int $since = null, bool $includeArchived = true, ?int $before = null,
?string $term = null): array {
$useCache = ($since === -1 && $includeArchived === true && $before === null && $term === null);
@@ -172,9 +133,14 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
/**
* Find all boards for a given user
*
* @param $userId
* @param null $limit
* @param null $offset
* @return array
*/
public function findAllByUser(string $userId, ?int $limit = null, ?int $offset = null, ?int $since = null,
bool $includeArchived = true, ?int $before = null, ?string $term = null): array {
bool $includeArchived = true, ?int $before = null, ?string $term = null) {
// FIXME this used to be a UNION to get boards owned by $userId and the user shares in one single query
// Is it possible with the query builder?
$qb = $this->db->getQueryBuilder();
@@ -283,9 +249,15 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
/**
* Find all boards for a given user
*
* @param $userId
* @param $groups
* @param null $limit
* @param null $offset
* @return array
*/
public function findAllByGroups(string $userId, array $groups, ?int $limit = null, ?int $offset = null, ?int $since = null,
bool $includeArchived = true, ?int $before = null, ?string $term = null): array {
bool $includeArchived = true, ?int $before = null, ?string $term = null) {
if (count($groups) <= 0) {
return [];
}
@@ -444,8 +416,8 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
return parent::delete($entity);
}
public function isOwner($userId, $id): bool {
$board = $this->find($id);
public function isOwner($userId, $boardId): bool {
$board = $this->find($boardId);
return ($board->getOwner() === $userId);
}

View File

@@ -27,44 +27,6 @@ use DateTime;
use DateTimeZone;
use Sabre\VObject\Component\VCalendar;
/**
* @method string getTitle()
* @method string getDescription()
* @method string getDescriptionPrev()
* @method int getStackId()
* @method int getOrder()
* @method int getLastModified()
* @method int getCreatedAt()
* @method bool getArchived()
* @method bool getNotified()
*
* @method void setLabels(Label[] $labels)
* @method null|Label[] getLabels()
*
* @method void setAssignedUsers(Assignment[] $users)
* @method null|User[] getAssignedUsers()
*
* @method void setAttachments(Attachment[] $attachments)
* @method null|Attachment[] getAttachments()
*
* @method void setAttachmentCount(int $count)
* @method null|int getAttachmentCount()
*
* @method void setCommentsUnread(int $count)
* @method null|int getCommentsUnread()
*
* @method void setCommentsCount(int $count)
* @method null|int getCommentsCount()
*
* @method void setOwner(string $user)
* @method null|string getOwner()
*
* @method void setRelatedStack(Stack $stack)
* @method null|Stack getRelatedStack()
*
* @method void setRelatedBoard(Board $board)
* @method null|Board getRelatedBoard()
*/
class Card extends RelationalEntity {
public const TITLE_MAX_LENGTH = 255;
@@ -108,7 +70,6 @@ class Card extends RelationalEntity {
$this->addType('archived', 'boolean');
$this->addType('notified', 'boolean');
$this->addType('deletedAt', 'integer');
$this->addType('duedate', 'datetime');
$this->addRelation('labels');
$this->addRelation('assignedUsers');
$this->addRelation('attachments');
@@ -126,6 +87,50 @@ class Card extends RelationalEntity {
$this->databaseType = $type;
}
public function getDuedate($isoFormat = false) {
if ($this->duedate === null) {
return null;
}
$dt = new DateTime($this->duedate);
if (!$isoFormat && $this->databaseType === 'mysql') {
return $dt->format('Y-m-d H:i:s');
}
return $dt->format('c');
}
public function jsonSerialize(): array {
$json = parent::jsonSerialize();
$json['overdue'] = self::DUEDATE_FUTURE;
$due = $this->duedate ? strtotime($this->duedate) : false;
if ($due !== false) {
$today = new DateTime();
$today->setTime(0, 0);
$match_date = new DateTime($this->duedate);
$match_date->setTime(0, 0);
$diff = $today->diff($match_date);
$diffDays = (integer) $diff->format('%R%a'); // Extract days count in interval
if ($diffDays === 1) {
$json['overdue'] = self::DUEDATE_NEXT;
}
if ($diffDays === 0) {
$json['overdue'] = self::DUEDATE_NOW;
}
if ($diffDays < 0) {
$json['overdue'] = self::DUEDATE_OVERDUE;
}
}
$json['duedate'] = $this->getDuedate(true);
unset($json['notified']);
unset($json['descriptionPrev']);
unset($json['relatedStack']);
unset($json['relatedBoard']);
return $json;
}
public function getCalendarObject(): VCalendar {
$calendar = new VCalendar();
$event = $calendar->createComponent('VTODO');
@@ -134,7 +139,7 @@ class Card extends RelationalEntity {
$creationDate = new DateTime();
$creationDate->setTimestamp($this->createdAt);
$event->DTSTAMP = $creationDate;
$event->DUE = new DateTime($this->getDuedate()->format('c'), new DateTimeZone('UTC'));
$event->DUE = new DateTime($this->getDuedate(true), new DateTimeZone('UTC'));
}
$event->add('RELATED-TO', 'deck-stack-' . $this->getStackId());

View File

@@ -238,21 +238,6 @@ class CardMapper extends QBMapper implements IPermissionMapper {
return $this->findEntities($qb);
}
public function findAllByBoardId(int $boardId, ?int $limit = null, ?int $offset = null): array {
$qb = $this->db->getQueryBuilder();
$qb->select('c.*')
->from('deck_cards', 'c')
->innerJoin('c', 'deck_stacks', 's', 's.id = c.stack_id')
->innerJoin('s', 'deck_boards', 'b', 'b.id = s.board_id')
->where($qb->expr()->eq('board_id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->eq('archived', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)))
->setMaxResults($limit)
->setFirstResult($offset)
->orderBy('c.lastmodified')
->addOrderBy('c.id');
return $this->findEntities($qb);
}
public function findAllWithDue($boardId) {
$qb = $this->db->getQueryBuilder();
$qb->select('c.*')
@@ -575,10 +560,10 @@ class CardMapper extends QBMapper implements IPermissionMapper {
$qb->execute();
}
public function isOwner($userId, $id): bool {
public function isOwner($userId, $cardId): bool {
$sql = 'SELECT owner FROM `*PREFIX*deck_boards` WHERE `id` IN (SELECT board_id FROM `*PREFIX*deck_stacks` WHERE id IN (SELECT stack_id FROM `*PREFIX*deck_cards` WHERE id = ?))';
$stmt = $this->db->prepare($sql);
$stmt->bindParam(1, $id, \PDO::PARAM_INT, 0);
$stmt->bindParam(1, $cardId, \PDO::PARAM_INT, 0);
$stmt->execute();
$row = $stmt->fetch();
return ($row['owner'] === $userId);

View File

@@ -24,7 +24,6 @@
namespace OCA\Deck\Db;
use OCP\ICacheFactory;
use OCP\ICache;
use OCP\IDBConnection;
use OCP\IRequest;
@@ -32,16 +31,13 @@ class ChangeHelper {
public const TYPE_BOARD = 'boardChanged';
public const TYPE_CARD = 'cardChanged';
private IDBConnection $db;
private ICache $cache;
private IRequest $request;
private ?string $userId;
private $db;
public function __construct(
IDBConnection $db,
ICacheFactory $cacheFactory,
IRequest $request,
?string $userId
$userId
) {
$this->db = $db;
$this->cache = $cacheFactory->createDistributed('deck_changes');

View File

@@ -23,15 +23,17 @@
namespace OCA\Deck\Db;
use OCP\AppFramework\Db\QBMapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\AppFramework\Db\Mapper;
/**
* Class DeckMapper
*
* @package OCA\Deck\Db
* @deprecated use QBMapper
*
* TODO: Move to QBMapper once Nextcloud 14 is a minimum requirement
*/
class DeckMapper extends QBMapper {
class DeckMapper extends Mapper {
/**
* @param $id
@@ -40,11 +42,11 @@ class DeckMapper extends QBMapper {
* @throws \OCP\AppFramework\Db\DoesNotExistException
*/
public function find($id) {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->getTableName())
->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)));
$sql = 'SELECT * FROM `' . $this->tableName . '` ' . 'WHERE `id` = ?';
return $this->findEntity($sql, [$id]);
}
return $this->findEntity($qb);
protected function execute($sql, array $params = [], $limit = null, $offset = null) {
return parent::execute($sql, $params, $limit, $offset);
}
}

View File

@@ -26,7 +26,6 @@ namespace OCA\Deck\Db;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\Entity;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
class LabelMapper extends DeckMapper implements IPermissionMapper {
@@ -34,105 +33,41 @@ class LabelMapper extends DeckMapper implements IPermissionMapper {
parent::__construct($db, 'deck_labels', Label::class);
}
/**
* @param numeric $boardId
* @param int|null $limit
* @param int|null $offset
* @return Label[]
* @throws \OCP\DB\Exception
*/
public function findAll($boardId, $limit = null, $offset = null): array {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->getTableName())
->where($qb->expr()->eq('board_id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
->setMaxResults($limit)
->setFirstResult($offset);
return $this->findEntities($qb);
public function findAll($boardId, $limit = null, $offset = null) {
$sql = 'SELECT * FROM `*PREFIX*deck_labels` WHERE `board_id` = ? ORDER BY `id`';
return $this->findEntities($sql, [$boardId], $limit, $offset);
}
/**
* @param Entity $entity
* @return Entity
* @throws \OCP\DB\Exception
*/
public function delete(Entity $entity): Entity {
public function delete(\OCP\AppFramework\Db\Entity $entity) {
// delete assigned labels
$this->deleteLabelAssignments($entity->getId());
// delete label
return parent::delete($entity);
}
/**
* @param numeric $cardId
* @param int|null $limit
* @param int|null $offset
* @return Label[]
* @throws \OCP\DB\Exception
*/
public function findAssignedLabelsForCard($cardId, $limit = null, $offset = null): array {
$qb = $this->db->getQueryBuilder();
$qb->select('l.*', 'card_id')
->from($this->getTableName(), 'l')
->innerJoin('l', 'deck_assigned_labels', 'al', 'l.id = al.label_id')
->where($qb->expr()->eq('card_id', $qb->createNamedParameter($cardId, IQueryBuilder::PARAM_INT)))
->orderBy('l.id')
->setMaxResults($limit)
->setFirstResult($offset);
return $this->findEntities($qb);
public function findAssignedLabelsForCard($cardId, $limit = null, $offset = null) {
$sql = 'SELECT l.*,card_id FROM `*PREFIX*deck_assigned_labels` as al INNER JOIN *PREFIX*deck_labels as l ON l.id = al.label_id WHERE `card_id` = ? ORDER BY l.id';
return $this->findEntities($sql, [$cardId], $limit, $offset);
}
public function findAssignedLabelsForBoard($boardId, $limit = null, $offset = null) {
$sql = 'SELECT c.id as card_id, l.id as id, l.title as title, l.color as color FROM `*PREFIX*deck_cards` as c ' .
' INNER JOIN `*PREFIX*deck_assigned_labels` as al ON al.card_id = c.id INNER JOIN `*PREFIX*deck_labels` as l ON al.label_id = l.id WHERE board_id=? ORDER BY l.id';
return $this->findEntities($sql, [$boardId], $limit, $offset);
}
/**
* @param numeric $boardId
* @param int|null $limit
* @param int|null $offset
* @return Label[]
* @throws \OCP\DB\Exception
*/
public function findAssignedLabelsForBoard($boardId, $limit = null, $offset = null): array {
$qb = $this->db->getQueryBuilder();
$qb->select('l.id as id', 'l.title as title', 'l.color as color')
->selectAlias('c.id', 'card_id')
->from($this->getTableName(), 'l')
->innerJoin('l', 'deck_assigned_labels', 'al', 'al.label_id = l.id')
->innerJoin('l', 'deck_cards', 'c', 'al.card_id = c.id')
->where($qb->expr()->eq('board_id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
->orderBy('l.id')
->setMaxResults($limit)
->setFirstResult($offset);
return $this->findEntities($qb);
}
/**
* @param Entity $entity
* @return Entity
* @throws \OCP\DB\Exception
*/
public function insert(Entity $entity): Entity {
public function insert(Entity $entity) {
$entity->setLastModified(time());
return parent::insert($entity);
}
/**
* @param Entity $entity
* @param bool $updateModified
* @return Entity
* @throws \OCP\DB\Exception
*/
public function update(Entity $entity, $updateModified = true): Entity {
public function update(Entity $entity, $updateModified = true) {
if ($updateModified) {
$entity->setLastModified(time());
}
return parent::update($entity);
}
/**
* @param numeric $boardId
* @return array
* @throws \OCP\DB\Exception
*/
public function getAssignedLabelsForBoard($boardId) {
$labels = $this->findAssignedLabelsForBoard($boardId);
$result = [];
@@ -145,51 +80,27 @@ class LabelMapper extends DeckMapper implements IPermissionMapper {
return $result;
}
/**
* @param numeric $labelId
* @return void
* @throws \OCP\DB\Exception
*/
public function deleteLabelAssignments($labelId) {
$qb = $this->db->getQueryBuilder();
$qb->delete('deck_assigned_labels')
->where($qb->expr()->eq('label_id', $qb->createNamedParameter($labelId, IQueryBuilder::PARAM_INT)));
$qb->executeStatement();
$sql = 'DELETE FROM `*PREFIX*deck_assigned_labels` WHERE label_id = ?';
$stmt = $this->db->prepare($sql);
$stmt->bindParam(1, $labelId, \PDO::PARAM_INT, 0);
$stmt->execute();
}
/**
* @param numeric $cardId
* @return void
* @throws \OCP\DB\Exception
*/
public function deleteLabelAssignmentsForCard($cardId) {
$qb = $this->db->getQueryBuilder();
$qb->delete('deck_assigned_labels')
->where($qb->expr()->eq('card_id', $qb->createNamedParameter($cardId, IQueryBuilder::PARAM_INT)));
$qb->executeStatement();
$sql = 'DELETE FROM `*PREFIX*deck_assigned_labels` WHERE card_id = ?';
$stmt = $this->db->prepare($sql);
$stmt->bindParam(1, $cardId, \PDO::PARAM_INT, 0);
$stmt->execute();
}
/**
* @param string $userId
* @param numeric $labelId
* @return bool
* @throws \OCP\DB\Exception
*/
public function isOwner($userId, $labelId): bool {
$qb = $this->db->getQueryBuilder();
$qb->select('l.id')
->from($this->getTableName(), 'l')
->innerJoin('l', 'deck_boards', 'b', 'l.board_id = b.id')
->where($qb->expr()->eq('l.id', $qb->createNamedParameter($labelId, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->eq('b.owner', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)));
return count($qb->executeQuery()->fetchAll()) > 0;
$sql = 'SELECT owner FROM `*PREFIX*deck_boards` WHERE `id` IN (SELECT board_id FROM `*PREFIX*deck_labels` WHERE id = ?)';
$stmt = $this->execute($sql, [$labelId]);
$row = $stmt->fetch();
return ($row['owner'] === $userId);
}
/**
* @param numeric $id
* @return int|null
*/
public function findBoardId($id): ?int {
try {
$entity = $this->find($id);

View File

@@ -72,9 +72,6 @@ class RelationalEntity extends Entity implements \JsonSerializable {
$propertyReflection = $reflection->getProperty($property);
if (!$propertyReflection->isPrivate() && !in_array($property, $this->_resolvedProperties, true)) {
$json[$property] = $this->getter($property);
if ($json[$property] instanceof \DateTimeInterface) {
$json[$property] = $json[$property]->format('c');
}
}
}
}

View File

@@ -26,7 +26,6 @@ namespace OCA\Deck\Db;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\Entity;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
class StackMapper extends DeckMapper implements IPermissionMapper {
@@ -39,112 +38,62 @@ class StackMapper extends DeckMapper implements IPermissionMapper {
/**
* @param numeric $id
* @return Stack
* @throws DoesNotExistException
* @param $id
* @throws MultipleObjectsReturnedException
* @throws \OCP\DB\Exception
* @throws DoesNotExistException
*/
public function find($id): Stack {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->getTableName())
->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)));
return $this->findEntity($qb);
$sql = 'SELECT * FROM `*PREFIX*deck_stacks` ' .
'WHERE `id` = ?';
return $this->findEntity($sql, [$id]);
}
/**
* @param $cardId
* @return Stack|null
* @throws \OCP\DB\Exception
*/
public function findStackFromCardId($cardId): ?Stack {
$qb = $this->db->getQueryBuilder();
$qb->select('s.*')
->from($this->getTableName(), 's')
->innerJoin('s', 'deck_cards', 'c', 's.id = c.stack_id')
->where($qb->expr()->eq('c.id', $qb->createNamedParameter($cardId, IQueryBuilder::PARAM_INT)));
$sql = <<<SQL
SELECT s.*
FROM `*PREFIX*deck_stacks` as `s`
INNER JOIN `*PREFIX*deck_cards` as `c` ON s.id = c.stack_id
WHERE c.id = ?
SQL;
try {
return $this->findEntity($qb);
return $this->findEntity($sql, [$cardId]);
} catch (MultipleObjectsReturnedException|DoesNotExistException $e) {
}
return null;
}
/**
* @param numeric $boardId
* @param int|null $limit
* @param int|null $offset
* @return Stack[]
* @throws \OCP\DB\Exception
*/
public function findAll($boardId, $limit = null, $offset = null): array {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->getTableName())
->where($qb->expr()->eq('board_id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->eq('deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)))
->setFirstResult($offset)
->setMaxResults($limit);
return $this->findEntities($qb);
public function findAll($boardId, $limit = null, $offset = null) {
$sql = 'SELECT * FROM `*PREFIX*deck_stacks` WHERE `board_id` = ? AND deleted_at = 0 ORDER BY `order`, `id`';
return $this->findEntities($sql, [$boardId], $limit, $offset);
}
/**
* @param numeric $boardId
* @param int|null $limit
* @param int|null $offset
* @return Stack[]
* @throws \OCP\DB\Exception
*/
public function findDeleted($boardId, $limit = null, $offset = null) {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->getTableName())
->where($qb->expr()->eq('board_id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->neq('deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)))
->setFirstResult($offset)
->setMaxResults($limit);
return $this->findEntities($qb);
$sql = 'SELECT * FROM `*PREFIX*deck_stacks` s
WHERE `s`.`board_id` = ? AND NOT s.deleted_at = 0';
return $this->findEntities($sql, [$boardId], $limit, $offset);
}
/**
* @param Entity $entity
* @return Entity
* @throws \OCP\DB\Exception
*/
public function delete(Entity $entity): Entity {
public function delete(Entity $entity) {
// delete cards on stack
$this->cardMapper->deleteByStack($entity->getId());
return parent::delete($entity);
}
/**
* @param numeric $userId
* @param numeric $stackId
* @return bool
* @throws \OCP\DB\Exception
*/
public function isOwner($userId, $id): bool {
$qb = $this->db->getQueryBuilder();
$qb->select('s.id')
->from($this->getTableName(), 's')
->innerJoin('s', 'deck_boards', 'b', 'b.id = s.board_id')
->where($qb->expr()->eq('s.id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->eq('owner', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)));
return count($qb->executeQuery()->fetchAll()) > 0;
public function isOwner($userId, $stackId): bool {
$sql = 'SELECT owner FROM `*PREFIX*deck_boards` WHERE `id` IN (SELECT board_id FROM `*PREFIX*deck_stacks` WHERE id = ?)';
$stmt = $this->execute($sql, [$stackId]);
$row = $stmt->fetch();
return ($row['owner'] === $userId);
}
/**
* @param numeric $id
* @return int|null
* @throws \OCP\DB\Exception
*/
public function findBoardId($id): ?int {
try {
$entity = $this->find($id);

View File

@@ -1,92 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2022 Raul Ferreira Fuentes <raul@nextcloud.com>
*
* @author Raul Ferreira Fuentes <raul@nextcloud.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Deck\Model;
use DateTime;
use OCA\Deck\Db\Board;
use OCA\Deck\Db\Card;
class CardDetails extends Card {
private Card $card;
private ?Board $board;
public function __construct(Card $card, ?Board $board = null) {
parent::__construct();
$this->card = $card;
$this->board = $board;
}
public function setBoard(?Board $board): void {
$this->board = $board;
}
public function jsonSerialize(array $extras = []): array {
$array = $this->card->jsonSerialize();
unset($array['notified'], $array['descriptionPrev'], $array['relatedStack'], $array['relatedBoard']);
$array['overdue'] = $this->getDueStatus();
$this->appendBoardDetails($array);
return $array;
}
private function getDueStatus(): int {
$today = new DateTime();
$today->setTime(0, 0);
$match_date = $this->card->getDuedate();
if (!$match_date) {
return Card::DUEDATE_FUTURE;
}
$match_date->setTime(0, 0);
$diff = $today->diff($match_date);
$diffDays = (int) $diff->format('%R%a'); // Extract days count in interval
if ($diffDays === 1) {
return Card::DUEDATE_NEXT;
}
if ($diffDays === 0) {
return Card::DUEDATE_NOW;
}
if ($diffDays < 0) {
return Card::DUEDATE_OVERDUE;
}
return Card::DUEDATE_FUTURE;
}
private function appendBoardDetails(&$array): void {
if (!$this->board) {
return;
}
$array['boardId'] = $this->board->id;
$array['board'] = (new BoardSummary($this->board))->jsonSerialize();
}
public function __call($name, $arguments) {
return $this->card->__call($name, $arguments);
}
}

View File

@@ -129,7 +129,7 @@ class NotificationHelper {
->setSubject('card-overdue', [
$card->getTitle(), $board->getTitle()
])
->setDateTime($card->getDuedate());
->setDateTime(new DateTime($card->getDuedate()));
$this->notificationManager->notify($notification);
}
}
@@ -242,7 +242,7 @@ class NotificationHelper {
}
return $this->boards[$boardId];
}
private function generateBoardShared(Board $board, string $userId): INotification {
$notification = $this->notificationManager->createNotification();
$notification

View File

@@ -114,7 +114,7 @@ class Notifier implements INotifier {
$dn = $params[2];
}
$notification->setParsedSubject(
$l->t('The card "%s" on "%s" has been assigned to you by %s.', [$params[0], $params[1], $dn])
(string) $l->t('The card "%s" on "%s" has been assigned to you by %s.', [$params[0], $params[1], $dn])
);
$notification->setRichSubject(
$l->t('{user} has assigned the card {deck-card} on {deck-board} to you.'),
@@ -151,7 +151,7 @@ class Notifier implements INotifier {
}
$notification->setParsedSubject(
$l->t('The card "%s" on "%s" has reached its due date.', $params)
(string) $l->t('The card "%s" on "%s" has reached its due date.', $params)
);
$notification->setRichSubject(
$l->t('The card {deck-card} on {deck-board} has reached its due date.'),
@@ -189,7 +189,7 @@ class Notifier implements INotifier {
$dn = $params[2];
}
$notification->setParsedSubject(
$l->t('%s has mentioned you in a comment on "%s".', [$dn, $params[0]])
(string) $l->t('%s has mentioned you in a comment on "%s".', [$dn, $params[0]])
);
$notification->setRichSubject(
$l->t('{user} has mentioned you in a comment on {deck-card}.'),
@@ -226,7 +226,7 @@ class Notifier implements INotifier {
$dn = $params[1];
}
$notification->setParsedSubject(
$l->t('The board "%s" has been shared with you by %s.', [$params[0], $dn])
(string) $l->t('The board "%s" has been shared with you by %s.', [$params[0], $dn])
);
$notification->setRichSubject(
$l->t('{user} has shared {deck-board} with you.'),

View File

@@ -54,11 +54,22 @@ use OCP\IURLGenerator;
class DeckProvider implements IFullTextSearchProvider {
public const DECK_PROVIDER_ID = 'deck';
private IL10N $l10n;
private IUrlGenerator $urlGenerator;
private FullTextSearchService $fullTextSearchService;
private ?IRunner $runner = null;
private ?IIndexOptions $indexOptions = null;
/** @var IL10N */
private $l10n;
/** @var IUrlGenerator */
private $urlGenerator;
/** @var FullTextSearchService */
private $fullTextSearchService;
/** @var IRunner */
private $runner;
/** @var IIndexOptions */
private $indexOptions = [];
/**

View File

@@ -1,169 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2022 Julien Veyssier <eneiluj@posteo.net>
*
* @author Julien Veyssier <eneiluj@posteo.net>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace OCA\Deck\Reference;
use OCA\Deck\AppInfo\Application;
use OCA\Deck\Db\Assignment;
use OCA\Deck\Db\Attachment;
use OCA\Deck\Db\Label;
use OCA\Deck\Model\CardDetails;
use OCA\Deck\Service\BoardService;
use OCA\Deck\Service\CardService;
use OCA\Deck\Service\StackService;
use OCP\Collaboration\Reference\IReference;
use OCP\Collaboration\Reference\IReferenceProvider;
use OCP\Collaboration\Reference\Reference;
use OCP\IURLGenerator;
class CardReferenceProvider implements IReferenceProvider {
private CardService $cardService;
private IURLGenerator $urlGenerator;
private BoardService $boardService;
private StackService $stackService;
private ?string $userId;
public function __construct(CardService $cardService,
BoardService $boardService,
StackService $stackService,
IURLGenerator $urlGenerator,
?string $userId) {
$this->cardService = $cardService;
$this->urlGenerator = $urlGenerator;
$this->boardService = $boardService;
$this->stackService = $stackService;
$this->userId = $userId;
}
/**
* @inheritDoc
*/
public function matchReference(string $referenceText): bool {
$start = $this->urlGenerator->getAbsoluteURL('/apps/' . Application::APP_ID);
$startIndex = $this->urlGenerator->getAbsoluteURL('/index.php/apps/' . Application::APP_ID);
// link example: https://nextcloud.local/index.php/apps/deck/#/board/2/card/11
$noIndexMatch = preg_match('/^' . preg_quote($start, '/') . '\/#\/board\/[0-9]+\/card\/[0-9]+$/', $referenceText) === 1;
$indexMatch = preg_match('/^' . preg_quote($startIndex, '/') . '\/#\/board\/[0-9]+\/card\/[0-9]+$/', $referenceText) === 1;
return $noIndexMatch || $indexMatch;
}
/**
* @inheritDoc
*/
public function resolveReference(string $referenceText): ?IReference {
if ($this->matchReference($referenceText)) {
$ids = $this->getBoardCardId($referenceText);
if ($ids !== null) {
[$boardId, $cardId] = $ids;
$card = $this->cardService->find((int) $cardId)->jsonSerialize();
$board = $this->boardService->find((int) $boardId)->jsonSerialize();
$stack = $this->stackService->find((int) $card['stackId'])->jsonSerialize();
$card = $this->sanitizeSerializedCard($card);
$board = $this->sanitizeSerializedBoard($board);
$stack = $this->sanitizeSerializedStack($stack);
$reference = new Reference($referenceText);
$reference->setRichObject(Application::APP_ID . '-card', [
'id' => $boardId . '/' . $cardId,
'card' => $card,
'board' => $board,
'stack' => $stack,
]);
return $reference;
}
}
return null;
}
private function sanitizeSerializedStack(array $stack): array {
$stack['cards'] = array_map(function (CardDetails $cardDetails) {
$result = $cardDetails->jsonSerialize();
unset($result['assignedUsers']);
return $result;
}, $stack['cards']);
return $stack;
}
private function sanitizeSerializedBoard(array $board): array {
unset($board['labels']);
$board['owner'] = $board['owner']->jsonSerialize();
unset($board['acl']);
unset($board['users']);
return $board;
}
private function sanitizeSerializedCard(array $card): array {
$card['labels'] = array_map(function (Label $label) {
return $label->jsonSerialize();
}, $card['labels']);
$card['assignedUsers'] = array_map(function (Assignment $assignment) {
$result = $assignment->jsonSerialize();
$result['participant'] = $result['participant']->jsonSerialize();
return $result;
}, $card['assignedUsers']);
$card['owner'] = $card['owner']->jsonSerialize();
unset($card['relatedStack']);
unset($card['relatedBoard']);
$card['attachments'] = array_map(function (Attachment $attachment) {
return $attachment->jsonSerialize();
}, $card['attachments']);
return $card;
}
private function getBoardCardId(string $url): ?array {
$start = $this->urlGenerator->getAbsoluteURL('/apps/' . Application::APP_ID);
$startIndex = $this->urlGenerator->getAbsoluteURL('/index.php/apps/' . Application::APP_ID);
preg_match('/^' . preg_quote($start, '/') . '\/#\/board\/([0-9]+)\/card\/([0-9]+)$/', $url, $matches);
if ($matches && count($matches) > 2) {
return [$matches[1], $matches[2]];
}
preg_match('/^' . preg_quote($startIndex, '/') . '\/#\/board\/([0-9]+)\/card\/([0-9]+)$/', $url, $matches2);
if ($matches2 && count($matches2) > 2) {
return [$matches2[1], $matches2[2]];
}
return null;
}
public function getCachePrefix(string $referenceId): string {
$ids = $this->getBoardCardId($referenceId);
if ($ids !== null) {
[$boardId, $cardId] = $ids;
return $boardId . '/' . $cardId;
}
return $referenceId;
}
public function getCacheKey(string $referenceId): ?string {
return $this->userId ?? '';
}
}

View File

@@ -60,23 +60,22 @@ class AttachmentService {
private $activityManager;
/** @var ChangeHelper */
private $changeHelper;
private IUserManager $userManager;
/** @var IUserManager */
private $userManager;
/** @var AttachmentServiceValidator */
private AttachmentServiceValidator $attachmentServiceValidator;
private $attachmentServiceValidator;
public function __construct(
AttachmentMapper $attachmentMapper,
CardMapper $cardMapper,
IUserManager $userManager,
ChangeHelper $changeHelper,
PermissionService $permissionService,
Application $application,
AttachmentCacheHelper $attachmentCacheHelper,
$userId,
IL10N $l10n,
ActivityManager $activityManager,
AttachmentServiceValidator $attachmentServiceValidator
) {
public function __construct(AttachmentMapper $attachmentMapper,
CardMapper $cardMapper,
IUserManager $userManager,
ChangeHelper $changeHelper,
PermissionService $permissionService,
Application $application,
AttachmentCacheHelper $attachmentCacheHelper,
$userId,
IL10N $l10n,
ActivityManager $activityManager,
AttachmentServiceValidator $attachmentServiceValidator) {
$this->attachmentMapper = $attachmentMapper;
$this->cardMapper = $cardMapper;
$this->permissionService = $permissionService;

View File

@@ -24,6 +24,7 @@
namespace OCA\Deck\Service;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use OCA\Deck\Activity\ActivityManager;
use OCA\Deck\Activity\ChangeSet;
use OCA\Deck\AppInfo\Application;
@@ -44,10 +45,8 @@ use OCA\Deck\Notification\NotificationHelper;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IConfig;
use OCP\IDBConnection;
use OCP\IGroupManager;
use OCP\IL10N;
use OCP\DB\Exception as DbException;
use OCA\Deck\Db\Board;
use OCA\Deck\Db\BoardMapper;
use OCA\Deck\Db\LabelMapper;
@@ -55,29 +54,30 @@ use OCP\IUserManager;
use OCA\Deck\BadRequestException;
use OCA\Deck\Validators\BoardServiceValidator;
use OCP\IURLGenerator;
use OCP\Server;
class BoardService {
private BoardMapper $boardMapper;
private StackMapper $stackMapper;
private LabelMapper $labelMapper;
private AclMapper $aclMapper;
private IConfig $config;
private IL10N $l10n;
private PermissionService $permissionService;
private NotificationHelper $notificationHelper;
private AssignmentMapper $assignedUsersMapper;
private IUserManager $userManager;
private IGroupManager $groupManager;
private ?string $userId;
private ActivityManager $activityManager;
private IEventDispatcher $eventDispatcher;
private ChangeHelper $changeHelper;
private CardMapper $cardMapper;
private ?array $boardsCache = null;
private IURLGenerator $urlGenerator;
private IDBConnection $connection;
private BoardServiceValidator $boardServiceValidator;
private $boardMapper;
private $stackMapper;
private $labelMapper;
private $aclMapper;
/** @var IConfig */
private $config;
private $l10n;
private $permissionService;
private $notificationHelper;
private $assignedUsersMapper;
private $userManager;
private $groupManager;
private $userId;
private $activityManager;
private $eventDispatcher;
private $changeHelper;
private $cardMapper;
private $boardsCache = null;
private $urlGenerator;
private $boardServiceValidator;
public function __construct(
BoardMapper $boardMapper,
@@ -96,9 +96,8 @@ class BoardService {
IEventDispatcher $eventDispatcher,
ChangeHelper $changeHelper,
IURLGenerator $urlGenerator,
IDBConnection $connection,
BoardServiceValidator $boardServiceValidator,
?string $userId
$userId
) {
$this->boardMapper = $boardMapper;
$this->stackMapper = $stackMapper;
@@ -117,7 +116,6 @@ class BoardService {
$this->userId = $userId;
$this->urlGenerator = $urlGenerator;
$this->cardMapper = $cardMapper;
$this->connection = $connection;
$this->boardServiceValidator = $boardServiceValidator;
}
@@ -128,6 +126,7 @@ class BoardService {
*/
public function setUserId(string $userId): void {
$this->userId = $userId;
$this->permissionService->setUserId($userId);
}
/**
@@ -182,7 +181,7 @@ class BoardService {
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException
*/
public function find($boardId) {
public function find($boardId, bool $allowDeleted = false) {
$this->boardServiceValidator->check(compact('boardId'));
if ($this->boardsCache && isset($this->boardsCache[$boardId])) {
return $this->boardsCache[$boardId];
@@ -193,7 +192,7 @@ class BoardService {
$this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_READ);
/** @var Board $board */
$board = $this->boardMapper->find($boardId, true, true);
$board = $this->boardMapper->find((int)$boardId, true, true, $allowDeleted);
$this->boardMapper->mapOwner($board);
if ($board->getAcl() !== null) {
foreach ($board->getAcl() as $acl) {
@@ -368,7 +367,7 @@ class BoardService {
$this->boardServiceValidator->check(compact('id'));
$this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_MANAGE);
$board = $this->find($id);
$board = $this->find($id, true);
$board->setDeletedAt(0);
$board = $this->boardMapper->update($board);
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_BOARD, $board, ActivityManager::SUBJECT_BOARD_RESTORE);
@@ -389,7 +388,7 @@ class BoardService {
$this->boardServiceValidator->check(compact('id'));
$this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_MANAGE);
$board = $this->find($id);
$board = $this->find($id, true);
$delete = $this->boardMapper->delete($board);
return $delete;
@@ -472,7 +471,7 @@ class BoardService {
$newAcl = $this->aclMapper->insert($acl);
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_BOARD, $newAcl, ActivityManager::SUBJECT_BOARD_SHARE, [], $this->userId);
$this->notificationHelper->sendBoardShared((int)$boardId, $acl);
$this->notificationHelper->sendBoardShared($boardId, $acl);
$this->boardMapper->mapAcl($newAcl);
$this->changeHelper->boardChanged($boardId);
@@ -481,7 +480,7 @@ class BoardService {
// TODO: use the dispatched event for this
try {
$resourceProvider = Server::get(\OCA\Deck\Collaboration\Resources\ResourceProvider::class);
$resourceProvider = \OC::$server->query(\OCA\Deck\Collaboration\Resources\ResourceProvider::class);
$resourceProvider->invalidateAccessCache($boardId);
} catch (\Exception $e) {
}
@@ -523,12 +522,18 @@ class BoardService {
}
/**
* @param $id
* @return \OCP\AppFramework\Db\Entity
* @throws DoesNotExistException
* @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException
*/
public function deleteAcl(int $id): bool {
public function deleteAcl($id) {
if (is_numeric($id) === false) {
throw new BadRequestException('id must be a number');
}
$this->permissionService->checkPermission($this->aclMapper, $id, Acl::PERMISSION_SHARE);
/** @var Acl $acl */
$acl = $this->aclMapper->find($id);
@@ -547,14 +552,16 @@ class BoardService {
$version = \OCP\Util::getVersion()[0];
if ($version >= 16) {
try {
$resourceProvider = Server::get(\OCA\Deck\Collaboration\Resources\ResourceProvider::class);
$resourceProvider = \OC::$server->query(\OCA\Deck\Collaboration\Resources\ResourceProvider::class);
$resourceProvider->invalidateAccessCache($acl->getBoardId());
} catch (\Exception $e) {
}
}
$delete = $this->aclMapper->delete($acl);
$this->eventDispatcher->dispatchTyped(new AclDeletedEvent($acl));
return (bool) $this->aclMapper->delete($acl);
return $delete;
}
/**
@@ -606,7 +613,7 @@ class BoardService {
}
public function transferBoardOwnership(int $boardId, string $newOwner, bool $changeContent = false): Board {
$this->connection->beginTransaction();
\OC::$server->getDatabaseConnection()->beginTransaction();
try {
$board = $this->boardMapper->find($boardId);
$previousOwner = $board->getOwner();
@@ -615,10 +622,7 @@ class BoardService {
if (!$changeContent) {
try {
$this->addAcl($boardId, Acl::PERMISSION_TYPE_USER, $previousOwner, true, true, true);
} catch (DbException $e) {
if ($e->getReason() !== DbException::REASON_UNIQUE_CONSTRAINT_VIOLATION) {
throw $e;
}
} catch (UniqueConstraintViolationException $e) {
}
}
$this->boardMapper->transferOwnership($previousOwner, $newOwner, $boardId);
@@ -628,10 +632,10 @@ class BoardService {
$this->assignedUsersMapper->remapAssignedUser($boardId, $previousOwner, $newOwner);
$this->cardMapper->remapCardOwner($boardId, $previousOwner, $newOwner);
}
$this->connection->commit();
\OC::$server->getDatabaseConnection()->commit();
return $this->boardMapper->find($boardId);
} catch (\Throwable $e) {
$this->connection->rollBack();
\OC::$server->getDatabaseConnection()->rollBack();
throw $e;
}
}

View File

@@ -46,31 +46,27 @@ use OCA\Deck\BadRequestException;
use OCA\Deck\Validators\CardServiceValidator;
use OCP\Comments\ICommentsManager;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IRequest;
use OCP\IUserManager;
use OCP\IURLGenerator;
use Psr\Log\LoggerInterface;
class CardService {
private CardMapper $cardMapper;
private StackMapper $stackMapper;
private BoardMapper $boardMapper;
private LabelMapper $labelMapper;
private PermissionService $permissionService;
private BoardService $boardService;
private NotificationHelper $notificationHelper;
private AssignmentMapper $assignedUsersMapper;
private AttachmentService $attachmentService;
private ?string $currentUser;
private ActivityManager $activityManager;
private ICommentsManager $commentsManager;
private ChangeHelper $changeHelper;
private IEventDispatcher $eventDispatcher;
private IUserManager $userManager;
private IURLGenerator $urlGenerator;
private LoggerInterface $logger;
private IRequest $request;
private CardServiceValidator $cardServiceValidator;
private $cardMapper;
private $stackMapper;
private $boardMapper;
private $labelMapper;
private $permissionService;
private $boardService;
private $notificationHelper;
private $assignedUsersMapper;
private $attachmentService;
private $currentUser;
private $activityManager;
private $commentsManager;
private $changeHelper;
private $eventDispatcher;
private $userManager;
private $urlGenerator;
private $cardServiceValidator;
public function __construct(
CardMapper $cardMapper,
@@ -88,10 +84,8 @@ class CardService {
ChangeHelper $changeHelper,
IEventDispatcher $eventDispatcher,
IURLGenerator $urlGenerator,
LoggerInterface $logger,
IRequest $request,
CardServiceValidator $cardServiceValidator,
?string $userId
$userId
) {
$this->cardMapper = $cardMapper;
$this->stackMapper = $stackMapper;
@@ -109,8 +103,6 @@ class CardService {
$this->eventDispatcher = $eventDispatcher;
$this->currentUser = $userId;
$this->urlGenerator = $urlGenerator;
$this->logger = $logger;
$this->request = $request;
$this->cardServiceValidator = $cardServiceValidator;
}
@@ -144,18 +136,23 @@ class CardService {
}
/**
* @param $cardId
* @return \OCA\Deck\Db\RelationalEntity
* @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException
*/
public function find(int $cardId) {
public function find($cardId) {
if (is_numeric($cardId) === false) {
throw new BadRequestException('card id must be a number');
}
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ);
$card = $this->cardMapper->find($cardId);
$assignedUsers = $this->assignedUsersMapper->findAll($card->getId());
$attachments = $this->attachmentService->findAll($cardId, true);
if ($this->request->getParam('apiVersion') === '1.0') {
if (\OC::$server->getRequest()->getParam('apiVersion') === '1.0') {
$attachments = array_filter($attachments, function ($attachment) {
return $attachment->getType() === 'deck_file';
});
@@ -170,7 +167,7 @@ class CardService {
try {
$this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_READ);
} catch (NoPermissionException $e) {
$this->logger->error('Unable to check permission for a previously obtained board ' . $boardId, ['exception' => $e]);
\OC::$server->getLogger()->error('Unable to check permission for a previously obtained board ' . $boardId, ['exception' => $e]);
return [];
}
$cards = $this->cardMapper->findCalendarEntries($boardId);
@@ -267,7 +264,7 @@ class CardService {
public function update($id, $title, $stackId, $type, $owner, $description = '', $order = 0, $duedate = null, $deletedAt = null, $archived = null) {
$this->cardServiceValidator->check(compact('id', 'title', 'stackId', 'type', 'owner', 'order'));
$this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT);
$this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT, null, true);
$this->permissionService->checkPermission($this->stackMapper, $stackId, Acl::PERMISSION_EDIT);
if ($this->boardService->isArchived($this->cardMapper, $id)) {
@@ -277,6 +274,14 @@ class CardService {
if ($archived !== null && $card->getArchived() && $archived === true) {
throw new StatusException('Operation not allowed. This card is archived.');
}
if ($card->getDeletedAt() !== 0) {
if ($deletedAt === null || $deletedAt > 0) {
// Only allow operations when restoring the card
throw new NoPermissionException('Operation not allowed. This card was deleted.');
}
}
$changes = new ChangeSet($card);
if ($card->getLastEditor() !== $this->currentUser && $card->getLastEditor() !== null) {
$this->activityManager->triggerEvent(
@@ -298,11 +303,11 @@ class CardService {
$card->setType($type);
$card->setOrder($order);
$card->setOwner($owner);
$card->setDuedate($duedate ? new \DateTime($duedate) : null);
$card->setDuedate($duedate);
$resetDuedateNotification = false;
if (
$card->getDuedate() === null ||
($card->getDuedate()) != ($changes->getBefore()->getDuedate())
(new \DateTime($card->getDuedate())) != (new \DateTime($changes->getBefore()->getDuedate() ?? ''))
) {
$card->setNotified(false);
$resetDuedateNotification = true;
@@ -431,7 +436,7 @@ class CardService {
* @throws StatusException
* @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws \OCP\AppFramework\Db\
* @throws BadRequestException
*/
public function archive($id) {

View File

@@ -31,7 +31,6 @@ use OCA\Circles\Model\Circle;
use OCA\Circles\Model\Member;
use OCA\Circles\Model\Probes\CircleProbe;
use OCP\App\IAppManager;
use OCP\Server;
use Throwable;
/**
@@ -39,7 +38,7 @@ use Throwable;
* having the app disabled is properly handled
*/
class CirclesService {
private bool $circlesEnabled;
private $circlesEnabled;
private $userCircleCache = [];
@@ -59,7 +58,8 @@ class CirclesService {
try {
// Enforce current user condition since we always want the full list of members
$circlesManager = Server::get(CirclesManager::class);
/** @var CirclesManager $circlesManager */
$circlesManager = \OC::$server->get(CirclesManager::class);
$circlesManager->startSuperSession();
return $circlesManager->getCircle($circleId);
} catch (Throwable $e) {
@@ -77,7 +77,8 @@ class CirclesService {
}
try {
$circlesManager = Server::get(CirclesManager::class);
/** @var CirclesManager $circlesManager */
$circlesManager = \OC::$server->get(CirclesManager::class);
$federatedUser = $circlesManager->getFederatedUser($userId, Member::TYPE_USER);
$circlesManager->startSession($federatedUser);
$circle = $circlesManager->getCircle($circleId);
@@ -105,7 +106,8 @@ class CirclesService {
}
try {
$circlesManager = Server::get(CirclesManager::class);
/** @var CirclesManager $circlesManager */
$circlesManager = \OC::$server->get(CirclesManager::class);
$federatedUser = $circlesManager->getFederatedUser($userId, Member::TYPE_USER);
$circlesManager->startSession($federatedUser);
$probe = new CircleProbe();

View File

@@ -40,14 +40,20 @@ use OutOfBoundsException;
use function is_numeric;
class CommentService {
private ICommentsManager $commentsManager;
private IUserManager $userManager;
private CardMapper $cardMapper;
private PermissionService $permissionService;
private ILogger $logger;
private ?string $userId;
public function __construct(ICommentsManager $commentsManager, PermissionService $permissionService, CardMapper $cardMapper, IUserManager $userManager, ILogger $logger, ?string $userId) {
/**
* @var ICommentsManager
*/
private $commentsManager;
/**
* @var IUserManager
*/
private $userManager;
/** @var ILogger */
private $logger;
private $userId;
public function __construct(ICommentsManager $commentsManager, PermissionService $permissionService, CardMapper $cardMapper, IUserManager $userManager, ILogger $logger, $userId) {
$this->commentsManager = $commentsManager;
$this->permissionService = $permissionService;
$this->cardMapper = $cardMapper;
@@ -77,24 +83,17 @@ class CommentService {
}
/**
* @param string $cardId
* @param string $message
* @param string $replyTo
* @return DataResponse
* @throws BadRequestException
* @throws NotFoundException|NoPermissionException
*/
public function create(string $cardId, string $message, string $replyTo = '0'): DataResponse {
if (!is_numeric($cardId)) {
throw new BadRequestException('A valid card id must be provided');
}
public function create(int $cardId, string $message, string $replyTo = '0'): DataResponse {
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ);
// Check if parent is a comment on the same card
if ($replyTo !== '0') {
try {
$comment = $this->commentsManager->get($replyTo);
if ($comment->getObjectType() !== Application::COMMENT_ENTITY_TYPE || $comment->getObjectId() !== $cardId) {
if ($comment->getObjectType() !== Application::COMMENT_ENTITY_TYPE || (int)$comment->getObjectId() !== $cardId) {
throw new CommentNotFoundException();
}
} catch (CommentNotFoundException $e) {
@@ -103,7 +102,7 @@ class CommentService {
}
try {
$comment = $this->commentsManager->create('users', $this->userId, Application::COMMENT_ENTITY_TYPE, $cardId);
$comment = $this->commentsManager->create('users', $this->userId, Application::COMMENT_ENTITY_TYPE, (string)$cardId);
$comment->setMessage($message);
$comment->setVerb('comment');
$comment->setParentId($replyTo);
@@ -139,7 +138,7 @@ class CommentService {
throw new NoPermissionException('Only authors are allowed to edit their comment.');
}
if ($comment->getParentId() !== '0') {
$this->permissionService->checkPermission($this->cardMapper, $comment->getParentId(), Acl::PERMISSION_READ);
$this->permissionService->checkPermission($this->cardMapper, (int)$comment->getParentId(), Acl::PERMISSION_READ);
}
$comment->setMessage($message);

View File

@@ -40,9 +40,9 @@ class ConfigService {
public const SETTING_BOARD_NOTIFICATION_DUE_ALL = 'all';
public const SETTING_BOARD_NOTIFICATION_DUE_DEFAULT = self::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED;
private IConfig $config;
private ?string $userId = null;
private IGroupManager $groupManager;
private $config;
private $userId;
private $groupManager;
public function __construct(
IConfig $config,
@@ -52,14 +52,11 @@ class ConfigService {
$this->config = $config;
}
public function getUserId(): ?string {
public function getUserId() {
if (!$this->userId) {
// We cannot use DI for the userId or UserSession as the ConfigService
// is initiated too early before the session is actually loaded
$user = \OCP\Server::get(IUserSession::class)->getUser();
$user = \OC::$server->get(IUserSession::class)->getUser();
$this->userId = $user ? $user->getUID() : null;
}
return $this->userId;
}
@@ -78,11 +75,8 @@ class ConfigService {
return $data;
}
/**
* @return bool|array{id: string, displayname: string}[]
* @throws NoPermissionException
*/
public function get(string $key) {
public function get($key) {
$result = null;
[$scope] = explode(':', $key, 2);
switch ($scope) {
case 'groupLimit':
@@ -96,12 +90,11 @@ class ConfigService {
}
return (bool)$this->config->getUserValue($this->getUserId(), Application::APP_ID, 'calendar', true);
case 'cardDetailsInModal':
if ($this->getUserId() === null) {
return false;
}
if ($this->getUserId() === null) {
return false;
}
return (bool)$this->config->getUserValue($this->getUserId(), Application::APP_ID, 'cardDetailsInModal', true);
}
return false;
}
public function isCalendarEnabled(int $boardId = null): bool {
@@ -164,10 +157,7 @@ class ConfigService {
return $result;
}
/**
* @return string[]
*/
private function setGroupLimit(array $value): array {
private function setGroupLimit($value) {
$groups = [];
foreach ($value as $group) {
$groups[] = $group['id'];
@@ -177,7 +167,7 @@ class ConfigService {
return $groups;
}
private function getGroupLimitList(): array {
private function getGroupLimitList() {
$value = $this->config->getAppValue(Application::APP_ID, 'groupLimit', '');
$groups = explode(',', $value);
if ($value === '') {
@@ -186,10 +176,9 @@ class ConfigService {
return $groups;
}
/** @return array{id: string, displayname: string}[] */
private function getGroupLimit() {
$groups = $this->getGroupLimitList();
$groups = array_map(function (string $groupId): ?array {
$groups = array_map(function ($groupId) {
/** @var IGroup $groups */
$group = $this->groupManager->get($groupId);
if ($group === null) {
@@ -210,4 +199,12 @@ class ConfigService {
return $this->config->getUserValue($userId ?? $this->getUserId(), 'deck', 'attachment_folder', '/Deck');
}
public function setAttachmentFolder(?string $userId = null, string $path): void {
if ($userId === null && $this->getUserId() === null) {
throw new NoPermissionException('Must be logged in get the attachment folder');
}
$this->config->setUserValue($userId ?? $this->getUserId(), 'deck', 'attachment_folder', $path);
}
}

View File

@@ -88,6 +88,18 @@ class DefaultBoardService {
* @throws BadRequestException
*/
public function createDefaultBoard(string $title, string $userId, string $color) {
if ($title === false || $title === null) {
throw new BadRequestException('title must be provided');
}
if ($userId === false || $userId === null) {
throw new BadRequestException('userId must be provided');
}
if ($color === false || $color === null) {
throw new BadRequestException('color must be provided');
}
$defaultBoard = $this->boardService->create($title, $userId, $color);
$defaultStacks = [];
$defaultCards = [];

View File

@@ -219,11 +219,8 @@ class FileService implements IAttachmentService {
throw new \Exception('no instance id!');
}
$name = 'appdata_' . $instanceId;
/** @var \OCP\Files\Folder $appDataFolder */
$appDataFolder = $this->rootFolder->get($name);
/** @var \OCP\Files\Folder $appDataFolder */
$appDataFolder = $appDataFolder->get('deck');
/** @var \OCP\Files\Folder $cardFolder */
$cardFolder = $appDataFolder->get($folderName);
return $cardFolder->get($attachment->getData());
}

View File

@@ -31,6 +31,7 @@ use OCA\Deck\Sharing\DeckShareProvider;
use OCA\Deck\StatusException;
use OCP\AppFramework\Http\StreamResponse;
use OCP\Constants;
use OCP\Files\Folder;
use OCP\Files\IMimeTypeDetector;
use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException;
@@ -44,19 +45,18 @@ use OCP\Share\IShare;
use Psr\Log\LoggerInterface;
class FilesAppService implements IAttachmentService, ICustomAttachmentService {
private IRequest $request;
private IRootFolder $rootFolder;
private DeckShareProvider $shareProvider;
private IManager $shareManager;
private ?string $userId;
private ConfigService $configService;
private IL10N $l10n;
private IPreview $preview;
private IMimeTypeDetector $mimeTypeDetector;
private PermissionService $permissionService;
private CardMapper $cardMapper;
private LoggerInterface $logger;
private IDBConnection $connection;
private $request;
private $rootFolder;
private $shareProvider;
private $shareManager;
private $userId;
private $configService;
private $l10n;
private $preview;
private $mimeTypeDetector;
private $permissionService;
private $cardMapper;
private $logger;
public function __construct(
IRequest $request,
@@ -70,8 +70,7 @@ class FilesAppService implements IAttachmentService, ICustomAttachmentService {
PermissionService $permissionService,
CardMapper $cardMapper,
LoggerInterface $logger,
IDBConnection $connection,
?string $userId
string $userId = null
) {
$this->request = $request;
$this->l10n = $l10n;
@@ -85,7 +84,6 @@ class FilesAppService implements IAttachmentService, ICustomAttachmentService {
$this->permissionService = $permissionService;
$this->cardMapper = $cardMapper;
$this->logger = $logger;
$this->connection = $connection;
}
public function listAttachments(int $cardId): array {
@@ -111,7 +109,9 @@ class FilesAppService implements IAttachmentService, ICustomAttachmentService {
}
public function getAttachmentCount(int $cardId): int {
$qb = $this->connection->getQueryBuilder();
/** @var IDBConnection $qb */
$db = \OC::$server->getDatabaseConnection();
$qb = $db->getQueryBuilder();
$qb->select('s.id', 'f.fileid', 'f.path')
->selectAlias('st.id', 'storage_string_id')
->from('share', 's')
@@ -126,7 +126,7 @@ class FilesAppService implements IAttachmentService, ICustomAttachmentService {
));
$count = 0;
$cursor = $qb->executeQuery();
$cursor = $qb->execute();
while ($data = $cursor->fetch()) {
if ($this->shareProvider->isAccessibleResult($data)) {
$count++;
@@ -190,6 +190,16 @@ class FilesAppService implements IAttachmentService, ICustomAttachmentService {
$folder = $userFolder->newFolder($this->configService->getAttachmentFolder());
}
if ($folder->isShared()) {
$folderName = $userFolder->getNonExistingName($this->configService->getAttachmentFolder());
$folder = $userFolder->newFolder($folderName);
$this->configService->setAttachmentFolder($this->userId, $folderName);
}
if (!$folder instanceof Folder || $folder->isShared()) {
throw new NotFoundException('No target folder found');
}
$fileName = $folder->getNonExistingName($fileName);
$target = $folder->newFile($fileName);
$content = fopen($file['tmp_name'], 'rb');

View File

@@ -47,22 +47,34 @@ use OCP\Comments\ICommentsManager;
use OCP\Comments\NotFoundException as CommentNotFoundException;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IUserManager;
use OCP\Server;
class BoardImportService {
private IUserManager $userManager;
private BoardMapper $boardMapper;
private AclMapper $aclMapper;
private LabelMapper $labelMapper;
private StackMapper $stackMapper;
private CardMapper $cardMapper;
private AssignmentMapper $assignmentMapper;
private AttachmentMapper $attachmentMapper;
private ICommentsManager $commentsManager;
private IEventDispatcher $eventDispatcher;
private string $system = '';
private ?ABoardImportService $systemInstance;
private array $allowedSystems = [];
/** @var IUserManager */
private $userManager;
/** @var BoardMapper */
private $boardMapper;
/** @var AclMapper */
private $aclMapper;
/** @var LabelMapper */
private $labelMapper;
/** @var StackMapper */
private $stackMapper;
/** @var CardMapper */
private $cardMapper;
/** @var AssignmentMapper */
private $assignmentMapper;
/** @var AttachmentMapper */
private $attachmentMapper;
/** @var ICommentsManager */
private $commentsManager;
/** @var IEventDispatcher */
private $eventDispatcher;
/** @var string */
private $system = '';
/** @var null|ABoardImportService */
private $systemInstance;
/** @var array */
private $allowedSystems = [];
/**
* Data object created from config JSON
*
@@ -77,7 +89,10 @@ class BoardImportService {
* @psalm-suppress PropertyNotSetInConstructor
*/
private $data;
private Board $board;
/**
* @var Board
*/
private $board;
public function __construct(
IUserManager $userManager,
@@ -183,7 +198,7 @@ class BoardImportService {
}
if (!is_object($this->systemInstance)) {
$systemClass = 'OCA\\Deck\\Service\\Importer\\Systems\\' . ucfirst($this->getSystem()) . 'Service';
$this->systemInstance = Server::get($systemClass);
$this->systemInstance = \OC::$server->get($systemClass);
$this->systemInstance->setImportService($this);
}
return $this->systemInstance;
@@ -328,7 +343,7 @@ class BoardImportService {
}
public function insertAttachment(Attachment $attachment, string $content): Attachment {
$service = Server::get(FileService::class);
$service = \OC::$server->get(FileService::class);
$folder = $service->getFolder($attachment);
if ($folder->fileExists($attachment->getData())) {

View File

@@ -91,10 +91,12 @@ class LabelService {
$this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_MANAGE);
$boardLabels = $this->labelMapper->findAll($boardId);
foreach ($boardLabels as $boardLabel) {
if ($boardLabel->getTitle() === $title) {
throw new BadRequestException('title must be unique');
break;
if (\is_array($boardLabels)) {
foreach ($boardLabels as $boardLabel) {
if ($boardLabel->getTitle() === $title) {
throw new BadRequestException('title must be unique');
break;
}
}
}
@@ -149,13 +151,15 @@ class LabelService {
$label = $this->find($id);
$boardLabels = $this->labelMapper->findAll($label->getBoardId());
foreach ($boardLabels as $boardLabel) {
if ($boardLabel->getId() === $label->getId()) {
continue;
}
if ($boardLabel->getTitle() === $title) {
throw new BadRequestException('title must be unique');
break;
if (\is_array($boardLabels)) {
foreach ($boardLabels as $boardLabel) {
if ($boardLabel->getId() === $label->getId()) {
continue;
}
if ($boardLabel->getTitle() === $title) {
throw new BadRequestException('title must be unique');
break;
}
}
}

View File

@@ -30,20 +30,31 @@ namespace OCA\Deck\Service;
use OCA\Deck\Db\AssignmentMapper;
use OCA\Deck\Db\Card;
use OCA\Deck\Db\CardMapper;
use OCA\Deck\Model\CardDetails;
use OCP\Comments\ICommentsManager;
use OCP\IGroupManager;
use OCA\Deck\Db\Board;
use OCA\Deck\Db\BoardMapper;
use OCA\Deck\Db\LabelMapper;
use OCP\IUserManager;
class OverviewService {
private BoardMapper $boardMapper;
private LabelMapper $labelMapper;
private CardMapper $cardMapper;
private AssignmentMapper $assignedUsersMapper;
private IUserManager $userManager;
private ICommentsManager $commentsManager;
private AttachmentService $attachmentService;
/** @var BoardMapper */
private $boardMapper;
/** @var LabelMapper */
private $labelMapper;
/** @var CardMapper */
private $cardMapper;
/** @var AssignmentMapper */
private $assignedUsersMapper;
/** @var IUserManager */
private $userManager;
/** @var IGroupManager */
private $groupManager;
/** @var ICommentsManager */
private $commentsManager;
/** @var AttachmentService */
private $attachmentService;
public function __construct(
BoardMapper $boardMapper,
@@ -51,6 +62,7 @@ class OverviewService {
CardMapper $cardMapper,
AssignmentMapper $assignedUsersMapper,
IUserManager $userManager,
IGroupManager $groupManager,
ICommentsManager $commentsManager,
AttachmentService $attachmentService
) {
@@ -59,6 +71,7 @@ class OverviewService {
$this->cardMapper = $cardMapper;
$this->assignedUsersMapper = $assignedUsersMapper;
$this->userManager = $userManager;
$this->groupManager = $groupManager;
$this->commentsManager = $commentsManager;
$this->attachmentService = $attachmentService;
}
@@ -80,37 +93,62 @@ class OverviewService {
}
public function findAllWithDue(string $userId): array {
$userBoards = $this->boardMapper->findAllForUser($userId);
$userBoards = $this->findAllBoardsFromUser($userId);
$allDueCards = [];
foreach ($userBoards as $userBoard) {
$allDueCards[] = array_map(function ($card) use ($userBoard, $userId) {
$this->enrich($card, $userId);
return (new CardDetails($card, $userBoard))->jsonSerialize();
$service = $this;
$allDueCards[] = array_map(static function ($card) use ($service, $userBoard, $userId) {
$service->enrich($card, $userId);
$cardData = $card->jsonSerialize();
$cardData['boardId'] = $userBoard->getId();
return $cardData;
}, $this->cardMapper->findAllWithDue($userBoard->getId()));
}
return array_merge(...$allDueCards);
return $allDueCards;
}
public function findUpcomingCards(string $userId): array {
$userBoards = $this->boardMapper->findAllForUser($userId);
$foundCards = [];
$userBoards = $this->findAllBoardsFromUser($userId);
$findCards = [];
foreach ($userBoards as $userBoard) {
$service = $this;
if (count($userBoard->getAcl()) === 0) {
// private board: get cards with due date
$cards = $this->cardMapper->findAllWithDue($userBoard->getId());
$findCards[] = array_map(static function ($card) use ($service, $userBoard, $userId) {
$service->enrich($card, $userId);
$cardData = $card->jsonSerialize();
$cardData['boardId'] = $userBoard->getId();
return $cardData;
}, $this->cardMapper->findAllWithDue($userBoard->getId()));
} else {
// shared board: get all my assigned or unassigned cards
$cards = $this->cardMapper->findToMeOrNotAssignedCards($userBoard->getId(), $userId);
$findCards[] = array_map(static function ($card) use ($service, $userBoard, $userId) {
$service->enrich($card, $userId);
$cardData = $card->jsonSerialize();
$cardData['boardId'] = $userBoard->getId();
return $cardData;
}, $this->cardMapper->findToMeOrNotAssignedCards($userBoard->getId(), $userId));
}
$foundCards[] = array_map(
function (Card $card) use ($userBoard, $userId) {
$this->enrich($card, $userId);
return (new CardDetails($card, $userBoard))->jsonSerialize();
},
$cards
);
}
return array_merge(...$foundCards);
return $findCards;
}
// FIXME: This is duplicate code with the board service
private function findAllBoardsFromUser(string $userId): array {
$userInfo = $this->getBoardPrerequisites($userId);
$userBoards = $this->boardMapper->findAllByUser($userInfo['user'], null, null);
$groupBoards = $this->boardMapper->findAllByGroups($userInfo['user'], $userInfo['groups'], null, null);
$circleBoards = $this->boardMapper->findAllByCircles($userInfo['user'], null, null);
return array_unique(array_merge($userBoards, $groupBoards, $circleBoards));
}
private function getBoardPrerequisites($userId): array {
$user = $this->userManager->get($userId);
$groups = $user !== null ? $this->groupManager->getUserGroupIds($user) : [];
return [
'user' => $userId,
'groups' => $groups
];
}
}

View File

@@ -23,12 +23,13 @@
namespace OCA\Deck\Service;
use OCP\Cache\CappedMemoryCache;
use OC\Cache\CappedMemoryCache;
use OCA\Circles\Model\Member;
use OCA\Deck\Db\Acl;
use OCA\Deck\Db\AclMapper;
use OCA\Deck\Db\Board;
use OCA\Deck\Db\BoardMapper;
use OCA\Deck\Db\CardMapper;
use OCA\Deck\Db\IPermissionMapper;
use OCA\Deck\Db\User;
use OCA\Deck\NoPermissionException;
@@ -63,8 +64,8 @@ class PermissionService {
/** @var array */
private $users = [];
private CappedMemoryCache $boardCache;
private CappedMemoryCache $permissionCache;
private $boardCache;
private $permissionCache;
public function __construct(
ILogger $logger,
@@ -97,13 +98,18 @@ class PermissionService {
* @param $boardId
* @return bool|array
*/
public function getPermissions($boardId) {
public function getPermissions($boardId, ?string $userId = null) {
if ($userId === null) {
$userId = $this->userId;
}
if ($cached = $this->permissionCache->get($boardId)) {
return $cached;
}
$owner = $this->userIsBoardOwner($boardId);
$acls = $this->aclMapper->findAll($boardId);
$board = $this->getBoard($boardId);
$owner = $this->userIsBoardOwner($boardId, $userId);
$acls = $board->getDeletedAt() === 0 ? $this->aclMapper->findAll($boardId) : [];
$permissions = [
Acl::PERMISSION_READ => $owner || $this->userCan($acls, Acl::PERMISSION_READ),
Acl::PERMISSION_EDIT => $owner || $this->userCan($acls, Acl::PERMISSION_EDIT),
@@ -111,7 +117,7 @@ class PermissionService {
Acl::PERMISSION_SHARE => ($owner || $this->userCan($acls, Acl::PERMISSION_SHARE))
&& (!$this->shareManager->sharingDisabledForUser($this->userId))
];
$this->permissionCache->set($boardId, $permissions);
$this->permissionCache->set((string)$boardId, $permissions);
return $permissions;
}
@@ -137,13 +143,10 @@ class PermissionService {
/**
* check permissions for replacing dark magic middleware
*
* @param $mapper IPermissionMapper|null null if $id is a boardId
* @param $id int unique identifier of the Entity
* @param $permission int
* @return bool
* @param numeric $id
* @throws NoPermissionException
*/
public function checkPermission($mapper, $id, $permission, $userId = null) {
public function checkPermission($mapper, $id, $permission, $userId = null, bool $allowDeletedCard = false) {
$boardId = $id;
if ($mapper instanceof IPermissionMapper && !($mapper instanceof BoardMapper)) {
$boardId = $mapper->findBoardId($id);
@@ -157,12 +160,20 @@ class PermissionService {
throw new NoPermissionException('Permission denied');
}
if ($this->userIsBoardOwner($boardId, $userId)) {
return true;
}
try {
$acls = $this->getBoard($boardId)->getAcl() ?? [];
$permissions = $this->getPermissions($boardId, $userId);
if ($permissions[$permission] === true) {
if (!$allowDeletedCard && $mapper instanceof CardMapper) {
$card = $mapper->find($id);
if ($card->getDeletedAt() > 0) {
throw new NoPermissionException('Card is deleted');
}
}
return true;
}
$acls = $this->getBoard((int)$boardId)->getAcl() ?? [];
$result = $this->userCan($acls, $permission, $userId);
if ($result) {
return true;
@@ -194,11 +205,11 @@ class PermissionService {
* @throws MultipleObjectsReturnedException
* @throws DoesNotExistException
*/
private function getBoard($boardId): Board {
if (!isset($this->boardCache[$boardId])) {
$this->boardCache[$boardId] = $this->boardMapper->find($boardId, false, true);
private function getBoard(int $boardId): Board {
if (!isset($this->boardCache[(string)$boardId])) {
$this->boardCache[(string)$boardId] = $this->boardMapper->find($boardId, false, true);
}
return $this->boardCache[$boardId];
return $this->boardCache[(string)$boardId];
}
/**

View File

@@ -30,32 +30,28 @@ use OCA\Deck\BadRequestException;
use OCA\Deck\Db\Acl;
use OCA\Deck\Db\AssignmentMapper;
use OCA\Deck\Db\BoardMapper;
use OCA\Deck\Db\Card;
use OCA\Deck\Db\CardMapper;
use OCA\Deck\Db\ChangeHelper;
use OCA\Deck\Db\LabelMapper;
use OCA\Deck\Db\Stack;
use OCA\Deck\Db\StackMapper;
use OCA\Deck\Model\CardDetails;
use OCA\Deck\NoPermissionException;
use OCA\Deck\StatusException;
use OCA\Deck\Validators\StackServiceValidator;
use Psr\Log\LoggerInterface;
class StackService {
private StackMapper $stackMapper;
private CardMapper $cardMapper;
private BoardMapper $boardMapper;
private LabelMapper $labelMapper;
private PermissionService $permissionService;
private BoardService $boardService;
private CardService $cardService;
private AssignmentMapper $assignedUsersMapper;
private AttachmentService $attachmentService;
private ActivityManager $activityManager;
private ChangeHelper $changeHelper;
private LoggerInterface $logger;
private StackServiceValidator $stackServiceValidator;
private $stackMapper;
private $cardMapper;
private $boardMapper;
private $labelMapper;
private $permissionService;
private $boardService;
private $cardService;
private $assignedUsersMapper;
private $attachmentService;
private $activityManager;
private $changeHelper;
private $stackServiceValidator;
public function __construct(
StackMapper $stackMapper,
@@ -68,9 +64,8 @@ class StackService {
AssignmentMapper $assignedUsersMapper,
AttachmentService $attachmentService,
ActivityManager $activityManager,
ChangeHelper $changeHelper,
LoggerInterface $logger,
StackServiceValidator $stackServiceValidator
StackServiceValidator $stackServiceValidator,
ChangeHelper $changeHelper
) {
$this->stackMapper = $stackMapper;
$this->boardMapper = $boardMapper;
@@ -83,7 +78,6 @@ class StackService {
$this->attachmentService = $attachmentService;
$this->activityManager = $activityManager;
$this->changeHelper = $changeHelper;
$this->logger = $logger;
$this->stackServiceValidator = $stackServiceValidator;
}
@@ -94,13 +88,9 @@ class StackService {
return;
}
$cards = array_map(
function (Card $card): CardDetails {
$this->cardService->enrich($card);
return new CardDetails($card);
},
$cards
);
foreach ($cards as $card) {
$this->cardService->enrich($card);
}
$stack->setCards($cards);
}
@@ -126,18 +116,12 @@ class StackService {
$this->permissionService->checkPermission($this->stackMapper, $stackId, Acl::PERMISSION_READ);
$stack = $this->stackMapper->find($stackId);
$cards = array_map(
function (Card $card): CardDetails {
$assignedUsers = $this->assignedUsersMapper->findAll($card->getId());
$card->setAssignedUsers($assignedUsers);
$card->setAttachmentCount($this->attachmentService->count($card->getId()));
return new CardDetails($card);
},
$this->cardMapper->findAll($stackId)
);
$cards = $this->cardMapper->findAll($stackId);
foreach ($cards as $cardIndex => $card) {
$assignedUsers = $this->assignedUsersMapper->findAll($card->getId());
$card->setAssignedUsers($assignedUsers);
$card->setAttachmentCount($this->attachmentService->count($card->getId()));
}
$stack->setCards($cards);
return $stack;
@@ -166,7 +150,7 @@ class StackService {
try {
$this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_READ);
} catch (NoPermissionException $e) {
$this->logger->error('Unable to check permission for a previously obtained board ' . $boardId, ['exception' => $e]);
\OC::$server->getLogger()->error('Unable to check permission for a previously obtained board ' . $boardId, ['exception' => $e]);
return [];
}
return $this->stackMapper->findAll($boardId);
@@ -326,7 +310,6 @@ class StackService {
$this->permissionService->checkPermission($this->stackMapper, $id, Acl::PERMISSION_MANAGE);
$stackToSort = $this->stackMapper->find($id);
$stacks = $this->stackMapper->findAll($stackToSort->getBoardId());
usort($stacks, static fn (Stack $stackA, Stack $stackB) => $stackA->getOrder() - $stackB->getOrder());
$result = [];
$i = 0;
foreach ($stacks as $stack) {

View File

@@ -65,16 +65,22 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
public const SHARE_TYPE_DECK_USER = IShare::TYPE_DECK_USER;
private IDBConnection $dbConnection;
private IManager $shareManager;
private AttachmentCacheHelper $attachmentCacheHelper;
private BoardMapper $boardMapper;
private CardMapper $cardMapper;
private PermissionService $permissionService;
private ITimeFactory $timeFactory;
private IL10N $l;
private IMimeTypeLoader $mimeTypeLoader;
private ?string $userId;
/** @var IDBConnection */
private $dbConnection;
/** @var IManager */
private $shareManager;
/** @var AttachmentCacheHelper */
private $attachmentCacheHelper;
/** @var BoardMapper */
private $boardMapper;
/** @var CardMapper */
private $cardMapper;
/** @var PermissionService */
private $permissionService;
/** @var ITimeFactory */
private $timeFactory;
/** @var IL10N */
private $l;
public function __construct(
IDBConnection $connection,
@@ -83,10 +89,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
CardMapper $cardMapper,
PermissionService $permissionService,
AttachmentCacheHelper $attachmentCacheHelper,
IL10N $l,
ITimeFactory $timeFactory,
IMimeTypeLoader $mimeTypeLoader,
?string $userId
IL10N $l
) {
$this->dbConnection = $connection;
$this->shareManager = $shareManager;
@@ -94,10 +97,9 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
$this->cardMapper = $cardMapper;
$this->attachmentCacheHelper = $attachmentCacheHelper;
$this->permissionService = $permissionService;
$this->l = $l;
$this->timeFactory = $timeFactory;
$this->mimeTypeLoader = $mimeTypeLoader;
$this->userId = $userId;
$this->timeFactory = \OC::$server->get(ITimeFactory::class);
}
public static function register(IEventDispatcher $dispatcher): void {
@@ -205,13 +207,13 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
->setValue('file_target', $qb->createNamedParameter($target))
->setValue('permissions', $qb->createNamedParameter($permissions))
->setValue('token', $qb->createNamedParameter($token))
->setValue('stime', $qb->createNamedParameter($this->timeFactory->getTime()));
->setValue('stime', $qb->createNamedParameter(\OC::$server->get(ITimeFactory::class)->getTime()));
if ($expirationDate !== null) {
$qb->setValue('expiration', $qb->createNamedParameter($expirationDate, 'datetime'));
}
$qb->executeStatement();
$qb->execute();
return $qb->getLastInsertId();
}
@@ -279,7 +281,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
$entryData = $data;
$entryData['permissions'] = $entryData['f_permissions'];
$entryData['parent'] = $entryData['f_parent'];
$share->setNodeCacheEntry(Cache::cacheEntryFromData($entryData, $this->mimeTypeLoader));
$share->setNodeCacheEntry(Cache::cacheEntryFromData($entryData, \OC::$server->get(IMimeTypeLoader::class)));
}
return $share;
}
@@ -472,14 +474,14 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
'file_target' => $qb->createNamedParameter($share->getTarget()),
'permissions' => $qb->createNamedParameter($share->getPermissions()),
'stime' => $qb->createNamedParameter($share->getShareTime()->getTimestamp()),
])->executeStatement();
])->execute();
} else {
// Already a userroom share. Update it.
$qb = $this->dbConnection->getQueryBuilder();
$qb->update('share')
->set('file_target', $qb->createNamedParameter($share->getTarget()))
->where($qb->expr()->eq('id', $qb->createNamedParameter($data['id'])))
->executeStatement();
->execute();
}
return $share;
@@ -489,7 +491,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
* @inheritDoc
* @returns
*/
public function getSharesInFolder($userId, Folder $node, $reshares, $shallow = true) {
public function getSharesInFolder($userId, Folder $node, $reshares) {
$qb = $this->dbConnection->getQueryBuilder();
$qb->select('*')
->from('share', 's')
@@ -516,11 +518,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
}
$qb->innerJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
if ($shallow) {
$qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
} else {
$qb->andWhere($qb->expr()->like('f.path', $qb->createNamedParameter($this->dbConnection->escapeLikeParameter($node->getInternalPath()) . '/%')));
}
$qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
$qb->orderBy('s.id');
@@ -634,8 +632,8 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
$start = 0;
while (true) {
/** @var IShare[] $shareSlice */
$shareSlice = array_slice($shares, $start, 1000);
$start += 1000;
$shareSlice = array_slice($shares, $start, 100);
$start += 100;
if ($shareSlice === []) {
break;
@@ -714,15 +712,15 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
* @return IShare[]
*/
public function getSharedWith($userId, $shareType, $node, $limit, $offset): array {
$allBoards = $this->boardMapper->findBoardIds($userId);
$allBoards = $this->boardMapper->findAllForUser($userId);
/** @var IShare[] $shares */
$shares = [];
$start = 0;
while (true) {
$boards = array_slice($allBoards, $start, 1000);
$start += 1000;
$boards = array_slice($allBoards, $start, 100);
$start += 100;
if ($boards === []) {
break;
@@ -752,6 +750,10 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
$qb->andWhere($qb->expr()->eq('s.file_source', $qb->createNamedParameter($node->getId())));
}
$boards = array_map(function (Board $board) {
return $board->getId();
}, $boards);
$qb->andWhere($qb->expr()->eq('s.share_type', $qb->createNamedParameter(IShare::TYPE_DECK)))
->andWhere($qb->expr()->in('db.id', $qb->createNamedParameter(
$boards,
@@ -819,7 +821,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
$qb->expr()->eq('s.item_type', $qb->createNamedParameter('folder'))
));
$cursor = $qb->executeQuery();
$cursor = $qb->execute();
while ($data = $cursor->fetch()) {
if (!$this->isAccessibleResult($data)) {
continue;
@@ -834,7 +836,9 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
}
$cursor->closeCursor();
return $this->resolveSharesForRecipient($shares, $this->userId);
$shares = $this->resolveSharesForRecipient($shares, \OC::$server->getUserSession()->getUser()->getUID());
return $shares;
}
public function isAccessibleResult(array $data): bool {
@@ -937,7 +941,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
));
$cursor = $qb->executeQuery();
$cursor = $qb->execute();
$users = [];
while ($row = $cursor->fetch()) {

View File

@@ -29,13 +29,14 @@ namespace OCA\Deck\Sharing;
use OC\Files\Filesystem;
use OCA\Deck\Service\ConfigService;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Server;
use OCP\Share\Events\VerifyMountPointEvent;
use OCP\Share\IShare;
use Symfony\Component\EventDispatcher\GenericEvent;
class Listener {
private ConfigService $configService;
/** @var ConfigService */
private $configService;
public function __construct(ConfigService $configService) {
$this->configService = $configService;
@@ -51,13 +52,13 @@ class Listener {
public static function listenPreShare(GenericEvent $event): void {
/** @var self $listener */
$listener = Server::get(self::class);
$listener = \OC::$server->query(self::class);
$listener->overwriteShareTarget($event);
}
public static function listenVerifyMountPointEvent(VerifyMountPointEvent $event): void {
/** @var self $listener */
$listener = Server::get(self::class);
$listener = \OC::$server->query(self::class);
$listener->overwriteMountPoint($event);
}

View File

@@ -115,7 +115,7 @@ class ShareAPIHelper {
*/
public function canAccessShare(IShare $share, string $user): bool {
try {
$this->permissionService->checkPermission($this->cardMapper, $share->getSharedWith(), Acl::PERMISSION_READ, $user);
$this->permissionService->checkPermission($this->cardMapper, (int)$share->getSharedWith(), Acl::PERMISSION_READ, $user);
} catch (NoPermissionException $e) {
return false;
}

18428
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,107 +1,100 @@
{
"name": "deck",
"description": "",
"version": "1.8.5",
"authors": [
{
"name": "Julius Härtl",
"email": "jus@bitgrid.net",
"role": "Developer"
},
{
"name": "Michael Weimann",
"email": "mail@michael-weimann.eu",
"role": "Developer"
}
],
"license": "agpl",
"private": true,
"scripts": {
"build": "NODE_ENV=production webpack --progress --config webpack.js",
"dev": "NODE_ENV=development webpack --progress --config webpack.js",
"watch": "NODE_ENV=development webpack --progress --watch --config webpack.js",
"serve": "webpack serve --node-env development --allowed-hosts all --config webpack.js",
"lint": "eslint --ext .js,.vue src",
"lint:fix": "eslint --ext .js,.vue src --fix",
"stylelint": "stylelint src",
"stylelint:fix": "stylelint src --fix",
"test": "jest",
"test:coverage": "jest --coverage"
},
"dependencies": {
"@babel/polyfill": "^7.12.1",
"@babel/runtime": "^7.19.0",
"@juliushaertl/vue-richtext": "^1.0.1",
"@nextcloud/auth": "^2.0.0",
"@nextcloud/axios": "^2.0.0",
"@nextcloud/dialogs": "^3.2.0",
"@nextcloud/event-bus": "^3.0.2",
"@nextcloud/files": "^2.1.0",
"@nextcloud/initial-state": "^2.0.0",
"@nextcloud/l10n": "^1.6.0",
"@nextcloud/moment": "^1.2.1",
"@nextcloud/router": "^2.0.0",
"@nextcloud/vue": "^7.3.0",
"@nextcloud/vue-dashboard": "^2.0.1",
"@nextcloud/vue-richtext": "^2.0.1",
"blueimp-md5": "^2.19.0",
"dompurify": "^2.4.0",
"lodash": "^4.17.21",
"markdown-it": "^13.0.1",
"markdown-it-link-attributes": "^4.0.1",
"markdown-it-task-checkbox": "^1.0.6",
"moment": "^2.29.4",
"nextcloud-vue-collections": "^0.10.0",
"p-queue": "^7.3.0",
"url-search-params-polyfill": "^8.1.1",
"vue": "^2.7.9",
"vue-at": "^2.5.0",
"vue-click-outside": "^1.1.0",
"vue-easymde": "^2.0.0",
"vue-infinite-loading": "^2.4.5",
"vue-material-design-icons": "^5.1.2",
"vue-router": "^3.6.5",
"vue-smooth-dnd": "^0.8.1",
"vuex": "^3.6.2",
"vuex-router-sync": "^5.0.0"
},
"browserslist": [
"extends @nextcloud/browserslist-config"
],
"engines": {
"node": "^16.0.0",
"npm": "^7.0.0 || ^8.0.0"
},
"devDependencies": {
"@nextcloud/babel-config": "^1.0.0",
"@nextcloud/browserslist-config": "^2.3.0",
"@nextcloud/eslint-config": "^8.0.0",
"@nextcloud/stylelint-config": "^2.2.0",
"@nextcloud/webpack-vue-config": "^5.3.0",
"@relative-ci/agent": "^4.1.0",
"@vue/test-utils": "^1.3.0",
"cypress": "^10.8.0",
"eslint-webpack-plugin": "^3.2.0",
"jest": "^29.0.1",
"jest-serializer-vue": "^2.0.2",
"stylelint-webpack-plugin": "^3.3.0",
"vue-jest": "^3.0.7",
"vue-template-compiler": "^2.7.9"
},
"jest": {
"moduleFileExtensions": [
"js",
"vue"
],
"moduleNameMapper": {
"^@/(.*)$": "<rootDir>/src/$1"
},
"transform": {
"^.+\\.js$": "<rootDir>/node_modules/babel-jest",
".*\\.(vue)$": "<rootDir>/node_modules/vue-jest"
},
"snapshotSerializers": [
"<rootDir>/node_modules/jest-serializer-vue"
]
}
"name": "deck",
"description": "",
"version": "1.7.5",
"authors": [
{
"name": "Julius Härtl",
"email": "jus@bitgrid.net",
"role": "Developer"
},
{
"name": "Michael Weimann",
"email": "mail@michael-weimann.eu",
"role": "Developer"
}
],
"license": "agpl",
"private": true,
"scripts": {
"build": "NODE_ENV=production webpack --progress --config webpack.js",
"dev": "NODE_ENV=development webpack --progress --config webpack.js",
"watch": "NODE_ENV=development webpack --progress --watch --config webpack.js",
"lint": "eslint --ext .js,.vue src",
"lint:fix": "eslint --ext .js,.vue src --fix",
"stylelint": "stylelint src",
"stylelint:fix": "stylelint src --fix",
"test": "jest",
"test:coverage": "jest --coverage"
},
"dependencies": {
"@babel/polyfill": "^7.12.1",
"@babel/runtime": "^7.17.9",
"@juliushaertl/vue-richtext": "^1.0.1",
"@nextcloud/auth": "^1.3.0",
"@nextcloud/axios": "^1.9.0",
"@nextcloud/dialogs": "^3.1.2",
"@nextcloud/event-bus": "^2.1.1",
"@nextcloud/files": "^2.1.0",
"@nextcloud/initial-state": "^1.2.1",
"@nextcloud/l10n": "^1.4.1",
"@nextcloud/moment": "^1.2.0",
"@nextcloud/router": "^2.0.0",
"@nextcloud/vue": "^5.3.1",
"@nextcloud/vue-dashboard": "^2.0.1",
"blueimp-md5": "^2.19.0",
"dompurify": "^2.3.6",
"lodash": "^4.17.21",
"markdown-it": "^12.3.2",
"markdown-it-link-attributes": "^4.0.0",
"markdown-it-task-checkbox": "^1.0.6",
"moment": "^2.29.2",
"nextcloud-vue-collections": "^0.9.0",
"p-queue": "^6.6.2",
"url-search-params-polyfill": "^8.1.1",
"vue": "^2.6.14",
"vue-at": "^2.5.0-beta.2",
"vue-click-outside": "^1.1.0",
"vue-easymde": "^2.0.0",
"vue-infinite-loading": "^2.4.5",
"vue-router": "^3.5.3",
"vue-smooth-dnd": "^0.8.1",
"vuex": "^3.6.2",
"vuex-router-sync": "^5.0.0"
},
"browserslist": [
"extends @nextcloud/browserslist-config"
],
"engines": {
"node": "^14.0.0",
"npm": "^7.0.0"
},
"devDependencies": {
"@nextcloud/babel-config": "^1.0.0",
"@nextcloud/browserslist-config": "^2.2.0",
"@nextcloud/eslint-config": "^6.1.2",
"@nextcloud/stylelint-config": "^2.1.2",
"@nextcloud/webpack-vue-config": "^5.0.0",
"@relative-ci/agent": "^3.1.2",
"@vue/test-utils": "^1.3.0",
"jest": "^27.5.1",
"jest-serializer-vue": "^2.0.2",
"vue-jest": "^3.0.7"
},
"jest": {
"moduleFileExtensions": [
"js",
"vue"
],
"moduleNameMapper": {
"^@/(.*)$": "<rootDir>/src/$1"
},
"transform": {
"^.+\\.js$": "<rootDir>/node_modules/babel-jest",
".*\\.(vue)$": "<rootDir>/node_modules/vue-jest"
},
"snapshotSerializers": [
"<rootDir>/node_modules/jest-serializer-vue"
]
}
}

View File

@@ -7,9 +7,6 @@
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
errorBaseline="tests/psalm-baseline.xml"
>
<stubs>
<file name="tests/stub.phpstub" preloadClasses="true"/>
</stubs>
<projectFiles>
<directory name="lib" />
<ignoreFiles>

View File

@@ -21,13 +21,14 @@
-->
<template>
<NcContent app-name="deck" :class="{ 'nav-hidden': !navShown, 'sidebar-hidden': !sidebarRouterView }">
<Content id="content" app-name="deck" :class="{ 'nav-hidden': !navShown, 'sidebar-hidden': !sidebarRouterView }">
<AppNavigation />
<NcAppContent>
<AppContent>
<router-view />
</NcAppContent>
</AppContent>
<NcModal v-if="cardDetailsInModal && $route.params.cardId"
<Modal
v-if="cardDetailsInModal && $route.params.cardId"
:clear-view-delay="0"
:title="t('deck', 'Card details')"
size="large"
@@ -35,17 +36,18 @@
<div class="modal__content modal__card">
<router-view name="sidebar" />
</div>
</NcModal>
</Modal>
<router-view name="sidebar" :visible="!cardDetailsInModal || !$route.params.cardId" />
</NcContent>
</Content>
</template>
<script>
import { mapState } from 'vuex'
import AppNavigation from './components/navigation/AppNavigation.vue'
import { NcModal, NcContent, NcAppContent } from '@nextcloud/vue'
import { BoardApi } from './services/BoardApi.js'
import AppNavigation from './components/navigation/AppNavigation'
import { Modal, Content, AppContent } from '@nextcloud/vue'
import { BoardApi } from './services/BoardApi'
import { emit, subscribe } from '@nextcloud/event-bus'
const boardApi = new BoardApi()
@@ -54,9 +56,9 @@ export default {
name: 'App',
components: {
AppNavigation,
NcModal,
NcContent,
NcAppContent,
Modal,
Content,
AppContent,
},
provide() {
return {
@@ -128,7 +130,7 @@ export default {
<style lang="scss" scoped>
#content-vue {
#content {
#app-content {
transition: margin-left 100ms ease;
position: relative;
@@ -156,37 +158,6 @@ export default {
</style>
<style lang="scss">
@import '../css/print';
.icon-activity {
background-image: url(../img/activity-dark.svg);
body[data-theme-dark] & {
background-image: url(../img/activity.svg);
}
}
.avatardiv.circles {
background: var(--color-primary);
}
.icon-circles {
background-image: url(../img/circles-dark.svg);
opacity: 1;
background-size: 20px;
background-position: center center;
}
.icon-circles-white, .icon-circles.icon-white {
background-image: url(../img/circles.svg);
opacity: 1;
background-size: 20px;
background-position: center center;
}
.icon-colorpicker {
background-image: url('../img/color_picker.svg');
}
.multiselect {
width: 100%;

View File

@@ -21,7 +21,7 @@
-->
<template>
<NcModal @close="close">
<Modal @close="close">
<div id="modal-inner" :class="{ 'icon-loading': loading }">
<h1>{{ t('deck', 'Select the board to link to a project') }}</h1>
<input v-model="filter" type="text" :placeholder="t('deck', 'Search by board title')">
@@ -38,17 +38,17 @@
{{ t('deck', 'Select board') }}
</button>
</div>
</NcModal>
</Modal>
</template>
<script>
import { NcModal } from '@nextcloud/vue'
import Modal from '@nextcloud/vue/dist/Components/Modal'
import axios from '@nextcloud/axios'
import { generateUrl } from '@nextcloud/router'
export default {
name: 'BoardSelector',
components: {
NcModal,
Modal,
},
data() {
return {

View File

@@ -21,11 +21,11 @@
-->
<template>
<NcModal class="card-selector" @close="close">
<Modal class="card-selector" @close="close">
<div class="modal-scroller">
<div v-if="!creating && !created" id="modal-inner" :class="{ 'icon-loading': loading }">
<h3>{{ t('deck', 'Create a new card') }}</h3>
<NcMultiselect v-model="selectedBoard"
<Multiselect v-model="selectedBoard"
:placeholder="t('deck', 'Select a board')"
:options="boards"
:disabled="loading"
@@ -44,9 +44,9 @@
<span>{{ props.option.title }}</span>
</span>
</template>
</NcMultiselect>
</Multiselect>
<NcMultiselect v-model="selectedStack"
<Multiselect v-model="selectedStack"
:placeholder="t('deck', 'Select a list')"
:options="stacksFromBoard"
:max-height="100"
@@ -71,22 +71,12 @@
</div>
</div>
<div v-else id="modal-inner">
<NcEmptyContent v-if="creating">
<template #icon>
<NcLoadingIcon />
</template>
<template #title>
{{ t('deck', 'Creating the new card …') }}
</template>
</NcEmptyContent>
<NcEmptyContent v-else-if="created">
<template #icon>
<CardPlusOutline />
</template>
<template #title>
{{ t('deck', 'Card "{card}" was added to "{board}"', { card: pendingTitle, board: selectedBoard.title }) }}
</template>
<template #action>
<EmptyContent v-if="creating" icon="icon-loading">
{{ t('deck', 'Creating the new card ') }}
</EmptyContent>
<EmptyContent v-else-if="created" icon="icon-checkmark">
{{ t('deck', 'Card "{card}" was added to "{board}"', { card: pendingTitle, board: selectedBoard.title }) }}
<template #desc>
<button class="primary" @click="openNewCard">
{{ t('deck', 'Open card') }}
</button>
@@ -94,29 +84,28 @@
{{ t('deck', 'Close') }}
</button>
</template>
</NcEmptyContent>
</EmptyContent>
</div>
</div>
</NcModal>
</Modal>
</template>
<script>
import { generateUrl } from '@nextcloud/router'
import { NcModal, NcMultiselect, NcEmptyContent, NcLoadingIcon } from '@nextcloud/vue'
import CardPlusOutline from 'vue-material-design-icons/CardPlusOutline.vue'
import Modal from '@nextcloud/vue/dist/Components/Modal'
import Multiselect from '@nextcloud/vue/dist/Components/Multiselect'
import EmptyContent from '@nextcloud/vue/dist/Components/EmptyContent'
import axios from '@nextcloud/axios'
import { CardApi } from './services/CardApi.js'
import { CardApi } from './services/CardApi'
const cardApi = new CardApi()
export default {
name: 'CardCreateDialog',
components: {
NcEmptyContent,
NcModal,
NcMultiselect,
NcLoadingIcon,
CardPlusOutline,
EmptyContent,
Modal,
Multiselect,
},
props: {
title: {
@@ -216,7 +205,6 @@ export default {
max-width: 400px;
padding: 10px;
min-height: 200px;
margin: auto;
}
.multiselect-board, .multiselect-list, input, textarea {

View File

@@ -21,10 +21,10 @@
-->
<template>
<NcModal class="card-selector" @close="close">
<Modal class="card-selector" @close="close">
<div id="modal-inner" :class="{ 'icon-loading': loading }">
<h3>{{ title }}</h3>
<NcMultiselect v-model="selectedBoard"
<Multiselect v-model="selectedBoard"
:placeholder="t('deck', 'Select a board')"
:options="boards"
:disabled="loading"
@@ -42,9 +42,9 @@
<span>{{ props.option.title }}</span>
</span>
</template>
</NcMultiselect>
</Multiselect>
<NcMultiselect v-model="selectedCard"
<Multiselect v-model="selectedCard"
:placeholder="t('deck', 'Select a card')"
:options="cardsFromBoard"
:disabled="loading || selectedBoard === ''"
@@ -57,19 +57,20 @@
{{ t('deck', 'Cancel') }}
</button>
</div>
</NcModal>
</Modal>
</template>
<script>
import { generateUrl } from '@nextcloud/router'
import { NcModal, NcMultiselect } from '@nextcloud/vue'
import Modal from '@nextcloud/vue/dist/Components/Modal'
import Multiselect from '@nextcloud/vue/dist/Components/Multiselect'
import axios from '@nextcloud/axios'
export default {
name: 'CardSelector',
components: {
NcModal,
NcMultiselect,
Modal,
Multiselect,
},
props: {
title: {

View File

@@ -36,10 +36,10 @@
<script>
import RichText from '@juliushaertl/vue-richtext'
import { NcUserBubble } from '@nextcloud/vue'
import { UserBubble } from '@nextcloud/vue'
import moment from '@nextcloud/moment'
import DOMPurify from 'dompurify'
import relativeDate from '../mixins/relativeDate.js'
import relativeDate from '../mixins/relativeDate'
const InternalLink = {
name: 'InternalLink',
@@ -93,7 +93,7 @@ export default {
break
case 'user':
parameters[key] = {
component: NcUserBubble,
component: UserBubble,
props: {
user: parameters[key].id,
displayName: parameters[key].name,

View File

@@ -37,7 +37,7 @@
<script>
import axios from '@nextcloud/axios'
import { generateOcsUrl } from '@nextcloud/router'
import ActivityEntry from './ActivityEntry.vue'
import ActivityEntry from './ActivityEntry'
import InfiniteLoading from 'vue-infinite-loading'
const ACTIVITY_FETCH_LIMIT = 50
@@ -84,7 +84,20 @@ export default {
params.append('object_id', '' + this.objectId)
params.append('limit', ACTIVITY_FETCH_LIMIT)
const response = await axios.get(generateOcsUrl(`apps/activity/api/v2/activity/${this.filter}`) + '?' + params)
const response = await axios.get(
generateOcsUrl(`apps/activity/api/v2/activity/${this.filter}`) + '?' + params,
{
validateStatus: (status) => {
return (status >= 200 && status < 300) || status === 304
},
},
)
if (response.status === 304) {
this.endReached = true
return []
}
let activities = response.data.ocs.data
if (this.filter === 'deck') {
// We need to manually filter activities here, since currently we use two different types and there is no way
@@ -95,7 +108,7 @@ export default {
})
}
this.activities.push(...activities)
if (response.data.ocs.meta.statuscode === 304 || activities.length === 0) {
if (activities.length === 0) {
this.endReached = true
return []
}

View File

@@ -27,21 +27,24 @@
@drop.prevent="handleDropFiles">
<slot />
<transition name="fade" mode="out-in">
<div v-show="isDraggingOver"
<div
v-show="isDraggingOver"
class="dragover">
<div class="drop-hint">
<div class="drop-hint__icon"
<div
class="drop-hint__icon"
:class="{
'icon-upload' : !isReadOnly,
'icon-error' : isReadOnly}" />
<h2 class="drop-hint__text">
<h2
class="drop-hint__text">
{{ dropHintText }}
</h2>
</div>
</div>
</transition>
<NcModal v-if="modalShow" :title="t('deck', 'File already exists')" @close="modalShow=false">
<Modal v-if="modalShow" :title="t('deck', 'File already exists')" @close="modalShow=false">
<div class="modal__content">
<h2>{{ t('deck', 'File already exists') }}</h2>
<p>
@@ -57,13 +60,13 @@
{{ t('deck', 'Keep existing file') }}
</button>
</div>
</NcModal>
</Modal>
</div>
</template>
<script>
import { NcModal } from '@nextcloud/vue'
import attachmentUpload from '../mixins/attachmentUpload.js'
import { Modal } from '@nextcloud/vue'
import attachmentUpload from '../mixins/attachmentUpload'
import { loadState } from '@nextcloud/initial-state'
let maxUploadSizeState
@@ -75,7 +78,7 @@ try {
export default {
name: 'AttachmentDragAndDrop',
components: { NcModal },
components: { Modal },
mixins: [attachmentUpload],
props: {
cardId: {

View File

@@ -25,11 +25,11 @@
<div v-if="overviewName" class="board-title">
<div class="board-bullet icon-calendar-dark" />
<h2>{{ overviewName }}</h2>
<NcActions>
<NcActionButton icon="icon-add" @click="clickShowAddCardModel">
<Actions>
<ActionButton icon="icon-add" @click="clickShowAddCardModel">
{{ t('deck', 'Add card') }}
</NcActionButton>
</NcActions>
</ActionButton>
</Actions>
<CardCreateDialog v-if="showAddCardModal" @close="clickHideAddCardModel" />
</div>
<div v-else-if="board" class="board-title">
@@ -49,11 +49,11 @@
<div v-if="board && canManage && !showArchived && !board.archived"
id="stack-add"
v-click-outside="hideAddStack">
<NcActions v-if="!isAddStackVisible">
<NcActionButton icon="icon-add" @click.stop="showAddStack">
<Actions v-if="!isAddStackVisible">
<ActionButton icon="icon-add" @click.stop="showAddStack">
{{ t('deck', 'Add list') }}
</NcActionButton>
</NcActions>
</ActionButton>
</Actions>
<form v-else @submit.prevent="addNewStack()">
<label for="new-stack-input-main" class="hidden-visually">{{ t('deck', 'Add list') }}</label>
<input id="new-stack-input-main"
@@ -70,145 +70,137 @@
</form>
</div>
<div v-if="board" class="board-action-buttons">
<div class="board-action-buttons__filter">
<NcPopover container=".board-action-buttons__filter"
:placement="'bottom-end'"
:aria-label="t('deck', 'Active filters')"
@show="filterVisible=true"
@hide="filterVisible=false">
<!-- We cannot use NcActions here are the popover trigger does not update on reactive icons -->
<NcButton slot="trigger"
:title="t('deck', 'Apply filter')"
class="filter-button"
type="tertiary-no-background">
<template #icon>
<FilterIcon v-if="isFilterActive" :size="20" decorative />
<FilterOffIcon v-else :size="20" decorative />
</template>
</NcButton>
<Popover @show="filterVisible=true" @hide="filterVisible=false">
<Actions slot="trigger" :title="t('deck', 'Apply filter')">
<ActionButton v-if="isFilterActive" icon="icon-filter_set" />
<ActionButton v-else icon="icon-filter" />
</Actions>
<div v-if="filterVisible" class="filter">
<h3>{{ t('deck', 'Filter by tag') }}</h3>
<div v-for="label in labelsSorted" :key="label.id" class="filter--item">
<input :id="label.id"
v-model="filter.tags"
type="checkbox"
class="checkbox"
:value="label.id"
@change="setFilter">
<label :for="label.id"><span class="label" :style="labelStyle(label)">{{ label.title }}</span></label>
</div>
<h3>{{ t('deck', 'Filter by assigned user') }}</h3>
<div class="filter--item">
<input id="unassigned"
v-model="filter.unassigned"
type="checkbox"
class="checkbox"
value="unassigned"
@change="setFilter"
@click="beforeSetFilter">
<label for="unassigned">{{ t('deck', 'Unassigned') }}</label>
</div>
<div v-for="user in board.users" :key="user.uid" class="filter--item">
<input :id="user.uid"
v-model="filter.users"
type="checkbox"
class="checkbox"
:value="user.uid"
@change="setFilter">
<label :for="user.uid"><NcAvatar :user="user.uid" :size="24" :disable-menu="true" /> {{ user.displayname }}</label>
</div>
<h3>{{ t('deck', 'Filter by due date') }}</h3>
<div class="filter--item">
<input id="overdue"
v-model="filter.due"
type="radio"
class="radio"
value="overdue"
@change="setFilter"
@click="beforeSetFilter">
<label for="overdue">{{ t('deck', 'Overdue') }}</label>
</div>
<div class="filter--item">
<input id="dueToday"
v-model="filter.due"
type="radio"
class="radio"
value="dueToday"
@change="setFilter"
@click="beforeSetFilter">
<label for="dueToday">{{ t('deck', 'Next 24 hours') }}</label>
</div>
<div class="filter--item">
<input id="dueWeek"
v-model="filter.due"
type="radio"
class="radio"
value="dueWeek"
@change="setFilter"
@click="beforeSetFilter">
<label for="dueWeek">{{ t('deck', 'Next 7 days') }}</label>
</div>
<div class="filter--item">
<input id="dueMonth"
v-model="filter.due"
type="radio"
class="radio"
value="dueMonth"
@change="setFilter"
@click="beforeSetFilter">
<label for="dueMonth">{{ t('deck', 'Next 30 days') }}</label>
</div>
<div class="filter--item">
<input id="noDue"
v-model="filter.due"
type="radio"
class="radio"
value="noDue"
@change="setFilter"
@click="beforeSetFilter">
<label for="noDue">{{ t('deck', 'No due date') }}</label>
</div>
<NcButton :disabled="!isFilterActive" :wide="true" @click="clearFilter">
{{ t('deck', 'Clear filter') }}
</NcButton>
<div v-if="filterVisible" class="filter">
<h3>{{ t('deck', 'Filter by tag') }}</h3>
<div v-for="label in labelsSorted" :key="label.id" class="filter--item">
<input
:id="label.id"
v-model="filter.tags"
type="checkbox"
class="checkbox"
:value="label.id"
@change="setFilter">
<label :for="label.id"><span class="label" :style="labelStyle(label)">{{ label.title }}</span></label>
</div>
</NcPopover>
</div>
<NcActions>
<NcActionButton @click="toggleShowArchived">
<template #icon>
<ArchiveIcon :size="20" decorative />
</template>
<h3>{{ t('deck', 'Filter by assigned user') }}</h3>
<div class="filter--item">
<input
id="unassigned"
v-model="filter.unassigned"
type="checkbox"
class="checkbox"
value="unassigned"
@change="setFilter"
@click="beforeSetFilter">
<label for="unassigned">{{ t('deck', 'Unassigned') }}</label>
</div>
<div v-for="user in board.users" :key="user.uid" class="filter--item">
<input
:id="user.uid"
v-model="filter.users"
type="checkbox"
class="checkbox"
:value="user.uid"
@change="setFilter">
<label :for="user.uid"><Avatar :user="user.uid" :size="24" :disable-menu="true" /> {{ user.displayname }}</label>
</div>
<h3>{{ t('deck', 'Filter by due date') }}</h3>
<div class="filter--item">
<input
id="overdue"
v-model="filter.due"
type="radio"
class="radio"
value="overdue"
@change="setFilter"
@click="beforeSetFilter">
<label for="overdue">{{ t('deck', 'Overdue') }}</label>
</div>
<div class="filter--item">
<input
id="dueToday"
v-model="filter.due"
type="radio"
class="radio"
value="dueToday"
@change="setFilter"
@click="beforeSetFilter">
<label for="dueToday">{{ t('deck', 'Next 24 hours') }}</label>
</div>
<div class="filter--item">
<input
id="dueWeek"
v-model="filter.due"
type="radio"
class="radio"
value="dueWeek"
@change="setFilter"
@click="beforeSetFilter">
<label for="dueWeek">{{ t('deck', 'Next 7 days') }}</label>
</div>
<div class="filter--item">
<input
id="dueMonth"
v-model="filter.due"
type="radio"
class="radio"
value="dueMonth"
@change="setFilter"
@click="beforeSetFilter">
<label for="dueMonth">{{ t('deck', 'Next 30 days') }}</label>
</div>
<div class="filter--item">
<input
id="noDue"
v-model="filter.due"
type="radio"
class="radio"
value="noDue"
@change="setFilter"
@click="beforeSetFilter">
<label for="noDue">{{ t('deck', 'No due date') }}</label>
</div>
<Button :disabled="!isFilterActive" @click="clearFilter">
{{ t('deck', 'Clear filter') }}
</Button>
</div>
</Popover>
<Actions>
<ActionButton
icon="icon-archive"
@click="toggleShowArchived">
{{ showArchived ? t('deck', 'Hide archived cards') : t('deck', 'Show archived cards') }}
</NcActionButton>
<NcActionButton v-if="compactMode"
</ActionButton>
<ActionButton v-if="compactMode"
icon="icon-toggle-compact-collapsed"
@click="toggleCompactMode">
<ArrowExpandVerticalIcon slot="icon" :size="20" decorative />
{{ t('deck', 'Toggle compact mode') }}
</NcActionButton>
<NcActionButton v-else
</ActionButton>
<ActionButton v-else
icon="icon-toggle-compact-expanded"
@click="toggleCompactMode">
<ArrowCollapseVerticalIcon slot="icon" :size="20" decorative />
{{ t('deck', 'Toggle compact mode') }}
</NcActionButton>
</NcActions>
<!-- FIXME: NcActionRouter currently doesn't work as an inline action -->
<NcActions>
<NcActionButton icon="icon-menu-sidebar"
:aria-label="t('deck', 'Open details')"
:title="t('deck', 'Details')"
@click="toggleDetailsView" />
</NcActions>
</ActionButton>
</Actions>
<!-- FIXME: ActionRouter currently doesn't work as an inline action -->
<Actions :title="t('deck', 'Details')">
<ActionButton icon="icon-menu-sidebar" @click="toggleDetailsView" />
</Actions>
</div>
</div>
</div>
@@ -216,29 +208,14 @@
<script>
import { mapState, mapGetters } from 'vuex'
import { NcActions, NcActionButton, NcAvatar, NcButton, NcPopover } from '@nextcloud/vue'
import labelStyle from '../mixins/labelStyle.js'
import CardCreateDialog from '../CardCreateDialog.vue'
import ArchiveIcon from 'vue-material-design-icons/Archive.vue'
import FilterIcon from 'vue-material-design-icons/Filter.vue'
import FilterOffIcon from 'vue-material-design-icons/FilterOff.vue'
import ArrowCollapseVerticalIcon from 'vue-material-design-icons/ArrowCollapseVertical.vue'
import ArrowExpandVerticalIcon from 'vue-material-design-icons/ArrowExpandVertical.vue'
import { Actions, ActionButton, Popover, Avatar } from '@nextcloud/vue'
import labelStyle from '../mixins/labelStyle'
import CardCreateDialog from '../CardCreateDialog'
export default {
name: 'Controls',
components: {
NcActions,
NcActionButton,
NcButton,
NcPopover,
NcAvatar,
CardCreateDialog,
ArchiveIcon,
FilterIcon,
FilterOffIcon,
ArrowCollapseVerticalIcon,
ArrowExpandVerticalIcon,
Actions, ActionButton, Popover, Avatar, CardCreateDialog,
},
mixins: [labelStyle],
props: {
@@ -281,12 +258,18 @@ export default {
}
},
isFilterActive() {
return this.filter.tags.length !== 0 || this.filter.users.length !== 0 || this.filter.due !== ''
if (this.filter.tags.length !== 0 || this.filter.users.length !== 0 || this.filter.due !== '') {
return true
}
return false
},
labelsSorted() {
return [...this.board.labels].sort((a, b) => (a.title < b.title) ? -1 : 1)
},
},
beforeDestroy() {
this.setPageTitle('')
},
watch: {
board(current, previous) {
if (current?.id !== previous?.id) {
@@ -297,9 +280,6 @@ export default {
}
},
},
beforeDestroy() {
this.setPageTitle('')
},
methods: {
beforeSetFilter(e) {
if (this.filter.due === e.target.value) {
@@ -380,7 +360,7 @@ export default {
<style lang="scss" scoped>
.controls {
display: flex;
margin: 5px;
padding: 3px;
height: 44px;
padding-left: 44px;
@@ -428,15 +408,18 @@ export default {
.board-action-buttons {
display: flex;
button {
border: 0;
width: 44px;
margin: 0 0 0 -1px;
background-color: transparent;
}
}
.deck-search {
display: flex;
align-items: center;
justify-content: center;
input[type=search] {
background-position: 5px;
padding-left: 24px !important;
padding-left: 24px;
}
}
@@ -458,9 +441,8 @@ export default {
}
.filter {
width: 240px;
max-height: calc(100vh - 150px);
position: relative;
width: 250px;
max-height: 80vh;
overflow: auto;
padding: 8px;
}
@@ -469,23 +451,8 @@ export default {
margin-top: 0px;
margin-bottom: 5px;
}
.filter-button {
padding: 0;
border-radius: 50%;
width: 44px;
height: 44px;
&:hover, &:focus {
background-color: rgba(127,127,127,0.25) !important;
}
}
</style>
<style lang="scss">
.popover:focus {
outline: 2px solid var(--color-main-text);
}
.tooltip-inner.popover-inner {
text-align: left;
}

View File

@@ -45,7 +45,6 @@ export default {
#app-sidebar .icon-close {
z-index: 100;
}
.app-deck .app-sidebar {
z-index: 1500 !important;
}

View File

@@ -30,14 +30,9 @@
<h2>{{ t('deck', 'Loading board') }}</h2>
<p />
</div>
<NcEmptyContent v-else-if="isEmpty" key="empty">
<template #icon>
<DeckIcon />
</template>
<template #title>
{{ t('deck', 'No lists available') }}
</template>
<template v-if="canManage" #action>
<EmptyContent v-else-if="isEmpty" key="empty" icon="icon-deck">
{{ t('deck', 'No lists available') }}
<template v-if="canManage" #desc>
{{ t('deck', 'Create a new list to add cards to this board') }}
<form @submit.prevent="addNewStack()">
<input id="new-stack-input-main"
@@ -53,7 +48,7 @@
value="">
</form>
</template>
</NcEmptyContent>
</EmptyContent>
<div v-else-if="!isEmpty && !loading" key="board" class="board">
<Container lock-axix="y"
orientation="horizontal"
@@ -78,12 +73,11 @@
import { Container, Draggable } from 'vue-smooth-dnd'
import { mapState, mapGetters } from 'vuex'
import Controls from '../Controls.vue'
import DeckIcon from '../icons/DeckIcon.vue'
import Stack from './Stack.vue'
import { NcEmptyContent } from '@nextcloud/vue'
import GlobalSearchResults from '../search/GlobalSearchResults.vue'
import { showError } from '../../helpers/errors.js'
import Controls from '../Controls'
import Stack from './Stack'
import { EmptyContent } from '@nextcloud/vue'
import GlobalSearchResults from '../search/GlobalSearchResults'
import { showError } from '../../helpers/errors'
export default {
name: 'Board',
@@ -91,10 +85,9 @@ export default {
GlobalSearchResults,
Controls,
Container,
DeckIcon,
Draggable,
Stack,
NcEmptyContent,
EmptyContent,
},
inject: [
'boardApi',
@@ -170,8 +163,8 @@ export default {
<style lang="scss" scoped>
@import '../../css/animations';
@import '../../css/variables';
@import '../../css/animations.scss';
@import '../../css/variables.scss';
form {
text-align: center;
@@ -229,7 +222,6 @@ export default {
padding: $stack-spacing;
overflow-x: hidden;
overflow-y: auto;
scrollbar-gutter: stable;
padding-top: 15px;
margin-top: -10px;
}

View File

@@ -21,57 +21,57 @@
-->
<template>
<NcAppSidebar v-if="board != null"
<AppSidebar v-if="board != null"
:actions="[]"
:title="board.title"
@close="closeSidebar">
<NcAppSidebarTab id="sharing"
<AppSidebarTab id="sharing"
:order="0"
:name="t('deck', 'Sharing')"
icon="icon-shared">
<SharingTabSidebar :board="board" />
</NcAppSidebarTab>
</AppSidebarTab>
<NcAppSidebarTab id="tags"
<AppSidebarTab id="tags"
:order="1"
:name="t('deck', 'Tags')"
icon="icon-tag">
<TagsTabSidebar :board="board" />
</NcAppSidebarTab>
</AppSidebarTab>
<NcAppSidebarTab v-if="canEdit"
<AppSidebarTab v-if="canEdit"
id="deleted"
:order="2"
:name="t('deck', 'Deleted items')"
icon="icon-delete">
<DeletedTabSidebar :board="board" />
</NcAppSidebarTab>
</AppSidebarTab>
<NcAppSidebarTab v-if="hasActivity"
<AppSidebarTab v-if="hasActivity"
id="activity"
:order="3"
:name="t('deck', 'Timeline')"
icon="icon-activity">
<TimelineTabSidebar :board="board" />
</NcAppSidebarTab>
</NcAppSidebar>
</AppSidebarTab>
</AppSidebar>
</template>
<script>
import { mapState, mapGetters } from 'vuex'
import SharingTabSidebar from './SharingTabSidebar.vue'
import TagsTabSidebar from './TagsTabSidebar.vue'
import DeletedTabSidebar from './DeletedTabSidebar.vue'
import TimelineTabSidebar from './TimelineTabSidebar.vue'
import { NcAppSidebar, NcAppSidebarTab } from '@nextcloud/vue'
import SharingTabSidebar from './SharingTabSidebar'
import TagsTabSidebar from './TagsTabSidebar'
import DeletedTabSidebar from './DeletedTabSidebar'
import TimelineTabSidebar from './TimelineTabSidebar'
import { AppSidebar, AppSidebarTab } from '@nextcloud/vue'
const capabilities = window.OC.getCapabilities()
export default {
name: 'BoardSidebar',
components: {
NcAppSidebar,
NcAppSidebarTab,
AppSidebar,
AppSidebarTab,
SharingTabSidebar,
TagsTabSidebar,
DeletedTabSidebar,

View File

@@ -8,7 +8,8 @@
<span>{{ deletedStack.title }}</span>
<span class="timestamp">{{ relativeDate(deletedStack.deletedAt*1000) }}</span>
</div>
<button :title="t('settings', 'Undo')"
<button
:title="t('settings', 'Undo')"
class="app-navigation-entry-deleted-button icon-history"
@click="stackUndoDelete(deletedStack)" />
</li>
@@ -22,7 +23,8 @@
<span>{{ deletedCard.title }}</span>
<span class="timestamp">{{ relativeDate(deletedCard.deletedAt*1000) }}</span>
</div>
<button :title="t('settings', 'Undo')"
<button
:title="t('settings', 'Undo')"
class="app-navigation-entry-deleted-button icon-history"
@click="cardUndoDelete(deletedCard)" />
</li>
@@ -32,7 +34,7 @@
<script>
import { mapState } from 'vuex'
import relativeDate from '../../mixins/relativeDate.js'
import relativeDate from '../../mixins/relativeDate'
export default {
name: 'DeletedTabSidebar',

View File

@@ -1,6 +1,7 @@
<template>
<div>
<NcMultiselect v-if="canShare"
<Multiselect
v-if="canShare"
v-model="addAcl"
:placeholder="t('deck', 'Share board with a user, group or circle …')"
:options="formatedSharees"
@@ -18,12 +19,13 @@
<template #noResult>
{{ isSearching ? t('deck', 'Searching for users, groups and circles …') : t('deck', 'No participants found') }}
</template>
</NcMultiselect>
</Multiselect>
<ul id="shareWithList"
<ul
id="shareWithList"
class="shareWithList">
<li>
<NcAvatar :user="board.owner.uid" />
<Avatar :user="board.owner.uid" />
<span class="has-tooltip username">
{{ board.owner.displayname }}
<span v-if="!isCurrentUser(board.owner.uid)" class="board-owner-label">
@@ -32,7 +34,7 @@
</span>
</li>
<li v-for="acl in board.acl" :key="acl.id">
<NcAvatar v-if="acl.type===0" :user="acl.participant.uid" />
<Avatar v-if="acl.type===0" :user="acl.participant.uid" />
<div v-if="acl.type===1" class="avatardiv icon icon-group" />
<div v-if="acl.type===7" class="avatardiv icon icon-circles" />
<span class="has-tooltip username">
@@ -41,31 +43,27 @@
<span v-if="acl.type===7">{{ t('deck', '(Circle)') }}</span>
</span>
<NcActionCheckbox v-if="!(isCurrentUser(acl.participant.uid) && acl.type === 0) && (canManage || (canEdit && canShare))" :checked="acl.permissionEdit" @change="clickEditAcl(acl)">
<ActionCheckbox v-if="!(isCurrentUser(acl.participant.uid) && acl.type === 0) && (canManage || (canEdit && canShare))" :checked="acl.permissionEdit" @change="clickEditAcl(acl)">
{{ t('deck', 'Can edit') }}
</NcActionCheckbox>
<NcActions v-if="!(isCurrentUser(acl.participant.uid) && acl.type === 0)" :force-menu="true">
<NcActionCheckbox v-if="canManage || canShare" :checked="acl.permissionShare" @change="clickShareAcl(acl)">
</ActionCheckbox>
<Actions v-if="!(isCurrentUser(acl.participant.uid) && acl.type === 0)" :force-menu="true">
<ActionCheckbox v-if="canManage || canShare" :checked="acl.permissionShare" @change="clickShareAcl(acl)">
{{ t('deck', 'Can share') }}
</NcActionCheckbox>
<NcActionCheckbox v-if="canManage" :checked="acl.permissionManage" @change="clickManageAcl(acl)">
</ActionCheckbox>
<ActionCheckbox v-if="canManage" :checked="acl.permissionManage" @change="clickManageAcl(acl)">
{{ t('deck', 'Can manage') }}
</NcActionCheckbox>
<NcActionCheckbox v-if="acl.type === 0 && isCurrentUser(board.owner.uid)" :checked="acl.owner" @change="clickTransferOwner(acl.participant.uid)">
</ActionCheckbox>
<ActionCheckbox v-if="acl.type === 0 && isCurrentUser(board.owner.uid)" :checked="acl.owner" @change="clickTransferOwner(acl.participant.uid)">
{{ t('deck', 'Owner') }}
</NcActionCheckbox>
<NcActionButton v-if="canManage" icon="icon-delete" @click="clickDeleteAcl(acl)">
</ActionCheckbox>
<ActionButton v-if="canManage" icon="icon-delete" @click="clickDeleteAcl(acl)">
{{ t('deck', 'Delete') }}
</NcActionButton>
</NcActions>
</ActionButton>
</Actions>
</li>
</ul>
<NcRelatedResourcesPanel v-if="board.id"
provider-id="deck"
:item-id="board.id" />
<CollectionList v-if="projectsEnabled && board.id"
<CollectionList v-if="board.id"
:id="`${board.id}`"
:name="board.title"
type="deck" />
@@ -73,24 +71,22 @@
</template>
<script>
import { NcAvatar, NcMultiselect, NcActions, NcActionButton, NcActionCheckbox, NcRelatedResourcesPanel } from '@nextcloud/vue'
import { Avatar, Multiselect, Actions, ActionButton, ActionCheckbox } from '@nextcloud/vue'
import { CollectionList } from 'nextcloud-vue-collections'
import { mapGetters, mapState } from 'vuex'
import { getCurrentUser } from '@nextcloud/auth'
import { showError, showSuccess } from '@nextcloud/dialogs'
import { loadState } from '@nextcloud/initial-state'
import debounce from 'lodash/debounce'
export default {
name: 'SharingTabSidebar',
components: {
NcAvatar,
NcActions,
NcActionButton,
NcActionCheckbox,
NcMultiselect,
Avatar,
Actions,
ActionButton,
ActionCheckbox,
Multiselect,
CollectionList,
NcRelatedResourcesPanel,
},
props: {
board: {
@@ -105,7 +101,6 @@ export default {
addAcl: null,
addAclForAPI: null,
newOwner: null,
projectsEnabled: loadState('core', 'projects_enabled', false),
}
},
computed: {
@@ -205,7 +200,7 @@ export default {
},
clickTransferOwner(newOwner) {
OC.dialogs.confirmDestructive(
t('deck', 'Are you sure you want to transfer the board {title} to {user}?', { title: this.board.title, user: newOwner }),
t('deck', 'Are you sure you want to transfer the board {title} for {user}?', { title: this.board.title, user: newOwner }),
t('deck', 'Transfer the board.'),
{
type: OC.dialogs.YES_NO_BUTTONS,
@@ -219,13 +214,13 @@ export default {
this.isLoading = true
await this.$store.dispatch('transferOwnership', {
boardId: this.board.id,
newOwner,
newOwner
})
const successMessage = t('deck', 'The board has been transferred to {user}', { user: newOwner })
const successMessage = t('deck', 'Transfer the board for {user} successfully', { user: newOwner })
showSuccess(successMessage)
this.$router.push({ name: 'main' })
} catch (e) {
const errorMessage = t('deck', 'Failed to transfer the board to {user}', { user: newOwner.user })
const errorMessage = t('deck', 'Failed to transfer the board for {user}', { user: newOwner.user })
showError(errorMessage)
} finally {
this.isLoading = false

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