Compare commits
133 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c0a8a00131 | ||
|
|
b686d446b1 | ||
|
|
8e60717cca | ||
|
|
b8b4d708f3 | ||
|
|
5bbd88be0b | ||
|
|
60e18f3556 | ||
|
|
4aef4db2c9 | ||
|
|
bb1022ac62 | ||
|
|
d36cc8e8b3 | ||
|
|
2221ed53b0 | ||
|
|
ae3a67bd43 | ||
|
|
c640b31384 | ||
|
|
546a3008b5 | ||
|
|
c25bd37971 | ||
|
|
36028cdfeb | ||
|
|
85ea22ff0c | ||
|
|
8cf08ddd08 | ||
|
|
5668abacec | ||
|
|
5ffdc3ec60 | ||
|
|
7d72a67c4c | ||
|
|
bab74ced75 | ||
|
|
f6a58bb8b7 | ||
|
|
5dacdf070e | ||
|
|
890291ccaa | ||
|
|
89771438f8 | ||
|
|
508bf95378 | ||
|
|
c15160dad1 | ||
|
|
7590f1d625 | ||
|
|
c7f09cbf82 | ||
|
|
4e14dfb15f | ||
|
|
84fe5bd9ef | ||
|
|
8cebc35573 | ||
|
|
37b88d0afc | ||
|
|
647bcd3167 | ||
|
|
30629aaacc | ||
|
|
0fbda02b80 | ||
|
|
4763a0621c | ||
|
|
fc7eda5706 | ||
|
|
2fdf50620e | ||
|
|
f20a91553f | ||
|
|
8283aa67f0 | ||
|
|
ababa900bb | ||
|
|
e147b43eb9 | ||
|
|
65675cdbde | ||
|
|
d32e942908 | ||
|
|
32a65e856c | ||
|
|
01522e69ea | ||
|
|
49d356f04f | ||
|
|
04e5310643 | ||
|
|
a293467b59 | ||
|
|
c2546206a3 | ||
|
|
9c406a34c5 | ||
|
|
360b4f57f5 | ||
|
|
460d06fe10 | ||
|
|
b3b2ee1966 | ||
|
|
7092dc06ab | ||
|
|
c47829a3d9 | ||
|
|
54479eee20 | ||
|
|
cdd788a6b8 | ||
|
|
f5242cd10c | ||
|
|
f0299486d6 | ||
|
|
38921cade8 | ||
|
|
8a3e679c33 | ||
|
|
d1b81e697f | ||
|
|
215fcf61bc | ||
|
|
e418373503 | ||
|
|
ca22b0ad2c | ||
|
|
e4cbc694d4 | ||
|
|
f53e51fc4e | ||
|
|
dcbbb22dda | ||
|
|
e85042e1b4 | ||
|
|
a720669354 | ||
|
|
216b9445d3 | ||
|
|
b21faa8501 | ||
|
|
1bc28c68a5 | ||
|
|
f78f8bfd7f | ||
|
|
01bddf029e | ||
|
|
bdead3cdd5 | ||
|
|
88d164b411 | ||
|
|
1638c3d350 | ||
|
|
454d515192 | ||
|
|
e60219c9df | ||
|
|
5c8c73f2ac | ||
|
|
fad63ac6f5 | ||
|
|
31eb8d6698 | ||
|
|
40967a4ee6 | ||
|
|
bfe9b05d69 | ||
|
|
82e3400162 | ||
|
|
a886b4ee78 | ||
|
|
618fb50618 | ||
|
|
f7aae7912d | ||
|
|
2976604b7b | ||
|
|
bbe482586b | ||
|
|
ff61238487 | ||
|
|
9e2dcb686f | ||
|
|
fcc96ca98d | ||
|
|
a43cee8a5d | ||
|
|
f4ccc506af | ||
|
|
fee49f3699 | ||
|
|
d43c7a48cc | ||
|
|
c0fad295b5 | ||
|
|
cb1314f067 | ||
|
|
ba68e4c2f7 | ||
|
|
bd8fd6a66b | ||
|
|
0eba8d0840 | ||
|
|
8fc95dc40d | ||
|
|
ecd3e25588 | ||
|
|
914f912612 | ||
|
|
e68f723095 | ||
|
|
5f71be2e7f | ||
|
|
bc2a72f035 | ||
|
|
cf4be82827 | ||
|
|
23580705aa | ||
|
|
65c8c394a8 | ||
|
|
422788a6a3 | ||
|
|
2d5e29de5d | ||
|
|
2a307b92a7 | ||
|
|
2d8dbc70ad | ||
|
|
cfee259b38 | ||
|
|
f94cdb3ebb | ||
|
|
1ed50fdca6 | ||
|
|
56e460004f | ||
|
|
a95f78d188 | ||
|
|
df09a9a7b2 | ||
|
|
990ee2aef9 | ||
|
|
486ecd12db | ||
|
|
c9cdd7bb11 | ||
|
|
2c753fd084 | ||
|
|
79d2d2f3f5 | ||
|
|
24d9b55bfc | ||
|
|
28cd9fcf77 | ||
|
|
d8a36f0602 | ||
|
|
de06033dcd |
@@ -1,8 +1,8 @@
|
||||
module.exports = {
|
||||
extends: [
|
||||
'@nextcloud',
|
||||
'@nextcloud'
|
||||
],
|
||||
rules: {
|
||||
'valid-jsdoc': ['off'],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
4
.github/workflows/appbuild.yml
vendored
4
.github/workflows/appbuild.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x]
|
||||
node-version: [12.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
@@ -17,8 +17,6 @@ jobs:
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Set up npm7
|
||||
run: npm i -g npm@7
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v1
|
||||
with:
|
||||
|
||||
2
.github/workflows/integration.yml
vendored
2
.github/workflows/integration.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
matrix:
|
||||
php-versions: ['7.4']
|
||||
databases: ['sqlite', 'mysql', 'pgsql']
|
||||
server-versions: ['stable22']
|
||||
server-versions: ['stable21']
|
||||
|
||||
name: php${{ matrix.php-versions }}-${{ matrix.databases }}-${{ matrix.server-versions }}
|
||||
|
||||
|
||||
11
.github/workflows/lint.yml
vendored
11
.github/workflows/lint.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php-versions: ['7.3', '7.4']
|
||||
php-versions: ['7.2', '7.3', '7.4']
|
||||
|
||||
name: php${{ matrix.php-versions }} lint
|
||||
steps:
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x]
|
||||
node-version: [12.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@@ -55,8 +55,6 @@ jobs:
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Set up npm7
|
||||
run: npm i -g npm@7
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: ESLint
|
||||
@@ -67,7 +65,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-versions: [14.x]
|
||||
node-versions: [12.x]
|
||||
|
||||
name: stylelint node${{ matrix.node-versions }}
|
||||
steps:
|
||||
@@ -78,9 +76,6 @@ jobs:
|
||||
with:
|
||||
node-versions: ${{ matrix.node-versions }}
|
||||
|
||||
- name: Set up npm7
|
||||
run: npm i -g npm@7
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
|
||||
4
.github/workflows/nightly.yml
vendored
4
.github/workflows/nightly.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x]
|
||||
node-version: [12.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
@@ -22,8 +22,6 @@ jobs:
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Set up npm7
|
||||
run: npm i -g npm@7
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v1
|
||||
with:
|
||||
|
||||
4
.github/workflows/nodejs.yml
vendored
4
.github/workflows/nodejs.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x]
|
||||
node-version: [12.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
@@ -17,8 +17,6 @@ jobs:
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Set up npm7
|
||||
run: npm i -g npm@7
|
||||
- name: install dependencies
|
||||
run: |
|
||||
npm ci
|
||||
|
||||
2
.github/workflows/phpunit.yml
vendored
2
.github/workflows/phpunit.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
matrix:
|
||||
php-versions: ['7.3', '7.4']
|
||||
databases: ['sqlite', 'mysql', 'pgsql']
|
||||
server-versions: ['stable22']
|
||||
server-versions: ['stable21']
|
||||
|
||||
name: php${{ matrix.php-versions }}-${{ matrix.databases }}-${{ matrix.server-versions }}
|
||||
|
||||
|
||||
2
.github/workflows/static-analysis.yml
vendored
2
.github/workflows/static-analysis.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
ocp-version: [ 'dev-stable22' ]
|
||||
ocp-version: [ 'dev-stable21' ]
|
||||
name: Nextcloud ${{ matrix.ocp-version }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
||||
162
CHANGELOG.md
162
CHANGELOG.md
@@ -1,116 +1,80 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## 1.5.7
|
||||
|
||||
### Added
|
||||
|
||||
- Transfer ownership @juliushaertl [#3665](https://github.com/nextcloud/deck/pull/3665)
|
||||
## 1.4.8
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix: Check all circle shares for permissions [#3721](https://github.com/nextcloud/deck/pull/3721)
|
||||
- Add a missing translation - not found in transifex [#3707](https://github.com/nextcloud/deck/pull/3707)
|
||||
- 🐛 Fix missing files sidebar [#3642](https://github.com/nextcloud/deck/pull/3642)
|
||||
- [stable23] Use explicit cast to make use of index [#3731](https://github.com/nextcloud/deck/pull/3731)
|
||||
- Fix hidden attachment icon on archived cards [#3735](https://github.com/nextcloud/deck/pull/3735)
|
||||
- [stable23] Sort boards non case sensitive [#3739](https://github.com/nextcloud/deck/pull/3739)
|
||||
- add autofocus on board edit #3326 @juliushaertl [#3743](https://github.com/nextcloud/deck/pull/3743)
|
||||
- Fix paramter replacements when creating deck cards from talk messages @juliushaertl [#3742](https://github.com/nextcloud/deck/pull/3742)
|
||||
- Fix text selection in dark mode and modal view [#3767](https://github.com/nextcloud/deck/pull/3767)
|
||||
- Fix cursor generation if no results are found [#3461](https://api.github.com/repos/nextcloud/deck/pulls/3461)
|
||||
- Allow to download an attachment without navigating to the files app [#3442](https://api.github.com/repos/nextcloud/deck/pulls/3442)
|
||||
- Exclude deleted boards in the selection for target [#3525](https://api.github.com/repos/nextcloud/deck/pulls/3525)
|
||||
- Make insert attachment buttom easy to click [#3616](https://api.github.com/repos/nextcloud/deck/pulls/3616)
|
||||
- Fix confusion between stackId and boardId in StackService [#3545](https://api.github.com/repos/nextcloud/deck/pulls/3545)
|
||||
|
||||
### Other
|
||||
|
||||
- Properly check for the stack AND setting board permissions [#3714](https://github.com/nextcloud/deck/pull/3714)
|
||||
- Add missing indices [#3756](https://github.com/nextcloud/deck/pull/3756)
|
||||
|
||||
|
||||
## 1.5.6
|
||||
## 1.4.7
|
||||
|
||||
### Fixed
|
||||
|
||||
- Allow to download an attachment without navigating to the files app [#3441](https://api.github.com/repos/nextcloud/deck/pulls/3441)
|
||||
- Fix CalDAV blocking and modernize circles API usage [#3527](https://api.github.com/repos/nextcloud/deck/pulls/3527)
|
||||
- CardApiController: Fix order of optional parameters [#3521](https://api.github.com/repos/nextcloud/deck/pulls/3521)
|
||||
- Fix cursor generation if no results are found [#3460](https://api.github.com/repos/nextcloud/deck/pulls/3460)
|
||||
- Exclude deleted boards in the selection for target [#3524](https://api.github.com/repos/nextcloud/deck/pulls/3524)
|
||||
- Generate fixed link for activity emails [#3627](https://api.github.com/repos/nextcloud/deck/pulls/3627)
|
||||
- Make insert attachment buttom easy to click [#3615](https://api.github.com/repos/nextcloud/deck/pulls/3615)
|
||||
- Fix confusion between stackId and boardId in StackService [#3544](https://api.github.com/repos/nextcloud/deck/pulls/3544)
|
||||
|
||||
## 1.5.5
|
||||
|
||||
- Fix release asset build
|
||||
|
||||
## 1.5.4
|
||||
## 1.4.6
|
||||
|
||||
### Fixed
|
||||
|
||||
- #3378 Fix menu button position in card modal
|
||||
- #3392 Use displayname instead of uid for mentions (reopened against master)
|
||||
- #3361 Improve combined search @eneiluj
|
||||
- #3381 Extend drag-and-drop zone in card sidebar @Artem4590
|
||||
- #3366 Fix optional parameter order
|
||||
- #3407 Keep exceptions http response generic
|
||||
- #3379 Fix menu button position in card modal
|
||||
- #3360 Improve combined search @eneiluj
|
||||
- #3367 Fix optional parameter order
|
||||
- #3393 Use displayname instead of uid for mentions
|
||||
- #3359 Rich object string parameters for notifications @juliushaertl
|
||||
- #3385 Extend drag-and-drop zone in card sidebar @Artem4590
|
||||
- #3408 Keep exceptions http response generic
|
||||
|
||||
|
||||
## 1.5.3
|
||||
|
||||
### Fied
|
||||
|
||||
- #3317 Additional check for stacks
|
||||
|
||||
|
||||
## 1.5.2
|
||||
## 1.4.5
|
||||
|
||||
### Fixed
|
||||
|
||||
- #3300 Fix print style issues
|
||||
- #3303 Delete file shares through attachments API
|
||||
- #3306 Return false instead of throwing when getting calendar setting
|
||||
- #3318 Additional check for stacks
|
||||
|
||||
## 1.5.1 - 2021-09-03
|
||||
|
||||
## 1.4.4
|
||||
|
||||
### Fixed
|
||||
|
||||
- #3224 Move circle checks to a unified service and improve member checks
|
||||
- #3231 Check for null value to avoid TypeError in the group manager
|
||||
- #3264 Defer obtaining the user session in the config service
|
||||
- #3301 Fix print style issues
|
||||
- #3307 Return false instead of throwing when getting calendar setting
|
||||
- #3227 Additional circle level check
|
||||
- #3304 Delete file shares through attachments API
|
||||
|
||||
|
||||
## 1.5.0 - 2021-07-09
|
||||
|
||||
### Added
|
||||
|
||||
* Nextcloud 22 compatibility
|
||||
* [#3105](https://github.com/nextcloud/deck/pull/3105) Compatibility with Cirlces changes in 22
|
||||
* [#3147](https://github.com/nextcloud/deck/pull/3147) Add card button to the dashboard widget @jakobroehrl
|
||||
* [#2854](https://github.com/nextcloud/deck/pull/2854) Add card button in card overview @jakobroehrl
|
||||
* [#3078](https://github.com/nextcloud/deck/pull/3078) Show on shared boards unassigned cards to all users @jakobroehrl
|
||||
## 1.4.3 - 2021-07-09
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#2935](https://github.com/nextcloud/deck/pull/2935) Rich object string parameters for notifications @nickvergessen
|
||||
* [#2950](https://github.com/nextcloud/deck/pull/2950) Remove notification on unshare and add type hints
|
||||
* [#2983](https://github.com/nextcloud/deck/pull/2983) Fix codemirror description width
|
||||
* [#2989](https://github.com/nextcloud/deck/pull/2989) Fix unified comments search with postgres
|
||||
* [#3005](https://github.com/nextcloud/deck/pull/3005) Do not query the lookupserver when looking for sharees
|
||||
* [#3011](https://github.com/nextcloud/deck/pull/3011) L10n: Spelling unification @Valdnet
|
||||
* [#3014](https://github.com/nextcloud/deck/pull/3014) Proper error handling when fetching comments fails
|
||||
* [#3016](https://github.com/nextcloud/deck/pull/3016) Allow searching for filters without a query to match all that have a given filter set
|
||||
* [#3021](https://github.com/nextcloud/deck/pull/3021) L10n: Add word "Card" @Valdnet
|
||||
* [#3025](https://github.com/nextcloud/deck/pull/3025) Show comment counter and highlight if unread comments are available
|
||||
* [#3036](https://github.com/nextcloud/deck/pull/3036) Add link to migration tool for Trello @maxammann
|
||||
* [#3037](https://github.com/nextcloud/deck/pull/3037) Catch any error during circle detail fetching
|
||||
* [#3038](https://github.com/nextcloud/deck/pull/3038) Get attachment from the user node instead of the share source
|
||||
* [#3092](https://github.com/nextcloud/deck/pull/3092) Refactor update to have proper order of optional parameters
|
||||
* [#3113](https://github.com/nextcloud/deck/pull/3113) Use new viewer syntax with destructuring object @azul
|
||||
* [#3142](https://github.com/nextcloud/deck/pull/3142) Always pass user id in share provider
|
||||
* [#3152](https://github.com/nextcloud/deck/pull/3152) Only offer stack creation in emptycontent with proper permissions
|
||||
* [#3165](https://github.com/nextcloud/deck/pull/3165) Always log generic exceptions
|
||||
* [#3168](https://github.com/nextcloud/deck/pull/3168) Reduce duplicate queries when fetching user boards an permissions
|
||||
* [#3143](https://github.com/nextcloud/deck/pull/3143) Always pass user id in share provider
|
||||
* [#3153](https://github.com/nextcloud/deck/pull/3153) Only offer stack creation in emptycontent with proper permissions
|
||||
* [#3164](https://github.com/nextcloud/deck/pull/3164) Always log generic exceptions
|
||||
* [#3169](https://github.com/nextcloud/deck/pull/3169) Reduce duplicate queries when fetching user boards an permissions
|
||||
|
||||
|
||||
## 1.4.2 - 2021-05-03
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#3030](https://github.com/nextcloud/deck/pull/3030) Proper error handling when fetching comments fails
|
||||
* [#3031](https://github.com/nextcloud/deck/pull/3031) Allow searching for filters without a query to match all that have a given filter set
|
||||
* [#3039](https://github.com/nextcloud/deck/pull/3039) Catch any error during circle detail fetching
|
||||
* [#3040](https://github.com/nextcloud/deck/pull/3040) Get attachment from the user node instead of the share source
|
||||
|
||||
## 1.4.1 - 2021-04-20
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#2984](https://github.com/nextcloud/deck/pull/2984) Fix codemirror description width
|
||||
* [#2990](https://github.com/nextcloud/deck/pull/2990) Fix unified comments search with postgres
|
||||
* [#2994](https://github.com/nextcloud/deck/pull/2994) Remove notification on unshare and add type hints
|
||||
* [#3006](https://github.com/nextcloud/deck/pull/3006) Only import debounce
|
||||
* [#3008](https://github.com/nextcloud/deck/pull/3008) Do not query the lookupserver when looking for sharees
|
||||
|
||||
|
||||
## 1.4.0 - 2021-04-13
|
||||
|
||||
@@ -146,15 +110,15 @@ All notable changes to this project will be documented in this file.
|
||||
## 1.3.0-beta2
|
||||
|
||||
### Fixed
|
||||
* [#2700](https://github.com/nextcloud/deck/pull/2700) Attempt to copy file on dropping it to deck
|
||||
* [#2701](https://github.com/nextcloud/deck/pull/2701) Fix uploading files by drag and drop
|
||||
* [#2700](https://github.com/nextcloud/deck/pull/2700) Attempt to copy file on dropping it to deck @juliushaertl
|
||||
* [#2701](https://github.com/nextcloud/deck/pull/2701) Fix uploading files by drag and drop @juliushaertl
|
||||
* [#2707](https://github.com/nextcloud/deck/pull/2707) L10n: Change to a capital letter @Valdnet
|
||||
* [#2712](https://github.com/nextcloud/deck/pull/2712) Docs: Fix table in section "GET /api/v1.0/config" @das-g
|
||||
* [#2716](https://github.com/nextcloud/deck/pull/2716) Remove repair step which is no longer needed as we cleanup properly
|
||||
* [#2716](https://github.com/nextcloud/deck/pull/2716) Remove repair step which is no longer needed as we cleanup properly @juliushaertl
|
||||
* [#2723](https://github.com/nextcloud/deck/pull/2723) Pad random color with leading zeroes @PVince81
|
||||
* [#2729](https://github.com/nextcloud/deck/pull/2729) Remove invalid activity parameters @nickvergessen
|
||||
* [#2750](https://github.com/nextcloud/deck/pull/2750) Fix deck activity emails not being translated @nickvergessen
|
||||
* [#2751](https://github.com/nextcloud/deck/pull/2751) Properly set author for activity events that are triggered by cron
|
||||
* [#2751](https://github.com/nextcloud/deck/pull/2751) Properly set author for activity events that are triggered by cron @juliushaertl
|
||||
|
||||
|
||||
## 1.2.2 - 2020-11-24
|
||||
@@ -263,31 +227,31 @@ All notable changes to this project will be documented in this file.
|
||||
### Fixed
|
||||
|
||||
|
||||
* [#2116](https://github.com/nextcloud/deck/pull/2116) Fix navigation layout issues
|
||||
* [#2118](https://github.com/nextcloud/deck/pull/2118) Use proper parameter when handling attachments
|
||||
* [#2116](https://github.com/nextcloud/deck/pull/2116) Fix navigation layout issues @juliushaertl
|
||||
* [#2118](https://github.com/nextcloud/deck/pull/2118) Use proper parameter when handling attachments @juliushaertl
|
||||
|
||||
## 1.0.4 - 2020-06-26
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#2062](https://github.com/nextcloud/deck/pull/2062) Fix saving card description after toggling checkboxes
|
||||
* [#2062](https://github.com/nextcloud/deck/pull/2062) Fix saving card description after toggling checkboxes @juliushaertl
|
||||
* [#2065](https://github.com/nextcloud/deck/pull/2065) Adding CSS rule for Markdown Blockquotes @reox
|
||||
* [#2059](https://github.com/nextcloud/deck/pull/2059) Fix fetching attachments on card change
|
||||
* [#2060](https://github.com/nextcloud/deck/pull/2060) Use mixing for relative date in card sidebar
|
||||
* [#2059](https://github.com/nextcloud/deck/pull/2059) Fix fetching attachments on card change @juliushaertl
|
||||
* [#2060](https://github.com/nextcloud/deck/pull/2060) Use mixing for relative date in card sidebar @juliushaertl
|
||||
|
||||
|
||||
## 1.0.3 - 2020-06-19
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#2019](https://github.com/nextcloud/deck/pull/2019) Remove old global css rule
|
||||
* [#2020](https://github.com/nextcloud/deck/pull/2020) Fix navigation issue with leftover nodes
|
||||
* [#2021](https://github.com/nextcloud/deck/pull/2021) Fix description issues
|
||||
* [#2022](https://github.com/nextcloud/deck/pull/2022) Fix replyto issues with the comments API
|
||||
* [#2027](https://github.com/nextcloud/deck/pull/2027) Allow to unassign current user from card
|
||||
* [#2019](https://github.com/nextcloud/deck/pull/2019) Remove old global css rule @juliushaertl
|
||||
* [#2020](https://github.com/nextcloud/deck/pull/2020) Fix navigation issue with leftover nodes @juliushaertl
|
||||
* [#2021](https://github.com/nextcloud/deck/pull/2021) Fix description issues @juliushaertl
|
||||
* [#2022](https://github.com/nextcloud/deck/pull/2022) Fix replyto issues with the comments API @juliushaertl
|
||||
* [#2027](https://github.com/nextcloud/deck/pull/2027) Allow to unassign current user from card @juliushaertl
|
||||
* [#2029](https://github.com/nextcloud/deck/pull/2029) Fix wording : stack -> list @cloud2018
|
||||
* [#2032](https://github.com/nextcloud/deck/pull/2032) Force order by id as second sorting key
|
||||
* [#2045](https://github.com/nextcloud/deck/pull/2045) Improve label styling
|
||||
* [#2032](https://github.com/nextcloud/deck/pull/2032) Force order by id as second sorting key @juliushaertl
|
||||
* [#2045](https://github.com/nextcloud/deck/pull/2045) Improve label styling @juliushaertl
|
||||
* [#2010](https://github.com/nextcloud/deck/pull/2010) User documentation fixes @Nyco
|
||||
* [#1998](https://github.com/nextcloud/deck/pull/1998) Add Checklist explaination to the doc @4rnoP
|
||||
|
||||
|
||||
3
Makefile
3
Makefile
@@ -50,7 +50,8 @@ ifeq (, $(shell which phpunit 2> /dev/null))
|
||||
php $(build_tools_directory)/phpunit.phar -c tests/phpunit.xml --coverage-clover build/php-unit.coverage.xml
|
||||
php $(build_tools_directory)/phpunit.phar -c tests/phpunit.integration.xml --coverage-clover build/php-integration.coverage.xml
|
||||
else
|
||||
phpunit -c tests/phpunit.integration.xml --testsuite=integration-database --coverage-clover build/php-integration.coverage.xml
|
||||
phpunit -c tests/phpunit.xml --coverage-clover build/php-unit.coverage.xml
|
||||
phpunit -c tests/phpunit.integration.xml --coverage-clover build/php-integration.coverage.xml
|
||||
endif
|
||||
|
||||
test-integration:
|
||||
|
||||
@@ -15,16 +15,11 @@ Deck is a kanban style organization tool aimed at personal planning and project
|
||||
- Keep track of changes in the activity stream
|
||||
- Get your project organized
|
||||
|
||||

|
||||
|
||||
### Mobile apps
|
||||
|
||||
- [Nextcloud Deck app for Android](https://github.com/stefan-niedermann/nextcloud-deck) - It is available in [F-Droid](https://f-droid.org/de/packages/it.niedermann.nextcloud.deck/) and the [Google Play Store](https://play.google.com/store/apps/details?id=it.niedermann.nextcloud.deck.play)
|
||||
- The [Nextcloud Deck app for Android](https://github.com/stefan-niedermann/nextcloud-deck) is available in the [Google Play Store](https://play.google.com/store/apps/details?id=it.niedermann.nextcloud.deck.play)
|
||||
|
||||
### 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
|
||||

|
||||
|
||||
## Installation/Update
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
- 🚀 Get your project organized
|
||||
|
||||
</description>
|
||||
<version>1.5.7</version>
|
||||
<version>1.4.8</version>
|
||||
<licence>agpl</licence>
|
||||
<author>Julius Härtl</author>
|
||||
<namespace>Deck</namespace>
|
||||
@@ -35,7 +35,7 @@
|
||||
<database min-version="9.4">pgsql</database>
|
||||
<database>sqlite</database>
|
||||
<database min-version="5.5">mysql</database>
|
||||
<nextcloud min-version="22" max-version="22"/>
|
||||
<nextcloud min-version="21" max-version="21"/>
|
||||
</dependencies>
|
||||
<background-jobs>
|
||||
<job>OCA\Deck\Cron\DeleteCron</job>
|
||||
@@ -44,7 +44,6 @@
|
||||
</background-jobs>
|
||||
<commands>
|
||||
<command>OCA\Deck\Command\UserExport</command>
|
||||
<command>OCA\Deck\Command\TransferOwnership</command>
|
||||
</commands>
|
||||
<activity>
|
||||
<settings>
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
return [
|
||||
'routes' => [
|
||||
['name' => 'page#index', 'url' => '/', 'verb' => 'GET'],
|
||||
['name' => 'page#redirectToCard', 'url' => '/card/{cardId}', 'verb' => 'GET'],
|
||||
|
||||
// boards
|
||||
['name' => 'board#index', 'url' => '/boards', 'verb' => 'GET'],
|
||||
@@ -39,7 +38,6 @@ return [
|
||||
['name' => 'board#updateAcl', 'url' => '/boards/{boardId}/acl/{aclId}', 'verb' => 'PUT'],
|
||||
['name' => 'board#deleteAcl', 'url' => '/boards/{boardId}/acl/{aclId}', 'verb' => 'DELETE'],
|
||||
['name' => 'board#clone', 'url' => '/boards/{boardId}/clone', 'verb' => 'POST'],
|
||||
['name' => 'board#transferOwner', 'url' => '/boards/{boardId}/transferOwner', 'verb' => 'PUT'],
|
||||
|
||||
// stacks
|
||||
['name' => 'stack#index', 'url' => '/stacks/{boardId}', 'verb' => 'GET'],
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
const babelConfig = require('@nextcloud/babel-config')
|
||||
|
||||
module.exports = babelConfig
|
||||
module.exports = {
|
||||
plugins: ['@babel/plugin-syntax-dynamic-import'],
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
modules: false
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
@@ -8,17 +8,12 @@
|
||||
"email": "jus@bitgrid.net"
|
||||
}
|
||||
],
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "7.3"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"cogpowered/finediff": "0.3.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"roave/security-advisories": "dev-master",
|
||||
"christophwurst/nextcloud": "^22@dev",
|
||||
"christophwurst/nextcloud": "^21@dev",
|
||||
"phpunit/phpunit": "^8",
|
||||
"nextcloud/coding-standard": "^0.5.0",
|
||||
"symfony/event-dispatcher": "^4.0",
|
||||
|
||||
1318
composer.lock
generated
1318
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,6 @@ Overall, Deck is easy to use. You can create boards, add users, share the Deck,
|
||||
3. [Handle cards options](#3-handle-cards-options)
|
||||
4. [Archive old tasks](#4-archive-old-tasks)
|
||||
5. [Manage your board](#5-manage-your-board)
|
||||
6. [New owner for the deck entities](#8-new-owner-for-the-deck-entities)
|
||||
|
||||
### 1. Create my first board
|
||||
In this example, we're going to create a board and share it with an other nextcloud user.
|
||||
@@ -91,22 +90,4 @@ For example the search `project tag:ToDo assigned:alice assigned:bob` will retur
|
||||
|
||||
Other text tokens will be used to perform a case-insensitive search on the card title and description
|
||||
|
||||
In addition, quotes can be used to pass a query with spaces, e.g. `"Exact match with spaces"` or `title:"My card"`.
|
||||
|
||||
### 8. New owner for the deck entities
|
||||
You can transfer ownership of boards, cards, etc to a new user, using `occ` command `deck:transfer-ownership`
|
||||
|
||||
```bash
|
||||
php occ deck:transfer-ownership previousOwner newOwner
|
||||
```
|
||||
|
||||
The transfer will preserve card details linked to the old owner, which can also be remapped by using the `--remap` option on the occ command.
|
||||
```bash
|
||||
php occ deck:transfer-ownership --remap previousOwner newOwner
|
||||
```
|
||||
|
||||
Individual boards can be transferred by adding the id of the board to the command:
|
||||
|
||||
```bash
|
||||
php occ deck:transfer-ownership previousOwner newOwner 123
|
||||
```
|
||||
In addition wuotes can be used to pass a query with spaces, e.g. `"Exact match with spaces"` or `title:"My card"`.
|
||||
|
||||
@@ -173,8 +173,11 @@ OC.L10N.register(
|
||||
"Owner" : "Besitzer",
|
||||
"Delete" : "Löschen",
|
||||
"Failed to create share with {displayName}" : "Fehler beim Erstellen der Freigabe mit dem Namen {displayName}",
|
||||
"Are you sure you want to transfer the board {title} to {user}?" : "Möchtest Du wirklich das Board {title} an {user} übertragen?",
|
||||
"Transfer the board." : "Board übertragen",
|
||||
"Transfer" : "Übertragen",
|
||||
"The board has been transferred to {user}" : "Das Board wurde an {user} übertragen",
|
||||
"Failed to transfer the board to {user}" : "Das Board konnte nicht an {user} übertragen werden",
|
||||
"Add a new list" : "Eine neue Liste hinzufügen",
|
||||
"Archive all cards" : "Alle Karten archivieren",
|
||||
"Delete list" : "Liste löschen",
|
||||
|
||||
@@ -171,8 +171,11 @@
|
||||
"Owner" : "Besitzer",
|
||||
"Delete" : "Löschen",
|
||||
"Failed to create share with {displayName}" : "Fehler beim Erstellen der Freigabe mit dem Namen {displayName}",
|
||||
"Are you sure you want to transfer the board {title} to {user}?" : "Möchtest Du wirklich das Board {title} an {user} übertragen?",
|
||||
"Transfer the board." : "Board übertragen",
|
||||
"Transfer" : "Übertragen",
|
||||
"The board has been transferred to {user}" : "Das Board wurde an {user} übertragen",
|
||||
"Failed to transfer the board to {user}" : "Das Board konnte nicht an {user} übertragen werden",
|
||||
"Add a new list" : "Eine neue Liste hinzufügen",
|
||||
"Archive all cards" : "Alle Karten archivieren",
|
||||
"Delete list" : "Liste löschen",
|
||||
|
||||
@@ -173,8 +173,11 @@ OC.L10N.register(
|
||||
"Owner" : "Besitzer",
|
||||
"Delete" : "Löschen",
|
||||
"Failed to create share with {displayName}" : "Fehler beim Erstellen der Freigabe mit dem Namen {displayName}",
|
||||
"Are you sure you want to transfer the board {title} to {user}?" : "Möchten Sie wirklich das Board {title} auf {user} übertragen?",
|
||||
"Transfer the board." : "Board übertragen.",
|
||||
"Transfer" : "Übertragen",
|
||||
"The board has been transferred to {user}" : "Das Board wurde auf {user} übertragen",
|
||||
"Failed to transfer the board to {user}" : "Das Board konnte nicht auf {user} übertragen werden",
|
||||
"Add a new list" : "Eine neue Liste hinzufügen",
|
||||
"Archive all cards" : "Alle Karten archivieren",
|
||||
"Delete list" : "Liste löschen",
|
||||
|
||||
@@ -171,8 +171,11 @@
|
||||
"Owner" : "Besitzer",
|
||||
"Delete" : "Löschen",
|
||||
"Failed to create share with {displayName}" : "Fehler beim Erstellen der Freigabe mit dem Namen {displayName}",
|
||||
"Are you sure you want to transfer the board {title} to {user}?" : "Möchten Sie wirklich das Board {title} auf {user} übertragen?",
|
||||
"Transfer the board." : "Board übertragen.",
|
||||
"Transfer" : "Übertragen",
|
||||
"The board has been transferred to {user}" : "Das Board wurde auf {user} übertragen",
|
||||
"Failed to transfer the board to {user}" : "Das Board konnte nicht auf {user} übertragen werden",
|
||||
"Add a new list" : "Eine neue Liste hinzufügen",
|
||||
"Archive all cards" : "Alle Karten archivieren",
|
||||
"Delete list" : "Liste löschen",
|
||||
|
||||
@@ -173,8 +173,11 @@ OC.L10N.register(
|
||||
"Owner" : "Właściciel",
|
||||
"Delete" : "Usuń",
|
||||
"Failed to create share with {displayName}" : "Nie udało się utworzyć udostępnienia dla {displayName}",
|
||||
"Are you sure you want to transfer the board {title} to {user}?" : "Czy na pewno chcesz przenieść tablicę {title} do {user}?",
|
||||
"Transfer the board." : "Przeniesienie tablicy.",
|
||||
"Transfer" : "Przenieś",
|
||||
"The board has been transferred to {user}" : "Tablica została przeniesiona do {user}",
|
||||
"Failed to transfer the board to {user}" : "Nie udało się przenieść tablicy do {user}",
|
||||
"Add a new list" : "Dodaj nową listę",
|
||||
"Archive all cards" : "Zarchiwizuj wszystkie karty",
|
||||
"Delete list" : "Usuń listę",
|
||||
|
||||
@@ -171,8 +171,11 @@
|
||||
"Owner" : "Właściciel",
|
||||
"Delete" : "Usuń",
|
||||
"Failed to create share with {displayName}" : "Nie udało się utworzyć udostępnienia dla {displayName}",
|
||||
"Are you sure you want to transfer the board {title} to {user}?" : "Czy na pewno chcesz przenieść tablicę {title} do {user}?",
|
||||
"Transfer the board." : "Przeniesienie tablicy.",
|
||||
"Transfer" : "Przenieś",
|
||||
"The board has been transferred to {user}" : "Tablica została przeniesiona do {user}",
|
||||
"Failed to transfer the board to {user}" : "Nie udało się przenieść tablicy do {user}",
|
||||
"Add a new list" : "Dodaj nową listę",
|
||||
"Archive all cards" : "Zarchiwizuj wszystkie karty",
|
||||
"Delete list" : "Usuń listę",
|
||||
|
||||
@@ -173,8 +173,11 @@ OC.L10N.register(
|
||||
"Owner" : "Sahibi",
|
||||
"Delete" : "Sil",
|
||||
"Failed to create share with {displayName}" : "{displayName} ile paylaşılamadı",
|
||||
"Are you sure you want to transfer the board {title} to {user}?" : "{title} panosunu {user} kullanıcısına aktarmak istediğinize emin misiniz?",
|
||||
"Transfer the board." : "Panoyu aktar.",
|
||||
"Transfer" : "Aktar",
|
||||
"The board has been transferred to {user}" : "Pano {user} kullanıcısına aktarıldı",
|
||||
"Failed to transfer the board to {user}" : "Pano {user} kullanıcısına aktarılamadı",
|
||||
"Add a new list" : "Yeni liste ekle",
|
||||
"Archive all cards" : "Tüm kartları arşivle",
|
||||
"Delete list" : "Listeyi sil",
|
||||
|
||||
@@ -171,8 +171,11 @@
|
||||
"Owner" : "Sahibi",
|
||||
"Delete" : "Sil",
|
||||
"Failed to create share with {displayName}" : "{displayName} ile paylaşılamadı",
|
||||
"Are you sure you want to transfer the board {title} to {user}?" : "{title} panosunu {user} kullanıcısına aktarmak istediğinize emin misiniz?",
|
||||
"Transfer the board." : "Panoyu aktar.",
|
||||
"Transfer" : "Aktar",
|
||||
"The board has been transferred to {user}" : "Pano {user} kullanıcısına aktarıldı",
|
||||
"Failed to transfer the board to {user}" : "Pano {user} kullanıcısına aktarılamadı",
|
||||
"Add a new list" : "Yeni liste ekle",
|
||||
"Archive all cards" : "Tüm kartları arşivle",
|
||||
"Delete list" : "Listeyi sil",
|
||||
|
||||
@@ -173,8 +173,11 @@ OC.L10N.register(
|
||||
"Owner" : "所有者",
|
||||
"Delete" : "刪除",
|
||||
"Failed to create share with {displayName}" : "無法為 {displayName} 創建分享",
|
||||
"Are you sure you want to transfer the board {title} to {user}?" : "您確定要將面板 {title} 轉讓給 {user} 嗎?",
|
||||
"Transfer the board." : "轉移面板。",
|
||||
"Transfer" : "轉移",
|
||||
"The board has been transferred to {user}" : "面板已轉讓給 {user}",
|
||||
"Failed to transfer the board to {user}" : "未能將面板轉移給 {user}",
|
||||
"Add a new list" : "添加一張新清單",
|
||||
"Archive all cards" : "封存所有卡片",
|
||||
"Delete list" : "刪除清單",
|
||||
|
||||
@@ -171,8 +171,11 @@
|
||||
"Owner" : "所有者",
|
||||
"Delete" : "刪除",
|
||||
"Failed to create share with {displayName}" : "無法為 {displayName} 創建分享",
|
||||
"Are you sure you want to transfer the board {title} to {user}?" : "您確定要將面板 {title} 轉讓給 {user} 嗎?",
|
||||
"Transfer the board." : "轉移面板。",
|
||||
"Transfer" : "轉移",
|
||||
"The board has been transferred to {user}" : "面板已轉讓給 {user}",
|
||||
"Failed to transfer the board to {user}" : "未能將面板轉移給 {user}",
|
||||
"Add a new list" : "添加一張新清單",
|
||||
"Archive all cards" : "封存所有卡片",
|
||||
"Delete list" : "刪除清單",
|
||||
|
||||
@@ -35,7 +35,6 @@ use OCP\IConfig;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\IUserManager;
|
||||
use OCP\L10N\IFactory;
|
||||
use OCA\Deck\Service\CardService;
|
||||
|
||||
class DeckProvider implements IProvider {
|
||||
|
||||
@@ -53,10 +52,8 @@ class DeckProvider implements IProvider {
|
||||
private $l10nFactory;
|
||||
/** @var IConfig */
|
||||
private $config;
|
||||
/** @var CardService */
|
||||
private $cardService;
|
||||
|
||||
public function __construct(IURLGenerator $urlGenerator, ActivityManager $activityManager, IUserManager $userManager, ICommentsManager $commentsManager, IFactory $l10n, IConfig $config, $userId, CardService $cardService) {
|
||||
public function __construct(IURLGenerator $urlGenerator, ActivityManager $activityManager, IUserManager $userManager, ICommentsManager $commentsManager, IFactory $l10n, IConfig $config, $userId) {
|
||||
$this->userId = $userId;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->activityManager = $activityManager;
|
||||
@@ -64,7 +61,6 @@ class DeckProvider implements IProvider {
|
||||
$this->userManager = $userManager;
|
||||
$this->l10nFactory = $l10n;
|
||||
$this->config = $config;
|
||||
$this->cardService = $cardService;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,7 +131,7 @@ class DeckProvider implements IProvider {
|
||||
|
||||
if (array_key_exists('board', $subjectParams)) {
|
||||
$archivedParam = $subjectParams['card']['archived'] ? 'archived/' : '';
|
||||
$card['link'] = $this->cardService->getRedirectUrlForCard($event->getObjectId());
|
||||
$card['link'] = $this->deckUrl('/board/' . $subjectParams['board']['id'] . '/' . $archivedParam . 'card/' . $event->getObjectId());
|
||||
}
|
||||
$params['card'] = $card;
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ class Application extends App implements IBootstrap {
|
||||
// Talk integration has its own entrypoint which already includes collections handling
|
||||
return;
|
||||
}
|
||||
Util::addScript('deck', 'deck-collections');
|
||||
Util::addScript('deck', 'collections');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace OCA\Deck\Command;
|
||||
|
||||
use OCA\Deck\Db\BoardMapper;
|
||||
use OCA\Deck\Service\BoardService;
|
||||
use OCA\Deck\Service\PermissionService;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Helper\QuestionHelper;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
|
||||
final class TransferOwnership extends Command {
|
||||
protected $boardService;
|
||||
protected $boardMapper;
|
||||
protected $permissionService;
|
||||
protected $questionHelper;
|
||||
|
||||
public function __construct(BoardService $boardService, BoardMapper $boardMapper, PermissionService $permissionService, QuestionHelper $questionHelper) {
|
||||
parent::__construct();
|
||||
|
||||
$this->boardService = $boardService;
|
||||
$this->boardMapper = $boardMapper;
|
||||
$this->permissionService = $permissionService;
|
||||
$this->questionHelper = $questionHelper;
|
||||
}
|
||||
|
||||
protected function configure() {
|
||||
$this
|
||||
->setName('deck:transfer-ownership')
|
||||
->setDescription('Change owner of deck boards')
|
||||
->addArgument(
|
||||
'owner',
|
||||
InputArgument::REQUIRED,
|
||||
'Owner uid'
|
||||
)
|
||||
->addArgument(
|
||||
'newOwner',
|
||||
InputArgument::REQUIRED,
|
||||
'New owner uid'
|
||||
)
|
||||
->addArgument(
|
||||
'boardId',
|
||||
InputArgument::OPTIONAL,
|
||||
'Single board ID'
|
||||
)
|
||||
->addOption(
|
||||
'remap',
|
||||
'r',
|
||||
InputOption::VALUE_NONE,
|
||||
'Reassign card details of the old owner to the new one'
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
$owner = $input->getArgument('owner');
|
||||
$newOwner = $input->getArgument('newOwner');
|
||||
$boardId = $input->getArgument('boardId');
|
||||
|
||||
$remapAssignment = $input->getOption('remap');
|
||||
|
||||
$this->boardService->setUserId($owner);
|
||||
$this->permissionService->setUserId($owner);
|
||||
|
||||
try {
|
||||
$board = $boardId ? $this->boardMapper->find($boardId) : null;
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln("Could not find a board for the provided id.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($boardId !== null && $board->getOwner() !== $owner) {
|
||||
$output->writeln("$owner is not the owner of the board $boardId (" . $board->getTitle() . ")");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($boardId) {
|
||||
$output->writeln("Transfer board " . $board->getTitle() . " from ". $board->getOwner() ." to $newOwner");
|
||||
} else {
|
||||
$output->writeln("Transfer all boards from $owner to $newOwner");
|
||||
}
|
||||
|
||||
$question = new ConfirmationQuestion('Do you really want to continue? (y/n) ', false);
|
||||
if (!$this->questionHelper->ask($input, $output, $question)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($boardId) {
|
||||
$this->boardService->transferBoardOwnership($boardId, $newOwner, $remapAssignment);
|
||||
$output->writeln("<info>Board " . $board->getTitle() . " from ". $board->getOwner() ." transferred to $newOwner completed</info>");
|
||||
return 0;
|
||||
}
|
||||
|
||||
foreach ($this->boardService->transferOwnership($owner, $newOwner, $remapAssignment) as $board) {
|
||||
$output->writeln(" - " . $board->getTitle() . " transferred");
|
||||
}
|
||||
$output->writeln("<info>All boards from $owner to $newOwner transferred</info>");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -24,12 +24,9 @@
|
||||
namespace OCA\Deck\Controller;
|
||||
|
||||
use OCA\Deck\Db\Acl;
|
||||
use OCA\Deck\Db\Board;
|
||||
use OCA\Deck\Service\BoardService;
|
||||
use OCA\Deck\Service\PermissionService;
|
||||
use OCP\AppFramework\ApiController;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\IRequest;
|
||||
|
||||
class BoardController extends ApiController {
|
||||
@@ -153,20 +150,9 @@ class BoardController extends ApiController {
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @param $boardId
|
||||
* @return Board
|
||||
* @return \OCP\Deck\DB\Board
|
||||
*/
|
||||
public function clone($boardId) {
|
||||
return $this->boardService->clone($boardId, $this->userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
public function transferOwner(int $boardId, string $newOwner): DataResponse {
|
||||
if ($this->permissionService->userIsBoardOwner($boardId, $this->userId)) {
|
||||
return new DataResponse($this->boardService->transferBoardOwnership($boardId, $newOwner), HTTP::STATUS_OK);
|
||||
}
|
||||
|
||||
return new DataResponse([], HTTP::STATUS_UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,8 +94,8 @@ class CardApiController extends ApiController {
|
||||
*
|
||||
* Update a card
|
||||
*/
|
||||
public function update($title, $type, $owner, $description = '', $order = 0, $duedate = null, $archived = null) {
|
||||
$card = $this->cardService->update($this->request->getParam('cardId'), $title, $this->request->getParam('stackId'), $type, $owner, $description, $order, $duedate, 0, $archived);
|
||||
public function update($title, $type, $order = 0, $description = '', $owner, $duedate = null, $archived = null) {
|
||||
$card = $this->cardService->update($this->request->getParam('cardId'), $title, $this->request->getParam('stackId'), $type, $order, $description, $owner, $duedate, 0, $archived);
|
||||
return new DataResponse($card, HTTP::STATUS_OK);
|
||||
}
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ class CardController extends Controller {
|
||||
* @return \OCP\AppFramework\Db\Entity
|
||||
*/
|
||||
public function update($id, $title, $stackId, $type, $order, $description, $duedate, $deletedAt) {
|
||||
return $this->cardService->update($id, $title, $stackId, $type, $this->userId, $description, $order, $duedate, $deletedAt);
|
||||
return $this->cardService->update($id, $title, $stackId, $type, $order, $description, $this->userId, $duedate, $deletedAt);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,20 +34,12 @@ use OCP\IInitialStateService;
|
||||
use OCP\IRequest;
|
||||
use OCP\AppFramework\Http\TemplateResponse;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCA\Deck\Db\CardMapper;
|
||||
use OCP\IURLGenerator;
|
||||
use \OCP\AppFramework\Http\RedirectResponse;
|
||||
use OCA\Deck\Db\Acl;
|
||||
use OCA\Deck\Service\CardService;
|
||||
|
||||
class PageController extends Controller {
|
||||
private $permissionService;
|
||||
private $initialState;
|
||||
private $configService;
|
||||
private $eventDispatcher;
|
||||
private $cardMapper;
|
||||
private $urlGenerator;
|
||||
private $cardService;
|
||||
|
||||
public function __construct(
|
||||
$AppName,
|
||||
@@ -55,10 +47,7 @@ class PageController extends Controller {
|
||||
PermissionService $permissionService,
|
||||
IInitialStateService $initialStateService,
|
||||
ConfigService $configService,
|
||||
IEventDispatcher $eventDispatcher,
|
||||
CardMapper $cardMapper,
|
||||
IURLGenerator $urlGenerator,
|
||||
CardService $cardService
|
||||
IEventDispatcher $eventDispatcher
|
||||
) {
|
||||
parent::__construct($AppName, $request);
|
||||
|
||||
@@ -66,9 +55,6 @@ class PageController extends Controller {
|
||||
$this->initialState = $initialStateService;
|
||||
$this->configService = $configService;
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
$this->cardMapper = $cardMapper;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->cardService = $cardService;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,17 +85,4 @@ class PageController extends Controller {
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @NoCSRFRequired
|
||||
*/
|
||||
public function redirectToCard($cardId): RedirectResponse {
|
||||
try {
|
||||
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ);
|
||||
return new RedirectResponse($this->cardService->getCardUrl($cardId));
|
||||
} catch (\Exception $e) {
|
||||
return new RedirectResponse($this->urlGenerator->linkToRouteAbsolute('deck.page.index'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +79,6 @@ class DeckWidget implements IWidget {
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function load(): void {
|
||||
\OCP\Util::addScript('deck', 'deck-dashboard');
|
||||
\OCP\Util::addScript('deck', 'dashboard');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ namespace OCA\Deck\Db;
|
||||
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IDBConnection;
|
||||
|
||||
class AclMapper extends DeckMapper implements IPermissionMapper {
|
||||
@@ -45,9 +44,9 @@ class AclMapper extends DeckMapper implements IPermissionMapper {
|
||||
return ($row['owner'] === $userId);
|
||||
}
|
||||
|
||||
public function findBoardId($id): ?int {
|
||||
public function findBoardId($aclId): ?int {
|
||||
try {
|
||||
$entity = $this->find($id);
|
||||
$entity = $this->find($aclId);
|
||||
return $entity->getBoardId();
|
||||
} catch (DoesNotExistException | MultipleObjectsReturnedException $e) {
|
||||
}
|
||||
@@ -58,16 +57,4 @@ class AclMapper extends DeckMapper implements IPermissionMapper {
|
||||
$sql = 'SELECT * from *PREFIX*deck_board_acl WHERE type = ? AND participant = ?';
|
||||
return $this->findEntities($sql, [$type, $participant]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \OCP\DB\Exception
|
||||
*/
|
||||
public function deleteParticipantFromBoard(int $boardId, int $type, string $participant): void {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->delete('deck_board_acl')
|
||||
->where($qb->expr()->eq('type', $qb->createNamedParameter($type, IQueryBuilder::PARAM_INT)))
|
||||
->andWhere($qb->expr()->eq('participant', $qb->createNamedParameter($participant, IQueryBuilder::PARAM_STR)))
|
||||
->andWhere($qb->expr()->eq('board_id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)));
|
||||
$qb->executeStatement();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ use OCA\Deck\NotFoundException;
|
||||
use OCA\Deck\Service\CirclesService;
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\AppFramework\Db\QBMapper;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\IUserManager;
|
||||
@@ -84,8 +83,8 @@ class AssignmentMapper extends QBMapper implements IPermissionMapper {
|
||||
return $this->cardMapper->isOwner($userId, $cardId);
|
||||
}
|
||||
|
||||
public function findBoardId($id): ?int {
|
||||
return $this->cardMapper->findBoardId($id);
|
||||
public function findBoardId($cardId): ?int {
|
||||
return $this->cardMapper->findBoardId($cardId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,39 +146,4 @@ class AssignmentMapper extends QBMapper implements IPermissionMapper {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function remapAssignedUser(int $boardId, string $userId, string $newUserId): void {
|
||||
$subQuery = $this->db->getQueryBuilder();
|
||||
$subQuery->selectAlias('a.id', 'id')
|
||||
->from('deck_assigned_users', 'a')
|
||||
->innerJoin('a', 'deck_cards', 'c', 'c.id = a.card_id')
|
||||
->innerJoin('c', 'deck_stacks', 's', 's.id = c.stack_id')
|
||||
->where($subQuery->expr()->eq('a.type', $subQuery->createNamedParameter(Assignment::TYPE_USER, IQueryBuilder::PARAM_INT)))
|
||||
->andWhere($subQuery->expr()->eq('a.participant', $subQuery->createNamedParameter($userId, IQueryBuilder::PARAM_STR)))
|
||||
->andWhere($subQuery->expr()->eq('s.board_id', $subQuery->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
|
||||
->setMaxResults(1000);
|
||||
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->update('deck_assigned_users')
|
||||
->set('participant', $qb->createParameter('participant'))
|
||||
->where($qb->expr()->in('id', $qb->createParameter('ids')));
|
||||
|
||||
$moreResults = true;
|
||||
do {
|
||||
$result = $subQuery->executeQuery();
|
||||
$ids = array_map(function ($item) {
|
||||
return $item['id'];
|
||||
}, $result->fetchAll());
|
||||
|
||||
if (count($ids) === 0 || $result->rowCount() === 0) {
|
||||
$moreResults = false;
|
||||
}
|
||||
|
||||
$qb->setParameter('participant', $newUserId, IQueryBuilder::PARAM_STR);
|
||||
$qb->setParameter('ids', $ids, IQueryBuilder::PARAM_INT_ARRAY);
|
||||
$qb->executeStatement();
|
||||
} while ($moreResults === true);
|
||||
|
||||
$result->closeCursor();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,9 +24,7 @@
|
||||
namespace OCA\Deck\Db;
|
||||
|
||||
use OC\Cache\CappedMemoryCache;
|
||||
use OCA\Deck\Service\CirclesService;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\IUserManager;
|
||||
use OCP\IGroupManager;
|
||||
@@ -38,10 +36,10 @@ class BoardMapper extends DeckMapper implements IPermissionMapper {
|
||||
private $stackMapper;
|
||||
private $userManager;
|
||||
private $groupManager;
|
||||
private $circlesService;
|
||||
private $logger;
|
||||
|
||||
/** @var CappedMemoryCache */
|
||||
private $circlesEnabled;
|
||||
|
||||
private $userBoardCache;
|
||||
|
||||
public function __construct(
|
||||
@@ -51,7 +49,6 @@ class BoardMapper extends DeckMapper implements IPermissionMapper {
|
||||
StackMapper $stackMapper,
|
||||
IUserManager $userManager,
|
||||
IGroupManager $groupManager,
|
||||
CirclesService $circlesService,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
parent::__construct($db, 'deck_boards', Board::class);
|
||||
@@ -60,10 +57,12 @@ class BoardMapper extends DeckMapper implements IPermissionMapper {
|
||||
$this->stackMapper = $stackMapper;
|
||||
$this->userManager = $userManager;
|
||||
$this->groupManager = $groupManager;
|
||||
$this->circlesService = $circlesService;
|
||||
$this->logger = $logger;
|
||||
|
||||
$this->userBoardCache = new CappedMemoryCache();
|
||||
|
||||
|
||||
$this->circlesEnabled = \OC::$server->getAppManager()->isEnabledForUser('circles');
|
||||
}
|
||||
|
||||
|
||||
@@ -182,7 +181,12 @@ class BoardMapper extends DeckMapper implements IPermissionMapper {
|
||||
}
|
||||
|
||||
public function findAllByCircles($userId, $limit = null, $offset = null, $since = -1,$includeArchived = true) {
|
||||
$circles = $this->circlesService->getUserCircles($userId);
|
||||
if (!$this->circlesEnabled) {
|
||||
return [];
|
||||
}
|
||||
$circles = array_map(function ($circle) {
|
||||
return $circle->getUniqueId();
|
||||
}, \OCA\Circles\Api\v1\Circles::joinedCircles($userId, true));
|
||||
if (count($circles) === 0) {
|
||||
return [];
|
||||
}
|
||||
@@ -273,11 +277,11 @@ class BoardMapper extends DeckMapper implements IPermissionMapper {
|
||||
return null;
|
||||
}
|
||||
if ($acl->getType() === Acl::PERMISSION_TYPE_CIRCLE) {
|
||||
if (!$this->circlesService->isCirclesEnabled()) {
|
||||
if (!$this->circlesEnabled) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
$circle = $this->circlesService->getCircle($acl->getParticipant());
|
||||
$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($acl->getParticipant(), true);
|
||||
if ($circle) {
|
||||
return new Circle($circle);
|
||||
}
|
||||
@@ -304,29 +308,4 @@ class BoardMapper extends DeckMapper implements IPermissionMapper {
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \OCP\DB\Exception
|
||||
*/
|
||||
public function transferOwnership(string $ownerId, string $newOwnerId, $boardId = null): void {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->update('deck_boards')
|
||||
->set('owner', $qb->createNamedParameter($newOwnerId, IQueryBuilder::PARAM_STR))
|
||||
->where($qb->expr()->eq('owner', $qb->createNamedParameter($ownerId, IQueryBuilder::PARAM_STR)));
|
||||
if ($boardId !== null) {
|
||||
$qb->andWhere($qb->expr()->eq('id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)));
|
||||
}
|
||||
$qb->executeStatement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset cache for a given board or a given user
|
||||
*/
|
||||
public function flushCache(?int $boardId = null, ?string $userId = null) {
|
||||
if ($userId) {
|
||||
unset($this->userBoardCache[$userId]);
|
||||
} else {
|
||||
$this->userBoardCache = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,18 +230,16 @@ class CardMapper extends QBMapper implements IPermissionMapper {
|
||||
return $this->findEntities($qb);
|
||||
}
|
||||
|
||||
public function findToMeOrNotAssignedCards($boardId, $username) {
|
||||
public function findAssignedCards($boardId, $username) {
|
||||
$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')
|
||||
->leftJoin('c', 'deck_assigned_users', 'u', 'c.id = u.card_id')
|
||||
->innerJoin('c', 'deck_assigned_users', 'u', 'c.id = u.card_id')
|
||||
->where($qb->expr()->eq('s.board_id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
|
||||
->andWhere($qb->expr()->orX(
|
||||
$qb->expr()->eq('u.participant', $qb->createNamedParameter($username, IQueryBuilder::PARAM_STR)),
|
||||
$qb->expr()->isNull('u.participant'))
|
||||
)
|
||||
->andWhere($qb->expr()->eq('u.participant', $qb->createNamedParameter($username, IQueryBuilder::PARAM_STR)))
|
||||
->andWhere($qb->expr()->eq('u.type', $qb->createNamedParameter(Acl::PERMISSION_TYPE_USER, IQueryBuilder::PARAM_INT)))
|
||||
// Filter out archived/deleted cards and board
|
||||
->andWhere($qb->expr()->eq('c.archived', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)))
|
||||
->andWhere($qb->expr()->eq('c.deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)))
|
||||
@@ -546,10 +544,10 @@ class CardMapper extends QBMapper implements IPermissionMapper {
|
||||
return ($row['owner'] === $userId);
|
||||
}
|
||||
|
||||
public function findBoardId($id): ?int {
|
||||
public function findBoardId($cardId): ?int {
|
||||
$sql = 'SELECT id 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);
|
||||
$stmt->bindParam(1, $cardId, \PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
return $stmt->fetchColumn() ?? null;
|
||||
}
|
||||
@@ -564,47 +562,4 @@ class CardMapper extends QBMapper implements IPermissionMapper {
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public function transferOwnership(string $ownerId, string $newOwnerId, int $boardId = null): void {
|
||||
$params = [
|
||||
'owner' => $ownerId,
|
||||
'newOwner' => $newOwnerId
|
||||
];
|
||||
$sql = "UPDATE `*PREFIX*{$this->tableName}` SET `owner` = :newOwner WHERE `owner` = :owner";
|
||||
$stmt = $this->db->executeQuery($sql, $params);
|
||||
$stmt->closeCursor();
|
||||
}
|
||||
|
||||
public function remapCardOwner(int $boardId, string $userId, string $newUserId): void {
|
||||
$subQuery = $this->db->getQueryBuilder();
|
||||
$subQuery->selectAlias('c.id', 'id')
|
||||
->from('deck_cards', 'c')
|
||||
->innerJoin('c', 'deck_stacks', 's', 's.id = c.stack_id')
|
||||
->where($subQuery->expr()->eq('c.owner', $subQuery->createNamedParameter($userId, IQueryBuilder::PARAM_STR)))
|
||||
->andWhere($subQuery->expr()->eq('s.board_id', $subQuery->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
|
||||
->setMaxResults(1000);
|
||||
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->update('deck_cards')
|
||||
->set('owner', $qb->createParameter('owner'))
|
||||
->where($qb->expr()->in('id', $qb->createParameter('ids')));
|
||||
|
||||
$moreResults = true;
|
||||
do {
|
||||
$result = $subQuery->executeQuery();
|
||||
$ids = array_map(function ($item) {
|
||||
return $item['id'];
|
||||
}, $result->fetchAll());
|
||||
|
||||
if (count($ids) === 0 || $result->rowCount() === 0) {
|
||||
$moreResults = false;
|
||||
}
|
||||
|
||||
$qb->setParameter('owner', $newUserId, IQueryBuilder::PARAM_STR);
|
||||
$qb->setParameter('ids', $ids, IQueryBuilder::PARAM_INT_ARRAY);
|
||||
$qb->executeStatement();
|
||||
} while ($moreResults === true);
|
||||
|
||||
$result->closeCursor();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ class Circle extends RelationalObject {
|
||||
public function getObjectSerialization() {
|
||||
return [
|
||||
'uid' => $this->object->getUniqueId(),
|
||||
'displayname' => $this->object->getDisplayName(),
|
||||
'typeString' => '',
|
||||
'displayname' => $this->object->getName(),
|
||||
'typeString' => $this->object->getTypeString(),
|
||||
'circleOwner' => $this->object->getOwner(),
|
||||
'type' => 7
|
||||
];
|
||||
|
||||
@@ -101,9 +101,9 @@ class LabelMapper extends DeckMapper implements IPermissionMapper {
|
||||
return ($row['owner'] === $userId);
|
||||
}
|
||||
|
||||
public function findBoardId($id): ?int {
|
||||
public function findBoardId($labelId): ?int {
|
||||
try {
|
||||
$entity = $this->find($id);
|
||||
$entity = $this->find($labelId);
|
||||
return $entity->getBoardId();
|
||||
} catch (DoesNotExistException $e) {
|
||||
} catch (MultipleObjectsReturnedException $e) {
|
||||
|
||||
@@ -75,9 +75,9 @@ class StackMapper extends DeckMapper implements IPermissionMapper {
|
||||
return ($row['owner'] === $userId);
|
||||
}
|
||||
|
||||
public function findBoardId($id): ?int {
|
||||
public function findBoardId($stackId): ?int {
|
||||
try {
|
||||
$entity = $this->find($id);
|
||||
$entity = $this->find($stackId);
|
||||
return $entity->getBoardId();
|
||||
} catch (DoesNotExistException $e) {
|
||||
} catch (MultipleObjectsReturnedException $e) {
|
||||
|
||||
@@ -51,11 +51,11 @@ class BeforeTemplateRenderedListener implements IEventListener {
|
||||
|
||||
$pathInfo = $this->request->getPathInfo();
|
||||
if (strpos($pathInfo, '/apps/calendar') === 0) {
|
||||
Util::addScript('deck', 'deck-calendar');
|
||||
Util::addScript('deck', 'calendar');
|
||||
}
|
||||
|
||||
if (strpos($pathInfo, '/call/') === 0 || strpos($pathInfo, '/apps/spreed') === 0) {
|
||||
Util::addScript('deck', 'deck-talk');
|
||||
Util::addScript('deck', 'talk');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright Copyright (c) 2022 Your name <your@email.com>
|
||||
*
|
||||
* @author Your name <your@email.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\Migration;
|
||||
|
||||
use Closure;
|
||||
use Doctrine\DBAL\Schema\SchemaException;
|
||||
use OCP\DB\ISchemaWrapper;
|
||||
use OCP\Migration\IOutput;
|
||||
use OCP\Migration\SimpleMigrationStep;
|
||||
|
||||
class Version10800Date20220422061816 extends SimpleMigrationStep {
|
||||
|
||||
/**
|
||||
* @param IOutput $output
|
||||
* @param Closure(): ISchemaWrapper $schemaClosure The `\Closure` returns a `ISchemaWrapper`
|
||||
* @param array $options
|
||||
* @return null|ISchemaWrapper
|
||||
* @throws SchemaException
|
||||
*/
|
||||
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
|
||||
$schema = $schemaClosure();
|
||||
|
||||
$indexAdded = $this->addIndex($schema,
|
||||
'deck_boards',
|
||||
'idx_owner_modified',
|
||||
[ 'owner', 'last_modified' ]
|
||||
);
|
||||
|
||||
$indexAdded = $this->addIndex($schema,
|
||||
'deck_board_acl',
|
||||
'idx_participant_type',
|
||||
[ 'participant', 'type']
|
||||
) || $indexAdded;
|
||||
|
||||
$indexAdded = $this->addIndex($schema,
|
||||
'deck_cards',
|
||||
'idx_due_notified_archived_deleted', [
|
||||
'duedate', 'notified', 'archived', 'deleted_at'
|
||||
],
|
||||
) || $indexAdded;
|
||||
|
||||
$indexAdded = $this->addIndex($schema,
|
||||
'deck_cards',
|
||||
'idx_last_editor', [
|
||||
'last_editor', 'description_prev'
|
||||
], [],
|
||||
// Adding a partial index on the description_prev as it is only used for a NULL check
|
||||
['lengths' => [null, 1]]
|
||||
) || $indexAdded;
|
||||
|
||||
$indexAdded = $this->addIndex($schema,
|
||||
'deck_attachment',
|
||||
'idx_cardid_deletedat',
|
||||
[ 'card_id', 'deleted_at']
|
||||
) || $indexAdded;
|
||||
|
||||
$indexAdded = $this->addIndex($schema,
|
||||
'deck_assigned_users',
|
||||
'idx_card_participant',
|
||||
[ 'card_id', 'participant']
|
||||
) || $indexAdded;
|
||||
|
||||
return $indexAdded ? $schema : null;
|
||||
}
|
||||
|
||||
private function addIndex(ISchemaWrapper $schema, string $table, string $indexName, array $columns, array $flags = [], array $options = []): bool {
|
||||
$table = $schema->getTable($table);
|
||||
if (!$table->hasIndex($indexName)) {
|
||||
$table->addIndex($columns, $indexName, $flags, $options);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -238,7 +238,7 @@ class DeckProvider implements IFullTextSearchProvider {
|
||||
*
|
||||
* @param ISearchRequest $request
|
||||
*/
|
||||
public function improveSearchRequest(ISearchRequest $searchRequest) {
|
||||
public function improveSearchRequest(ISearchRequest $request) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -24,14 +24,12 @@
|
||||
|
||||
namespace OCA\Deck\Service;
|
||||
|
||||
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
||||
use OCA\Deck\Activity\ActivityManager;
|
||||
use OCA\Deck\Activity\ChangeSet;
|
||||
use OCA\Deck\AppInfo\Application;
|
||||
use OCA\Deck\Db\Acl;
|
||||
use OCA\Deck\Db\AclMapper;
|
||||
use OCA\Deck\Db\AssignmentMapper;
|
||||
use OCA\Deck\Db\CardMapper;
|
||||
use OCA\Deck\Db\ChangeHelper;
|
||||
use OCA\Deck\Db\IPermissionMapper;
|
||||
use OCA\Deck\Db\Label;
|
||||
@@ -52,7 +50,6 @@ use OCA\Deck\Db\BoardMapper;
|
||||
use OCA\Deck\Db\LabelMapper;
|
||||
use OCP\IUserManager;
|
||||
use OCA\Deck\BadRequestException;
|
||||
use OCP\IURLGenerator;
|
||||
|
||||
class BoardService {
|
||||
private $boardMapper;
|
||||
@@ -71,10 +68,8 @@ class BoardService {
|
||||
private $activityManager;
|
||||
private $eventDispatcher;
|
||||
private $changeHelper;
|
||||
private $cardMapper;
|
||||
|
||||
private $boardsCache = null;
|
||||
private $urlGenerator;
|
||||
|
||||
|
||||
public function __construct(
|
||||
@@ -87,13 +82,11 @@ class BoardService {
|
||||
PermissionService $permissionService,
|
||||
NotificationHelper $notificationHelper,
|
||||
AssignmentMapper $assignedUsersMapper,
|
||||
CardMapper $cardMapper,
|
||||
IUserManager $userManager,
|
||||
IGroupManager $groupManager,
|
||||
ActivityManager $activityManager,
|
||||
IEventDispatcher $eventDispatcher,
|
||||
ChangeHelper $changeHelper,
|
||||
IURLGenerator $urlGenerator,
|
||||
$userId
|
||||
) {
|
||||
$this->boardMapper = $boardMapper;
|
||||
@@ -111,8 +104,6 @@ class BoardService {
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
$this->changeHelper = $changeHelper;
|
||||
$this->userId = $userId;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->cardMapper = $cardMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -521,14 +512,11 @@ class BoardService {
|
||||
$acl->setPermissionManage($manage);
|
||||
$newAcl = $this->aclMapper->insert($acl);
|
||||
|
||||
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_BOARD, $newAcl, ActivityManager::SUBJECT_BOARD_SHARE, [], $this->userId);
|
||||
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_BOARD, $newAcl, ActivityManager::SUBJECT_BOARD_SHARE);
|
||||
$this->notificationHelper->sendBoardShared((int)$boardId, $acl);
|
||||
$this->boardMapper->mapAcl($newAcl);
|
||||
$this->changeHelper->boardChanged($boardId);
|
||||
|
||||
$board = $this->boardMapper->find($boardId);
|
||||
$this->clearBoardFromCache($board);
|
||||
|
||||
// TODO: use the dispatched event for this
|
||||
try {
|
||||
$resourceProvider = \OC::$server->query(\OCA\Deck\Collaboration\Resources\ResourceProvider::class);
|
||||
@@ -679,43 +667,6 @@ class BoardService {
|
||||
return $newBoard;
|
||||
}
|
||||
|
||||
public function transferBoardOwnership(int $boardId, string $newOwner, bool $changeContent = false): Board {
|
||||
\OC::$server->getDatabaseConnection()->beginTransaction();
|
||||
try {
|
||||
$board = $this->boardMapper->find($boardId);
|
||||
$previousOwner = $board->getOwner();
|
||||
$this->clearBoardFromCache($board);
|
||||
$this->aclMapper->deleteParticipantFromBoard($boardId, Acl::PERMISSION_TYPE_USER, $newOwner);
|
||||
if (!$changeContent) {
|
||||
try {
|
||||
$this->addAcl($boardId, Acl::PERMISSION_TYPE_USER, $previousOwner, true, true, true);
|
||||
} catch (UniqueConstraintViolationException $e) {
|
||||
}
|
||||
}
|
||||
$this->boardMapper->transferOwnership($previousOwner, $newOwner, $boardId);
|
||||
|
||||
// Optionally also change user assignments and card owner information
|
||||
if ($changeContent) {
|
||||
$this->assignedUsersMapper->remapAssignedUser($boardId, $previousOwner, $newOwner);
|
||||
$this->cardMapper->remapCardOwner($boardId, $previousOwner, $newOwner);
|
||||
}
|
||||
\OC::$server->getDatabaseConnection()->commit();
|
||||
return $this->boardMapper->find($boardId);
|
||||
} catch (\Throwable $e) {
|
||||
\OC::$server->getDatabaseConnection()->rollBack();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
public function transferOwnership(string $owner, string $newOwner, bool $changeContent = false): \Generator {
|
||||
$boards = $this->boardMapper->findAllByUser($owner);
|
||||
foreach ($boards as $board) {
|
||||
if ($board->getOwner() === $owner) {
|
||||
yield $this->transferBoardOwnership($board->getId(), $newOwner, $changeContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function enrichWithStacks($board, $since = -1) {
|
||||
$stacks = $this->stackMapper->findAll($board->getId(), null, null, $since);
|
||||
|
||||
@@ -743,23 +694,4 @@ class BoardService {
|
||||
}
|
||||
$board->setUsers(array_values($boardUsers));
|
||||
}
|
||||
|
||||
public function getBoardUrl($endpoint) {
|
||||
return $this->urlGenerator->linkToRouteAbsolute('deck.page.index') . '#' . $endpoint;
|
||||
}
|
||||
|
||||
private function clearBoardsCache() {
|
||||
$this->boardsCache = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean a given board data from the Cache
|
||||
*/
|
||||
private function clearBoardFromCache(Board $board) {
|
||||
$boardId = $board->getId();
|
||||
$boardOwnerId = $board->getOwner();
|
||||
|
||||
$this->boardMapper->flushCache($boardId, $boardOwnerId);
|
||||
unset($this->boardsCache[$boardId]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ use OCA\Deck\Db\StackMapper;
|
||||
use OCA\Deck\Event\CardCreatedEvent;
|
||||
use OCA\Deck\Event\CardDeletedEvent;
|
||||
use OCA\Deck\Event\CardUpdatedEvent;
|
||||
use OCA\Deck\NoPermissionException;
|
||||
use OCA\Deck\Notification\NotificationHelper;
|
||||
use OCA\Deck\Db\BoardMapper;
|
||||
use OCA\Deck\Db\LabelMapper;
|
||||
@@ -46,7 +45,6 @@ use OCA\Deck\BadRequestException;
|
||||
use OCP\Comments\ICommentsManager;
|
||||
use OCP\EventDispatcher\IEventDispatcher;
|
||||
use OCP\IUserManager;
|
||||
use OCP\IURLGenerator;
|
||||
|
||||
class CardService {
|
||||
private $cardMapper;
|
||||
@@ -64,7 +62,6 @@ class CardService {
|
||||
private $changeHelper;
|
||||
private $eventDispatcher;
|
||||
private $userManager;
|
||||
private $urlGenerator;
|
||||
|
||||
public function __construct(
|
||||
CardMapper $cardMapper,
|
||||
@@ -81,7 +78,6 @@ class CardService {
|
||||
IUserManager $userManager,
|
||||
ChangeHelper $changeHelper,
|
||||
IEventDispatcher $eventDispatcher,
|
||||
IURLGenerator $urlGenerator,
|
||||
$userId
|
||||
) {
|
||||
$this->cardMapper = $cardMapper;
|
||||
@@ -99,7 +95,6 @@ class CardService {
|
||||
$this->changeHelper = $changeHelper;
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
$this->currentUser = $userId;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
}
|
||||
|
||||
public function enrich($card) {
|
||||
@@ -159,12 +154,7 @@ class CardService {
|
||||
}
|
||||
|
||||
public function findCalendarEntries($boardId) {
|
||||
try {
|
||||
$this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_READ);
|
||||
} catch (NoPermissionException $e) {
|
||||
\OC::$server->getLogger()->error('Unable to check permission for a previously obtained board ' . $boardId, ['exception' => $e]);
|
||||
return [];
|
||||
}
|
||||
$this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_READ);
|
||||
$cards = $this->cardMapper->findCalendarEntries($boardId);
|
||||
foreach ($cards as $card) {
|
||||
$this->enrich($card);
|
||||
@@ -267,9 +257,9 @@ class CardService {
|
||||
* @param $title
|
||||
* @param $stackId
|
||||
* @param $type
|
||||
* @param $owner
|
||||
* @param $description
|
||||
* @param $order
|
||||
* @param $description
|
||||
* @param $owner
|
||||
* @param $duedate
|
||||
* @return \OCP\AppFramework\Db\Entity
|
||||
* @throws StatusException
|
||||
@@ -278,7 +268,7 @@ class CardService {
|
||||
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
|
||||
* @throws BadRequestException
|
||||
*/
|
||||
public function update($id, $title, $stackId, $type, $owner, $description = '', $order = 0, $duedate = null, $deletedAt = null, $archived = null) {
|
||||
public function update($id, $title, $stackId, $type, $order = 0, $description = '', $owner, $duedate = null, $deletedAt = null, $archived = null) {
|
||||
if (is_numeric($id) === false) {
|
||||
throw new BadRequestException('card id must be a number');
|
||||
}
|
||||
@@ -607,13 +597,27 @@ class CardService {
|
||||
$this->eventDispatcher->dispatchTyped(new CardUpdatedEvent($card));
|
||||
}
|
||||
|
||||
public function getCardUrl($cardId) {
|
||||
$boardId = $this->cardMapper->findBoardId($cardId);
|
||||
/**
|
||||
*
|
||||
* @return array
|
||||
* @throws \OCA\Deck\NoPermissionException
|
||||
* @throws BadRequestException
|
||||
*/
|
||||
public function findAllWithDue($userId) {
|
||||
$cards = $this->cardMapper->findAllWithDue($userId);
|
||||
|
||||
return $this->urlGenerator->linkToRouteAbsolute('deck.page.index') . "#/board/$boardId/card/$cardId";
|
||||
return $cards;
|
||||
}
|
||||
|
||||
public function getRedirectUrlForCard($cardId) {
|
||||
return $this->urlGenerator->linkToRouteAbsolute('deck.page.index') . "card/$cardId";
|
||||
/**
|
||||
*
|
||||
* @return array
|
||||
* @throws \OCA\Deck\NoPermissionException
|
||||
* @throws BadRequestException
|
||||
*/
|
||||
public function findAssignedCards($userId) {
|
||||
$cards = $this->cardMapper->findAssignedCards($userId);
|
||||
|
||||
return $cards;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,12 +26,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace OCA\Deck\Service;
|
||||
|
||||
use OCA\Circles\CirclesManager;
|
||||
use OCA\Circles\Model\Circle;
|
||||
use OCA\Circles\Model\Member;
|
||||
use OCA\Circles\Model\Probes\CircleProbe;
|
||||
use OCA\Circles\Api\v1\Circles;
|
||||
use OCP\App\IAppManager;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Wrapper around circles app API since it is not in a public namespace so we need to make sure that
|
||||
@@ -44,66 +40,24 @@ class CirclesService {
|
||||
$this->circlesEnabled = $appManager->isEnabledForUser('circles');
|
||||
}
|
||||
|
||||
public function isCirclesEnabled(): bool {
|
||||
return $this->circlesEnabled;
|
||||
}
|
||||
|
||||
public function getCircle(string $circleId): ?Circle {
|
||||
public function getCircle($circleId) {
|
||||
if (!$this->circlesEnabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
// Enforce current user condition since we always want the full list of members
|
||||
/** @var CirclesManager $circlesManager */
|
||||
$circlesManager = \OC::$server->get(CirclesManager::class);
|
||||
$circlesManager->startSuperSession();
|
||||
return $circlesManager->getCircle($circleId);
|
||||
} catch (Throwable $e) {
|
||||
}
|
||||
return null;
|
||||
return \OCA\Circles\Api\v1\Circles::detailsCircle($circleId, true);
|
||||
}
|
||||
|
||||
public function isUserInCircle(string $circleId, string $userId): bool {
|
||||
public function isUserInCircle($circleId, $userId): bool {
|
||||
if (!$this->circlesEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
/** @var CirclesManager $circlesManager */
|
||||
$circlesManager = \OC::$server->get(CirclesManager::class);
|
||||
$federatedUser = $circlesManager->getFederatedUser($userId, Member::TYPE_USER);
|
||||
$circlesManager->startSession($federatedUser);
|
||||
$circle = $circlesManager->getCircle($circleId);
|
||||
$member = $circle->getInitiator();
|
||||
return $member !== null && $member->getLevel() >= Member::LEVEL_MEMBER;
|
||||
} catch (Throwable $e) {
|
||||
$member = \OCA\Circles\Api\v1\Circles::getMember($circleId, $userId, 1, true);
|
||||
return $member->getLevel() >= Circles::LEVEL_MEMBER;
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $userId
|
||||
* @return string[] circle single ids
|
||||
*/
|
||||
public function getUserCircles(string $userId): array {
|
||||
if (!$this->circlesEnabled) {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
/** @var CirclesManager $circlesManager */
|
||||
$circlesManager = \OC::$server->get(CirclesManager::class);
|
||||
$federatedUser = $circlesManager->getFederatedUser($userId, Member::TYPE_USER);
|
||||
$circlesManager->startSession($federatedUser);
|
||||
$probe = new CircleProbe();
|
||||
$probe->mustBeMember();
|
||||
return array_map(function (Circle $circle) {
|
||||
return $circle->getSingleId();
|
||||
}, $circlesManager->getCircles($probe));
|
||||
} catch (Throwable $e) {
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,29 +46,20 @@ class ConfigService {
|
||||
|
||||
public function __construct(
|
||||
IConfig $config,
|
||||
IGroupManager $groupManager
|
||||
IGroupManager $groupManager,
|
||||
IUserSession $userSession
|
||||
) {
|
||||
// Session is required here in order to make the tests properly inject the userId later on
|
||||
$this->userId = $userSession->getUser() ? $userSession->getUser()->getUID() : null;
|
||||
$this->groupManager = $groupManager;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function getUserId() {
|
||||
if (!$this->userId) {
|
||||
$user = \OC::$server->get(IUserSession::class)->getUser();
|
||||
$this->userId = $user ? $user->getUID() : null;
|
||||
}
|
||||
return $this->userId;
|
||||
}
|
||||
|
||||
public function getAll(): array {
|
||||
if ($this->getUserId() === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$data = [
|
||||
'calendar' => $this->isCalendarEnabled()
|
||||
];
|
||||
if ($this->groupManager->isAdmin($this->getUserId())) {
|
||||
if ($this->groupManager->isAdmin($this->userId)) {
|
||||
$data['groupLimit'] = $this->get('groupLimit');
|
||||
}
|
||||
return $data;
|
||||
@@ -79,47 +70,43 @@ class ConfigService {
|
||||
[$scope] = explode(':', $key, 2);
|
||||
switch ($scope) {
|
||||
case 'groupLimit':
|
||||
if ($this->getUserId() === null || !$this->groupManager->isAdmin($this->getUserId())) {
|
||||
if (!$this->groupManager->isAdmin($this->userId)) {
|
||||
throw new NoPermissionException('You must be admin to get the group limit');
|
||||
}
|
||||
return $this->getGroupLimit();
|
||||
case 'calendar':
|
||||
if ($this->getUserId() === null) {
|
||||
if ($this->userId === null) {
|
||||
return false;
|
||||
}
|
||||
return (bool)$this->config->getUserValue($this->getUserId(), Application::APP_ID, 'calendar', true);
|
||||
return (bool)$this->config->getUserValue($this->userId, Application::APP_ID, 'calendar', true);
|
||||
}
|
||||
}
|
||||
|
||||
public function isCalendarEnabled(int $boardId = null): bool {
|
||||
if ($this->getUserId() === null) {
|
||||
if ($this->userId === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$defaultState = (bool)$this->config->getUserValue($this->getUserId(), Application::APP_ID, 'calendar', true);
|
||||
$defaultState = (bool)$this->config->getUserValue($this->userId, Application::APP_ID, 'calendar', true);
|
||||
if ($boardId === null) {
|
||||
return $defaultState;
|
||||
}
|
||||
|
||||
return (bool)$this->config->getUserValue($this->getUserId(), Application::APP_ID, 'board:' . $boardId . ':calendar', $defaultState);
|
||||
return (bool)$this->config->getUserValue($this->userId, Application::APP_ID, 'board:' . $boardId . ':calendar', $defaultState);
|
||||
}
|
||||
|
||||
public function set($key, $value) {
|
||||
if ($this->getUserId() === null) {
|
||||
throw new NoPermissionException('Must be logged in to set user config');
|
||||
}
|
||||
|
||||
$result = null;
|
||||
[$scope] = explode(':', $key, 2);
|
||||
switch ($scope) {
|
||||
case 'groupLimit':
|
||||
if (!$this->groupManager->isAdmin($this->getUserId())) {
|
||||
if (!$this->groupManager->isAdmin($this->userId)) {
|
||||
throw new NoPermissionException('You must be admin to set the group limit');
|
||||
}
|
||||
$result = $this->setGroupLimit($value);
|
||||
break;
|
||||
case 'calendar':
|
||||
$this->config->setUserValue($this->getUserId(), Application::APP_ID, 'calendar', (string)$value);
|
||||
$this->config->setUserValue($this->userId, Application::APP_ID, 'calendar', (int)$value);
|
||||
$result = $value;
|
||||
break;
|
||||
case 'board':
|
||||
@@ -127,7 +114,7 @@ class ConfigService {
|
||||
if ($boardConfigKey === 'notify-due' && !in_array($value, [self::SETTING_BOARD_NOTIFICATION_DUE_ALL, self::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED, self::SETTING_BOARD_NOTIFICATION_DUE_OFF], true)) {
|
||||
throw new BadRequestException('Board notification option must be one of: off, assigned, all');
|
||||
}
|
||||
$this->config->setUserValue($this->getUserId(), Application::APP_ID, $key, (string)$value);
|
||||
$this->config->setUserValue($this->userId, Application::APP_ID, $key, $value);
|
||||
$result = $value;
|
||||
}
|
||||
return $result;
|
||||
@@ -169,10 +156,6 @@ class ConfigService {
|
||||
}
|
||||
|
||||
public function getAttachmentFolder(): string {
|
||||
if ($this->getUserId() === null) {
|
||||
throw new NoPermissionException('Must be logged in get the attachment folder');
|
||||
}
|
||||
|
||||
return $this->config->getUserValue($this->getUserId(), 'deck', 'attachment_folder', '/Deck');
|
||||
return $this->config->getUserValue($this->userId, 'deck', 'attachment_folder', '/Deck');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ class OverviewService {
|
||||
$service = $this;
|
||||
|
||||
if (count($userBoard->getAcl()) === 0) {
|
||||
// private board: get cards with due date
|
||||
// get cards with due date
|
||||
$findCards[] = array_map(static function ($card) use ($service, $userBoard, $userId) {
|
||||
$service->enrich($card, $userId);
|
||||
$cardData = $card->jsonSerialize();
|
||||
@@ -122,13 +122,13 @@ class OverviewService {
|
||||
return $cardData;
|
||||
}, $this->cardMapper->findAllWithDue($userBoard->getId()));
|
||||
} else {
|
||||
// shared board: get all my assigned or unassigned cards
|
||||
// get assigned cards
|
||||
$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));
|
||||
}, $this->cardMapper->findAssignedCards($userBoard->getId(), $userId));
|
||||
}
|
||||
}
|
||||
return $findCards;
|
||||
|
||||
@@ -33,7 +33,6 @@ use OCA\Deck\Db\IPermissionMapper;
|
||||
use OCA\Deck\Db\User;
|
||||
use OCA\Deck\NoPermissionException;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||
use OCP\IConfig;
|
||||
use OCP\IGroupManager;
|
||||
@@ -43,8 +42,6 @@ use OCP\Share\IManager;
|
||||
|
||||
class PermissionService {
|
||||
|
||||
/** @var CirclesService */
|
||||
private $circlesService;
|
||||
/** @var BoardMapper */
|
||||
private $boardMapper;
|
||||
/** @var AclMapper */
|
||||
@@ -64,11 +61,11 @@ class PermissionService {
|
||||
/** @var array */
|
||||
private $users = [];
|
||||
|
||||
private $circlesEnabled = false;
|
||||
private $boardCache;
|
||||
|
||||
public function __construct(
|
||||
ILogger $logger,
|
||||
CirclesService $circlesService,
|
||||
AclMapper $aclMapper,
|
||||
BoardMapper $boardMapper,
|
||||
IUserManager $userManager,
|
||||
@@ -77,7 +74,6 @@ class PermissionService {
|
||||
IConfig $config,
|
||||
$userId
|
||||
) {
|
||||
$this->circlesService = $circlesService;
|
||||
$this->aclMapper = $aclMapper;
|
||||
$this->boardMapper = $boardMapper;
|
||||
$this->logger = $logger;
|
||||
@@ -88,6 +84,9 @@ class PermissionService {
|
||||
$this->userId = $userId;
|
||||
|
||||
$this->boardCache = new CappedMemoryCache();
|
||||
|
||||
$this->circlesEnabled = \OC::$server->getAppManager()->isEnabledForUser('circles') &&
|
||||
(version_compare(\OC::$server->getAppManager()->getAppVersion('circles'), '0.17.1') >= 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -211,11 +210,10 @@ class PermissionService {
|
||||
return $acl->getPermission($permission);
|
||||
}
|
||||
|
||||
if ($this->circlesService->isCirclesEnabled() && $acl->getType() === Acl::PERMISSION_TYPE_CIRCLE) {
|
||||
if ($this->circlesEnabled && $acl->getType() === Acl::PERMISSION_TYPE_CIRCLE) {
|
||||
try {
|
||||
if ($this->circlesService->isUserInCircle($acl->getParticipant(), $userId) && $acl->getPermission($permission)) {
|
||||
return true;
|
||||
}
|
||||
$member = \OCA\Circles\Api\v1\Circles::getMember($acl->getParticipant(), $this->userId, 1, true);
|
||||
return $member->getLevel() >= Member::LEVEL_MEMBER && $acl->getPermission($permission);
|
||||
} catch (\Exception $e) {
|
||||
$this->logger->info('Member not found in circle that was accessed. This should not happen.');
|
||||
}
|
||||
@@ -243,7 +241,6 @@ class PermissionService {
|
||||
if (array_key_exists((string) $boardId, $this->users) && !$refresh) {
|
||||
return $this->users[(string) $boardId];
|
||||
}
|
||||
|
||||
try {
|
||||
$board = $this->boardMapper->find($boardId);
|
||||
} catch (DoesNotExistException $e) {
|
||||
@@ -281,19 +278,15 @@ class PermissionService {
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->circlesService->isCirclesEnabled() && $acl->getType() === Acl::PERMISSION_TYPE_CIRCLE) {
|
||||
if ($this->circlesEnabled && $acl->getType() === Acl::PERMISSION_TYPE_CIRCLE) {
|
||||
try {
|
||||
$circle = $this->circlesService->getCircle($acl->getParticipant());
|
||||
$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($acl->getParticipant(), true);
|
||||
if ($circle === null) {
|
||||
$this->logger->info('No circle found for acl rule ' . $acl->getId());
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($circle->getInheritedMembers() as $member) {
|
||||
if ($member->getUserType() !== 1 || $member->getLevel() < Member::LEVEL_MEMBER) {
|
||||
// deck currently only supports user members in circles
|
||||
continue;
|
||||
}
|
||||
foreach ($circle->getMembers() as $member) {
|
||||
$user = $this->userManager->get($member->getUserId());
|
||||
if ($user === null) {
|
||||
$this->logger->info('No user found for circle member ' . $member->getUserId());
|
||||
@@ -311,10 +304,6 @@ class PermissionService {
|
||||
}
|
||||
|
||||
public function canCreate() {
|
||||
if ($this->userId === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$groups = $this->getGroupLimitList();
|
||||
if (count($groups) === 0) {
|
||||
return true;
|
||||
@@ -335,13 +324,4 @@ class PermissionService {
|
||||
}
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a different user than the current one, e.g. when no user is available in occ
|
||||
*
|
||||
* @param string $userId
|
||||
*/
|
||||
public function setUserId(string $userId): void {
|
||||
$this->userId = $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ use OCA\Deck\Db\ChangeHelper;
|
||||
use OCA\Deck\Db\LabelMapper;
|
||||
use OCA\Deck\Db\Stack;
|
||||
use OCA\Deck\Db\StackMapper;
|
||||
use OCA\Deck\NoPermissionException;
|
||||
use OCA\Deck\StatusException;
|
||||
|
||||
class StackService {
|
||||
@@ -143,12 +142,7 @@ class StackService {
|
||||
}
|
||||
|
||||
public function findCalendarEntries($boardId) {
|
||||
try {
|
||||
$this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_READ);
|
||||
} catch (NoPermissionException $e) {
|
||||
\OC::$server->getLogger()->error('Unable to check permission for a previously obtained board ' . $boardId, ['exception' => $e]);
|
||||
return [];
|
||||
}
|
||||
$this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_READ);
|
||||
return $this->stackMapper->findAll($boardId);
|
||||
}
|
||||
|
||||
@@ -181,7 +175,6 @@ class StackService {
|
||||
if (array_key_exists($card->id, $labels)) {
|
||||
$cards[$cardIndex]->setLabels($labels[$card->id]);
|
||||
}
|
||||
$cards[$cardIndex]->setAttachmentCount($this->attachmentService->count($card->getId()));
|
||||
}
|
||||
$stacks[$stackIndex]->setCards($cards);
|
||||
}
|
||||
|
||||
42793
package-lock.json
generated
42793
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
81
package.json
81
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "deck",
|
||||
"description": "",
|
||||
"version": "1.5.7",
|
||||
"version": "1.4.8",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Julius Härtl",
|
||||
@@ -29,29 +29,29 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/polyfill": "^7.12.1",
|
||||
"@babel/runtime": "^7.14.6",
|
||||
"@babel/runtime": "^7.13.10",
|
||||
"@juliushaertl/vue-richtext": "^1.0.1",
|
||||
"@nextcloud/auth": "^1.3.0",
|
||||
"@nextcloud/axios": "^1.6.0",
|
||||
"@nextcloud/dialogs": "^3.1.2",
|
||||
"@nextcloud/event-bus": "^2.0.0",
|
||||
"@nextcloud/files": "^2.0.0",
|
||||
"@nextcloud/dialogs": "^3.1.1",
|
||||
"@nextcloud/event-bus": "^1.2.0",
|
||||
"@nextcloud/files": "^1.1.0",
|
||||
"@nextcloud/initial-state": "^1.2.0",
|
||||
"@nextcloud/l10n": "^1.4.1",
|
||||
"@nextcloud/moment": "^1.1.1",
|
||||
"@nextcloud/router": "^2.0.0",
|
||||
"@nextcloud/vue": "^3.10.1",
|
||||
"@nextcloud/vue-dashboard": "^2.0.1",
|
||||
"@nextcloud/router": "^1.2.0",
|
||||
"@nextcloud/vue": "^3.8.0",
|
||||
"@nextcloud/vue-dashboard": "^1.1.0",
|
||||
"blueimp-md5": "^2.18.0",
|
||||
"dompurify": "^2.2.9",
|
||||
"dompurify": "^2.2.7",
|
||||
"lodash": "^4.17.21",
|
||||
"markdown-it": "^12.0.6",
|
||||
"markdown-it": "^12.0.4",
|
||||
"markdown-it-task-lists": "^2.1.1",
|
||||
"moment": "^2.29.1",
|
||||
"nextcloud-vue-collections": "^0.9.0",
|
||||
"p-queue": "^6.6.2",
|
||||
"url-search-params-polyfill": "^8.1.1",
|
||||
"vue": "^2.6.14",
|
||||
"vue": "^2.6.12",
|
||||
"vue-at": "^2.5.0-beta.2",
|
||||
"vue-click-outside": "^1.1.0",
|
||||
"vue-easymde": "^1.4.0",
|
||||
@@ -65,20 +65,57 @@
|
||||
"extends @nextcloud/browserslist-config"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=14.0.0",
|
||||
"npm": ">=7.0.0"
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nextcloud/babel-config": "^1.0.0-beta.1",
|
||||
"@nextcloud/browserslist-config": "^2.1.0",
|
||||
"@nextcloud/eslint-config": "^5.1.0",
|
||||
"@nextcloud/stylelint-config": "^1.0.0-beta.0",
|
||||
"@nextcloud/webpack-vue-config": "^4.0.3",
|
||||
"@relative-ci/agent": "^2.0.0",
|
||||
"@vue/test-utils": "^1.2.1",
|
||||
"jest": "^27.0.4",
|
||||
"@babel/core": "^7.13.14",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||
"@babel/preset-env": "^7.13.12",
|
||||
"@nextcloud/browserslist-config": "^1.0.0",
|
||||
"@nextcloud/eslint-config": "^2.2.0",
|
||||
"@nextcloud/eslint-plugin": "^1.5.0",
|
||||
"@nextcloud/webpack-vue-config": "^1.4.1",
|
||||
"@relative-ci/agent": "^1.5.0",
|
||||
"@vue/test-utils": "^1.1.3",
|
||||
"acorn": "^8.1.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-jest": "^26.6.3",
|
||||
"babel-loader": "^8.2.2",
|
||||
"css-loader": "^4.3.0",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-standard": "^14.1.1",
|
||||
"eslint-friendly-formatter": "^4.0.1",
|
||||
"eslint-loader": "^4.0.2",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^4.3.1",
|
||||
"eslint-plugin-standard": "^4.1.0",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"file-loader": "^6.2.0",
|
||||
"jest": "^26.6.3",
|
||||
"jest-serializer-vue": "^2.0.2",
|
||||
"vue-jest": "^3.0.7"
|
||||
"minimist": "^1.2.5",
|
||||
"node-sass": "^4.14.1",
|
||||
"raw-loader": "^4.0.2",
|
||||
"sass-loader": "^10.1.1",
|
||||
"style-loader": "^1.3.0",
|
||||
"stylelint": "^13.12.0",
|
||||
"stylelint-config-recommended": "^4.0.0",
|
||||
"stylelint-config-recommended-scss": "^4.2.0",
|
||||
"stylelint-scss": "^3.19.0",
|
||||
"stylelint-webpack-plugin": "^2.1.1",
|
||||
"url-loader": "^4.1.1",
|
||||
"vue-jest": "^3.0.7",
|
||||
"vue-loader": "^15.9.6",
|
||||
"vue-template-compiler": "^2.6.12",
|
||||
"webpack": "^4.46.0",
|
||||
"webpack-cli": "^3.3.12",
|
||||
"webpack-dev-server": "^3.11.2",
|
||||
"webpack-merge": "^5.7.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.0.0",
|
||||
"npm": "^7.0.0"
|
||||
},
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
|
||||
@@ -72,10 +72,10 @@
|
||||
</div>
|
||||
<div v-else id="modal-inner">
|
||||
<EmptyContent v-if="creating" icon="icon-loading">
|
||||
{{ t('deck', 'Creating the new card …') }}
|
||||
{{ 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 }) }}
|
||||
{{ t('deck', '"{card}" was added to "{board}"', { card: pendingTitle, board: selectedBoard.title }) }}
|
||||
<template #desc>
|
||||
<button class="primary" @click="openNewCard">
|
||||
{{ t('deck', 'Open card') }}
|
||||
@@ -168,7 +168,6 @@ export default {
|
||||
|
||||
},
|
||||
close() {
|
||||
this.$emit('close')
|
||||
this.$root.$emit('close')
|
||||
},
|
||||
async select() {
|
||||
|
||||
@@ -79,7 +79,7 @@ export default {
|
||||
parameters.after.name = moment(dateTime).format('L LTS')
|
||||
}
|
||||
|
||||
Object.keys(parameters).forEach(function(key, index) {
|
||||
Object.keys(parameters).map(function(key, index) {
|
||||
const { type } = parameters[key]
|
||||
switch (type) {
|
||||
case 'highlight':
|
||||
|
||||
@@ -84,7 +84,7 @@ 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)
|
||||
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
|
||||
|
||||
@@ -25,12 +25,6 @@
|
||||
<div v-if="overviewName" class="board-title">
|
||||
<div class="board-bullet icon-calendar-dark" />
|
||||
<h2>{{ overviewName }}</h2>
|
||||
<Actions>
|
||||
<ActionButton icon="icon-add" @click="clickShowAddCardModel">
|
||||
{{ t('deck', 'Add card') }}
|
||||
</ActionButton>
|
||||
</Actions>
|
||||
<CardCreateDialog v-if="showAddCardModal" @close="clickHideAddCardModel" />
|
||||
</div>
|
||||
<div v-else-if="board" class="board-title">
|
||||
<div :style="{backgroundColor: '#' + board.color}" class="board-bullet" />
|
||||
@@ -212,12 +206,11 @@
|
||||
import { mapState, mapGetters } from 'vuex'
|
||||
import { Actions, ActionButton, Popover, Avatar } from '@nextcloud/vue'
|
||||
import labelStyle from '../mixins/labelStyle'
|
||||
import CardCreateDialog from '../CardCreateDialog'
|
||||
|
||||
export default {
|
||||
name: 'Controls',
|
||||
components: {
|
||||
Actions, ActionButton, Popover, Avatar, CardCreateDialog,
|
||||
Actions, ActionButton, Popover, Avatar,
|
||||
},
|
||||
mixins: [labelStyle],
|
||||
props: {
|
||||
@@ -240,7 +233,6 @@ export default {
|
||||
showArchived: false,
|
||||
isAddStackVisible: false,
|
||||
filter: { tags: [], users: [], due: '', unassigned: false },
|
||||
showAddCardModal: false,
|
||||
}
|
||||
},
|
||||
|
||||
@@ -326,12 +318,6 @@ export default {
|
||||
this.$store.dispatch('setFilter', { ...filterReset })
|
||||
this.filter = filterReset
|
||||
},
|
||||
clickShowAddCardModel() {
|
||||
this.showAddCardModal = true
|
||||
},
|
||||
clickHideAddCardModel() {
|
||||
this.showAddCardModal = false
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -53,9 +53,6 @@
|
||||
<ActionCheckbox v-if="canManage" :checked="acl.permissionManage" @change="clickManageAcl(acl)">
|
||||
{{ t('deck', 'Can manage') }}
|
||||
</ActionCheckbox>
|
||||
<ActionCheckbox v-if="acl.type === 0 && isCurrentUser(board.owner.uid)" :checked="acl.owner" @change="clickTransferOwner(acl.participant.uid)">
|
||||
{{ t('deck', 'Owner') }}
|
||||
</ActionCheckbox>
|
||||
<ActionButton v-if="canManage" icon="icon-delete" @click="clickDeleteAcl(acl)">
|
||||
{{ t('deck', 'Delete') }}
|
||||
</ActionButton>
|
||||
@@ -75,7 +72,7 @@ import { Avatar, Multiselect, Actions, ActionButton, ActionCheckbox } from '@nex
|
||||
import { CollectionList } from 'nextcloud-vue-collections'
|
||||
import { mapGetters, mapState } from 'vuex'
|
||||
import { getCurrentUser } from '@nextcloud/auth'
|
||||
import { showError, showSuccess } from '@nextcloud/dialogs'
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
import debounce from 'lodash/debounce'
|
||||
|
||||
export default {
|
||||
@@ -100,7 +97,6 @@ export default {
|
||||
isSearching: false,
|
||||
addAcl: null,
|
||||
addAclForAPI: null,
|
||||
newOwner: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -198,38 +194,6 @@ export default {
|
||||
clickDeleteAcl(acl) {
|
||||
this.$store.dispatch('deleteAclFromCurrentBoard', acl)
|
||||
},
|
||||
clickTransferOwner(newOwner) {
|
||||
OC.dialogs.confirmDestructive(
|
||||
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,
|
||||
confirm: t('deck', 'Transfer'),
|
||||
confirmClasses: 'error',
|
||||
cancel: t('deck', 'Cancel'),
|
||||
},
|
||||
async(result) => {
|
||||
if (result) {
|
||||
try {
|
||||
this.isLoading = true
|
||||
await this.$store.dispatch('transferOwnership', {
|
||||
boardId: this.board.id,
|
||||
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 for {user}', { user: newOwner.user })
|
||||
showError(errorMessage)
|
||||
} finally {
|
||||
this.isLoading = false
|
||||
}
|
||||
}
|
||||
},
|
||||
true
|
||||
)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -264,14 +264,12 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@use 'sass:math';
|
||||
|
||||
@import './../../css/variables';
|
||||
|
||||
.stack {
|
||||
width: $stack-width + $stack-spacing*3;
|
||||
margin-left: math.div($stack-spacing, 2);
|
||||
margin-right: math.div($stack-spacing, 2);
|
||||
margin-left: $stack-spacing/2;
|
||||
margin-right: $stack-spacing/2;
|
||||
}
|
||||
|
||||
.stack__header {
|
||||
|
||||
@@ -228,7 +228,7 @@ export default {
|
||||
throw new Error(t('files', 'Invalid path selected'))
|
||||
}
|
||||
|
||||
axios.post(generateOcsUrl('apps/files_sharing/api/v1/shares'), {
|
||||
axios.post(generateOcsUrl('apps/files_sharing/api/v1', 2) + 'shares', {
|
||||
path,
|
||||
shareType: 12,
|
||||
shareWith: '' + this.cardId,
|
||||
@@ -245,7 +245,7 @@ export default {
|
||||
},
|
||||
showViewer(attachment) {
|
||||
if (attachment.extendedData.fileid && window.OCA.Viewer.availableHandlers.map(handler => handler.mimes).flat().includes(attachment.extendedData.mimetype)) {
|
||||
window.OCA.Viewer.open({ path: attachment.extendedData.path })
|
||||
window.OCA.Viewer.open(attachment.extendedData.path)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -205,8 +205,6 @@ export default {
|
||||
max-width: calc(100% - #{$modal-padding*2});
|
||||
padding: 0 14px;
|
||||
max-height: 100%;
|
||||
user-select: text;
|
||||
-webkit-user-select: text;
|
||||
&::v-deep {
|
||||
.app-sidebar-header {
|
||||
position: sticky;
|
||||
|
||||
@@ -28,11 +28,11 @@
|
||||
:members="members"
|
||||
name-key="displayname"
|
||||
:tab-select="true">
|
||||
<template #item="s">
|
||||
<template v-slot:item="s">
|
||||
<Avatar class="atwho-li--avatar" :user="s.item.uid" :size="24" />
|
||||
<span class="atwho-li--name" v-text="s.item.displayname" />
|
||||
</template>
|
||||
<template #embeddedItem="scope">
|
||||
<template v-slot:embeddedItem="scope">
|
||||
<span>
|
||||
<UserBubble v-if="scope.current.uid"
|
||||
:data-mention-id="scope.current.uid"
|
||||
|
||||
@@ -315,12 +315,6 @@ h5 {
|
||||
border-left: 1px solid var(--color-main-text);
|
||||
}
|
||||
|
||||
.CodeMirror-selected,
|
||||
.CodeMirror-line::selection, .CodeMirror-line>span::selection, .CodeMirror-line>span>span::selection {
|
||||
background: var(--color-primary-element) !important;
|
||||
color: var(--color-primary-text) !important;
|
||||
}
|
||||
|
||||
.editor-preview,
|
||||
.editor-statusbar {
|
||||
display: none;
|
||||
|
||||
@@ -35,14 +35,14 @@
|
||||
<Avatar v-if="user.type === 1"
|
||||
:user="user.participant.uid"
|
||||
:display-name="user.participant.displayname"
|
||||
:tooltip-message="user.participant.displayname + ' ' + t('deck', '(Group)')"
|
||||
:tooltip-message="user.participant.displayname + ' ' + t('deck', '(group)')"
|
||||
:is-no-user="true"
|
||||
:disable-="true"
|
||||
:size="32" />
|
||||
<Avatar v-if="user.type === 7"
|
||||
:user="user.participant.uid"
|
||||
:display-name="user.participant.displayname"
|
||||
:tooltip-message="user.participant.displayname + ' ' + t('deck', '(Circle)')"
|
||||
:tooltip-message="user.participant.displayname + ' ' + t('deck', '(circle)')"
|
||||
:is-no-user="true"
|
||||
:disable-="true"
|
||||
:size="32" />
|
||||
@@ -72,7 +72,7 @@ export default {
|
||||
props: {
|
||||
users: {
|
||||
type: Array,
|
||||
default: () => ([]),
|
||||
default: () => { return {} },
|
||||
},
|
||||
},
|
||||
data() {
|
||||
@@ -132,7 +132,7 @@ export default {
|
||||
margin-top: 5px;
|
||||
position: relative;
|
||||
flex-grow: 1;
|
||||
::v-deep .popovermenu {
|
||||
/deep/ .popovermenu {
|
||||
margin-right: -4px;
|
||||
img {
|
||||
padding: 0;
|
||||
@@ -152,7 +152,7 @@ export default {
|
||||
padding-right: $avatar-offset;
|
||||
flex-direction: row-reverse;
|
||||
.avatardiv,
|
||||
::v-deep .avatardiv {
|
||||
/deep/ .avatardiv {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
box-sizing: content-box !important;
|
||||
@@ -167,7 +167,7 @@ export default {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
&:hover div:nth-child(n+2) ::v-deep .avatardiv {
|
||||
&:hover div:nth-child(n+2) /deep/ .avatardiv {
|
||||
margin-right: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ export default {
|
||||
if (this.card.commentsUnread > 0) {
|
||||
return t('deck', '{count} comments, {unread} unread', {
|
||||
count: this.card.commentsCount,
|
||||
unread: this.card.commentsUnread,
|
||||
unread: this.card.commentsUnread
|
||||
})
|
||||
}
|
||||
return null
|
||||
|
||||
@@ -66,11 +66,7 @@
|
||||
:placeholder="t('deck', 'Select a list')"
|
||||
:options="stacksFromBoard"
|
||||
:max-height="100"
|
||||
label="title">
|
||||
<span slot="noOptions">
|
||||
{{ t('deck', 'List is empty') }}
|
||||
</span>
|
||||
</Multiselect>
|
||||
label="title" />
|
||||
|
||||
<button :disabled="!isBoardAndStackChoosen" class="primary" @click="moveCard">
|
||||
{{ t('deck', 'Move card') }}
|
||||
@@ -135,7 +131,7 @@ export default {
|
||||
},
|
||||
activeBoards() {
|
||||
return this.$store.getters.boards.filter((item) => item.deletedAt === 0 && item.archived === false)
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openCard() {
|
||||
|
||||
@@ -163,7 +163,7 @@ export default {
|
||||
if (this.isAdmin) {
|
||||
this.groupLimit = this.$store.getters.config('groupLimit')
|
||||
this.groupLimitDisabled = false
|
||||
axios.get(generateOcsUrl('cloud/groups')).then((response) => {
|
||||
axios.get(generateOcsUrl('cloud', 2) + 'groups').then((response) => {
|
||||
this.groups = response.data.ocs.data.groups.reduce((obj, item) => {
|
||||
obj.push({
|
||||
id: item,
|
||||
|
||||
@@ -125,10 +125,7 @@
|
||||
<div :style="{ backgroundColor: getColor }" class="color0 icon-colorpicker app-navigation-entry-bullet" />
|
||||
</ColorPicker>
|
||||
<form @submit.prevent.stop="applyEdit">
|
||||
<input v-model="editTitle"
|
||||
v-focus
|
||||
type="text"
|
||||
required>
|
||||
<input v-model="editTitle" type="text" required>
|
||||
<input type="submit" value="" class="icon-confirm">
|
||||
<Actions><ActionButton icon="icon-close" @click.stop.prevent="cancelEdit" /></Actions>
|
||||
</form>
|
||||
@@ -152,9 +149,6 @@ export default {
|
||||
directives: {
|
||||
ClickOutside,
|
||||
},
|
||||
inject: [
|
||||
'boardApi',
|
||||
],
|
||||
props: {
|
||||
board: {
|
||||
type: Object,
|
||||
@@ -309,6 +303,9 @@ export default {
|
||||
this.updateDueSetting = null
|
||||
},
|
||||
},
|
||||
inject: [
|
||||
'boardApi',
|
||||
],
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
boardsSorted() {
|
||||
return [...this.boards].sort((a, b) => a.title.localeCompare(b.title))
|
||||
return [...this.boards].sort((a, b) => (a.title < b.title) ? -1 : 1)
|
||||
},
|
||||
collapsible() {
|
||||
return this.boards.length > 0
|
||||
|
||||
@@ -66,7 +66,7 @@ const createCancelToken = () => axios.CancelToken.source()
|
||||
function search({ query, cursor }) {
|
||||
const cancelToken = createCancelToken()
|
||||
|
||||
const request = async() => axios.get(generateOcsUrl('apps/deck/api/v1.0/search'), {
|
||||
const request = async() => axios.get(generateOcsUrl('apps/deck/api/v1.0', 2) + '/search', {
|
||||
cancelToken: cancelToken.token,
|
||||
params: {
|
||||
term: query,
|
||||
|
||||
@@ -44,37 +44,15 @@ window.addEventListener('DOMContentLoaded', () => {
|
||||
window.OCA.Talk.registerMessageAction({
|
||||
label: t('deck', 'Create a card'),
|
||||
icon: 'icon-deck',
|
||||
async callback({ message: { message, messageParameters, actorDisplayName }, metadata: { name: conversationName, token: conversationToken } }) {
|
||||
const parsedMessage = message.replace(/{[a-z0-9-_]+}/gi, function(parameter) {
|
||||
const parameterName = parameter.substr(1, parameter.length - 2)
|
||||
|
||||
if (messageParameters[parameterName]) {
|
||||
if (messageParameters[parameterName].type === 'file' && messageParameters[parameterName].path) {
|
||||
return messageParameters[parameterName].path
|
||||
}
|
||||
if (messageParameters[parameterName].type === 'user' || messageParameters[parameterName].type === 'call') {
|
||||
return '@' + messageParameters[parameterName].name
|
||||
}
|
||||
if (messageParameters[parameterName].name) {
|
||||
return messageParameters[parameterName].name
|
||||
}
|
||||
}
|
||||
|
||||
// Do not replace so insert with curly braces again
|
||||
return parameter
|
||||
})
|
||||
|
||||
const shortenedMessageCandidate = parsedMessage.replace(/^(.{255}[^\s]*).*/, '$1')
|
||||
const shortenedMessage = shortenedMessageCandidate === '' ? parsedMessage.substr(0, 255) : shortenedMessageCandidate
|
||||
async callback({ message: { message, actorDisplayName }, metadata: { name: conversationName, token: conversationToken } }) {
|
||||
const shortenedMessageCandidate = message.replace(/^(.{255}[^\s]*).*/, '$1')
|
||||
const shortenedMessage = shortenedMessageCandidate === '' ? message.substr(0, 255) : shortenedMessageCandidate
|
||||
try {
|
||||
await buildSelector(CardCreateDialog, {
|
||||
title: shortenedMessage,
|
||||
description: parsedMessage + '\n\n' + '['
|
||||
+ t('deck', 'Message from {author} in {conversationName}', {
|
||||
author: actorDisplayName,
|
||||
conversationName,
|
||||
})
|
||||
+ '](' + window.location.protocol + '//' + window.location.host + generateUrl('/call/' + conversationToken) + ')',
|
||||
description: message + '\n\n' + '['
|
||||
+ t('deck', 'Message from {author} in {conversationName}', { author: actorDisplayName, conversationName })
|
||||
+ '](' + generateUrl('/call/' + conversationToken) + ')',
|
||||
})
|
||||
} catch (e) {
|
||||
console.debug('Card creation dialog was canceled')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*
|
||||
* @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net>
|
||||
*
|
||||
* @author Julius Härtl <jus@bitgrid.net>
|
||||
@@ -84,7 +84,7 @@ export default {
|
||||
},
|
||||
colorIsValid(hex) {
|
||||
|
||||
const re = /[A-Fa-f0-9]{6}/
|
||||
const re = new RegExp('[A-Fa-f0-9]{6}')
|
||||
if (re.test(hex)) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ export class CommentApi {
|
||||
}
|
||||
|
||||
async loadComments({ cardId, limit, offset }) {
|
||||
const api = await axios.get(generateOcsUrl(`apps/deck/api/v1.0/cards/${cardId}/comments`), {
|
||||
const api = await axios.get(generateOcsUrl('apps/deck/api/v1.0/cards', 2) + `${cardId}/comments`, {
|
||||
params: { limit, offset },
|
||||
headers: { 'OCS-APIRequest': 'true' },
|
||||
})
|
||||
@@ -39,7 +39,7 @@ export class CommentApi {
|
||||
}
|
||||
|
||||
async createComment({ cardId, comment, replyTo }) {
|
||||
const api = await axios.post(generateOcsUrl(`apps/deck/api/v1.0/cards/${cardId}/comments`), {
|
||||
const api = await axios.post(generateOcsUrl('apps/deck/api/v1.0/cards', 2) + `${cardId}/comments`, {
|
||||
message: `${comment}`,
|
||||
parentId: replyTo ? replyTo.id : null,
|
||||
})
|
||||
@@ -47,14 +47,14 @@ export class CommentApi {
|
||||
}
|
||||
|
||||
async updateComment({ cardId, id, comment }) {
|
||||
const api = await axios.put(generateOcsUrl(`apps/deck/api/v1.0/cards/${cardId}/comments/${id}`), {
|
||||
const api = await axios.put(generateOcsUrl('apps/deck/api/v1.0/cards', 2) + `${cardId}/comments/${id}`, {
|
||||
message: `${comment}`,
|
||||
})
|
||||
return api.data.ocs.data
|
||||
}
|
||||
|
||||
async deleteComment({ cardId, id }) {
|
||||
const api = await axios.delete(generateOcsUrl(`apps/deck/api/v1.0/cards/${cardId}/comments/${id}`))
|
||||
const api = await axios.delete(generateOcsUrl('apps/deck/api/v1.0/cards', 2) + `${cardId}/comments/${id}`)
|
||||
return api.data.ocs.data
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import { generateOcsUrl } from '@nextcloud/router'
|
||||
export class OverviewApi {
|
||||
|
||||
url(url) {
|
||||
return generateOcsUrl(`apps/deck/api/v1.0/${url}`)
|
||||
return generateOcsUrl('apps/deck/api/v1.0') + url
|
||||
}
|
||||
|
||||
get(filter) {
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
import axios from '@nextcloud/axios'
|
||||
import { generateOcsUrl } from '@nextcloud/router'
|
||||
|
||||
const shareUrl = generateOcsUrl('apps/files_sharing/api/v1/shares')
|
||||
const shareUrl = generateOcsUrl('apps/files_sharing/api/v1', 2) + 'shares'
|
||||
|
||||
const createShare = async function({ path, permissions, shareType, shareWith, publicUpload, password, sendPasswordByTalk, expireDate, label }) {
|
||||
try {
|
||||
|
||||
@@ -26,7 +26,7 @@ import { loadState } from '@nextcloud/initial-state'
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import axios from '@nextcloud/axios'
|
||||
import { generateOcsUrl, generateUrl } from '@nextcloud/router'
|
||||
import { generateOcsUrl } from '@nextcloud/router'
|
||||
import { BoardApi } from '../services/BoardApi'
|
||||
import actions from './actions'
|
||||
import stack from './stack'
|
||||
@@ -317,7 +317,7 @@ export default new Vuex.Store({
|
||||
async setConfig({ commit }, config) {
|
||||
for (const key in config) {
|
||||
try {
|
||||
await axios.post(generateOcsUrl(`apps/deck/api/v1.0/config/${key}`), {
|
||||
await axios.post(generateOcsUrl('apps/deck/api/v1.0/config') + key, {
|
||||
value: config[key],
|
||||
})
|
||||
commit('SET_CONFIG', { key, value: config[key] })
|
||||
@@ -422,7 +422,7 @@ export default new Vuex.Store({
|
||||
params.append('itemType', [0, 1, 4, 7])
|
||||
params.append('lookup', false)
|
||||
|
||||
const response = await axios.get(generateOcsUrl('apps/files_sharing/api/v1/sharees'), { params })
|
||||
const response = await axios.get(generateOcsUrl('apps/files_sharing/api/v1') + 'sharees', { params })
|
||||
commit('setSharees', response.data.ocs.data)
|
||||
},
|
||||
|
||||
@@ -494,10 +494,5 @@ export default new Vuex.Store({
|
||||
dispatch('loadBoardById', acl.boardId)
|
||||
})
|
||||
},
|
||||
async transferOwnership({ commit }, { boardId, newOwner }) {
|
||||
await axios.put(generateUrl(`apps/deck/boards/${boardId}/transferOwner`), {
|
||||
newOwner,
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
@@ -21,39 +21,32 @@
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<DashboardWidget :items="cards"
|
||||
empty-content-icon="icon-deck"
|
||||
:empty-content-message="t('deck', 'No upcoming cards')"
|
||||
:show-more-text="t('deck', 'upcoming cards')"
|
||||
:loading="loading"
|
||||
@hide="() => {}"
|
||||
@markDone="() => {}">
|
||||
<template #default="{ item }">
|
||||
<a :key="item.id"
|
||||
:href="cardLink(item)"
|
||||
target="_blank"
|
||||
class="card">
|
||||
<div class="card--header">
|
||||
<DueDate class="right" :card="item" />
|
||||
<span class="title">{{ item.title }}</span>
|
||||
</div>
|
||||
<ul v-if="item.labels && item.labels.length"
|
||||
class="labels">
|
||||
<li v-for="label in item.labels" :key="label.id" :style="labelStyle(label)">
|
||||
<span>{{ label.title }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</a>
|
||||
</template>
|
||||
</DashboardWidget>
|
||||
<div class="center-button">
|
||||
<button @click="toggleAddCardModel">
|
||||
{{ t('deck', 'Add card') }}
|
||||
</button>
|
||||
<CardCreateDialog v-if="showAddCardModal" @close="toggleAddCardModel" />
|
||||
</div>
|
||||
</div>
|
||||
<DashboardWidget :items="cards"
|
||||
empty-content-icon="icon-deck"
|
||||
:empty-content-message="t('deck', 'No upcoming cards')"
|
||||
:show-more-text="t('deck', 'upcoming cards')"
|
||||
:show-more-url="showMoreUrl"
|
||||
:loading="loading"
|
||||
@hide="() => {}"
|
||||
@markDone="() => {}">
|
||||
<template v-slot:default="{ item }">
|
||||
<a :key="item.id"
|
||||
:href="cardLink(item)"
|
||||
target="_blank"
|
||||
class="card">
|
||||
<div class="card--header">
|
||||
<DueDate class="right" :card="item" />
|
||||
<span class="title">{{ item.title }}</span>
|
||||
</div>
|
||||
<ul v-if="item.labels && item.labels.length"
|
||||
class="labels">
|
||||
<li v-for="label in item.labels" :key="label.id" :style="labelStyle(label)">
|
||||
<span>{{ label.title }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</a>
|
||||
</template>
|
||||
</DashboardWidget>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -62,20 +55,17 @@ import { mapGetters } from 'vuex'
|
||||
import labelStyle from './../mixins/labelStyle'
|
||||
import DueDate from '../components/cards/badges/DueDate'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
import CardCreateDialog from '../CardCreateDialog'
|
||||
|
||||
export default {
|
||||
name: 'Dashboard',
|
||||
components: {
|
||||
DueDate,
|
||||
DashboardWidget,
|
||||
CardCreateDialog,
|
||||
},
|
||||
mixins: [labelStyle],
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
showAddCardModal: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -91,7 +81,7 @@ export default {
|
||||
list.sort((a, b) => {
|
||||
return (new Date(a.duedate)).getTime() - (new Date(b.duedate)).getTime()
|
||||
})
|
||||
return list.slice(0, 6)
|
||||
return list
|
||||
},
|
||||
cardLink() {
|
||||
return (card) => {
|
||||
@@ -108,21 +98,12 @@ export default {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
toggleAddCardModel() {
|
||||
this.showAddCardModal = !this.showAddCardModal
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './../css/labels';
|
||||
|
||||
.center-button {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#deck-widget-empty-content {
|
||||
text-align: center;
|
||||
margin-top: 5vh;
|
||||
|
||||
@@ -1,3 +1,32 @@
|
||||
const stylelintConfig = require('@nextcloud/stylelint-config')
|
||||
|
||||
module.exports = stylelintConfig
|
||||
module.exports = {
|
||||
extends: 'stylelint-config-recommended-scss',
|
||||
rules: {
|
||||
indentation: 'tab',
|
||||
'selector-type-no-unknown': null,
|
||||
'number-leading-zero': null,
|
||||
'rule-empty-line-before': [
|
||||
'always',
|
||||
{
|
||||
ignore: ['after-comment', 'inside-block']
|
||||
}
|
||||
],
|
||||
'declaration-empty-line-before': [
|
||||
'never',
|
||||
{
|
||||
ignore: ['after-declaration']
|
||||
}
|
||||
],
|
||||
'comment-empty-line-before': null,
|
||||
'selector-type-case': null,
|
||||
'selector-list-comma-newline-after': null,
|
||||
'no-descending-specificity': null,
|
||||
'string-quotes': 'single',
|
||||
'selector-pseudo-element-no-unknown': [
|
||||
true,
|
||||
{
|
||||
ignorePseudoElements: ['v-deep']
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: ['stylelint-scss']
|
||||
}
|
||||
|
||||
@@ -23,6 +23,6 @@
|
||||
|
||||
|
||||
style('deck', 'globalstyles');
|
||||
script('deck', 'deck-main');
|
||||
script('deck', 'main');
|
||||
|
||||
\OC::$server->getEventDispatcher()->dispatch('\OCP\Collaboration\Resources::loadAdditionalScripts');
|
||||
|
||||
@@ -1,314 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace OCA\Deck\Service;
|
||||
|
||||
use OCA\Deck\Db\Acl;
|
||||
use OCA\Deck\Db\Assignment;
|
||||
use OCA\Deck\Db\AssignmentMapper;
|
||||
use OCA\Deck\Db\Board;
|
||||
use OCA\Deck\Db\Card;
|
||||
|
||||
/**
|
||||
* @group DB
|
||||
* @coversDefaultClass \OCA\Deck\Service\BoardService
|
||||
*/
|
||||
class TransferOwnershipTest extends \Test\TestCase {
|
||||
private const TEST_USER_1 = 'test-share-user1';
|
||||
private const TEST_USER_2 = 'test-user2';
|
||||
private const TEST_USER_3 = 'test-user3';
|
||||
private const TEST_GROUP = 'test-share-user1';
|
||||
|
||||
/** @var BoardService */
|
||||
protected $boardService;
|
||||
/** @var CardService */
|
||||
protected $cardService;
|
||||
/** @var StackService */
|
||||
protected $stackService;
|
||||
/** @var AssignmentMapper */
|
||||
protected $assignmentMapper;
|
||||
/** @var AssignmentService */
|
||||
private $assignmentService;
|
||||
/** @var Board */
|
||||
private $board;
|
||||
private $cards;
|
||||
private $stacks;
|
||||
|
||||
public static function setUpBeforeClass(): void {
|
||||
parent::setUpBeforeClass();
|
||||
|
||||
$backend = new \Test\Util\User\Dummy();
|
||||
\OC_User::useBackend($backend);
|
||||
\OC::$server->getUserManager()->registerBackend($backend);
|
||||
$backend->createUser(self::TEST_USER_1, self::TEST_USER_1);
|
||||
$backend->createUser(self::TEST_USER_2, self::TEST_USER_2);
|
||||
$backend->createUser(self::TEST_USER_3, self::TEST_USER_3);
|
||||
// create group
|
||||
$groupBackend = new \Test\Util\Group\Dummy();
|
||||
$groupBackend->createGroup(self::TEST_GROUP);
|
||||
$groupBackend->addToGroup(self::TEST_USER_1, self::TEST_GROUP);
|
||||
\OC::$server->getGroupManager()->addBackend($groupBackend);
|
||||
}
|
||||
|
||||
public function setUp(): void {
|
||||
parent::setUp();
|
||||
\OC::$server->getUserSession()->login(self::TEST_USER_1, self::TEST_USER_1);
|
||||
$this->boardService = \OC::$server->query(BoardService::class);
|
||||
$this->stackService = \OC::$server->query(StackService::class);
|
||||
$this->cardService = \OC::$server->query(CardService::class);
|
||||
$this->assignmentService = \OC::$server->query(AssignmentService::class);
|
||||
$this->assignmentMapper = \OC::$server->query(AssignmentMapper::class);
|
||||
$this->createBoardWithExampleData();
|
||||
}
|
||||
|
||||
public function createBoardWithExampleData() {
|
||||
$stacks = [];
|
||||
$board = $this->boardService->create('Test', self::TEST_USER_1, '000000');
|
||||
$id = $board->getId();
|
||||
$this->boardService->addAcl($id, Acl::PERMISSION_TYPE_GROUP, self::TEST_GROUP, true, true, true);
|
||||
$this->boardService->addAcl($id, Acl::PERMISSION_TYPE_USER, self::TEST_USER_3, false, true, false);
|
||||
$stacks[] = $this->stackService->create('Stack A', $id, 1);
|
||||
$stacks[] = $this->stackService->create('Stack B', $id, 1);
|
||||
$stacks[] = $this->stackService->create('Stack C', $id, 1);
|
||||
$cards[] = $this->cardService->create('Card 1', $stacks[0]->getId(), 'text', 0, self::TEST_USER_1);
|
||||
$cards[] = $this->cardService->create('Card 2', $stacks[0]->getId(), 'text', 0, self::TEST_USER_1);
|
||||
$this->assignmentService->assignUser($cards[0]->getId(), self::TEST_USER_1);
|
||||
$this->board = $board;
|
||||
$this->cards = $cards;
|
||||
$this->stacks = $stacks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testTransferBoardOwnership() {
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2));
|
||||
$board = $this->boardService->find($this->board->getId());
|
||||
$boardOwner = $board->getOwner();
|
||||
$this->assertEquals(self::TEST_USER_2, $boardOwner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testTransferBoardOwnershipWithData() {
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2));
|
||||
$board = $this->boardService->find($this->board->getId());
|
||||
|
||||
$boardOwner = $board->getOwner();
|
||||
$this->assertEquals(self::TEST_USER_2, $boardOwner);
|
||||
|
||||
$cards = $this->cards;
|
||||
$newOwnerOwnsTheCards = (bool)array_product(array_filter($cards, function (Card $card) {
|
||||
$cardUpdated = $this->cardService->find($card->getId());
|
||||
return $cardUpdated->getOwner() === self::TEST_USER_2;
|
||||
}));
|
||||
$this->assertTrue($newOwnerOwnsTheCards);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testTransferACLOwnership() {
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2, true));
|
||||
$board = $this->boardService->find($this->board->getId());
|
||||
$acl = $board->getAcl();
|
||||
$this->assertBoardDoesNotHaveAclUser($board, self::TEST_USER_1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testTransferACLOwnershipPreserveOwner() {
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2, false));
|
||||
$board = $this->boardService->find($this->board->getId());
|
||||
$acl = $board->getAcl();
|
||||
$this->assertBoardHasAclUser($board, self::TEST_USER_1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testNoTransferAclOwnershipIfGroupType() {
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2));
|
||||
$board = $this->boardService->find($this->board->getId());
|
||||
$acl = $board->getAcl();
|
||||
$isGroupInAcl = (bool)array_filter($acl, function ($item) {
|
||||
return $item->getParticipant() === self::TEST_GROUP && $item->getType() === Acl::PERMISSION_TYPE_GROUP;
|
||||
});
|
||||
$this->assertTrue($isGroupInAcl);
|
||||
}
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testTransferCardOwnership() {
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2, true));
|
||||
$card = $this->cardService->find($this->cards[0]->getId());
|
||||
$cardOwner = $card->getOwner();
|
||||
$this->assertEquals(self::TEST_USER_2, $cardOwner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testTransferPreserveCardOwnership() {
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2, false));
|
||||
$card = $this->cardService->find($this->cards[0]->getId());
|
||||
$cardOwner = $card->getOwner();
|
||||
$this->assertEquals(self::TEST_USER_1, $cardOwner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testReassignCardToNewOwner() {
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2, true));
|
||||
$participantsUIDs = array_map(function ($user) {
|
||||
return $user->getParticipant();
|
||||
}, $this->assignmentMapper->findAll($this->cards[0]->getId()));
|
||||
$this->assertContains(self::TEST_USER_2, $participantsUIDs);
|
||||
$this->assertNotContains(self::TEST_USER_1, $participantsUIDs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testNoReassignCardToNewOwner() {
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2, false));
|
||||
$participantsUIDs = array_map(function ($user) {
|
||||
return $user->getParticipant();
|
||||
}, $this->assignmentMapper->findAll($this->cards[0]->getId()));
|
||||
$this->assertContains(self::TEST_USER_1, $participantsUIDs);
|
||||
$this->assertNotContains(self::TEST_USER_2, $participantsUIDs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testReassignCardToNewParticipantOnlyIfParticipantHasUserType() {
|
||||
$this->assignmentService->assignUser($this->cards[1]->getId(), self::TEST_USER_1, Assignment::TYPE_GROUP);
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2));
|
||||
$participantsUIDs = array_map(function ($user) {
|
||||
return $user->getParticipant();
|
||||
}, $this->assignmentMapper->findAll($this->cards[1]->getId()));
|
||||
$this->assertContains(self::TEST_USER_1, $participantsUIDs);
|
||||
$this->assertNotContains(self::TEST_USER_2, $participantsUIDs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testTargetAlreadyParticipantOfBoard() {
|
||||
$this->expectNotToPerformAssertions();
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_3));
|
||||
}
|
||||
|
||||
private function assertBoardHasAclUser($board, $userId) {
|
||||
$hasUser = (bool)array_filter($board->getAcl(), function ($item) use ($userId) {
|
||||
return $item->getParticipant() === $userId && $item->getType() === Acl::PERMISSION_TYPE_USER;
|
||||
});
|
||||
self::assertTrue($hasUser, 'user ' . $userId . ' should be in the board acl list');
|
||||
}
|
||||
|
||||
private function assertBoardDoesNotHaveAclUser($board, $userId) {
|
||||
$hasUser = (bool)array_filter($board->getAcl(), function ($item) use ($userId) {
|
||||
return $item->getParticipant() === $userId && $item->getType() === Acl::PERMISSION_TYPE_USER;
|
||||
});
|
||||
self::assertFalse($hasUser, 'user ' . $userId . ' should not be in the board acl list');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testDontRemoveOldOwnerFromAcl() {
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2));
|
||||
$board = $this->boardService->find($this->board->getId());
|
||||
|
||||
$this->assertBoardDoesNotHaveAclUser($board, self::TEST_USER_2);
|
||||
$this->assertBoardHasAclUser($board, self::TEST_USER_3);
|
||||
$this->assertBoardHasAclUser($board, self::TEST_USER_1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testRemoveOldOwnerFromAclForChange() {
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_2, true));
|
||||
$board = $this->boardService->find($this->board->getId());
|
||||
$this->assertBoardDoesNotHaveAclUser($board, self::TEST_USER_2);
|
||||
$this->assertBoardHasAclUser($board, self::TEST_USER_3);
|
||||
$this->assertBoardDoesNotHaveAclUser($board, self::TEST_USER_1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testMergePermissions() {
|
||||
$this->boardService->addAcl($this->board->getId(), Acl::PERMISSION_TYPE_USER, self::TEST_USER_2, true, false, true);
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_3));
|
||||
$board = $this->boardService->find($this->board->getId());
|
||||
$acl = $board->getAcl();
|
||||
$isMerged = (bool)array_filter($acl, function ($item) {
|
||||
return $item->getParticipant() === self::TEST_USER_1
|
||||
&& $item->getType() === Acl::PERMISSION_TYPE_USER
|
||||
&& $item->getPermission(Acl::PERMISSION_EDIT)
|
||||
&& $item->getPermission(Acl::PERMISSION_SHARE)
|
||||
&& $item->getPermission(Acl::PERMISSION_MANAGE);
|
||||
});
|
||||
$this->assertTrue($isMerged);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testTargetAlreadyParticipantOfCard() {
|
||||
$this->expectNotToPerformAssertions();
|
||||
$this->assignmentService->assignUser($this->cards[0]->getId(), self::TEST_USER_3, Assignment::TYPE_USER);
|
||||
iterator_to_array($this->boardService->transferOwnership(self::TEST_USER_1, self::TEST_USER_3));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::transferOwnership
|
||||
*/
|
||||
public function testTransferSingleBoardAssignment() {
|
||||
// Arrange separate board next to the one being transferred
|
||||
$board = $this->boardService->create('Test 2', self::TEST_USER_1, '000000');
|
||||
$id = $board->getId();
|
||||
$this->boardService->addAcl($id, Acl::PERMISSION_TYPE_USER, self::TEST_USER_1, true, true, true);
|
||||
$this->boardService->addAcl($id, Acl::PERMISSION_TYPE_GROUP, self::TEST_GROUP, true, true, true);
|
||||
$this->boardService->addAcl($id, Acl::PERMISSION_TYPE_USER, self::TEST_USER_3, false, true, false);
|
||||
$stacks[] = $this->stackService->create('Stack A', $id, 1);
|
||||
$stacks[] = $this->stackService->create('Stack B', $id, 1);
|
||||
$stacks[] = $this->stackService->create('Stack C', $id, 1);
|
||||
$cards[] = $this->cardService->create('Card 1', $stacks[0]->getId(), 'text', 0, self::TEST_USER_1);
|
||||
$cards[] = $this->cardService->create('Card 2', $stacks[0]->getId(), 'text', 0, self::TEST_USER_1);
|
||||
$this->assignmentService->assignUser($cards[0]->getId(), self::TEST_USER_1);
|
||||
|
||||
// Act
|
||||
$this->boardService->transferBoardOwnership($this->board->getId(), self::TEST_USER_2, true);
|
||||
|
||||
// Assert that the selected board was transferred
|
||||
$card = $this->cardService->find($this->cards[0]->getId());
|
||||
$this->assertEquals(self::TEST_USER_2, $card->getOwner());
|
||||
|
||||
$participantsUIDs = array_map(function ($assignment) {
|
||||
return $assignment->getParticipant();
|
||||
}, $this->assignmentMapper->findAll($this->cards[0]->getId()));
|
||||
$this->assertContains(self::TEST_USER_2, $participantsUIDs);
|
||||
$this->assertNotContains(self::TEST_USER_1, $participantsUIDs);
|
||||
|
||||
// Assert that other board remained unchanged
|
||||
$card = $this->cardService->find($cards[0]->getId());
|
||||
$this->assertEquals(self::TEST_USER_1, $card->getOwner());
|
||||
|
||||
$participantsUIDs = array_map(function ($assignment) {
|
||||
return $assignment->getParticipant();
|
||||
}, $this->assignmentMapper->findAll($cards[0]->getId()));
|
||||
$this->assertContains(self::TEST_USER_1, $participantsUIDs);
|
||||
$this->assertNotContains(self::TEST_USER_2, $participantsUIDs);
|
||||
}
|
||||
|
||||
public function tearDown(): void {
|
||||
$this->boardService->deleteForce($this->board->getId());
|
||||
parent::tearDown();
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ composer dump-autoload
|
||||
if [ -z "$EXECUTOR_NUMBER" ]; then
|
||||
EXECUTOR_NUMBER=0
|
||||
fi
|
||||
PORT=$((9090 + $EXECUTOR_NUMBER))
|
||||
PORT=$((8080 + $EXECUTOR_NUMBER))
|
||||
echo $PORT
|
||||
php -S localhost:$PORT -t $OC_PATH &
|
||||
PHPPID=$!
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<files psalm-version="4.7.3@38c452ae584467e939d55377aaf83b5a26f19dd1">
|
||||
<files psalm-version="4.7.0@d4377c0baf3ffbf0b1ec6998e8d1be2a40971005">
|
||||
<file src="lib/Activity/ActivityManager.php">
|
||||
<TypeDoesNotContainType occurrences="1">
|
||||
<code>$message !== null</code>
|
||||
@@ -38,6 +38,11 @@
|
||||
<code>$this->userId</code>
|
||||
</UndefinedThisPropertyFetch>
|
||||
</file>
|
||||
<file src="lib/Controller/BoardController.php">
|
||||
<UndefinedDocblockClass occurrences="1">
|
||||
<code>\OCP\Deck\DB\Board</code>
|
||||
</UndefinedDocblockClass>
|
||||
</file>
|
||||
<file src="lib/Controller/CommentsApiController.php">
|
||||
<InvalidScalarArgument occurrences="6">
|
||||
<code>$cardId</code>
|
||||
@@ -91,10 +96,19 @@
|
||||
<code>$cardId</code>
|
||||
</ParamNameMismatch>
|
||||
</file>
|
||||
<file src="lib/Db/AttachmentMapper.php">
|
||||
<UndefinedVariable occurrences="1">
|
||||
<code>$query</code>
|
||||
</UndefinedVariable>
|
||||
</file>
|
||||
<file src="lib/Db/BoardMapper.php">
|
||||
<ParamNameMismatch occurrences="1">
|
||||
<code>$boardId</code>
|
||||
</ParamNameMismatch>
|
||||
<UndefinedClass occurrences="2">
|
||||
<code>\OCA\Circles\Api\v1\Circles</code>
|
||||
<code>\OCA\Circles\Api\v1\Circles</code>
|
||||
</UndefinedClass>
|
||||
</file>
|
||||
<file src="lib/Db/Card.php">
|
||||
<UndefinedClass occurrences="2">
|
||||
@@ -133,7 +147,8 @@
|
||||
<UndefinedClass occurrences="1">
|
||||
<code>\OCA\Circles\Model\Circle</code>
|
||||
</UndefinedClass>
|
||||
<UndefinedDocblockClass occurrences="4">
|
||||
<UndefinedDocblockClass occurrences="5">
|
||||
<code>$this->object</code>
|
||||
<code>$this->object</code>
|
||||
<code>$this->object</code>
|
||||
<code>$this->object</code>
|
||||
@@ -156,17 +171,15 @@
|
||||
<code>$stackId</code>
|
||||
</ParamNameMismatch>
|
||||
</file>
|
||||
<file src="lib/Migration/Version10800Date20220422061816.php">
|
||||
<MoreSpecificImplementedParamType occurrences="1">
|
||||
<code>$schemaClosure</code>
|
||||
</MoreSpecificImplementedParamType>
|
||||
</file>
|
||||
<file src="lib/Notification/Notifier.php">
|
||||
<RedundantCast occurrences="4">
|
||||
<RedundantCast occurrences="7">
|
||||
<code>(string) $l->t('%s has mentioned you in a comment on "%s".', [$dn, $params[0]])</code>
|
||||
<code>(string) $l->t('The board "%s" has been shared with you by %s.', [$params[0], $dn])</code>
|
||||
<code>(string) $l->t('The card "%s" on "%s" has been assigned to you by %s.', [$params[0], $params[1], $dn])</code>
|
||||
<code>(string) $l->t('The card "%s" on "%s" has reached its due date.', $params)</code>
|
||||
<code>(string) $l->t('{user} has assigned the card "%s" on "%s" to you.', [$params[0], $params[1]])</code>
|
||||
<code>(string) $l->t('{user} has mentioned you in a comment on "%s".', [$params[0]])</code>
|
||||
<code>(string) $l->t('{user} has shared the board %s with you.', [$params[0]])</code>
|
||||
</RedundantCast>
|
||||
</file>
|
||||
<file src="lib/Provider/DeckProvider.php">
|
||||
@@ -190,19 +203,18 @@
|
||||
</TooManyArguments>
|
||||
</file>
|
||||
<file src="lib/Service/CardService.php">
|
||||
<TooFewArguments occurrences="1">
|
||||
<code>findAssignedCards</code>
|
||||
</TooFewArguments>
|
||||
<UndefinedDocblockClass occurrences="1">
|
||||
<code>\OCP\AppFramework\Db\</code>
|
||||
</UndefinedDocblockClass>
|
||||
</file>
|
||||
<file src="lib/Service/CirclesService.php">
|
||||
<UndefinedClass occurrences="1">
|
||||
<code>?Circle</code>
|
||||
<UndefinedClass occurrences="2">
|
||||
<code>\OCA\Circles\Api\v1\Circles</code>
|
||||
<code>\OCA\Circles\Api\v1\Circles</code>
|
||||
</UndefinedClass>
|
||||
<UndefinedDocblockClass occurrences="3">
|
||||
<code>$circlesManager</code>
|
||||
<code>$circlesManager</code>
|
||||
<code>$circlesManager</code>
|
||||
</UndefinedDocblockClass>
|
||||
</file>
|
||||
<file src="lib/Service/CommentService.php">
|
||||
<UndefinedThisPropertyAssignment occurrences="2">
|
||||
@@ -254,9 +266,10 @@
|
||||
</MissingDependency>
|
||||
</file>
|
||||
<file src="lib/Service/PermissionService.php">
|
||||
<UndefinedClass occurrences="2">
|
||||
<code>$circle</code>
|
||||
<UndefinedClass occurrences="3">
|
||||
<code>Member</code>
|
||||
<code>\OCA\Circles\Api\v1\Circles</code>
|
||||
<code>\OCA\Circles\Api\v1\Circles</code>
|
||||
</UndefinedClass>
|
||||
</file>
|
||||
<file src="lib/Service/StackService.php">
|
||||
@@ -271,9 +284,6 @@
|
||||
<InvalidReturnType occurrences="1">
|
||||
<code>getSharesInFolder</code>
|
||||
</InvalidReturnType>
|
||||
<InvalidThrow occurrences="1">
|
||||
<code>throw new GenericShareException('Already shared', $this->l->t('Path is already shared with this card'), 403);</code>
|
||||
</InvalidThrow>
|
||||
<MissingDependency occurrences="8">
|
||||
<code>GenericShareException</code>
|
||||
<code>GenericShareException</code>
|
||||
|
||||
@@ -169,15 +169,18 @@ class ActivityManagerTest extends TestCase {
|
||||
$this->mockUser('user2'),
|
||||
];
|
||||
$event = $this->createMock(IEvent::class);
|
||||
$event->expects($this->once())
|
||||
$event->expects($this->at(0))
|
||||
->method('getObjectType')
|
||||
->willReturn($objectType);
|
||||
$event->expects($this->once())
|
||||
$event->expects($this->at(0))
|
||||
->method('getObjectId')
|
||||
->willReturn(1);
|
||||
$event->expects($this->exactly(2))
|
||||
$event->expects($this->at(2))
|
||||
->method('setAffectedUser')
|
||||
->withConsecutive(['user1'], ['user2']);
|
||||
->with('user1');
|
||||
$event->expects($this->at(3))
|
||||
->method('setAffectedUser')
|
||||
->with('user2');
|
||||
$mapper = null;
|
||||
switch ($objectType) {
|
||||
case ActivityManager::DECK_OBJECT_BOARD:
|
||||
@@ -193,7 +196,10 @@ class ActivityManagerTest extends TestCase {
|
||||
$this->permissionService->expects($this->once())
|
||||
->method('findUsers')
|
||||
->willReturn($users);
|
||||
$this->manager->expects($this->exactly(2))
|
||||
$this->manager->expects($this->at(0))
|
||||
->method('publish')
|
||||
->with($event);
|
||||
$this->manager->expects($this->at(1))
|
||||
->method('publish')
|
||||
->with($event);
|
||||
$this->invokePrivate($this->activityManager, 'sendToUsers', [$event]);
|
||||
|
||||
@@ -38,7 +38,6 @@ use OCP\L10N\IFactory;
|
||||
use OCP\RichObjectStrings\IValidator;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit_Framework_MockObject_MockObject as MockObject;
|
||||
use OCA\Deck\Service\CardService;
|
||||
|
||||
class DeckProviderTest extends TestCase {
|
||||
|
||||
@@ -57,9 +56,6 @@ class DeckProviderTest extends TestCase {
|
||||
/** @var ICommentsManager|MockObject */
|
||||
private $commentsManager;
|
||||
|
||||
/** @var CardService|MockObject */
|
||||
private $cardService;
|
||||
|
||||
/** @var string */
|
||||
private $userId = 'admin';
|
||||
|
||||
@@ -71,9 +67,7 @@ class DeckProviderTest extends TestCase {
|
||||
$this->commentsManager = $this->createMock(ICommentsManager::class);
|
||||
$this->l10nFactory = $this->createMock(IFactory::class);
|
||||
$this->config = $this->createMock(IConfig::class);
|
||||
$this->config = $this->createMock(IConfig::class);
|
||||
$this->cardService = $this->createMock(CardService::class);
|
||||
$this->provider = new DeckProvider($this->urlGenerator, $this->activityManager, $this->userManager, $this->commentsManager, $this->l10nFactory, $this->config, $this->userId, $this->cardService);
|
||||
$this->provider = new DeckProvider($this->urlGenerator, $this->activityManager, $this->userManager, $this->commentsManager, $this->l10nFactory, $this->config, $this->userId);
|
||||
}
|
||||
|
||||
private function mockEvent($objectType, $objectId, $objectName, $subject, $subjectParameters = []) {
|
||||
|
||||
@@ -66,14 +66,18 @@ class DeleteCronTest extends \Test\TestCase {
|
||||
$this->boardMapper->expects($this->once())
|
||||
->method('findToDelete')
|
||||
->willReturn($boards);
|
||||
$this->boardMapper->expects($this->exactly(count($boards)))
|
||||
$this->boardMapper->expects($this->at(1))
|
||||
->method('delete')
|
||||
->withConsecutive(
|
||||
[$boards[0]],
|
||||
[$boards[1]],
|
||||
[$boards[2]],
|
||||
[$boards[3]]
|
||||
);
|
||||
->with($boards[0]);
|
||||
$this->boardMapper->expects($this->at(2))
|
||||
->method('delete')
|
||||
->with($boards[1]);
|
||||
$this->boardMapper->expects($this->at(3))
|
||||
->method('delete')
|
||||
->with($boards[2]);
|
||||
$this->boardMapper->expects($this->at(4))
|
||||
->method('delete')
|
||||
->with($boards[3]);
|
||||
|
||||
$attachment = new Attachment();
|
||||
$attachment->setType('deck_file');
|
||||
|
||||
@@ -54,7 +54,10 @@ class ScheduledNoificationsTest extends \Test\TestCase {
|
||||
$this->cardMapper->expects($this->once())
|
||||
->method('findOverdue')
|
||||
->willReturn($cards);
|
||||
$this->notificationHelper->expects($this->exactly(2))
|
||||
$this->notificationHelper->expects($this->at(0))
|
||||
->method('sendCardDuedate')
|
||||
->with($c1);
|
||||
$this->notificationHelper->expects($this->at(1))
|
||||
->method('sendCardDuedate')
|
||||
->with($c1);
|
||||
$this->scheduledNotifications->run(null);
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
namespace OCA\Deck\Db;
|
||||
|
||||
use OCA\Deck\Service\CirclesService;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\IUserManager;
|
||||
use Psr\Log\LoggerInterface;
|
||||
@@ -57,7 +56,6 @@ class AclMapperTest extends MapperTestUtility {
|
||||
\OC::$server->query(StackMapper::class),
|
||||
$this->userManager,
|
||||
$this->groupManager,
|
||||
$this->createMock(CirclesService::class),
|
||||
$this->createMock(LoggerInterface::class)
|
||||
);
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
namespace OCA\Deck\Db;
|
||||
|
||||
use OCA\Deck\Service\CirclesService;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\IUserManager;
|
||||
@@ -64,7 +63,6 @@ class BoardMapperTest extends MapperTestUtility {
|
||||
\OC::$server->query(StackMapper::class),
|
||||
$this->userManager,
|
||||
$this->groupManager,
|
||||
$this->createMock(CirclesService::class),
|
||||
$this->createMock(LoggerInterface::class)
|
||||
);
|
||||
$this->aclMapper = \OC::$server->query(AclMapper::class);
|
||||
|
||||
@@ -114,18 +114,17 @@ class NotificationHelperTest extends \Test\TestCase {
|
||||
}
|
||||
|
||||
public function testSendCardDuedate() {
|
||||
$param1 = ['foo', 'bar', 'asd'];
|
||||
$param2 = 'deck';
|
||||
$param3 = 'board:234:notify-due';
|
||||
$DUE_ASSIGNED = ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED;
|
||||
|
||||
$this->config->expects($this->exactly(3))
|
||||
$this->config->expects($this->at(0))
|
||||
->method('getUserValue')
|
||||
->withConsecutive(
|
||||
[$param1[0], $param2, $param3, $DUE_ASSIGNED],
|
||||
[$param1[1], $param2, $param3, $DUE_ASSIGNED],
|
||||
[$param1[2], $param2, $param3, $DUE_ASSIGNED],
|
||||
)
|
||||
->with('foo', 'deck', 'board:234:notify-due', ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED)
|
||||
->willReturn(ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ALL);
|
||||
$this->config->expects($this->at(1))
|
||||
->method('getUserValue')
|
||||
->with('bar', 'deck', 'board:234:notify-due', ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED)
|
||||
->willReturn(ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ALL);
|
||||
$this->config->expects($this->at(2))
|
||||
->method('getUserValue')
|
||||
->with('asd', 'deck', 'board:234:notify-due', ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED)
|
||||
->willReturn(ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ALL);
|
||||
|
||||
$card = Card::fromParams([
|
||||
@@ -181,12 +180,24 @@ class NotificationHelperTest extends \Test\TestCase {
|
||||
$n3->expects($this->once())->method('setSubject')->with('card-overdue', ['MyCardTitle', 'MyBoardTitle'])->willReturn($n3);
|
||||
$n3->expects($this->once())->method('setDateTime')->willReturn($n3);
|
||||
|
||||
$this->notificationManager->expects($this->exactly(3))
|
||||
$this->notificationManager->expects($this->at(0))
|
||||
->method('createNotification')
|
||||
->willReturnOnConsecutiveCalls($n1, $n2, $n3);
|
||||
$this->notificationManager->expects($this->exactly(3))
|
||||
->willReturn($n1);
|
||||
$this->notificationManager->expects($this->at(1))
|
||||
->method('notify')
|
||||
->withConsecutive([$n1], [$n2], [$n3]);
|
||||
->with($n1);
|
||||
$this->notificationManager->expects($this->at(2))
|
||||
->method('createNotification')
|
||||
->willReturn($n2);
|
||||
$this->notificationManager->expects($this->at(3))
|
||||
->method('notify')
|
||||
->with($n2);
|
||||
$this->notificationManager->expects($this->at(4))
|
||||
->method('createNotification')
|
||||
->willReturn($n3);
|
||||
$this->notificationManager->expects($this->at(5))
|
||||
->method('notify')
|
||||
->with($n3);
|
||||
|
||||
$this->cardMapper->expects($this->once())
|
||||
->method('markNotified')
|
||||
@@ -196,19 +207,18 @@ class NotificationHelperTest extends \Test\TestCase {
|
||||
}
|
||||
|
||||
public function testSendCardDuedateAssigned() {
|
||||
$param1 = ['foo', 'bar', 'asd'];
|
||||
$param2 = 'deck';
|
||||
$param3 = 'board:234:notify-due';
|
||||
$DUE_ASSIGNED = ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED;
|
||||
|
||||
$this->config->expects($this->exactly(3))
|
||||
$this->config->expects($this->at(0))
|
||||
->method('getUserValue')
|
||||
->withConsecutive(
|
||||
[$param1[0], $param2, $param3, $DUE_ASSIGNED],
|
||||
[$param1[1], $param2, $param3, $DUE_ASSIGNED],
|
||||
[$param1[2], $param2, $param3, $DUE_ASSIGNED]
|
||||
)
|
||||
->willReturn($DUE_ASSIGNED);
|
||||
->with('foo', 'deck', 'board:234:notify-due', ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED)
|
||||
->willReturn(ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED);
|
||||
$this->config->expects($this->at(1))
|
||||
->method('getUserValue')
|
||||
->with('bar', 'deck', 'board:234:notify-due', ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED)
|
||||
->willReturn(ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED);
|
||||
$this->config->expects($this->at(2))
|
||||
->method('getUserValue')
|
||||
->with('asd', 'deck', 'board:234:notify-due', ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED)
|
||||
->willReturn(ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED);
|
||||
|
||||
$users = [
|
||||
new DummyUser('foo'), new DummyUser('bar'), new DummyUser('asd')
|
||||
@@ -268,12 +278,24 @@ class NotificationHelperTest extends \Test\TestCase {
|
||||
$n3->expects($this->once())->method('setSubject')->with('card-overdue', ['MyCardTitle', 'MyBoardTitle'])->willReturn($n3);
|
||||
$n3->expects($this->once())->method('setDateTime')->willReturn($n3);
|
||||
|
||||
$this->notificationManager->expects($this->exactly(3))
|
||||
$this->notificationManager->expects($this->at(0))
|
||||
->method('createNotification')
|
||||
->willReturnOnConsecutiveCalls($n1, $n2, $n3);
|
||||
$this->notificationManager->expects($this->exactly(3))
|
||||
->willReturn($n1);
|
||||
$this->notificationManager->expects($this->at(1))
|
||||
->method('notify')
|
||||
->withConsecutive([$n1], [$n2], [$n3]);
|
||||
->with($n1);
|
||||
$this->notificationManager->expects($this->at(2))
|
||||
->method('createNotification')
|
||||
->willReturn($n2);
|
||||
$this->notificationManager->expects($this->at(3))
|
||||
->method('notify')
|
||||
->with($n2);
|
||||
$this->notificationManager->expects($this->at(4))
|
||||
->method('createNotification')
|
||||
->willReturn($n3);
|
||||
$this->notificationManager->expects($this->at(5))
|
||||
->method('notify')
|
||||
->with($n3);
|
||||
|
||||
$this->cardMapper->expects($this->once())
|
||||
->method('markNotified')
|
||||
@@ -284,20 +306,18 @@ class NotificationHelperTest extends \Test\TestCase {
|
||||
|
||||
|
||||
public function testSendCardDuedateNever() {
|
||||
$param1 = ['foo', 'bar', 'asd'];
|
||||
$param2 = 'deck';
|
||||
$param3 = 'board:234:notify-due';
|
||||
$DUE_ASSIGNED = ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED;
|
||||
$DUE_OFF = ConfigService::SETTING_BOARD_NOTIFICATION_DUE_OFF;
|
||||
|
||||
$this->config->expects($this->exactly(3))
|
||||
$this->config->expects($this->at(0))
|
||||
->method('getUserValue')
|
||||
->withConsecutive(
|
||||
[$param1[0], $param2, $param3, $DUE_ASSIGNED],
|
||||
[$param1[1], $param2, $param3, $DUE_ASSIGNED],
|
||||
[$param1[2], $param2, $param3, $DUE_ASSIGNED]
|
||||
)
|
||||
->willReturnOnConsecutiveCalls($DUE_ASSIGNED, $DUE_ASSIGNED, $DUE_OFF);
|
||||
->with('foo', 'deck', 'board:234:notify-due', ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED)
|
||||
->willReturn(ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED);
|
||||
$this->config->expects($this->at(1))
|
||||
->method('getUserValue')
|
||||
->with('bar', 'deck', 'board:234:notify-due', ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED)
|
||||
->willReturn(ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED);
|
||||
$this->config->expects($this->at(2))
|
||||
->method('getUserValue')
|
||||
->with('asd', 'deck', 'board:234:notify-due', ConfigService::SETTING_BOARD_NOTIFICATION_DUE_ASSIGNED)
|
||||
->willReturn(ConfigService::SETTING_BOARD_NOTIFICATION_DUE_OFF);
|
||||
|
||||
$users = [
|
||||
new DummyUser('foo'), new DummyUser('bar'), new DummyUser('asd')
|
||||
@@ -350,12 +370,18 @@ class NotificationHelperTest extends \Test\TestCase {
|
||||
$n2->expects($this->once())->method('setSubject')->with('card-overdue', ['MyCardTitle', 'MyBoardTitle'])->willReturn($n2);
|
||||
$n2->expects($this->once())->method('setDateTime')->willReturn($n2);
|
||||
|
||||
$this->notificationManager->expects($this->exactly(2))
|
||||
$this->notificationManager->expects($this->at(0))
|
||||
->method('createNotification')
|
||||
->willReturnOnConsecutiveCalls($n1, $n2);
|
||||
$this->notificationManager->expects($this->exactly(2))
|
||||
->willReturn($n1);
|
||||
$this->notificationManager->expects($this->at(1))
|
||||
->method('notify')
|
||||
->withConsecutive([$n1], [$n2]);
|
||||
->with($n1);
|
||||
$this->notificationManager->expects($this->at(2))
|
||||
->method('createNotification')
|
||||
->willReturn($n2);
|
||||
$this->notificationManager->expects($this->at(3))
|
||||
->method('notify')
|
||||
->with($n2);
|
||||
|
||||
$this->cardMapper->expects($this->once())
|
||||
->method('markNotified')
|
||||
@@ -397,10 +423,10 @@ class NotificationHelperTest extends \Test\TestCase {
|
||||
$notification->expects($this->once())->method('setSubject')->with('card-assigned', ['MyCardTitle', 'MyBoardTitle', 'admin'])->willReturn($notification);
|
||||
$notification->expects($this->once())->method('setDateTime')->willReturn($notification);
|
||||
|
||||
$this->notificationManager->expects($this->once())
|
||||
$this->notificationManager->expects($this->at(0))
|
||||
->method('createNotification')
|
||||
->willReturn($notification);
|
||||
$this->notificationManager->expects($this->once())
|
||||
$this->notificationManager->expects($this->at(1))
|
||||
->method('notify')
|
||||
->with($notification);
|
||||
|
||||
@@ -425,10 +451,10 @@ class NotificationHelperTest extends \Test\TestCase {
|
||||
$notification->expects($this->once())->method('setSubject')->with('board-shared', ['MyBoardTitle', 'admin'])->willReturn($notification);
|
||||
$notification->expects($this->once())->method('setDateTime')->willReturn($notification);
|
||||
|
||||
$this->notificationManager->expects($this->once())
|
||||
$this->notificationManager->expects($this->at(0))
|
||||
->method('createNotification')
|
||||
->willReturn($notification);
|
||||
$this->notificationManager->expects($this->once())
|
||||
$this->notificationManager->expects($this->at(1))
|
||||
->method('notify')
|
||||
->with($notification);
|
||||
|
||||
@@ -464,10 +490,10 @@ class NotificationHelperTest extends \Test\TestCase {
|
||||
$notification->expects($this->once())->method('setSubject')->with('board-shared', ['MyBoardTitle', 'admin'])->willReturn($notification);
|
||||
$notification->expects($this->once())->method('setDateTime')->willReturn($notification);
|
||||
|
||||
$this->notificationManager->expects($this->once())
|
||||
$this->notificationManager->expects($this->at(0))
|
||||
->method('createNotification')
|
||||
->willReturn($notification);
|
||||
$this->notificationManager->expects($this->once())
|
||||
$this->notificationManager->expects($this->at(1))
|
||||
->method('notify')
|
||||
->with($notification);
|
||||
|
||||
@@ -514,12 +540,19 @@ class NotificationHelperTest extends \Test\TestCase {
|
||||
$notification2->expects($this->once())->method('setSubject')->with('card-comment-mentioned', ['MyCard', 1, 'admin'])->willReturn($notification2);
|
||||
$notification2->expects($this->once())->method('setDateTime')->willReturn($notification2);
|
||||
|
||||
$this->notificationManager->expects($this->exactly(2))
|
||||
$this->notificationManager->expects($this->at(0))
|
||||
->method('createNotification')
|
||||
->willReturnOnConsecutiveCalls($notification1, $notification2);
|
||||
$this->notificationManager->expects($this->exactly(2))
|
||||
->willReturn($notification1);
|
||||
$this->notificationManager->expects($this->at(1))
|
||||
->method('notify')
|
||||
->withConsecutive([$notification1], [$notification2]);
|
||||
->with($notification1);
|
||||
|
||||
$this->notificationManager->expects($this->at(2))
|
||||
->method('createNotification')
|
||||
->willReturn($notification2);
|
||||
$this->notificationManager->expects($this->at(3))
|
||||
->method('notify')
|
||||
->with($notification2);
|
||||
|
||||
$this->notificationHelper->sendMention($comment);
|
||||
}
|
||||
|
||||
@@ -110,16 +110,8 @@ class AttachmentServiceTest extends TestCase {
|
||||
$this->cache = $this->createMock(ICache::class);
|
||||
$this->cacheFactory->expects($this->any())->method('createDistributed')->willReturn($this->cache);
|
||||
|
||||
$this->appContainer->expects($this->exactly(2))
|
||||
->method('query')
|
||||
->withConsecutive(
|
||||
[FileService::class],
|
||||
[FilesAppService::class]
|
||||
)
|
||||
->willReturnOnConsecutiveCalls(
|
||||
$this->attachmentServiceImpl,
|
||||
$this->filesAppServiceImpl
|
||||
);
|
||||
$this->appContainer->expects($this->at(0))->method('query')->with(FileService::class)->willReturn($this->attachmentServiceImpl);
|
||||
$this->appContainer->expects($this->at(1))->method('query')->with(FilesAppService::class)->willReturn($this->filesAppServiceImpl);
|
||||
|
||||
$this->application->expects($this->any())
|
||||
->method('getContainer')
|
||||
@@ -137,18 +129,9 @@ class AttachmentServiceTest extends TestCase {
|
||||
$fileServiceMock = $this->createMock(FileService::class);
|
||||
$fileAppServiceMock = $this->createMock(FilesAppService::class);
|
||||
|
||||
$appContainer->expects($this->exactly(3))
|
||||
->method('query')
|
||||
->withConsecutive(
|
||||
[FileService::class],
|
||||
[FilesAppService::class],
|
||||
[MyAttachmentService::class]
|
||||
)
|
||||
->willReturnOnConsecutiveCalls(
|
||||
$fileServiceMock,
|
||||
$fileAppServiceMock,
|
||||
new MyAttachmentService()
|
||||
);
|
||||
$appContainer->expects($this->at(0))->method('query')->with(FileService::class)->willReturn($fileServiceMock);
|
||||
$appContainer->expects($this->at(1))->method('query')->with(FilesAppService::class)->willReturn($fileAppServiceMock);
|
||||
$appContainer->expects($this->at(2))->method('query')->with(MyAttachmentService::class)->willReturn(new MyAttachmentService());
|
||||
|
||||
$application->expects($this->any())
|
||||
->method('getContainer')
|
||||
@@ -165,24 +148,12 @@ class AttachmentServiceTest extends TestCase {
|
||||
$appContainer = $this->createMock(IAppContainer::class);
|
||||
$fileServiceMock = $this->createMock(FileService::class);
|
||||
$fileAppServiceMock = $this->createMock(FilesAppService::class);
|
||||
|
||||
$appContainer->expects($this->exactly(3))
|
||||
->method('query')
|
||||
->withConsecutive(
|
||||
[FileService::class],
|
||||
[FilesAppService::class],
|
||||
[MyAttachmentService::class]
|
||||
)
|
||||
->willReturnOnConsecutiveCalls(
|
||||
$fileServiceMock,
|
||||
$fileAppServiceMock,
|
||||
new MyAttachmentService()
|
||||
);
|
||||
|
||||
$appContainer->expects($this->at(0))->method('query')->with(FileService::class)->willReturn($fileServiceMock);
|
||||
$appContainer->expects($this->at(1))->method('query')->with(FilesAppService::class)->willReturn($fileAppServiceMock);
|
||||
$appContainer->expects($this->at(2))->method('query')->with(MyAttachmentService::class)->willReturn(new MyAttachmentService());
|
||||
$application->expects($this->any())
|
||||
->method('getContainer')
|
||||
->willReturn($appContainer);
|
||||
|
||||
$attachmentService = new AttachmentService($this->attachmentMapper, $this->cardMapper, $this->changeHelper, $this->permissionService, $application, $this->cacheFactory, $this->userId, $this->l10n, $this->activityManager);
|
||||
$attachmentService->registerAttachmentService('custom', MyAttachmentService::class);
|
||||
$attachmentService->getService('deck_file_invalid');
|
||||
@@ -214,17 +185,12 @@ class AttachmentServiceTest extends TestCase {
|
||||
->with(123)
|
||||
->willReturn($attachments);
|
||||
|
||||
$this->attachmentServiceImpl->expects($this->exactly(2))
|
||||
$this->attachmentServiceImpl->expects($this->at(0))
|
||||
->method('extendData')
|
||||
->withConsecutive(
|
||||
[$attachments[0]],
|
||||
[$attachments[1]],
|
||||
)
|
||||
->willReturnOnConsecutiveCalls(
|
||||
$attachments[0],
|
||||
$attachments[1],
|
||||
);
|
||||
|
||||
->with($attachments[0]);
|
||||
$this->attachmentServiceImpl->expects($this->at(1))
|
||||
->method('extendData')
|
||||
->with($attachments[1]);
|
||||
$this->assertEquals($attachments, $this->attachmentService->findAll(123, false));
|
||||
}
|
||||
|
||||
@@ -249,15 +215,12 @@ class AttachmentServiceTest extends TestCase {
|
||||
->with(123, false)
|
||||
->willReturn($attachmentsDeleted);
|
||||
|
||||
$this->attachmentServiceImpl->expects($this->exactly(4))
|
||||
$this->attachmentServiceImpl->expects($this->at(0))
|
||||
->method('extendData')
|
||||
->withConsecutive(
|
||||
[$attachments[0]],
|
||||
[$attachments[1]],
|
||||
[$attachmentsDeleted[0]],
|
||||
[$attachmentsDeleted[1]]
|
||||
);
|
||||
|
||||
->with($attachments[0]);
|
||||
$this->attachmentServiceImpl->expects($this->at(1))
|
||||
->method('extendData')
|
||||
->with($attachments[1]);
|
||||
$this->assertEquals(array_merge($attachments, $attachmentsDeleted), $this->attachmentService->findAll(123, true));
|
||||
}
|
||||
|
||||
@@ -433,6 +396,5 @@ class AttachmentServiceTest extends TestCase {
|
||||
->method('allowUndo')
|
||||
->willReturn(false);
|
||||
$actual = $this->attachmentService->restore(1, 1);
|
||||
$this->assertEquals($expected, $actual);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ use OCA\Deck\Db\Assignment;
|
||||
use OCA\Deck\Db\AssignmentMapper;
|
||||
use OCA\Deck\Db\Board;
|
||||
use OCA\Deck\Db\BoardMapper;
|
||||
use OCA\Deck\Db\CardMapper;
|
||||
use OCA\Deck\Db\ChangeHelper;
|
||||
use OCA\Deck\Db\LabelMapper;
|
||||
use OCA\Deck\Db\StackMapper;
|
||||
@@ -43,7 +42,6 @@ use OCP\IUser;
|
||||
use OCP\IUserManager;
|
||||
use OCP\IGroupManager;
|
||||
use \Test\TestCase;
|
||||
use OCP\IURLGenerator;
|
||||
|
||||
class BoardServiceTest extends TestCase {
|
||||
|
||||
@@ -59,8 +57,6 @@ class BoardServiceTest extends TestCase {
|
||||
private $boardMapper;
|
||||
/** @var StackMapper */
|
||||
private $stackMapper;
|
||||
/** @var CardMapper */
|
||||
private $cardMapper;
|
||||
/** @var PermissionService */
|
||||
private $permissionService;
|
||||
/** @var NotificationHelper */
|
||||
@@ -78,8 +74,6 @@ class BoardServiceTest extends TestCase {
|
||||
/** @var IEventDispatcher */
|
||||
private $eventDispatcher;
|
||||
private $userId = 'admin';
|
||||
/** @var IURLGenerator */
|
||||
private $urlGenerator;
|
||||
|
||||
public function setUp(): void {
|
||||
parent::setUp();
|
||||
@@ -88,7 +82,6 @@ class BoardServiceTest extends TestCase {
|
||||
$this->boardMapper = $this->createMock(BoardMapper::class);
|
||||
$this->stackMapper = $this->createMock(StackMapper::class);
|
||||
$this->config = $this->createMock(IConfig::class);
|
||||
$this->cardMapper = $this->createMock(CardMapper::class);
|
||||
$this->labelMapper = $this->createMock(LabelMapper::class);
|
||||
$this->permissionService = $this->createMock(PermissionService::class);
|
||||
$this->notificationHelper = $this->createMock(NotificationHelper::class);
|
||||
@@ -98,7 +91,6 @@ class BoardServiceTest extends TestCase {
|
||||
$this->activityManager = $this->createMock(ActivityManager::class);
|
||||
$this->changeHelper = $this->createMock(ChangeHelper::class);
|
||||
$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
|
||||
$this->urlGenerator = $this->createMock(IURLGenerator::class);
|
||||
|
||||
$this->service = new BoardService(
|
||||
$this->boardMapper,
|
||||
@@ -110,13 +102,11 @@ class BoardServiceTest extends TestCase {
|
||||
$this->permissionService,
|
||||
$this->notificationHelper,
|
||||
$this->assignedUsersMapper,
|
||||
$this->cardMapper,
|
||||
$this->userManager,
|
||||
$this->groupManager,
|
||||
$this->activityManager,
|
||||
$this->eventDispatcher,
|
||||
$this->changeHelper,
|
||||
$this->urlGenerator,
|
||||
$this->userId
|
||||
);
|
||||
|
||||
@@ -154,7 +144,7 @@ class BoardServiceTest extends TestCase {
|
||||
->method('find')
|
||||
->with(1)
|
||||
->willReturn($b1);
|
||||
$this->permissionService->expects($this->any())
|
||||
$this->permissionService->expects($this->once())
|
||||
->method('findUsers')
|
||||
->willReturn([
|
||||
'admin' => 'admin',
|
||||
@@ -258,14 +248,6 @@ class BoardServiceTest extends TestCase {
|
||||
->method('insert')
|
||||
->with($acl)
|
||||
->willReturn($acl);
|
||||
$this->permissionService->expects($this->any())
|
||||
->method('findUsers')
|
||||
->willReturn([
|
||||
'admin' => 'admin',
|
||||
]);
|
||||
$this->boardMapper->expects($this->once())
|
||||
->method('find')
|
||||
->willReturn(new Board());
|
||||
$this->assertEquals($acl, $this->service->addAcl(
|
||||
123, 'user', 'admin', true, true, true
|
||||
));
|
||||
@@ -308,39 +290,30 @@ class BoardServiceTest extends TestCase {
|
||||
$existingAcl->setPermissionEdit($currentUserAcl[0]);
|
||||
$existingAcl->setPermissionShare($currentUserAcl[1]);
|
||||
$existingAcl->setPermissionManage($currentUserAcl[2]);
|
||||
|
||||
$this->permissionService->expects($this->at(0))
|
||||
->method('checkPermission')
|
||||
->with($this->boardMapper, 123, Acl::PERMISSION_SHARE, null);
|
||||
if ($currentUserAcl[2]) {
|
||||
$this->permissionService->expects($this->exactly(2))
|
||||
$this->permissionService->expects($this->at(1))
|
||||
->method('checkPermission')
|
||||
->withConsecutive(
|
||||
[$this->boardMapper, 123, Acl::PERMISSION_SHARE, null],
|
||||
[$this->boardMapper, 123, Acl::PERMISSION_MANAGE, null]
|
||||
);
|
||||
->with($this->boardMapper, 123, Acl::PERMISSION_MANAGE, null);
|
||||
} else {
|
||||
$this->aclMapper->expects($this->once())
|
||||
->method('findAll')
|
||||
->willReturn([$existingAcl]);
|
||||
|
||||
$this->permissionService->expects($this->exactly(2))
|
||||
$this->permissionService->expects($this->at(1))
|
||||
->method('checkPermission')
|
||||
->withConsecutive(
|
||||
[$this->boardMapper, 123, Acl::PERMISSION_SHARE, null],
|
||||
[$this->boardMapper, 123, Acl::PERMISSION_MANAGE, null]
|
||||
)
|
||||
->will(
|
||||
$this->onConsecutiveCalls(
|
||||
true,
|
||||
$this->throwException(new NoPermissionException('No permission'))
|
||||
)
|
||||
);
|
||||
|
||||
$this->permissionService->expects($this->exactly(3))
|
||||
->with($this->boardMapper, 123, Acl::PERMISSION_MANAGE, null)
|
||||
->willThrowException(new NoPermissionException('No permission'));
|
||||
$this->permissionService->expects($this->at(2))
|
||||
->method('userCan')
|
||||
->willReturnOnConsecutiveCalls(
|
||||
$currentUserAcl[0],
|
||||
$currentUserAcl[1],
|
||||
$currentUserAcl[2]
|
||||
);
|
||||
->willReturn($currentUserAcl[0]);
|
||||
$this->permissionService->expects($this->at(3))
|
||||
->method('userCan')
|
||||
->willReturn($currentUserAcl[1]);
|
||||
$this->permissionService->expects($this->at(4))
|
||||
->method('userCan')
|
||||
->willReturn($currentUserAcl[2]);
|
||||
}
|
||||
|
||||
$user = $this->createMock(IUser::class);
|
||||
@@ -355,14 +328,6 @@ class BoardServiceTest extends TestCase {
|
||||
$acl->resolveRelation('participant', function ($participant) use (&$user) {
|
||||
return null;
|
||||
});
|
||||
$this->boardMapper->expects($this->once())
|
||||
->method('find')
|
||||
->willReturn(new Board());
|
||||
$this->permissionService->expects($this->any())
|
||||
->method('findUsers')
|
||||
->willReturn([
|
||||
'admin' => 'admin',
|
||||
]);
|
||||
$this->notificationHelper->expects($this->once())
|
||||
->method('sendBoardShared');
|
||||
$expected = clone $acl;
|
||||
|
||||
@@ -43,7 +43,6 @@ use OCP\IUserManager;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Test\TestCase;
|
||||
use OCP\IURLGenerator;
|
||||
|
||||
class CardServiceTest extends TestCase {
|
||||
|
||||
@@ -77,9 +76,6 @@ class CardServiceTest extends TestCase {
|
||||
/** @var ChangeHelper|MockObject */
|
||||
private $changeHelper;
|
||||
|
||||
/** @var IURLGenerator|MockObject */
|
||||
private $urlGenerator;
|
||||
|
||||
public function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->cardMapper = $this->createMock(CardMapper::class);
|
||||
@@ -96,7 +92,6 @@ class CardServiceTest extends TestCase {
|
||||
$this->userManager = $this->createMock(IUserManager::class);
|
||||
$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
|
||||
$this->changeHelper = $this->createMock(ChangeHelper::class);
|
||||
$this->urlGenerator = $this->createMock(IURLGenerator::class);
|
||||
$this->cardService = new CardService(
|
||||
$this->cardMapper,
|
||||
$this->stackMapper,
|
||||
@@ -112,7 +107,6 @@ class CardServiceTest extends TestCase {
|
||||
$this->userManager,
|
||||
$this->changeHelper,
|
||||
$this->eventDispatcher,
|
||||
$this->urlGenerator,
|
||||
'user1'
|
||||
);
|
||||
}
|
||||
@@ -202,7 +196,7 @@ class CardServiceTest extends TestCase {
|
||||
$this->cardMapper->expects($this->once())->method('update')->willReturnCallback(function ($c) {
|
||||
return $c;
|
||||
});
|
||||
$actual = $this->cardService->update(123, 'newtitle', 234, 'text', 'admin', 'foo', 999, '2017-01-01 00:00:00', null);
|
||||
$actual = $this->cardService->update(123, 'newtitle', 234, 'text', 999, 'foo', 'admin', '2017-01-01 00:00:00', null);
|
||||
$this->assertEquals('newtitle', $actual->getTitle());
|
||||
$this->assertEquals(234, $actual->getStackId());
|
||||
$this->assertEquals('text', $actual->getType());
|
||||
@@ -218,7 +212,7 @@ class CardServiceTest extends TestCase {
|
||||
$this->cardMapper->expects($this->once())->method('find')->willReturn($card);
|
||||
$this->cardMapper->expects($this->never())->method('update');
|
||||
$this->expectException(StatusException::class);
|
||||
$this->cardService->update(123, 'newtitle', 234, 'text', 'admin', 'foo', 999, '2017-01-01 00:00:00', null, true);
|
||||
$this->cardService->update(123, 'newtitle', 234, 'text', 999, 'foo', 'admin', '2017-01-01 00:00:00', null, true);
|
||||
}
|
||||
|
||||
public function testRename() {
|
||||
|
||||
@@ -35,7 +35,6 @@ use OCP\IConfig;
|
||||
use OCP\IGroup;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\ILogger;
|
||||
use OCP\IRequest;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserManager;
|
||||
use OCP\Share\IManager;
|
||||
@@ -63,9 +62,7 @@ class PermissionServiceTest extends \Test\TestCase {
|
||||
|
||||
public function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->logger = $this->createMock(ILogger::class);
|
||||
$this->request = $this->createMock(IRequest::class);
|
||||
$this->circlesService = $this->createMock(CirclesService::class);
|
||||
$this->logger = $this->request = $this->createMock(ILogger::class);
|
||||
$this->aclMapper = $this->createMock(AclMapper::class);
|
||||
$this->boardMapper = $this->createMock(BoardMapper::class);
|
||||
$this->userManager = $this->createMock(IUserManager::class);
|
||||
@@ -75,7 +72,6 @@ class PermissionServiceTest extends \Test\TestCase {
|
||||
|
||||
$this->service = new PermissionService(
|
||||
$this->logger,
|
||||
$this->circlesService,
|
||||
$this->aclMapper,
|
||||
$this->boardMapper,
|
||||
$this->userManager,
|
||||
@@ -139,17 +135,13 @@ class PermissionServiceTest extends \Test\TestCase {
|
||||
}
|
||||
|
||||
public function testUserIsBoardOwner() {
|
||||
$adminBoard = new Board();
|
||||
$adminBoard->setOwner('admin');
|
||||
$userBoard = new Board();
|
||||
$userBoard->setOwner('user1');
|
||||
|
||||
$this->boardMapper->expects($this->exactly(2))
|
||||
->method('find')
|
||||
->withConsecutive([123], [234])
|
||||
->willReturnOnConsecutiveCalls($adminBoard, $userBoard);
|
||||
|
||||
$board = new Board();
|
||||
$board->setOwner('admin');
|
||||
$this->boardMapper->expects($this->at(0))->method('find')->with(123)->willReturn($board);
|
||||
$this->assertEquals(true, $this->service->userIsBoardOwner(123));
|
||||
$board = new Board();
|
||||
$board->setOwner('user1');
|
||||
$this->boardMapper->expects($this->at(0))->method('find')->with(234)->willReturn($board);
|
||||
$this->assertEquals(false, $this->service->userIsBoardOwner(234));
|
||||
}
|
||||
|
||||
@@ -340,7 +332,7 @@ class PermissionServiceTest extends \Test\TestCase {
|
||||
$aclGroup->setParticipant('group1');
|
||||
|
||||
$board = $this->createMock(Board::class);
|
||||
$board->expects($this->once())
|
||||
$board->expects($this->at(0))
|
||||
->method('__call')
|
||||
->with('getOwner', [])
|
||||
->willReturn('user1');
|
||||
@@ -352,11 +344,14 @@ class PermissionServiceTest extends \Test\TestCase {
|
||||
->method('find')
|
||||
->with(123)
|
||||
->willReturn($board);
|
||||
$this->userManager->expects($this->exactly(2))
|
||||
$this->userManager->expects($this->at(0))
|
||||
->method('get')
|
||||
->withConsecutive(['user1'], ['user2'])
|
||||
->willReturnOnConsecutiveCalls($user1, $user2);
|
||||
|
||||
->with('user1')
|
||||
->willReturn($user1);
|
||||
$this->userManager->expects($this->at(1))
|
||||
->method('get')
|
||||
->with('user2')
|
||||
->willReturn($user2);
|
||||
$group = $this->createMock(IGroup::class);
|
||||
$group->expects($this->once())
|
||||
->method('getUsers')
|
||||
|
||||
@@ -75,7 +75,7 @@ class CardControllerTest extends TestCase {
|
||||
public function testUpdate() {
|
||||
$this->cardService->expects($this->once())
|
||||
->method('update')
|
||||
->with(1, 'title', 3, 'text', $this->userId, 'foo', 5, '2017-01-01 00:00:00')
|
||||
->with(1, 'title', 3, 'text', 5, 'foo', $this->userId, '2017-01-01 00:00:00')
|
||||
->willReturn(1);
|
||||
$this->assertEquals(1, $this->controller->update(1, 'title', 3, 'text', 5, 'foo', '2017-01-01 00:00:00', null));
|
||||
}
|
||||
|
||||
@@ -24,56 +24,32 @@
|
||||
|
||||
namespace OCA\Deck\Controller;
|
||||
|
||||
use OCA\Deck\Db\CardMapper;
|
||||
use OCA\Deck\Service\CardService;
|
||||
use OCA\Deck\Service\ConfigService;
|
||||
use OCA\Deck\Service\PermissionService;
|
||||
use OCP\EventDispatcher\IEventDispatcher;
|
||||
use OCP\IInitialStateService;
|
||||
use OCP\IL10N;
|
||||
use OCP\IRequest;
|
||||
use OCP\IURLGenerator;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class PageControllerTest extends TestCase {
|
||||
class PageControllerTest extends \Test\TestCase {
|
||||
private $controller;
|
||||
private $request;
|
||||
private $l10n;
|
||||
private $permissionService;
|
||||
private $initialState;
|
||||
private $configService;
|
||||
private $eventDispatcher;
|
||||
/**
|
||||
* @var mixed|CardMapper|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private $cardMapper;
|
||||
/**
|
||||
* @var mixed|IURLGenerator|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private $urlGenerator;
|
||||
/**
|
||||
* @var mixed|CardService|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private $cardService;
|
||||
|
||||
public function setUp(): void {
|
||||
$this->l10n = $this->createMock(IL10N::class);
|
||||
$this->request = $this->createMock(IRequest::class);
|
||||
$this->permissionService = $this->createMock(PermissionService::class);
|
||||
$this->configService = $this->createMock(ConfigService::class);
|
||||
$this->initialState = $this->createMock(IInitialStateService::class);
|
||||
$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
|
||||
$this->cardMapper = $this->createMock(CardMapper::class);
|
||||
$this->urlGenerator = $this->createMock(IURLGenerator::class);
|
||||
$this->cardService = $this->createMock(CardService::class);
|
||||
|
||||
$this->controller = new PageController(
|
||||
'deck',
|
||||
$this->request,
|
||||
$this->permissionService,
|
||||
$this->initialState,
|
||||
$this->configService,
|
||||
$this->eventDispatcher,
|
||||
$this->cardMapper,
|
||||
$this->urlGenerator,
|
||||
$this->cardService
|
||||
'deck', $this->request, $this->permissionService, $this->initialState, $this->configService, $this->eventDispatcher
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
43
webpack.js
43
webpack.js
@@ -1,20 +1,33 @@
|
||||
const webpackConfig = require('@nextcloud/webpack-vue-config')
|
||||
const path = require('path')
|
||||
const { merge } = require('webpack-merge')
|
||||
|
||||
webpackConfig.entry = {
|
||||
...webpackConfig.entry,
|
||||
collections: path.join(__dirname, 'src', 'init-collections.js'),
|
||||
dashboard: path.join(__dirname, 'src', 'init-dashboard.js'),
|
||||
calendar: path.join(__dirname, 'src', 'init-calendar.js'),
|
||||
talk: path.join(__dirname, 'src', 'init-talk.js'),
|
||||
const config = {
|
||||
entry: {
|
||||
collections: path.join(__dirname, 'src', 'init-collections.js'),
|
||||
dashboard: path.join(__dirname, 'src', 'init-dashboard.js'),
|
||||
calendar: path.join(__dirname, 'src', 'init-calendar.js'),
|
||||
talk: path.join(__dirname, 'src', 'init-talk.js'),
|
||||
},
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
jsonpFunction: 'webpackJsonpOCADeck',
|
||||
chunkFilename: '[name].js?v=[contenthash]',
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['*', '.js', '.vue', '.json'],
|
||||
modules: [
|
||||
path.resolve(__dirname, 'node_modules'),
|
||||
'node_modules',
|
||||
],
|
||||
},
|
||||
stats: {
|
||||
context: path.resolve(__dirname, 'src'),
|
||||
assets: true,
|
||||
entrypoints: true,
|
||||
chunks: true,
|
||||
modules: true
|
||||
}
|
||||
}
|
||||
|
||||
webpackConfig.stats = {
|
||||
context: path.resolve(__dirname, 'src'),
|
||||
assets: true,
|
||||
entrypoints: true,
|
||||
chunks: true,
|
||||
modules: true,
|
||||
}
|
||||
|
||||
module.exports = webpackConfig
|
||||
module.exports = merge(webpackConfig, config)
|
||||
|
||||
Reference in New Issue
Block a user