Compare commits
533 Commits
v1.7.3
...
fix-archiv
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5959fa8da | ||
|
|
b47c7aca34 | ||
|
|
ca91e7a2ed | ||
|
|
b92fddaf65 | ||
|
|
b7de565bac | ||
|
|
9c8e1a9f6e | ||
|
|
7e479b0505 | ||
|
|
8f65ec2ede | ||
|
|
6912ae09cf | ||
|
|
eaa3315348 | ||
|
|
5669bd73cc | ||
|
|
57989384fa | ||
|
|
74c04b2d71 | ||
|
|
74565debbb | ||
|
|
a2744823c1 | ||
|
|
a918459105 | ||
|
|
f9acf7778f | ||
|
|
8537bd00c7 | ||
|
|
4b62c34cc3 | ||
|
|
94d84f2b16 | ||
|
|
14e7c33886 | ||
|
|
60ee9f77ca | ||
|
|
3eaba6fe1a | ||
|
|
cef14ed254 | ||
|
|
0828ae6017 | ||
|
|
3af54d7186 | ||
|
|
f01a4433ed | ||
|
|
b64b29cf6e | ||
|
|
d93b431554 | ||
|
|
d00bd159d2 | ||
|
|
816a8c08f0 | ||
|
|
2c3113334a | ||
|
|
857a0797b4 | ||
|
|
efc3511e15 | ||
|
|
aaccd2e7d2 | ||
|
|
1921143bfd | ||
|
|
07b7df8e68 | ||
|
|
c4804cfcb7 | ||
|
|
6bc5f1df47 | ||
|
|
f8a8cc691c | ||
|
|
a4b2a137e5 | ||
|
|
96b5c3da1d | ||
|
|
a716c0968a | ||
|
|
48c8333ed1 | ||
|
|
8224ff13c3 | ||
|
|
e150cd25e8 | ||
|
|
6206a0cdd1 | ||
|
|
d66b54dd13 | ||
|
|
5491c9444e | ||
|
|
0fc5708253 | ||
|
|
918342eeb7 | ||
|
|
ec66e0f291 | ||
|
|
d76a1f539b | ||
|
|
c81501c2ea | ||
|
|
d62bd4e99a | ||
|
|
863ce50a27 | ||
|
|
a9c4e626ac | ||
|
|
982df96c3c | ||
|
|
bc070cbeb9 | ||
|
|
dbac5f82d3 | ||
|
|
58c7786cf7 | ||
|
|
14db941950 | ||
|
|
36a531c204 | ||
|
|
0fa1f74699 | ||
|
|
9189723970 | ||
|
|
d7bcdeb5a7 | ||
|
|
4d9e81e22f | ||
|
|
466c39d12a | ||
|
|
86e7d04c80 | ||
|
|
a6b5ae3fde | ||
|
|
bb3f41dd69 | ||
|
|
b2bdf4a49d | ||
|
|
91268cdd4c | ||
|
|
6b621d2faa | ||
|
|
93db4fd2d8 | ||
|
|
f166552de0 | ||
|
|
aab3352624 | ||
|
|
26f33e5bc6 | ||
|
|
da4db42380 | ||
|
|
aa46b49ab7 | ||
|
|
b70e893364 | ||
|
|
a6bb454df5 | ||
|
|
099e76aeab | ||
|
|
309b00f2d9 | ||
|
|
acd181133c | ||
|
|
86f8999d30 | ||
|
|
661a64656e | ||
|
|
3380103a8f | ||
|
|
7ebf6e4150 | ||
|
|
05fdd9765c | ||
|
|
72a8c4dd83 | ||
|
|
423630bea6 | ||
|
|
2c9bcbae0b | ||
|
|
f70747ea15 | ||
|
|
b4c1525958 | ||
|
|
ed5df26704 | ||
|
|
d8253d41fd | ||
|
|
4eb7988e2c | ||
|
|
4f68aed812 | ||
|
|
322d01d3e1 | ||
|
|
aa34a0cce3 | ||
|
|
93a988f8f1 | ||
|
|
630fa5b07e | ||
|
|
77f623d261 | ||
|
|
30a4e88cff | ||
|
|
01b897bd8b | ||
|
|
be36e6de6a | ||
|
|
96b7a7ccb3 | ||
|
|
d8dd65d7ee | ||
|
|
aecdcb847d | ||
|
|
a383d389c4 | ||
|
|
565b2edfdd | ||
|
|
c1b4beeb64 | ||
|
|
9d489564d6 | ||
|
|
24a4260e55 | ||
|
|
af8e61ece6 | ||
|
|
f9836d4dfb | ||
|
|
982b867a04 | ||
|
|
a6c9bd5c09 | ||
|
|
8008b9d0cb | ||
|
|
7f01db17d0 | ||
|
|
9ec44bdadd | ||
|
|
660290121c | ||
|
|
7dab7fad81 | ||
|
|
7b0630143d | ||
|
|
17258783c2 | ||
|
|
9398d86fba | ||
|
|
88ef90fce7 | ||
|
|
4213ec0986 | ||
|
|
f4b2563629 | ||
|
|
baf0e0c1f5 | ||
|
|
b888a65b8b | ||
|
|
a6eda5a0b8 | ||
|
|
6449082349 | ||
|
|
44127d4bf6 | ||
|
|
0c95e7ca1e | ||
|
|
e29ac75f3d | ||
|
|
7dba89a03a | ||
|
|
61d23ddc6f | ||
|
|
fc921143d3 | ||
|
|
395c79b32a | ||
|
|
7c683efce6 | ||
|
|
f07eb17dff | ||
|
|
242906162f | ||
|
|
c423f6ecd8 | ||
|
|
3c83320c20 | ||
|
|
89068641ee | ||
|
|
71e5c0d743 | ||
|
|
3e46fe777d | ||
|
|
a73d790a95 | ||
|
|
40b8596275 | ||
|
|
6487ed966f | ||
|
|
c5cb8ed5a7 | ||
|
|
d7ee3b72a6 | ||
|
|
36e2443267 | ||
|
|
2c1b95a3cb | ||
|
|
0628624edf | ||
|
|
2bd854ff18 | ||
|
|
18b6ed080c | ||
|
|
5010f0e0e1 | ||
|
|
82c7145163 | ||
|
|
cb60e70ae9 | ||
|
|
f8a255a9f0 | ||
|
|
38040cc246 | ||
|
|
0961bf088f | ||
|
|
76afb87624 | ||
|
|
8dc8513263 | ||
|
|
4d3f2bf1e4 | ||
|
|
4c82154eb0 | ||
|
|
858334cc64 | ||
|
|
7bb02a9b63 | ||
|
|
1551cdf517 | ||
|
|
8a8a1ac060 | ||
|
|
123e43e626 | ||
|
|
03e54ffdff | ||
|
|
c897074cb3 | ||
|
|
03fa4dc816 | ||
|
|
3ea4c635d0 | ||
|
|
78ed0852ea | ||
|
|
89d46dcab4 | ||
|
|
411626c038 | ||
|
|
56e3215785 | ||
|
|
b81f55057a | ||
|
|
e2dc1c2684 | ||
|
|
e2c5367050 | ||
|
|
15c48b919d | ||
|
|
7ad36b07b1 | ||
|
|
85dbb18663 | ||
|
|
a712be416e | ||
|
|
2246e12a6a | ||
|
|
0975eb7d78 | ||
|
|
f4610dc6eb | ||
|
|
df5b2abf21 | ||
|
|
e865627158 | ||
|
|
fdd6b78fa8 | ||
|
|
58db7712ea | ||
|
|
325ec9ae55 | ||
|
|
935a2a240d | ||
|
|
a0ca4f0a33 | ||
|
|
a0c47f8115 | ||
|
|
957776871d | ||
|
|
fe7d318f3d | ||
|
|
b8155835b6 | ||
|
|
74d9e63888 | ||
|
|
7c5601eed6 | ||
|
|
49acc1a88f | ||
|
|
f072b06b81 | ||
|
|
4be99a93c8 | ||
|
|
e761c9aec9 | ||
|
|
1032e8fb06 | ||
|
|
36d9cd1c76 | ||
|
|
281dcf464e | ||
|
|
90bed2da26 | ||
|
|
ba1f1a99ed | ||
|
|
cdd838cffe | ||
|
|
d1997c0f65 | ||
|
|
1cfc20365e | ||
|
|
ed8877ca6b | ||
|
|
de0dc2782f | ||
|
|
e33dd1527f | ||
|
|
9171ffc88a | ||
|
|
eb65468382 | ||
|
|
7c40172c40 | ||
|
|
ab48cccefc | ||
|
|
1b38ebe89e | ||
|
|
c235f05340 | ||
|
|
3a7219a94f | ||
|
|
accff8c8b6 | ||
|
|
9a9ac07ab2 | ||
|
|
2d6433ab4d | ||
|
|
937d93894a | ||
|
|
fc122027cb | ||
|
|
1e790b7a20 | ||
|
|
33dcef981a | ||
|
|
1c59fd7ed3 | ||
|
|
4d559d4094 | ||
|
|
96b852a0e7 | ||
|
|
aacf6b5d52 | ||
|
|
2573b5728c | ||
|
|
9eb2c04a26 | ||
|
|
71b19be030 | ||
|
|
48d28dc317 | ||
|
|
73c5127088 | ||
|
|
a8831b2c9e | ||
|
|
d8a40611f8 | ||
|
|
762afcfc21 | ||
|
|
6b0e5ae392 | ||
|
|
660621bffb | ||
|
|
ba64441619 | ||
|
|
d63234f385 | ||
|
|
bd4223c721 | ||
|
|
5cbdbc7520 | ||
|
|
5c95b5ac98 | ||
|
|
ef1800c50a | ||
|
|
5c2a6d6f7c | ||
|
|
acdff604e4 | ||
|
|
0aff6c1561 | ||
|
|
6c556263c6 | ||
|
|
e639456a82 | ||
|
|
5dedf7bec3 | ||
|
|
cb8ef37c79 | ||
|
|
ad007bd51a | ||
|
|
ae499d513a | ||
|
|
507c80afc7 | ||
|
|
3d02cacc4d | ||
|
|
f9e96922eb | ||
|
|
791239eabb | ||
|
|
4c72f6d1fb | ||
|
|
34e3310669 | ||
|
|
4bd45d1f5b | ||
|
|
55d02d4955 | ||
|
|
f5fd8c9fe5 | ||
|
|
ff39027869 | ||
|
|
3b1bae3775 | ||
|
|
ef0dde23d0 | ||
|
|
512537afe5 | ||
|
|
e85782da4d | ||
|
|
d86a10af32 | ||
|
|
ceab78e2d8 | ||
|
|
11afab61d7 | ||
|
|
801e691011 | ||
|
|
b3f7c648db | ||
|
|
3842950309 | ||
|
|
57ef6f02bc | ||
|
|
ffb916a48a | ||
|
|
3f78ee72b4 | ||
|
|
2d41ce0ae7 | ||
|
|
484a47e0fd | ||
|
|
09d67f1c05 | ||
|
|
167ca9a595 | ||
|
|
6d9df29a4e | ||
|
|
5ef7ca7723 | ||
|
|
bac0313d7c | ||
|
|
af64824733 | ||
|
|
ad490ce006 | ||
|
|
ff4de2c77b | ||
|
|
bc542aad12 | ||
|
|
1211077dc8 | ||
|
|
9de6a61ea5 | ||
|
|
cc1f059950 | ||
|
|
ef3a754033 | ||
|
|
e24bd88971 | ||
|
|
caf2193a0f | ||
|
|
cb27f36f66 | ||
|
|
6ec8e7ac3b | ||
|
|
dd566ee112 | ||
|
|
7f230f2999 | ||
|
|
48d8e2f453 | ||
|
|
865842e5b8 | ||
|
|
fda26f521f | ||
|
|
70e35f77bf | ||
|
|
0af348fb02 | ||
|
|
b67ae13f3c | ||
|
|
d9252e37b3 | ||
|
|
3b6e3d636d | ||
|
|
0443ca3185 | ||
|
|
01e2708233 | ||
|
|
9d3f09fafa | ||
|
|
22a208e505 | ||
|
|
cbc26cd135 | ||
|
|
8c5c7d13b8 | ||
|
|
7e042c9dab | ||
|
|
4a744bac5c | ||
|
|
89c22acb95 | ||
|
|
007ed35a66 | ||
|
|
2bb0e268c8 | ||
|
|
d6c7601a14 | ||
|
|
a79ec6c5ed | ||
|
|
4eea383f74 | ||
|
|
45746fbf34 | ||
|
|
7ac40d2d99 | ||
|
|
bebd157586 | ||
|
|
02a6fa7418 | ||
|
|
bc16421b64 | ||
|
|
bcc4cf8b57 | ||
|
|
d7418c7ad1 | ||
|
|
c7fb25e3f8 | ||
|
|
9e26af66bf | ||
|
|
b741ea79e5 | ||
|
|
7d2f5065be | ||
|
|
a9e7f94409 | ||
|
|
d3be13182d | ||
|
|
a4658be5b6 | ||
|
|
b3f252ee46 | ||
|
|
f98b5764ea | ||
|
|
9f8fcec1ad | ||
|
|
deb4b71e7b | ||
|
|
90a2b07e5f | ||
|
|
e69f909b61 | ||
|
|
0686575484 | ||
|
|
c7cadedd21 | ||
|
|
78d41878e8 | ||
|
|
a527ccd8ed | ||
|
|
5f5f745892 | ||
|
|
6160d67032 | ||
|
|
641341d75d | ||
|
|
146af217a0 | ||
|
|
4a0410b609 | ||
|
|
e858a42455 | ||
|
|
b037cb0e82 | ||
|
|
5455b436f6 | ||
|
|
786e13b0b7 | ||
|
|
759fb1bcbc | ||
|
|
227c962ec4 | ||
|
|
f03ffd13a0 | ||
|
|
00120a6b37 | ||
|
|
884121bdae | ||
|
|
48b92ce0b1 | ||
|
|
f8e1326837 | ||
|
|
00cf15935b | ||
|
|
172ee5a228 | ||
|
|
2f2a43e9c6 | ||
|
|
a9e32dfc99 | ||
|
|
5450b0fd0b | ||
|
|
e09581aa78 | ||
|
|
e08a8ff132 | ||
|
|
8ee0a0fad0 | ||
|
|
4b3ed4f43d | ||
|
|
6ed2e11730 | ||
|
|
e784dafefe | ||
|
|
6cdc6f7bdb | ||
|
|
60a7a7cf94 | ||
|
|
765c0ea17c | ||
|
|
de7de4cd8a | ||
|
|
19473ddba9 | ||
|
|
14421b533d | ||
|
|
21fc5d590f | ||
|
|
24651db512 | ||
|
|
27644bd032 | ||
|
|
0c2e7fae9f | ||
|
|
9d4824bb23 | ||
|
|
3b19b4212b | ||
|
|
69c2b3ffbb | ||
|
|
92ca6261b8 | ||
|
|
9e5e160845 | ||
|
|
6a66e920fe | ||
|
|
cab9f6ab4e | ||
|
|
0395f01c33 | ||
|
|
de88f17a1a | ||
|
|
9db8f9c924 | ||
|
|
7328a27524 | ||
|
|
8ee41e9608 | ||
|
|
0ed6403141 | ||
|
|
6980661a8e | ||
|
|
4797313f9e | ||
|
|
b17774da6e | ||
|
|
a4bba21610 | ||
|
|
7e1d522601 | ||
|
|
cd2225bbc8 | ||
|
|
62af22c928 | ||
|
|
2b531c5302 | ||
|
|
41ed0cee1d | ||
|
|
ce7da62a88 | ||
|
|
f93772ebc9 | ||
|
|
f63b052864 | ||
|
|
43dbdd049f | ||
|
|
6a489eaaf3 | ||
|
|
3a783a722a | ||
|
|
44481e1c2a | ||
|
|
e3d1970369 | ||
|
|
2c7708dab1 | ||
|
|
e156ff77f8 | ||
|
|
5f5f22ee8c | ||
|
|
011b60b3bf | ||
|
|
9bd8669cf4 | ||
|
|
4b5a47f127 | ||
|
|
db45e7907c | ||
|
|
03f400620e | ||
|
|
d938a528c3 | ||
|
|
2309749d15 | ||
|
|
b37b8eaeaf | ||
|
|
9c57243d5a | ||
|
|
6518cd464c | ||
|
|
7e32a16969 | ||
|
|
349c94ee23 | ||
|
|
167774e3b0 | ||
|
|
f2ba1bd4ab | ||
|
|
3ce8041a12 | ||
|
|
a4bbf8f233 | ||
|
|
1b813c4ea2 | ||
|
|
e6c2d85197 | ||
|
|
23ae20efe7 | ||
|
|
37b3f03809 | ||
|
|
43540b008c | ||
|
|
169ccbb47f | ||
|
|
0af35817a6 | ||
|
|
c942542079 | ||
|
|
8a6d8e0549 | ||
|
|
0c4dbebaeb | ||
|
|
5995ec299c | ||
|
|
e2c82fe3dc | ||
|
|
39f6c12d33 | ||
|
|
ae24d9ef03 | ||
|
|
5a1f5757c1 | ||
|
|
b194b88c49 | ||
|
|
b86fbb3cd8 | ||
|
|
9fca104059 | ||
|
|
9369a697e3 | ||
|
|
ebbafbe55d | ||
|
|
6bf9ba397e | ||
|
|
7b7af75802 | ||
|
|
723ce6c893 | ||
|
|
ed3be361b5 | ||
|
|
0b6990f828 | ||
|
|
2af94410f5 | ||
|
|
b348565449 | ||
|
|
aa06255e26 | ||
|
|
a0d967cdc7 | ||
|
|
494a72709d | ||
|
|
8947cebf04 | ||
|
|
b51993db0c | ||
|
|
5c8f80a907 | ||
|
|
9fab40d12a | ||
|
|
420a5fa782 | ||
|
|
fe335ea865 | ||
|
|
ad04a483e3 | ||
|
|
b3228f1e27 | ||
|
|
249935fc66 | ||
|
|
53c0ccfba8 | ||
|
|
4706adb0d5 | ||
|
|
53b6bf0986 | ||
|
|
65d9a75421 | ||
|
|
c089192904 | ||
|
|
a8af3310b4 | ||
|
|
58e6989307 | ||
|
|
18f7ea2a7e | ||
|
|
4e8219c6fa | ||
|
|
24f7ef69c7 | ||
|
|
1578c13bf5 | ||
|
|
ca2aa5d7f7 | ||
|
|
4d43f83443 | ||
|
|
319869bc6d | ||
|
|
405fb52cb2 | ||
|
|
76a6fad4e2 | ||
|
|
47be49253b | ||
|
|
5177c793a7 | ||
|
|
bb06ac0c42 | ||
|
|
20668bef9e | ||
|
|
747f8d4567 | ||
|
|
501927c844 | ||
|
|
d03ae91d11 | ||
|
|
cc2f45f764 | ||
|
|
713dcd5d08 | ||
|
|
8b69c90bf1 | ||
|
|
5513122ca9 | ||
|
|
7507ac31f7 | ||
|
|
49e51675d3 | ||
|
|
056d54d313 | ||
|
|
00eac849fe | ||
|
|
75a17dae2c | ||
|
|
62c81ac785 | ||
|
|
15c5170195 | ||
|
|
4b302c0330 | ||
|
|
7977fa40e7 | ||
|
|
45c4c507bc | ||
|
|
33f2e03e13 | ||
|
|
56391021a4 | ||
|
|
ab831c2604 | ||
|
|
11fc4d88aa | ||
|
|
57dd1982a0 | ||
|
|
3f754dc662 | ||
|
|
0c5b1a88a6 | ||
|
|
1d5fdef4b4 | ||
|
|
815b8597d1 | ||
|
|
53e3a7ae7f | ||
|
|
04974d37d6 | ||
|
|
8c1e53a8df | ||
|
|
8399b00a10 | ||
|
|
9244adee30 | ||
|
|
3265a9de7b | ||
|
|
ec602f3e15 | ||
|
|
6ed7f672fc | ||
|
|
c9bb49e0f7 |
@@ -3,7 +3,10 @@ root = true
|
|||||||
[*]
|
[*]
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
end_of_line = lf
|
end_of_line = lf
|
||||||
|
indent_size = tab
|
||||||
|
indent_style = tab
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
[*.{js,vue}]
|
[*.{js,vue}]
|
||||||
indent_style = tab
|
indent_style = tab
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
|
root: true,
|
||||||
extends: [
|
extends: [
|
||||||
'@nextcloud',
|
'@nextcloud',
|
||||||
],
|
],
|
||||||
@@ -7,6 +8,7 @@ module.exports = {
|
|||||||
'jsdoc/require-param-type': ['off'],
|
'jsdoc/require-param-type': ['off'],
|
||||||
'jsdoc/check-param-names': ['off'],
|
'jsdoc/check-param-names': ['off'],
|
||||||
'jsdoc/no-undefined-types': ['off'],
|
'jsdoc/no-undefined-types': ['off'],
|
||||||
'jsdoc/require-property-description' : ['off']
|
'jsdoc/require-property-description': ['off'],
|
||||||
|
'import/no-named-as-default-member': ['off']
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
8
.github/workflows/appbuild.yml
vendored
@@ -1,7 +1,11 @@
|
|||||||
name: Package build
|
name: Package build
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- master
|
||||||
|
- stable*
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -20,7 +24,7 @@ jobs:
|
|||||||
- name: Set up npm7
|
- name: Set up npm7
|
||||||
run: npm i -g npm@7
|
run: npm i -g npm@7
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
uses: shivammathur/setup-php@2.18.0
|
uses: shivammathur/setup-php@2.21.2
|
||||||
with:
|
with:
|
||||||
php-version: '7.4'
|
php-version: '7.4'
|
||||||
tools: composer
|
tools: composer
|
||||||
|
|||||||
2
.github/workflows/appstore-build-publish.yml
vendored
@@ -66,7 +66,7 @@ jobs:
|
|||||||
run: npm i -g npm@"${{ steps.versions.outputs.npmVersion }}"
|
run: npm i -g npm@"${{ steps.versions.outputs.npmVersion }}"
|
||||||
|
|
||||||
- name: Set up php ${{ env.PHP_VERSION }}
|
- name: Set up php ${{ env.PHP_VERSION }}
|
||||||
uses: shivammathur/setup-php@2.18.0
|
uses: shivammathur/setup-php@2.21.2
|
||||||
with:
|
with:
|
||||||
php-version: ${{ env.PHP_VERSION }}
|
php-version: ${{ env.PHP_VERSION }}
|
||||||
coverage: none
|
coverage: none
|
||||||
|
|||||||
7
.github/workflows/command-rebase.yml
vendored
@@ -9,9 +9,14 @@ on:
|
|||||||
issue_comment:
|
issue_comment:
|
||||||
types: created
|
types: created
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
rebase:
|
rebase:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: none
|
||||||
|
|
||||||
# On pull requests and if the comment starts with `/rebase`
|
# On pull requests and if the comment starts with `/rebase`
|
||||||
if: github.event.issue.pull_request != '' && startsWith(github.event.comment.body, '/rebase')
|
if: github.event.issue.pull_request != '' && startsWith(github.event.comment.body, '/rebase')
|
||||||
@@ -32,7 +37,7 @@ jobs:
|
|||||||
token: ${{ secrets.COMMAND_BOT_PAT }}
|
token: ${{ secrets.COMMAND_BOT_PAT }}
|
||||||
|
|
||||||
- name: Automatic Rebase
|
- name: Automatic Rebase
|
||||||
uses: cirrus-actions/rebase@1.5
|
uses: cirrus-actions/rebase@1.7
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.COMMAND_BOT_PAT }}
|
GITHUB_TOKEN: ${{ secrets.COMMAND_BOT_PAT }}
|
||||||
|
|
||||||
|
|||||||
112
.github/workflows/cypress.yml
vendored
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
name: Cypress
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- stable*
|
||||||
|
|
||||||
|
env:
|
||||||
|
APP_NAME: deck
|
||||||
|
CYPRESS_baseUrl: http://localhost:8081/index.php
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
cypress:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
node-version: [14.x]
|
||||||
|
# containers: [1, 2, 3]
|
||||||
|
php-versions: [ '7.4' ]
|
||||||
|
databases: [ 'sqlite' ]
|
||||||
|
server-versions: [ 'master' ]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
- name: Set up npm7
|
||||||
|
run: npm i -g npm@7
|
||||||
|
|
||||||
|
- name: Checkout server
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
repository: nextcloud/server
|
||||||
|
ref: ${{ matrix.server-versions }}
|
||||||
|
|
||||||
|
- name: Checkout submodules
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
auth_header="$(git config --local --get http.https://github.com/.extraheader)"
|
||||||
|
git submodule sync --recursive
|
||||||
|
git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1
|
||||||
|
|
||||||
|
- name: Checkout ${{ env.APP_NAME }}
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
path: apps/${{ env.APP_NAME }}
|
||||||
|
|
||||||
|
- name: Set up php ${{ matrix.php-versions }}
|
||||||
|
uses: shivammathur/setup-php@2.21.2
|
||||||
|
with:
|
||||||
|
php-version: ${{ matrix.php-versions }}
|
||||||
|
extensions: mbstring, iconv, fileinfo, intl, sqlite, pdo_sqlite, zip, gd, apcu
|
||||||
|
ini-values:
|
||||||
|
apc.enable_cli=on
|
||||||
|
coverage: none
|
||||||
|
|
||||||
|
- name: Set up Nextcloud
|
||||||
|
env:
|
||||||
|
DB_PORT: 4444
|
||||||
|
PHP_CLI_SERVER_WORKERS: 10
|
||||||
|
run: |
|
||||||
|
mkdir data
|
||||||
|
php occ maintenance:install --verbose --database=${{ matrix.databases }} --database-name=nextcloud --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
|
||||||
|
php occ config:system:set memcache.local --value="\\OC\\Memcache\\APCu"
|
||||||
|
php occ config:system:set debug --value=true --type=boolean
|
||||||
|
php -f index.php
|
||||||
|
php -S 0.0.0.0:8081 &
|
||||||
|
export OC_PASS=1234561
|
||||||
|
php occ user:add --password-from-env user1
|
||||||
|
php occ user:add --password-from-env user2
|
||||||
|
php occ app:enable deck
|
||||||
|
php occ app:list
|
||||||
|
cd apps/deck
|
||||||
|
composer install --no-dev
|
||||||
|
npm ci
|
||||||
|
npm run build
|
||||||
|
cd ../../
|
||||||
|
curl -v http://localhost:8081/index.php/login
|
||||||
|
|
||||||
|
- name: Cypress run
|
||||||
|
uses: cypress-io/github-action@v4
|
||||||
|
with:
|
||||||
|
record: true
|
||||||
|
parallel: false
|
||||||
|
wait-on: '${{ env.CYPRESS_baseUrl }}'
|
||||||
|
working-directory: 'apps/${{ env.APP_NAME }}'
|
||||||
|
config: defaultCommandTimeout=10000,video=false
|
||||||
|
env:
|
||||||
|
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||||
|
npm_package_name: ${{ env.APP_NAME }}
|
||||||
|
|
||||||
|
- name: Upload test failure screenshots
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
if: failure()
|
||||||
|
with:
|
||||||
|
name: Upload screenshots
|
||||||
|
path: apps/${{ env.APP_NAME }}/cypress/screenshots/
|
||||||
|
retention-days: 5
|
||||||
|
|
||||||
|
- name: Upload nextcloud logs
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
if: failure()
|
||||||
|
with:
|
||||||
|
name: Upload nextcloud log
|
||||||
|
path: data/nextcloud.log
|
||||||
|
retention-days: 5
|
||||||
@@ -8,13 +8,20 @@ name: Dependabot
|
|||||||
on:
|
on:
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
branches:
|
branches:
|
||||||
|
- main
|
||||||
- master
|
- master
|
||||||
- stable*
|
- stable*
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
auto-approve-merge:
|
auto-approve-merge:
|
||||||
if: github.actor == 'dependabot[bot]'
|
if: github.actor == 'dependabot[bot]'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
# for hmarr/auto-approve-action to approve PRs
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
# Github actions bot approve
|
# Github actions bot approve
|
||||||
|
|||||||
16
.github/workflows/integration.yml
vendored
@@ -2,6 +2,14 @@ name: Integration tests
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/integration.yml'
|
||||||
|
- 'appinfo/**'
|
||||||
|
- 'lib/**'
|
||||||
|
- 'templates/**'
|
||||||
|
- 'tests/**'
|
||||||
|
- 'composer.json'
|
||||||
|
- 'composer.lock'
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
@@ -19,7 +27,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
php-versions: ['7.4']
|
php-versions: ['7.4']
|
||||||
databases: ['sqlite', 'mysql', 'pgsql']
|
databases: ['sqlite', 'mysql', 'pgsql']
|
||||||
server-versions: ['stable24']
|
server-versions: ['master']
|
||||||
|
|
||||||
name: php${{ matrix.php-versions }}-${{ matrix.databases }}-${{ matrix.server-versions }}
|
name: php${{ matrix.php-versions }}-${{ matrix.databases }}-${{ matrix.server-versions }}
|
||||||
|
|
||||||
@@ -54,7 +62,7 @@ jobs:
|
|||||||
auth_header="$(git config --local --get http.https://github.com/.extraheader)"
|
auth_header="$(git config --local --get http.https://github.com/.extraheader)"
|
||||||
git submodule sync --recursive
|
git submodule sync --recursive
|
||||||
git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1
|
git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1
|
||||||
cd build/integration && composer require --dev phpunit/phpunit:~8
|
cd build/integration && composer require --dev phpunit/phpunit:~9
|
||||||
|
|
||||||
- name: Checkout app
|
- name: Checkout app
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
@@ -62,7 +70,7 @@ jobs:
|
|||||||
path: apps/${{ env.APP_NAME }}
|
path: apps/${{ env.APP_NAME }}
|
||||||
|
|
||||||
- name: Set up php ${{ matrix.php-versions }}
|
- name: Set up php ${{ matrix.php-versions }}
|
||||||
uses: shivammathur/setup-php@2.18.0
|
uses: shivammathur/setup-php@2.21.2
|
||||||
with:
|
with:
|
||||||
php-version: ${{ matrix.php-versions }}
|
php-version: ${{ matrix.php-versions }}
|
||||||
tools: phpunit
|
tools: phpunit
|
||||||
@@ -71,7 +79,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Set up PHPUnit
|
- name: Set up PHPUnit
|
||||||
working-directory: apps/${{ env.APP_NAME }}
|
working-directory: apps/${{ env.APP_NAME }}
|
||||||
run: composer i
|
run: composer i --no-dev
|
||||||
|
|
||||||
- name: Set up Nextcloud
|
- name: Set up Nextcloud
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
4
.github/workflows/lint.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Set up php${{ matrix.php-versions }}
|
- name: Set up php${{ matrix.php-versions }}
|
||||||
uses: shivammathur/setup-php@2.18.0
|
uses: shivammathur/setup-php@2.21.2
|
||||||
with:
|
with:
|
||||||
php-version: ${{ matrix.php-versions }}
|
php-version: ${{ matrix.php-versions }}
|
||||||
coverage: none
|
coverage: none
|
||||||
@@ -33,7 +33,7 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
- name: Set up php
|
- name: Set up php
|
||||||
uses: shivammathur/setup-php@2.18.0
|
uses: shivammathur/setup-php@2.21.2
|
||||||
with:
|
with:
|
||||||
php-version: 7.4
|
php-version: 7.4
|
||||||
coverage: none
|
coverage: none
|
||||||
|
|||||||
2
.github/workflows/nightly.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
|||||||
- name: Set up npm7
|
- name: Set up npm7
|
||||||
run: npm i -g npm@7
|
run: npm i -g npm@7
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
uses: shivammathur/setup-php@2.18.0
|
uses: shivammathur/setup-php@2.21.2
|
||||||
with:
|
with:
|
||||||
php-version: '7.4'
|
php-version: '7.4'
|
||||||
tools: composer
|
tools: composer
|
||||||
|
|||||||
12
.github/workflows/phpunit.yml
vendored
@@ -2,6 +2,14 @@ name: PHPUnit
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/phpunit.yml'
|
||||||
|
- 'appinfo/**'
|
||||||
|
- 'lib/**'
|
||||||
|
- 'templates/**'
|
||||||
|
- 'tests/**'
|
||||||
|
- 'composer.json'
|
||||||
|
- 'composer.lock'
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
@@ -20,7 +28,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
php-versions: ['7.4', '8.0', '8.1']
|
php-versions: ['7.4', '8.0', '8.1']
|
||||||
databases: ['sqlite', 'mysql', 'pgsql']
|
databases: ['sqlite', 'mysql', 'pgsql']
|
||||||
server-versions: ['stable24']
|
server-versions: ['master']
|
||||||
|
|
||||||
name: php${{ matrix.php-versions }}-${{ matrix.databases }}-${{ matrix.server-versions }}
|
name: php${{ matrix.php-versions }}-${{ matrix.databases }}-${{ matrix.server-versions }}
|
||||||
|
|
||||||
@@ -62,7 +70,7 @@ jobs:
|
|||||||
path: apps/${{ env.APP_NAME }}
|
path: apps/${{ env.APP_NAME }}
|
||||||
|
|
||||||
- name: Set up php ${{ matrix.php-versions }}
|
- name: Set up php ${{ matrix.php-versions }}
|
||||||
uses: shivammathur/setup-php@2.18.0
|
uses: shivammathur/setup-php@2.21.2
|
||||||
with:
|
with:
|
||||||
php-version: ${{ matrix.php-versions }}
|
php-version: ${{ matrix.php-versions }}
|
||||||
tools: phpunit
|
tools: phpunit
|
||||||
|
|||||||
2
.github/workflows/update-nextcloud-ocp.yml
vendored
@@ -49,7 +49,7 @@ jobs:
|
|||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
uses: peter-evans/create-pull-request@v3
|
uses: peter-evans/create-pull-request@v4
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.COMMAND_BOT_PAT }}
|
token: ${{ secrets.COMMAND_BOT_PAT }}
|
||||||
commit-message: Update psalm baseline
|
commit-message: Update psalm baseline
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[main]
|
[main]
|
||||||
host = https://www.transifex.com
|
host = https://www.transifex.com
|
||||||
lang_map = bg_BG: bg, cs_CZ: cs, fi_FI: fi, hu_HU: hu, nb_NO: nb, sk_SK: sk, th_TH: th, ja_JP: ja
|
lang_map = hu_HU: hu, nb_NO: nb, sk_SK: sk, th_TH: th, ja_JP: ja, bg_BG: bg, cs_CZ: cs, fi_FI: fi
|
||||||
|
|
||||||
[o:nextcloud:p:nextcloud:r:deck]
|
[o:nextcloud:p:nextcloud:r:deck]
|
||||||
file_filter = translationfiles/<lang>/deck.po
|
file_filter = translationfiles/<lang>/deck.po
|
||||||
|
|||||||
65
CHANGELOG.md
@@ -1,40 +1,45 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
## 1.7.3
|
## 1.8.0-beta.1
|
||||||
|
### Enhancements
|
||||||
|
|
||||||
|
- Nextcloud 25 compatibility
|
||||||
|
- Performance improvements
|
||||||
|
- Use capped memory cache for board permissions @juliushaertl [#3980](https://github.com/nextcloud/deck/pull/3980)
|
||||||
|
- Improve CalDAV integration performance @juliushaertl [#3982](https://github.com/nextcloud/deck/pull/3982)
|
||||||
|
- Simpify query for getting shared files @juliushaertl [#3983](https://github.com/nextcloud/deck/pull/3983)
|
||||||
|
- Accessibility improvements
|
||||||
|
- Add a11y label for sidebar button @marcelklehr [#3986](https://github.com/nextcloud/deck/pull/3986)
|
||||||
|
- Improve filter popover accessibility @juliushaertl [#3820](https://github.com/nextcloud/deck/pull/3820)
|
||||||
|
- Set ids to skip to content/navigation @juliushaertl [#3924](https://github.com/nextcloud/deck/pull/3924)
|
||||||
|
- Invert icons properly in dark mode @juliushaertl [#3939](https://github.com/nextcloud/deck/pull/3939)
|
||||||
|
- Bump dependencies
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- feat: add validators to check values in services @juliushaertl [#4176](https://github.com/nextcloud/deck/pull/4176)
|
- set last modified when the card was found. Fixes #3763 @ylebre [#3796](https://github.com/nextcloud/deck/pull/3796)
|
||||||
- Add integration test for attachment handling on cards [#4178](https://github.com/nextcloud/deck/pull/4178)
|
- Increase file count after sharing @luka-nextcloud [#3682](https://github.com/nextcloud/deck/pull/3682)
|
||||||
- disables autocomplete on card creation @juliushaertl [#4182](https://github.com/nextcloud/deck/pull/4182)
|
- Align Duedate-delete icon properly - fixes nextcloud/deck#3791 @Ben-Ro [#3811](https://github.com/nextcloud/deck/pull/3811)
|
||||||
- minor style fixes [#4202](https://github.com/nextcloud/deck/pull/4202)
|
- Fix for issue #3637 @flummer [#3833](https://github.com/nextcloud/deck/pull/3833)
|
||||||
|
- Switch to 'markdown-it-task-checkbox' for rendering of task lists @q-wertz [#3898](https://github.com/nextcloud/deck/pull/3898)
|
||||||
|
- Make rename functions accessibly by keyboard navigation @juliushaertl [#3813](https://github.com/nextcloud/deck/pull/3813)
|
||||||
|
- Prevent opening card and applyLabelFilter on card drag end @eneiluj [#3916](https://github.com/nextcloud/deck/pull/3916)
|
||||||
|
- Inserted required property in the rename list field, to prevent the l… @mstolf [#3862](https://github.com/nextcloud/deck/pull/3862)
|
||||||
|
- Fix share provider for master changes @nickvergessen [#3942](https://github.com/nextcloud/deck/pull/3942)
|
||||||
|
- Fetch attachment folder for the correct user during cron job @juliushaertl [#3952](https://github.com/nextcloud/deck/pull/3952)
|
||||||
|
- Fix z-index for deck sidebar @Raudius [#3884](https://github.com/nextcloud/deck/pull/3884)
|
||||||
|
|
||||||
|
### Other
|
||||||
|
|
||||||
## 1.7.2
|
- Switch from OC::$server->get to OCP\Server::get @CarlSchwan [#3801](https://github.com/nextcloud/deck/pull/3801)
|
||||||
|
- Add performance section in README @eneiluj [#3830](https://github.com/nextcloud/deck/pull/3830)
|
||||||
### Fixed
|
- Fix static analysis by stubbing more circle methods @juliushaertl [#3900](https://github.com/nextcloud/deck/pull/3900)
|
||||||
|
- fix(docs): fix links to JSON schemas for Trello @wiktor2200 [#3872](https://github.com/nextcloud/deck/pull/3872)
|
||||||
- Cache user membership for circles [#4132](https://github.com/nextcloud/deck/pull/4132)
|
- Move to OCP\Collaboration\Resources\LoadAdditionalScriptsEvent @juliushaertl [#3818](https://github.com/nextcloud/deck/pull/3818)
|
||||||
- Set event link also for notifications that get emitted from activities [#4118](https://github.com/nextcloud/deck/pull/4118)
|
- Rename settings to deck settings @PVince81 [#3928](https://github.com/nextcloud/deck/pull/3928)
|
||||||
- Fix Card menu not displaying when description is not set [#4103](https://github.com/nextcloud/deck/pull/4103)
|
- SCSS cleanup @juliushaertl [#3803](https://github.com/nextcloud/deck/pull/3803)
|
||||||
- disable Create card button while no stack is chosen [#4019](https://github.com/nextcloud/deck/pull/4019)
|
- Hide deprecated projects in sidebar and card details by default @Pytal [#3984](https://github.com/nextcloud/deck/pull/3984)
|
||||||
- to nextcloud/OCP package in stable24 [#4093](https://github.com/nextcloud/deck/pull/4093)
|
|
||||||
- Fix attachment creator name: show display name [#4037](https://github.com/nextcloud/deck/pull/4037)
|
|
||||||
- Use capped memory cache for board permissions [#3997](https://github.com/nextcloud/deck/pull/3997)
|
|
||||||
- Improve CalDAV integration performance [#3995](https://github.com/nextcloud/deck/pull/3995)
|
|
||||||
- Fetch attachment folder for the correct user during cron job [#3959](https://github.com/nextcloud/deck/pull/3959)
|
|
||||||
- Switch to 'markdown-it-task-checkbox' for rendering of task lists [#3925](https://github.com/nextcloud/deck/pull/3925)
|
|
||||||
- Prevent opening card and applyLabelFilter on card drag end [#3917](https://github.com/nextcloud/deck/pull/3917)
|
|
||||||
- Fix for issue #3637 [#3901](https://github.com/nextcloud/deck/pull/3901)
|
|
||||||
- Fix z-index for deck sidebar [#3885](https://github.com/nextcloud/deck/pull/3885)
|
|
||||||
|
|
||||||
## 1.7.1
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Align Duedate-delete icon properly - fixes nextcloud/deck#3791 [#3817](https://github.com/nextcloud/deck/pull/3817)
|
|
||||||
- Increase file count after sharing [#3806](https://github.com/nextcloud/deck/pull/3806)
|
|
||||||
- Fetch full board data after cloning [#3781](https://github.com/nextcloud/deck/pull/3781)
|
|
||||||
|
|
||||||
## 1.7.0
|
## 1.7.0
|
||||||
|
|
||||||
@@ -86,7 +91,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Adapt the card modal to upstream changes [#3764](https://github.com/nextcloud/deck/pull/3764)
|
- Adapt the card modal to upstream changes [#3764](https://github.com/nextcloud/deck/pull/3764)
|
||||||
- Fix text selection in dark mode and modal view [#3765](https://github.com/nextcloud/deck/pull/3765)
|
- Fix text selection in dark mode and modal view [#3765](https://github.com/nextcloud/deck/pull/3765)
|
||||||
- Add missing indices [#3754](https://github.com/nextcloud/deck/pull/3754)
|
- Add missing indices [#3754](https://github.com/nextcloud/deck/pull/3754)
|
||||||
- Handle qb mapper exception messages properly @juliushaertl [#3769](https://github.com/nextcloud/deck/pull/3769)
|
|
||||||
|
|
||||||
## 1.6.0-beta1
|
## 1.6.0-beta1
|
||||||
|
|
||||||
|
|||||||
10
Makefile
@@ -30,6 +30,16 @@ build: clean-dist install-deps build-js
|
|||||||
|
|
||||||
release: clean-dist install-deps-nodev build-js
|
release: clean-dist install-deps-nodev build-js
|
||||||
|
|
||||||
|
lint: lint-js lint-php
|
||||||
|
|
||||||
|
lint-js:
|
||||||
|
npm run lint
|
||||||
|
npm run stylelint
|
||||||
|
|
||||||
|
lint-php:
|
||||||
|
composer run lint 1>/dev/null
|
||||||
|
composer run cs:check
|
||||||
|
|
||||||
build-js: install-deps-js
|
build-js: install-deps-js
|
||||||
npm run build
|
npm run build
|
||||||
|
|
||||||
|
|||||||
22
README.md
@@ -24,9 +24,9 @@ Deck is a kanban style organization tool aimed at personal planning and project
|
|||||||
### 3rd-Party Integrations
|
### 3rd-Party Integrations
|
||||||
|
|
||||||
- [trello-to-deck](https://github.com/maxammann/trello-to-deck) - Migrates cards from Trello
|
- [trello-to-deck](https://github.com/maxammann/trello-to-deck) - Migrates cards from Trello
|
||||||
- [mail2deck](https://github.com/newroco/mail2deck) - Provides an "email in" solution
|
- [mail2deck](https://github.com/newroco/mail2deck) - Provides an "email in" solution
|
||||||
- [A-deck](https://github.com/leoossa/A-deck) - Chrome Extension that allows to create new card in selected stack based on current tab
|
- [A-deck](https://github.com/leoossa/A-deck) - Chrome Extension that allows to create new card in selected stack based on current tab
|
||||||
|
|
||||||
## Installation/Update
|
## Installation/Update
|
||||||
|
|
||||||
This app is supposed to work on the two latest Nextcloud versions.
|
This app is supposed to work on the two latest Nextcloud versions.
|
||||||
@@ -52,14 +52,32 @@ Please make sure you have installed the following dependencies: `make, which, ta
|
|||||||
|
|
||||||
Instead of setting everything up manually, you can just [download the nightly build](https://github.com/nextcloud/deck/releases/tag/nightly) instead. These builds are updated every 24 hours, and are pre-configured with all the needed dependencies.
|
Instead of setting everything up manually, you can just [download the nightly build](https://github.com/nextcloud/deck/releases/tag/nightly) instead. These builds are updated every 24 hours, and are pre-configured with all the needed dependencies.
|
||||||
|
|
||||||
|
## Performance limitations
|
||||||
|
|
||||||
|
Deck is not yet ready for intensive usage.
|
||||||
|
A lot of database queries are generated when the number of boards, cards and attachments is high.
|
||||||
|
For example, a user having access to 13 boards, with each board having on average 100 cards,
|
||||||
|
and each card having on average 5 attachments,
|
||||||
|
would generate 6500 database queries when doing the file related queries
|
||||||
|
which would increase the page loading time significantly.
|
||||||
|
|
||||||
|
Improvements on Nextcloud server and Deck itself will improve the situation.
|
||||||
|
|
||||||
## Developing
|
## Developing
|
||||||
|
|
||||||
|
### Nextcloud environment
|
||||||
|
|
||||||
|
You need to setup a [development environment](https://docs.nextcloud.com/server/latest/developer_manual//getting_started/devenv.html) of the current nextcloud version. You can also alternatively install & run the [nextcloud docker container](https://github.com/juliushaertl/nextcloud-docker-dev).
|
||||||
|
After the finished installation, you can clone the deck project directly in the `/[nextcloud-docker-dev-dir]/workspace/server/apps/` folder.
|
||||||
|
|
||||||
### PHP
|
### PHP
|
||||||
|
|
||||||
Nothing to prepare, just dig into the code.
|
Nothing to prepare, just dig into the code.
|
||||||
|
|
||||||
### JavaScript
|
### JavaScript
|
||||||
|
|
||||||
|
This requires at least Node 16 and npm 7 to be installed.
|
||||||
|
|
||||||
Deck requires running a `make build-js` to install npm dependencies and build the JavaScript code using webpack. While developing you can also use `make watch` to rebuild everytime the code changes.
|
Deck requires running a `make build-js` to install npm dependencies and build the JavaScript code using webpack. While developing you can also use `make watch` to rebuild everytime the code changes.
|
||||||
|
|
||||||
#### Hot reloading
|
#### Hot reloading
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
- 🚀 Get your project organized
|
- 🚀 Get your project organized
|
||||||
|
|
||||||
</description>
|
</description>
|
||||||
<version>1.7.3</version>
|
<version>1.9.0-beta.1</version>
|
||||||
<licence>agpl</licence>
|
<licence>agpl</licence>
|
||||||
<author>Julius Härtl</author>
|
<author>Julius Härtl</author>
|
||||||
<namespace>Deck</namespace>
|
<namespace>Deck</namespace>
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
<database min-version="9.4">pgsql</database>
|
<database min-version="9.4">pgsql</database>
|
||||||
<database>sqlite</database>
|
<database>sqlite</database>
|
||||||
<database min-version="8.0">mysql</database>
|
<database min-version="8.0">mysql</database>
|
||||||
<nextcloud min-version="24" max-version="24"/>
|
<nextcloud min-version="26" max-version="26"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<background-jobs>
|
<background-jobs>
|
||||||
<job>OCA\Deck\Cron\DeleteCron</job>
|
<job>OCA\Deck\Cron\DeleteCron</job>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
"symfony/event-dispatcher": "^4.0",
|
"symfony/event-dispatcher": "^4.0",
|
||||||
"vimeo/psalm": "^4.3",
|
"vimeo/psalm": "^4.3",
|
||||||
"php-parallel-lint/php-parallel-lint": "^1.2",
|
"php-parallel-lint/php-parallel-lint": "^1.2",
|
||||||
"nextcloud/ocp": "dev-stable24"
|
"nextcloud/ocp": "dev-master"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"optimize-autoloader": true,
|
"optimize-autoloader": true,
|
||||||
@@ -36,6 +36,7 @@
|
|||||||
"cs:check": "php-cs-fixer fix --dry-run --diff",
|
"cs:check": "php-cs-fixer fix --dry-run --diff",
|
||||||
"cs:fix": "php-cs-fixer fix",
|
"cs:fix": "php-cs-fixer fix",
|
||||||
"psalm": "psalm",
|
"psalm": "psalm",
|
||||||
|
"psalm:update-baseline": "psalm --update-baseline",
|
||||||
"psalm:fix": "psalm --alter --issues=InvalidReturnType,InvalidNullableReturnType,MismatchingDocblockParamType,MismatchingDocblockReturnType,MissingParamType,InvalidFalsableReturnType",
|
"psalm:fix": "psalm --alter --issues=InvalidReturnType,InvalidNullableReturnType,MismatchingDocblockParamType,MismatchingDocblockReturnType,MissingParamType,InvalidFalsableReturnType",
|
||||||
"test": [
|
"test": [
|
||||||
"@test:unit",
|
"@test:unit",
|
||||||
|
|||||||
420
composer.lock
generated
9
css/deck.css
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
.icon-deck {
|
||||||
|
background-image: url(../img/deck-dark.svg);
|
||||||
|
filter: var(--background-invert-if-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-deck-white, .icon-deck.icon-white {
|
||||||
|
background-image: url(../img/deck.svg);
|
||||||
|
filter: var(--background-invert-if-dark);
|
||||||
|
}
|
||||||
@@ -1 +0,0 @@
|
|||||||
@include icon-black-white('deck', 'deck', 1);
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* @copyright Copyright (c) 2016 Julius Härtl <jus@bitgrid.net>
|
|
||||||
*
|
|
||||||
* @author Julius Härtl <jus@bitgrid.net>
|
|
||||||
* @author Artem Anufrij <artem.anufrij@live.de>
|
|
||||||
* @author Marin Treselj <marin@pixelipo.com>
|
|
||||||
* @author Oskar Kurz <oskar.kurz@gmail.com>
|
|
||||||
* @author Ryan Fletcher <ryan.fletcher@codepassion.ca>
|
|
||||||
*
|
|
||||||
* @license GNU AGPL version 3 or any later version
|
|
||||||
*
|
|
||||||
* 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/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
@import 'icons';
|
|
||||||
@import 'print';
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
/**
|
|
||||||
* Custom icons
|
|
||||||
*/
|
|
||||||
@include icon-black-white('deck', 'deck', 1);
|
|
||||||
@include icon-black-white('archive', 'deck', 1);
|
|
||||||
@include icon-black-white('circles', 'deck', 1);
|
|
||||||
@include icon-black-white('clone', 'deck', 1);
|
|
||||||
@include icon-black-white('filter', 'deck', 1);
|
|
||||||
@include icon-black-white('filter_set', 'deck', 1);
|
|
||||||
@include icon-black-white('attach', 'deck', 1);
|
|
||||||
@include icon-black-white('reply', 'deck', 1);
|
|
||||||
@include icon-black-white('notifications-dark', 'deck', 1);
|
|
||||||
@include icon-black-white('description', 'deck', 1);
|
|
||||||
|
|
||||||
.icon-toggle-compact-collapsed {
|
|
||||||
@include icon-color('toggle-view-expand', 'deck', $color-black);
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-toggle-compact-expanded {
|
|
||||||
@include icon-color('toggle-view-collapse', 'deck', $color-black);
|
|
||||||
}
|
|
||||||
.icon-activity {
|
|
||||||
@include icon-color('activity-dark', 'activity', $color-black);
|
|
||||||
}
|
|
||||||
.icon-comment--unread {
|
|
||||||
@include icon-color('comment', 'actions', $color-primary, 1, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
.avatardiv.circles {
|
|
||||||
background: var(--color-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-circles {
|
|
||||||
opacity: 1;
|
|
||||||
background-size: 20px;
|
|
||||||
background-position: center center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-colorpicker {
|
|
||||||
background-image: url('../img/color_picker.svg');
|
|
||||||
}
|
|
||||||
17
cypress.config.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
const { defineConfig } = require('cypress')
|
||||||
|
|
||||||
|
module.exports = defineConfig({
|
||||||
|
projectId: '1s7wkc',
|
||||||
|
viewportWidth: 1280,
|
||||||
|
viewportHeight: 720,
|
||||||
|
e2e: {
|
||||||
|
// We've imported your old cypress plugins here.
|
||||||
|
// You may want to clean this up later by importing these.
|
||||||
|
setupNodeEvents(on, config) {
|
||||||
|
return require('./cypress/plugins/index.js')(on, config)
|
||||||
|
},
|
||||||
|
baseUrl: 'http://nextcloud.local/index.php',
|
||||||
|
experimentalSessionAndOrigin: true,
|
||||||
|
specPattern: 'cypress/e2e/**/*.{js,jsx,ts,tsx}',
|
||||||
|
},
|
||||||
|
})
|
||||||
41
cypress/e2e/boardFeatures.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { randHash } from '../utils'
|
||||||
|
const randUser = randHash()
|
||||||
|
|
||||||
|
describe('Board', function() {
|
||||||
|
const password = 'pass123'
|
||||||
|
|
||||||
|
before(function() {
|
||||||
|
cy.nextcloudCreateUser(randUser, password)
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
cy.login(randUser, password)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Can create a board', function() {
|
||||||
|
const board = 'Test'
|
||||||
|
|
||||||
|
cy.intercept({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/index.php/apps/deck/boards',
|
||||||
|
}).as('createBoardRequest')
|
||||||
|
|
||||||
|
// Click "Add board"
|
||||||
|
cy.openLeftSidebar()
|
||||||
|
cy.get('#app-navigation-vue .app-navigation__list .app-navigation-entry')
|
||||||
|
.eq(3).find('a').first().click({ force: true })
|
||||||
|
|
||||||
|
// Type the board title
|
||||||
|
cy.get('.board-create form input[type=text]')
|
||||||
|
.type(board, { force: true })
|
||||||
|
|
||||||
|
// Submit
|
||||||
|
cy.get('.board-create form input[type=submit]')
|
||||||
|
.first().click({ force: true })
|
||||||
|
|
||||||
|
cy.wait('@createBoardRequest').its('response.statusCode').should('equal', 200)
|
||||||
|
|
||||||
|
cy.get('.app-navigation__list .app-navigation-entry__children .app-navigation-entry')
|
||||||
|
.contains(board).should('be.visible')
|
||||||
|
})
|
||||||
|
})
|
||||||
67
cypress/e2e/cardFeatures.js
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import { randHash } from '../utils'
|
||||||
|
const randUser = randHash()
|
||||||
|
|
||||||
|
const testBoardData = {
|
||||||
|
title: 'MyBoardTest',
|
||||||
|
color: '00ff00',
|
||||||
|
stacks: [
|
||||||
|
{
|
||||||
|
title: 'TestList',
|
||||||
|
cards: [
|
||||||
|
{
|
||||||
|
title: 'Hello world',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Card', function() {
|
||||||
|
before(function() {
|
||||||
|
cy.nextcloudCreateUser(randUser, randUser)
|
||||||
|
cy.createExampleBoard({
|
||||||
|
user: randUser,
|
||||||
|
password: randUser,
|
||||||
|
board: testBoardData,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
cy.login(randUser, randUser)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Can show card details modal', function() {
|
||||||
|
cy.openLeftSidebar()
|
||||||
|
cy.getNavigationEntry(testBoardData.title)
|
||||||
|
.first().click({ force: true })
|
||||||
|
|
||||||
|
cy.get('.board .stack').eq(0).within(() => {
|
||||||
|
cy.get('.card:contains("Hello world")').should('be.visible').click()
|
||||||
|
})
|
||||||
|
|
||||||
|
cy.get('.modal__card').should('be.visible')
|
||||||
|
cy.get('.app-sidebar-header__maintitle').contains('Hello world')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Can add a card', function() {
|
||||||
|
const newCardTitle = 'Write some cypress tests'
|
||||||
|
|
||||||
|
cy.openLeftSidebar()
|
||||||
|
cy.getNavigationEntry(testBoardData.title)
|
||||||
|
.first().click({ force: true })
|
||||||
|
|
||||||
|
cy.get('.board .stack').eq(0).within(() => {
|
||||||
|
cy.get('.card:contains("Hello world")').should('be.visible')
|
||||||
|
|
||||||
|
cy.get('.button-vue[aria-label*="Add card"]')
|
||||||
|
.first().click()
|
||||||
|
|
||||||
|
cy.get('.stack__card-add form input#new-stack-input-main')
|
||||||
|
.type(newCardTitle)
|
||||||
|
cy.get('.stack__card-add form input[type=submit]')
|
||||||
|
.first().click()
|
||||||
|
cy.get(`.card:contains("${newCardTitle}")`).should('be.visible')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
31
cypress/e2e/deckDashboard.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { randHash } from '../utils'
|
||||||
|
const randUser = randHash()
|
||||||
|
|
||||||
|
describe('Deck dashboard', function() {
|
||||||
|
const password = 'pass123'
|
||||||
|
|
||||||
|
before(function() {
|
||||||
|
cy.nextcloudCreateUser(randUser, password)
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
cy.login(randUser, password)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Can show the right title on the dashboard', function() {
|
||||||
|
cy.get('.board-title h2')
|
||||||
|
.should('have.length', 1).first()
|
||||||
|
.should('have.text', 'Upcoming cards')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Can see the default "Personal Board" created for user by default', function() {
|
||||||
|
const defaultBoard = 'Personal'
|
||||||
|
|
||||||
|
cy.openLeftSidebar()
|
||||||
|
cy.get('.app-navigation-entry-wrapper[icon=icon-deck]')
|
||||||
|
.find('ul.app-navigation-entry__children .app-navigation-entry:contains(' + defaultBoard + ')')
|
||||||
|
.first()
|
||||||
|
.contains(defaultBoard)
|
||||||
|
.should('be.visible')
|
||||||
|
})
|
||||||
|
})
|
||||||
30
cypress/e2e/stackFeatures.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { randHash } from '../utils'
|
||||||
|
const randUser = randHash()
|
||||||
|
|
||||||
|
describe('Stack', function() {
|
||||||
|
const board = 'TestBoard'
|
||||||
|
const password = 'pass123'
|
||||||
|
const stack = 'List 1'
|
||||||
|
|
||||||
|
before(function() {
|
||||||
|
cy.nextcloudCreateUser(randUser, password)
|
||||||
|
cy.deckCreateBoard({ user: randUser, password }, board)
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
cy.logout()
|
||||||
|
cy.login(randUser, password)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Can create a stack', function() {
|
||||||
|
cy.openLeftSidebar()
|
||||||
|
cy.getNavigationEntry(board)
|
||||||
|
.click({ force: true })
|
||||||
|
|
||||||
|
cy.get('#stack-add button').first().click()
|
||||||
|
cy.get('#stack-add form input#new-stack-input-main').type(stack)
|
||||||
|
cy.get('#stack-add form input[type=submit]').first().click()
|
||||||
|
|
||||||
|
cy.get('.board .stack').eq(0).contains(stack).should('be.visible')
|
||||||
|
})
|
||||||
|
})
|
||||||
5
cypress/fixtures/example.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"name": "Using fixtures to represent data",
|
||||||
|
"email": "hello@cypress.io",
|
||||||
|
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||||
|
}
|
||||||
22
cypress/plugins/index.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/// <reference types="cypress" />
|
||||||
|
// ***********************************************************
|
||||||
|
// This example plugins/index.js can be used to load plugins
|
||||||
|
//
|
||||||
|
// You can change the location of this file or turn off loading
|
||||||
|
// the plugins file with the 'pluginsFile' configuration option.
|
||||||
|
//
|
||||||
|
// You can read more here:
|
||||||
|
// https://on.cypress.io/plugins-guide
|
||||||
|
// ***********************************************************
|
||||||
|
|
||||||
|
// This function is called when a project is opened or re-opened (e.g. due to
|
||||||
|
// the project's config changing)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Cypress.PluginConfig}
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
module.exports = (on, config) => {
|
||||||
|
// `on` is used to hook into various events Cypress emits
|
||||||
|
// `config` is the resolved Cypress config
|
||||||
|
}
|
||||||
159
cypress/support/commands.js
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>
|
||||||
|
*
|
||||||
|
* @author John Molakvoæ <skjnldsv@protonmail.com>
|
||||||
|
*
|
||||||
|
* @license GNU AGPL version 3 or any later version
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
const url = Cypress.config('baseUrl').replace(/\/index.php\/?$/g, '')
|
||||||
|
Cypress.env('baseUrl', url)
|
||||||
|
|
||||||
|
Cypress.Commands.add('login', (user, password, route = '/apps/deck/') => {
|
||||||
|
const session = `${user}-${Date.now()}`
|
||||||
|
cy.session(session, function() {
|
||||||
|
cy.visit(route)
|
||||||
|
cy.get('input[name=user]').type(user)
|
||||||
|
cy.get('input[name=password]').type(password)
|
||||||
|
cy.get('form[name=login] [type=submit]').click()
|
||||||
|
cy.url().should('include', route)
|
||||||
|
})
|
||||||
|
cy.visit(route)
|
||||||
|
})
|
||||||
|
|
||||||
|
Cypress.Commands.add('logout', (route = '/') => {
|
||||||
|
cy.session('_guest', function() {})
|
||||||
|
})
|
||||||
|
|
||||||
|
Cypress.Commands.add('nextcloudCreateUser', (user, password) => {
|
||||||
|
cy.clearCookies()
|
||||||
|
cy.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: `${Cypress.env('baseUrl')}/ocs/v1.php/cloud/users?format=json`,
|
||||||
|
form: true,
|
||||||
|
body: {
|
||||||
|
userid: user,
|
||||||
|
password,
|
||||||
|
},
|
||||||
|
auth: { user: 'admin', pass: 'admin' },
|
||||||
|
headers: {
|
||||||
|
'OCS-ApiRequest': 'true',
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
},
|
||||||
|
}).then((response) => {
|
||||||
|
cy.log(`Created user ${user}`, response.status)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Cypress.Commands.add('nextcloudUpdateUser', (user, password, key, value) => {
|
||||||
|
cy.request({
|
||||||
|
method: 'PUT',
|
||||||
|
url: `${Cypress.env('baseUrl')}/ocs/v2.php/cloud/users/${user}`,
|
||||||
|
form: true,
|
||||||
|
body: { key, value },
|
||||||
|
auth: { user, pass: password },
|
||||||
|
headers: {
|
||||||
|
'OCS-ApiRequest': 'true',
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
},
|
||||||
|
}).then((response) => {
|
||||||
|
cy.log(`Updated user ${user} ${key} to ${value}`, response.status)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Cypress.Commands.add('openLeftSidebar', () => {
|
||||||
|
cy.get('.app-navigation button.app-navigation-toggle').click()
|
||||||
|
})
|
||||||
|
|
||||||
|
Cypress.Commands.add('deckCreateBoard', ({ user, password }, title) => {
|
||||||
|
cy.login(user, password)
|
||||||
|
|
||||||
|
cy.get('.app-navigation button.app-navigation-toggle').click()
|
||||||
|
cy.get('#app-navigation-vue .app-navigation__list .app-navigation-entry')
|
||||||
|
.eq(3)
|
||||||
|
.find('a')
|
||||||
|
.first()
|
||||||
|
.click({ force: true })
|
||||||
|
|
||||||
|
cy.get('.board-create form input[type=text]').type(title, { force: true })
|
||||||
|
|
||||||
|
cy.get('.board-create form input[type=submit]')
|
||||||
|
.first()
|
||||||
|
.click({ force: true })
|
||||||
|
})
|
||||||
|
|
||||||
|
Cypress.Commands.add('deckCreateList', ({ user, password }, title) => {
|
||||||
|
cy.login(user, password)
|
||||||
|
|
||||||
|
cy.get('.app-navigation button.app-navigation-toggle').click()
|
||||||
|
cy.get('#app-navigation-vue .app-navigation__list .app-navigation-entry')
|
||||||
|
.eq(3)
|
||||||
|
.find('a.app-navigation-entry-link')
|
||||||
|
.first()
|
||||||
|
.click({ force: true })
|
||||||
|
|
||||||
|
cy.get('#stack-add button').first().click()
|
||||||
|
cy.get('#stack-add form input#new-stack-input-main').type(title)
|
||||||
|
cy.get('#stack-add form input[type=submit]').first().click()
|
||||||
|
})
|
||||||
|
|
||||||
|
Cypress.Commands.add('createExampleBoard', ({ user, password, board }) => {
|
||||||
|
cy.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: `${Cypress.env('baseUrl')}/index.php/apps/deck/api/v1.0/boards`,
|
||||||
|
auth: {
|
||||||
|
user,
|
||||||
|
password,
|
||||||
|
},
|
||||||
|
body: { title: board.title, color: board.color ?? 'ff0000' },
|
||||||
|
}).then((boardResponse) => {
|
||||||
|
expect(boardResponse.status).to.eq(200)
|
||||||
|
const boardData = boardResponse.body
|
||||||
|
for (const stackIndex in board.stacks) {
|
||||||
|
const stack = board.stacks[stackIndex]
|
||||||
|
cy.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: `${Cypress.env('baseUrl')}/index.php/apps/deck/api/v1.0/boards/${boardData.id}/stacks`,
|
||||||
|
auth: {
|
||||||
|
user,
|
||||||
|
password,
|
||||||
|
},
|
||||||
|
body: { title: stack.title, order: 0 },
|
||||||
|
}).then((stackResponse) => {
|
||||||
|
const stackData = stackResponse.body
|
||||||
|
for (const cardIndex in stack.cards) {
|
||||||
|
const card = stack.cards[cardIndex]
|
||||||
|
cy.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: `${Cypress.env('baseUrl')}/index.php/apps/deck/api/v1.0/boards/${boardData.id}/stacks/${stackData.id}/cards`,
|
||||||
|
auth: {
|
||||||
|
user,
|
||||||
|
password,
|
||||||
|
},
|
||||||
|
body: { title: card.title },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Cypress.Commands.add('getNavigationEntry', (boardTitle) => {
|
||||||
|
return cy.get('.app-navigation-entry-wrapper[icon=icon-deck]')
|
||||||
|
.find('ul.app-navigation-entry__children .app-navigation-entry:contains(' + boardTitle + ')')
|
||||||
|
.find('a.app-navigation-entry-link')
|
||||||
|
})
|
||||||
20
cypress/support/e2e.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// ***********************************************************
|
||||||
|
// This example support/index.js is processed and
|
||||||
|
// loaded automatically before your test files.
|
||||||
|
//
|
||||||
|
// This is a great place to put global configuration and
|
||||||
|
// behavior that modifies Cypress.
|
||||||
|
//
|
||||||
|
// You can change the location of this file or turn off
|
||||||
|
// automatically serving support files with the
|
||||||
|
// 'supportFile' configuration option.
|
||||||
|
//
|
||||||
|
// You can read more here:
|
||||||
|
// https://on.cypress.io/configuration
|
||||||
|
// ***********************************************************
|
||||||
|
|
||||||
|
// Import commands.js using ES2015 syntax:
|
||||||
|
import './commands'
|
||||||
|
|
||||||
|
// Alternatively you can use CommonJS syntax:
|
||||||
|
// require('./commands')
|
||||||
1
cypress/utils/index.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export const randHash = () => Math.random().toString(36).replace(/[^a-z]+/g, '').slice(0, 10)
|
||||||
@@ -90,7 +90,7 @@ Steps:
|
|||||||
* Create the configuration file
|
* Create the configuration file
|
||||||
* Execute the import informing the import file path, data file and source as `Trello JSON`
|
* Execute the import informing the import file path, data file and source as `Trello JSON`
|
||||||
|
|
||||||
Create the configuration file respecting the [JSON Schema](https://github.com/nextcloud/deck/blob/master/lib/Service/fixtures/config-trelloJson-schema.json) for import `Trello JSON`
|
Create the configuration file respecting the [JSON Schema](https://github.com/nextcloud/deck/blob/master/lib/Service/Importer/fixtures/config-trelloJson-schema.json) for import `Trello JSON`
|
||||||
|
|
||||||
Example configuration file:
|
Example configuration file:
|
||||||
```json
|
```json
|
||||||
@@ -120,7 +120,7 @@ https://api.trello.com/1/members/me/boards?key={yourKey}&token={yourToken}&field
|
|||||||
This ID you will use in the configuration file in the `board` property
|
This ID you will use in the configuration file in the `board` property
|
||||||
* Create the configuration file
|
* Create the configuration file
|
||||||
|
|
||||||
Create the configuration file respecting the [JSON Schema](https://github.com/nextcloud/deck/blob/master/lib/Service/fixtures/config-trelloApi-schema.json) for import `Trello JSON`
|
Create the configuration file respecting the [JSON Schema](https://github.com/nextcloud/deck/blob/master/lib/Service/Importer/fixtures/config-trelloApi-schema.json) for import `Trello JSON`
|
||||||
|
|
||||||
Example configuration file:
|
Example configuration file:
|
||||||
```json
|
```json
|
||||||
|
|||||||
4
img/activity-dark.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="32" width="32" version="1.0" viewbox="0 0 32 32">
|
||||||
|
<path d="m16 1-10 18h11l-1 12 10-18h-11z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 205 B |
4
img/activity.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="32" width="32" version="1.0" viewBox="0 0 32 32">
|
||||||
|
<path d="m16 1-10 18h11l-1 12 10-18h-11z" fill="#FFF"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 217 B |
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><g transform="translate(0 -1036.362)" fill="#fff"><path d="M1.93 1041.296c-.185 0-.336.138-.336.31v9.842c0 .172.15.313.336.313h12.517c.185 0 .333-.14.333-.313v-9.842c0-.172-.148-.31-.333-.31H1.93zm4.124 1.507h4.223c.39 0 .705.314.705.704v.43c0 .39-.315.705-.705.705H6.054a.703.703 0 0 1-.705-.705v-.43c0-.39.314-.704.705-.704z"/><rect width="15.742" height="2.296" x=".136" y="1037.543" ry="0"/></g></svg>
|
|
||||||
|
Before Width: | Height: | Size: 488 B |
1
img/circles-dark.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 58 58" width="512" height="512"><g fill="#000"><path d="M54.319 37.839C54.762 35.918 55 33.96 55 32c0-9.095-4.631-17.377-12.389-22.153a1 1 0 1 0-1.049 1.703C48.724 15.96 53 23.604 53 32c0 1.726-.2 3.451-.573 5.147A6.992 6.992 0 0 0 51 37c-3.86 0-7 3.141-7 7s3.14 7 7 7 7-3.141 7-7a7.006 7.006 0 0 0-3.681-6.161zM38.171 54.182A23.867 23.867 0 0 1 29 56a24.047 24.047 0 0 1-17.017-7.092A6.974 6.974 0 0 0 14 44c0-3.859-3.14-7-7-7s-7 3.141-7 7 3.14 7 7 7a6.952 6.952 0 0 0 3.381-.875C15.26 55.136 21.994 58 29 58c3.435 0 6.778-.663 9.936-1.971.51-.211.753-.796.542-1.307a1.001 1.001 0 0 0-1.307-.54zM4 31.213a1 1 0 0 0 1.068-.927c.712-10.089 7.586-18.52 17.22-21.314C23.142 11.874 25.825 14 29 14c3.86 0 7-3.141 7-7s-3.14-7-7-7c-3.851 0-6.985 3.127-6.999 6.975C11.42 9.922 3.851 19.12 3.073 30.146A.999.999 0 0 0 4 31.213z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 885 B |
@@ -1 +1 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 58 58" width="512" height="512"><g fill="#000"><path d="M54.319 37.839C54.762 35.918 55 33.96 55 32c0-9.095-4.631-17.377-12.389-22.153a1 1 0 1 0-1.049 1.703C48.724 15.96 53 23.604 53 32c0 1.726-.2 3.451-.573 5.147A6.992 6.992 0 0 0 51 37c-3.86 0-7 3.141-7 7s3.14 7 7 7 7-3.141 7-7a7.006 7.006 0 0 0-3.681-6.161zM38.171 54.182A23.867 23.867 0 0 1 29 56a24.047 24.047 0 0 1-17.017-7.092A6.974 6.974 0 0 0 14 44c0-3.859-3.14-7-7-7s-7 3.141-7 7 3.14 7 7 7a6.952 6.952 0 0 0 3.381-.875C15.26 55.136 21.994 58 29 58c3.435 0 6.778-.663 9.936-1.971.51-.211.753-.796.542-1.307a1.001 1.001 0 0 0-1.307-.54zM4 31.213a1 1 0 0 0 1.068-.927c.712-10.089 7.586-18.52 17.22-21.314C23.142 11.874 25.825 14 29 14c3.86 0 7-3.141 7-7s-3.14-7-7-7c-3.851 0-6.985 3.127-6.999 6.975C11.42 9.922 3.851 19.12 3.073 30.146A.999.999 0 0 0 4 31.213z"/></g></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 58 58" width="512" height="512"><g fill="#fff"><path d="M54.319 37.839C54.762 35.918 55 33.96 55 32c0-9.095-4.631-17.377-12.389-22.153a1 1 0 1 0-1.049 1.703C48.724 15.96 53 23.604 53 32c0 1.726-.2 3.451-.573 5.147A6.992 6.992 0 0 0 51 37c-3.86 0-7 3.141-7 7s3.14 7 7 7 7-3.141 7-7a7.006 7.006 0 0 0-3.681-6.161zM38.171 54.182A23.867 23.867 0 0 1 29 56a24.047 24.047 0 0 1-17.017-7.092A6.974 6.974 0 0 0 14 44c0-3.859-3.14-7-7-7s-7 3.141-7 7 3.14 7 7 7a6.952 6.952 0 0 0 3.381-.875C15.26 55.136 21.994 58 29 58c3.435 0 6.778-.663 9.936-1.971.51-.211.753-.796.542-1.307a1.001 1.001 0 0 0-1.307-.54zM4 31.213a1 1 0 0 0 1.068-.927c.712-10.089 7.586-18.52 17.22-21.314C23.142 11.874 25.825 14 29 14c3.86 0 7-3.141 7-7s-3.14-7-7-7c-3.851 0-6.985 3.127-6.999 6.975C11.42 9.922 3.851 19.12 3.073 30.146A.999.999 0 0 0 4 31.213z"/></g></svg>
|
||||||
|
Before Width: | Height: | Size: 885 B After Width: | Height: | Size: 885 B |
@@ -1 +0,0 @@
|
|||||||
<svg width="16" height="16" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M11.8 13.8H2.2V4.2h9.6m1.2 0c0-.67-.53-1.2-1.2-1.2H2.2C1.53 3 1 3.53 1 4.2v9.6c0 .67.53 1.2 1.2 1.2h9.6c.67 0 1.2-.53 1.2-1.2"/><path d="m4.2 1c-0.67 0-1.2 0.54-1.2 1.2h10.8v10.8c0.67 0 1.2-0.53 1.2-1.2v-9.6c0-0.67-0.53-1.2-1.2-1.2z"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 327 B |
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16"><path d="M15 15s-.4-7.8-7-10V1L1 8l7 7v-4c5.1 0 7 4 7 4z"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 128 B |
@@ -183,10 +183,8 @@ OC.L10N.register(
|
|||||||
"Failed to transfer the board to {user}" : "Неуспешно прехвърляне на таблото на {user}",
|
"Failed to transfer the board to {user}" : "Неуспешно прехвърляне на таблото на {user}",
|
||||||
"Add a new list" : "Добавяне на нов списък",
|
"Add a new list" : "Добавяне на нов списък",
|
||||||
"Archive all cards" : "Архивира всички карти",
|
"Archive all cards" : "Архивира всички карти",
|
||||||
"Unarchive all cards" : "Разархивиране на всички карти",
|
|
||||||
"Delete list" : "Изтрива списък",
|
"Delete list" : "Изтрива списък",
|
||||||
"Archive all cards in this list" : "Архивира всички карти в този списък",
|
"Archive all cards in this list" : "Архивира всички карти в този списък",
|
||||||
"Unarchive all cards in this list" : "Разархивиране всички карти в този списък",
|
|
||||||
"Add a new card" : "Добави нова карта",
|
"Add a new card" : "Добави нова карта",
|
||||||
"Card name" : "Име на карта",
|
"Card name" : "Име на карта",
|
||||||
"List deleted" : "Списъкът е изтрит",
|
"List deleted" : "Списъкът е изтрит",
|
||||||
@@ -262,7 +260,6 @@ OC.L10N.register(
|
|||||||
"Shared with you" : "Споделени с вас",
|
"Shared with you" : "Споделени с вас",
|
||||||
"Deck settings" : "Настройки на платформата",
|
"Deck settings" : "Настройки на платформата",
|
||||||
"Use bigger card view" : "Използва по-голям изглед на картата",
|
"Use bigger card view" : "Използва по-голям изглед на картата",
|
||||||
"Show card ID badge" : "Показване на обозначение за самоличност на картата",
|
|
||||||
"Show boards in calendar/tasks" : "Показване на таблата в календар / задачи",
|
"Show boards in calendar/tasks" : "Показване на таблата в календар / задачи",
|
||||||
"Limit deck usage of groups" : "Ограничава използването на набора от групи",
|
"Limit deck usage of groups" : "Ограничава използването на набора от групи",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Ограничаването на приложението Deck/набор/ ще блокира потребителите, които не са част от тези групи, да създават свои собствени табла. Потребителите все още ще могат да работят на таблата, които са споделени с тях.",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Ограничаването на приложението Deck/набор/ ще блокира потребителите, които не са част от тези групи, да създават свои собствени табла. Потребителите все още ще могат да работят на таблата, които са споделени с тях.",
|
||||||
|
|||||||
@@ -181,10 +181,8 @@
|
|||||||
"Failed to transfer the board to {user}" : "Неуспешно прехвърляне на таблото на {user}",
|
"Failed to transfer the board to {user}" : "Неуспешно прехвърляне на таблото на {user}",
|
||||||
"Add a new list" : "Добавяне на нов списък",
|
"Add a new list" : "Добавяне на нов списък",
|
||||||
"Archive all cards" : "Архивира всички карти",
|
"Archive all cards" : "Архивира всички карти",
|
||||||
"Unarchive all cards" : "Разархивиране на всички карти",
|
|
||||||
"Delete list" : "Изтрива списък",
|
"Delete list" : "Изтрива списък",
|
||||||
"Archive all cards in this list" : "Архивира всички карти в този списък",
|
"Archive all cards in this list" : "Архивира всички карти в този списък",
|
||||||
"Unarchive all cards in this list" : "Разархивиране всички карти в този списък",
|
|
||||||
"Add a new card" : "Добави нова карта",
|
"Add a new card" : "Добави нова карта",
|
||||||
"Card name" : "Име на карта",
|
"Card name" : "Име на карта",
|
||||||
"List deleted" : "Списъкът е изтрит",
|
"List deleted" : "Списъкът е изтрит",
|
||||||
@@ -260,7 +258,6 @@
|
|||||||
"Shared with you" : "Споделени с вас",
|
"Shared with you" : "Споделени с вас",
|
||||||
"Deck settings" : "Настройки на платформата",
|
"Deck settings" : "Настройки на платформата",
|
||||||
"Use bigger card view" : "Използва по-голям изглед на картата",
|
"Use bigger card view" : "Използва по-голям изглед на картата",
|
||||||
"Show card ID badge" : "Показване на обозначение за самоличност на картата",
|
|
||||||
"Show boards in calendar/tasks" : "Показване на таблата в календар / задачи",
|
"Show boards in calendar/tasks" : "Показване на таблата в календар / задачи",
|
||||||
"Limit deck usage of groups" : "Ограничава използването на набора от групи",
|
"Limit deck usage of groups" : "Ограничава използването на набора от групи",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Ограничаването на приложението Deck/набор/ ще блокира потребителите, които не са част от тези групи, да създават свои собствени табла. Потребителите все още ще могат да работят на таблата, които са споделени с тях.",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Ограничаването на приложението Deck/набор/ ще блокира потребителите, които не са част от тези групи, да създават свои собствени табла. Потребителите все още ще могат да работят на таблата, които са споделени с тях.",
|
||||||
|
|||||||
@@ -183,10 +183,8 @@ OC.L10N.register(
|
|||||||
"Failed to transfer the board to {user}" : "Nepodařilo se předat vlastnictví tabule uživateli {user}",
|
"Failed to transfer the board to {user}" : "Nepodařilo se předat vlastnictví tabule uživateli {user}",
|
||||||
"Add a new list" : "Přidat nový sloupec",
|
"Add a new list" : "Přidat nový sloupec",
|
||||||
"Archive all cards" : "Archivovat všechny karty",
|
"Archive all cards" : "Archivovat všechny karty",
|
||||||
"Unarchive all cards" : "Zrušit archivaci všech karet",
|
|
||||||
"Delete list" : "Smazat seznam",
|
"Delete list" : "Smazat seznam",
|
||||||
"Archive all cards in this list" : "Archivovat všechny karty v tomto seznamu",
|
"Archive all cards in this list" : "Archivovat všechny karty v tomto seznamu",
|
||||||
"Unarchive all cards in this list" : "Zrušit archivaci všech karet v tomto seznamu",
|
|
||||||
"Add a new card" : "Přidat novou kartu",
|
"Add a new card" : "Přidat novou kartu",
|
||||||
"Card name" : "Název karty",
|
"Card name" : "Název karty",
|
||||||
"List deleted" : "Seznam smazán",
|
"List deleted" : "Seznam smazán",
|
||||||
@@ -262,7 +260,6 @@ OC.L10N.register(
|
|||||||
"Shared with you" : "Sdíleno s vámi",
|
"Shared with you" : "Sdíleno s vámi",
|
||||||
"Deck settings" : "Nastavení pro Deck",
|
"Deck settings" : "Nastavení pro Deck",
|
||||||
"Use bigger card view" : "Použít větší zobrazení karet",
|
"Use bigger card view" : "Použít větší zobrazení karet",
|
||||||
"Show card ID badge" : "Zobrazit odznáček s identifikátorem karty",
|
|
||||||
"Show boards in calendar/tasks" : "Zobrazit tabule v kalendáři/úkolech",
|
"Show boards in calendar/tasks" : "Zobrazit tabule v kalendáři/úkolech",
|
||||||
"Limit deck usage of groups" : "Omezit využití deck na skupiny",
|
"Limit deck usage of groups" : "Omezit využití deck na skupiny",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Omezení nastavené pro Deck brání uživatelům, kteří nejsou součástí těchto skupin, ve vytváření vlastních tabulí. Nicméně i tak ale pořád budou moci pracovat na tabulích, které jsou jim nasdíleny.",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Omezení nastavené pro Deck brání uživatelům, kteří nejsou součástí těchto skupin, ve vytváření vlastních tabulí. Nicméně i tak ale pořád budou moci pracovat na tabulích, které jsou jim nasdíleny.",
|
||||||
|
|||||||
@@ -181,10 +181,8 @@
|
|||||||
"Failed to transfer the board to {user}" : "Nepodařilo se předat vlastnictví tabule uživateli {user}",
|
"Failed to transfer the board to {user}" : "Nepodařilo se předat vlastnictví tabule uživateli {user}",
|
||||||
"Add a new list" : "Přidat nový sloupec",
|
"Add a new list" : "Přidat nový sloupec",
|
||||||
"Archive all cards" : "Archivovat všechny karty",
|
"Archive all cards" : "Archivovat všechny karty",
|
||||||
"Unarchive all cards" : "Zrušit archivaci všech karet",
|
|
||||||
"Delete list" : "Smazat seznam",
|
"Delete list" : "Smazat seznam",
|
||||||
"Archive all cards in this list" : "Archivovat všechny karty v tomto seznamu",
|
"Archive all cards in this list" : "Archivovat všechny karty v tomto seznamu",
|
||||||
"Unarchive all cards in this list" : "Zrušit archivaci všech karet v tomto seznamu",
|
|
||||||
"Add a new card" : "Přidat novou kartu",
|
"Add a new card" : "Přidat novou kartu",
|
||||||
"Card name" : "Název karty",
|
"Card name" : "Název karty",
|
||||||
"List deleted" : "Seznam smazán",
|
"List deleted" : "Seznam smazán",
|
||||||
@@ -260,7 +258,6 @@
|
|||||||
"Shared with you" : "Sdíleno s vámi",
|
"Shared with you" : "Sdíleno s vámi",
|
||||||
"Deck settings" : "Nastavení pro Deck",
|
"Deck settings" : "Nastavení pro Deck",
|
||||||
"Use bigger card view" : "Použít větší zobrazení karet",
|
"Use bigger card view" : "Použít větší zobrazení karet",
|
||||||
"Show card ID badge" : "Zobrazit odznáček s identifikátorem karty",
|
|
||||||
"Show boards in calendar/tasks" : "Zobrazit tabule v kalendáři/úkolech",
|
"Show boards in calendar/tasks" : "Zobrazit tabule v kalendáři/úkolech",
|
||||||
"Limit deck usage of groups" : "Omezit využití deck na skupiny",
|
"Limit deck usage of groups" : "Omezit využití deck na skupiny",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Omezení nastavené pro Deck brání uživatelům, kteří nejsou součástí těchto skupin, ve vytváření vlastních tabulí. Nicméně i tak ale pořád budou moci pracovat na tabulích, které jsou jim nasdíleny.",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Omezení nastavené pro Deck brání uživatelům, kteří nejsou součástí těchto skupin, ve vytváření vlastních tabulí. Nicméně i tak ale pořád budou moci pracovat na tabulích, které jsou jim nasdíleny.",
|
||||||
|
|||||||
@@ -183,10 +183,8 @@ OC.L10N.register(
|
|||||||
"Failed to transfer the board to {user}" : "Das Board konnte nicht an {user} übertragen werden",
|
"Failed to transfer the board to {user}" : "Das Board konnte nicht an {user} übertragen werden",
|
||||||
"Add a new list" : "Eine neue Liste hinzufügen",
|
"Add a new list" : "Eine neue Liste hinzufügen",
|
||||||
"Archive all cards" : "Alle Karten archivieren",
|
"Archive all cards" : "Alle Karten archivieren",
|
||||||
"Unarchive all cards" : "Alle Karten dearchivieren",
|
|
||||||
"Delete list" : "Liste löschen",
|
"Delete list" : "Liste löschen",
|
||||||
"Archive all cards in this list" : "Alle Karten in dieser Liste archivieren",
|
"Archive all cards in this list" : "Alle Karten in dieser Liste archivieren",
|
||||||
"Unarchive all cards in this list" : "Alle Karten dieser Liste dearchivieren",
|
|
||||||
"Add a new card" : "Neue Karte hinzufügen",
|
"Add a new card" : "Neue Karte hinzufügen",
|
||||||
"Card name" : "Kartenname",
|
"Card name" : "Kartenname",
|
||||||
"List deleted" : "Liste gelöscht",
|
"List deleted" : "Liste gelöscht",
|
||||||
@@ -215,10 +213,10 @@ OC.L10N.register(
|
|||||||
"The title cannot be empty." : "Der Titel darf nicht leer sein.",
|
"The title cannot be empty." : "Der Titel darf nicht leer sein.",
|
||||||
"No comments yet. Begin the discussion!" : "Bislang keine Kommentare. Beginne die Diskussion!",
|
"No comments yet. Begin the discussion!" : "Bislang keine Kommentare. Beginne die Diskussion!",
|
||||||
"Failed to load comments" : "Das Laden der Kommentare ist fehlgeschlagen",
|
"Failed to load comments" : "Das Laden der Kommentare ist fehlgeschlagen",
|
||||||
"Assign a tag to this card…" : "Dieser Karte ein Schlagwort zuweisen …",
|
"Assign a tag to this card…" : "Dieser Karte ein Schlagwort zuweisen…",
|
||||||
"Assign to users" : "Benutzern zuweisen",
|
"Assign to users" : "Benutzern zuweisen",
|
||||||
"Assign to users/groups/circles" : "An Benutzer, Gruppen oder Kreise zuweisen",
|
"Assign to users/groups/circles" : "An Benutzer, Gruppen oder Kreise zuweisen",
|
||||||
"Assign a user to this card…" : "Diese Karte einem Benutzer zuweisen …",
|
"Assign a user to this card…" : "Diese Karte einem Benutzer zuweisen…",
|
||||||
"Due date" : "Fälligkeitsdatum",
|
"Due date" : "Fälligkeitsdatum",
|
||||||
"Set a due date" : "Ein Ablaufdatum setzen",
|
"Set a due date" : "Ein Ablaufdatum setzen",
|
||||||
"Remove due date" : "Fälligkeitsdatum löschen",
|
"Remove due date" : "Fälligkeitsdatum löschen",
|
||||||
@@ -237,7 +235,7 @@ OC.L10N.register(
|
|||||||
"Description" : "Beschreibung",
|
"Description" : "Beschreibung",
|
||||||
"(Unsaved)" : "(nicht gespeichert)",
|
"(Unsaved)" : "(nicht gespeichert)",
|
||||||
"(Saving…)" : "(Speichere…)",
|
"(Saving…)" : "(Speichere…)",
|
||||||
"Formatting help" : "Hilfe zur Formatierung",
|
"Formatting help" : "Formatierungshilfe",
|
||||||
"Edit description" : "Beschreibung bearbeiten",
|
"Edit description" : "Beschreibung bearbeiten",
|
||||||
"View description" : "Beschreibung anzeigen",
|
"View description" : "Beschreibung anzeigen",
|
||||||
"Add Attachment" : "Anhang anhängen",
|
"Add Attachment" : "Anhang anhängen",
|
||||||
|
|||||||
@@ -181,10 +181,8 @@
|
|||||||
"Failed to transfer the board to {user}" : "Das Board konnte nicht an {user} übertragen werden",
|
"Failed to transfer the board to {user}" : "Das Board konnte nicht an {user} übertragen werden",
|
||||||
"Add a new list" : "Eine neue Liste hinzufügen",
|
"Add a new list" : "Eine neue Liste hinzufügen",
|
||||||
"Archive all cards" : "Alle Karten archivieren",
|
"Archive all cards" : "Alle Karten archivieren",
|
||||||
"Unarchive all cards" : "Alle Karten dearchivieren",
|
|
||||||
"Delete list" : "Liste löschen",
|
"Delete list" : "Liste löschen",
|
||||||
"Archive all cards in this list" : "Alle Karten in dieser Liste archivieren",
|
"Archive all cards in this list" : "Alle Karten in dieser Liste archivieren",
|
||||||
"Unarchive all cards in this list" : "Alle Karten dieser Liste dearchivieren",
|
|
||||||
"Add a new card" : "Neue Karte hinzufügen",
|
"Add a new card" : "Neue Karte hinzufügen",
|
||||||
"Card name" : "Kartenname",
|
"Card name" : "Kartenname",
|
||||||
"List deleted" : "Liste gelöscht",
|
"List deleted" : "Liste gelöscht",
|
||||||
@@ -213,10 +211,10 @@
|
|||||||
"The title cannot be empty." : "Der Titel darf nicht leer sein.",
|
"The title cannot be empty." : "Der Titel darf nicht leer sein.",
|
||||||
"No comments yet. Begin the discussion!" : "Bislang keine Kommentare. Beginne die Diskussion!",
|
"No comments yet. Begin the discussion!" : "Bislang keine Kommentare. Beginne die Diskussion!",
|
||||||
"Failed to load comments" : "Das Laden der Kommentare ist fehlgeschlagen",
|
"Failed to load comments" : "Das Laden der Kommentare ist fehlgeschlagen",
|
||||||
"Assign a tag to this card…" : "Dieser Karte ein Schlagwort zuweisen …",
|
"Assign a tag to this card…" : "Dieser Karte ein Schlagwort zuweisen…",
|
||||||
"Assign to users" : "Benutzern zuweisen",
|
"Assign to users" : "Benutzern zuweisen",
|
||||||
"Assign to users/groups/circles" : "An Benutzer, Gruppen oder Kreise zuweisen",
|
"Assign to users/groups/circles" : "An Benutzer, Gruppen oder Kreise zuweisen",
|
||||||
"Assign a user to this card…" : "Diese Karte einem Benutzer zuweisen …",
|
"Assign a user to this card…" : "Diese Karte einem Benutzer zuweisen…",
|
||||||
"Due date" : "Fälligkeitsdatum",
|
"Due date" : "Fälligkeitsdatum",
|
||||||
"Set a due date" : "Ein Ablaufdatum setzen",
|
"Set a due date" : "Ein Ablaufdatum setzen",
|
||||||
"Remove due date" : "Fälligkeitsdatum löschen",
|
"Remove due date" : "Fälligkeitsdatum löschen",
|
||||||
@@ -235,7 +233,7 @@
|
|||||||
"Description" : "Beschreibung",
|
"Description" : "Beschreibung",
|
||||||
"(Unsaved)" : "(nicht gespeichert)",
|
"(Unsaved)" : "(nicht gespeichert)",
|
||||||
"(Saving…)" : "(Speichere…)",
|
"(Saving…)" : "(Speichere…)",
|
||||||
"Formatting help" : "Hilfe zur Formatierung",
|
"Formatting help" : "Formatierungshilfe",
|
||||||
"Edit description" : "Beschreibung bearbeiten",
|
"Edit description" : "Beschreibung bearbeiten",
|
||||||
"View description" : "Beschreibung anzeigen",
|
"View description" : "Beschreibung anzeigen",
|
||||||
"Add Attachment" : "Anhang anhängen",
|
"Add Attachment" : "Anhang anhängen",
|
||||||
|
|||||||
@@ -183,10 +183,8 @@ OC.L10N.register(
|
|||||||
"Failed to transfer the board to {user}" : "Das Board konnte nicht auf {user} übertragen werden",
|
"Failed to transfer the board to {user}" : "Das Board konnte nicht auf {user} übertragen werden",
|
||||||
"Add a new list" : "Eine neue Liste hinzufügen",
|
"Add a new list" : "Eine neue Liste hinzufügen",
|
||||||
"Archive all cards" : "Alle Karten archivieren",
|
"Archive all cards" : "Alle Karten archivieren",
|
||||||
"Unarchive all cards" : "Alle Karten dearchivieren",
|
|
||||||
"Delete list" : "Liste löschen",
|
"Delete list" : "Liste löschen",
|
||||||
"Archive all cards in this list" : "Alle Karten in dieser Liste archivieren",
|
"Archive all cards in this list" : "Alle Karten in dieser Liste archivieren",
|
||||||
"Unarchive all cards in this list" : "Alle Karten in dieser Liste dearchivieren",
|
|
||||||
"Add a new card" : "Neue Karte hinzufügen",
|
"Add a new card" : "Neue Karte hinzufügen",
|
||||||
"Card name" : "Kartenname",
|
"Card name" : "Kartenname",
|
||||||
"List deleted" : "Liste gelöscht",
|
"List deleted" : "Liste gelöscht",
|
||||||
@@ -262,7 +260,6 @@ OC.L10N.register(
|
|||||||
"Shared with you" : "Mit Ihnen geteilt",
|
"Shared with you" : "Mit Ihnen geteilt",
|
||||||
"Deck settings" : "Deck-Einstellungen",
|
"Deck settings" : "Deck-Einstellungen",
|
||||||
"Use bigger card view" : "Größere Kartenansicht verwenden",
|
"Use bigger card view" : "Größere Kartenansicht verwenden",
|
||||||
"Show card ID badge" : "Abzeichen mit Karten-ID zeigen",
|
|
||||||
"Show boards in calendar/tasks" : "Board in Kalender/Aufgaben anzeigen",
|
"Show boards in calendar/tasks" : "Board in Kalender/Aufgaben anzeigen",
|
||||||
"Limit deck usage of groups" : "Nutzung auf Gruppen einschränken",
|
"Limit deck usage of groups" : "Nutzung auf Gruppen einschränken",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Wenn Sie Deck einschränken, können Benutzer, die nicht zu diesen Gruppen gehören, keine eigenen Boards erstellen. Die Benutzer können weiterhin an Boards arbeiten, die für sie freigegeben wurden.",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Wenn Sie Deck einschränken, können Benutzer, die nicht zu diesen Gruppen gehören, keine eigenen Boards erstellen. Die Benutzer können weiterhin an Boards arbeiten, die für sie freigegeben wurden.",
|
||||||
|
|||||||
@@ -181,10 +181,8 @@
|
|||||||
"Failed to transfer the board to {user}" : "Das Board konnte nicht auf {user} übertragen werden",
|
"Failed to transfer the board to {user}" : "Das Board konnte nicht auf {user} übertragen werden",
|
||||||
"Add a new list" : "Eine neue Liste hinzufügen",
|
"Add a new list" : "Eine neue Liste hinzufügen",
|
||||||
"Archive all cards" : "Alle Karten archivieren",
|
"Archive all cards" : "Alle Karten archivieren",
|
||||||
"Unarchive all cards" : "Alle Karten dearchivieren",
|
|
||||||
"Delete list" : "Liste löschen",
|
"Delete list" : "Liste löschen",
|
||||||
"Archive all cards in this list" : "Alle Karten in dieser Liste archivieren",
|
"Archive all cards in this list" : "Alle Karten in dieser Liste archivieren",
|
||||||
"Unarchive all cards in this list" : "Alle Karten in dieser Liste dearchivieren",
|
|
||||||
"Add a new card" : "Neue Karte hinzufügen",
|
"Add a new card" : "Neue Karte hinzufügen",
|
||||||
"Card name" : "Kartenname",
|
"Card name" : "Kartenname",
|
||||||
"List deleted" : "Liste gelöscht",
|
"List deleted" : "Liste gelöscht",
|
||||||
@@ -260,7 +258,6 @@
|
|||||||
"Shared with you" : "Mit Ihnen geteilt",
|
"Shared with you" : "Mit Ihnen geteilt",
|
||||||
"Deck settings" : "Deck-Einstellungen",
|
"Deck settings" : "Deck-Einstellungen",
|
||||||
"Use bigger card view" : "Größere Kartenansicht verwenden",
|
"Use bigger card view" : "Größere Kartenansicht verwenden",
|
||||||
"Show card ID badge" : "Abzeichen mit Karten-ID zeigen",
|
|
||||||
"Show boards in calendar/tasks" : "Board in Kalender/Aufgaben anzeigen",
|
"Show boards in calendar/tasks" : "Board in Kalender/Aufgaben anzeigen",
|
||||||
"Limit deck usage of groups" : "Nutzung auf Gruppen einschränken",
|
"Limit deck usage of groups" : "Nutzung auf Gruppen einschränken",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Wenn Sie Deck einschränken, können Benutzer, die nicht zu diesen Gruppen gehören, keine eigenen Boards erstellen. Die Benutzer können weiterhin an Boards arbeiten, die für sie freigegeben wurden.",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Wenn Sie Deck einschränken, können Benutzer, die nicht zu diesen Gruppen gehören, keine eigenen Boards erstellen. Die Benutzer können weiterhin an Boards arbeiten, die für sie freigegeben wurden.",
|
||||||
|
|||||||
@@ -183,10 +183,8 @@ OC.L10N.register(
|
|||||||
"Failed to transfer the board to {user}" : "Failed to transfer the board to {user}",
|
"Failed to transfer the board to {user}" : "Failed to transfer the board to {user}",
|
||||||
"Add a new list" : "Añadir una lista nueva",
|
"Add a new list" : "Añadir una lista nueva",
|
||||||
"Archive all cards" : "Archivar todas las tarjetas",
|
"Archive all cards" : "Archivar todas las tarjetas",
|
||||||
"Unarchive all cards" : "Desarchivar todas las tarjetas",
|
|
||||||
"Delete list" : "Eliminar lista",
|
"Delete list" : "Eliminar lista",
|
||||||
"Archive all cards in this list" : "Archivar todas las tarjetas en esta lista",
|
"Archive all cards in this list" : "Archivar todas las tarjetas en esta lista",
|
||||||
"Unarchive all cards in this list" : "Desarchivar todas las tarjetas en esta lista",
|
|
||||||
"Add a new card" : "Añadir una nueva tarjeta",
|
"Add a new card" : "Añadir una nueva tarjeta",
|
||||||
"Card name" : "Nombre de la tarjeta",
|
"Card name" : "Nombre de la tarjeta",
|
||||||
"List deleted" : "Lista borrada",
|
"List deleted" : "Lista borrada",
|
||||||
@@ -262,7 +260,6 @@ OC.L10N.register(
|
|||||||
"Shared with you" : "Compartido contigo",
|
"Shared with you" : "Compartido contigo",
|
||||||
"Deck settings" : "Configuración del tablero",
|
"Deck settings" : "Configuración del tablero",
|
||||||
"Use bigger card view" : "Usar vista de tarjeta mayor",
|
"Use bigger card view" : "Usar vista de tarjeta mayor",
|
||||||
"Show card ID badge" : "Mostrar insignia de la ID de tarjeta",
|
|
||||||
"Show boards in calendar/tasks" : "Mostrar tableros en calendario/tareas",
|
"Show boards in calendar/tasks" : "Mostrar tableros en calendario/tareas",
|
||||||
"Limit deck usage of groups" : "Limitar el uso de Deck a grupos",
|
"Limit deck usage of groups" : "Limitar el uso de Deck a grupos",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Limitar Deck impedirá que usuarios que no formen parte de esos grupos creen sus propios tableros. Los usuarios todavía podrán trabajar en tableros que hayan sido compartidos con ellos.",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Limitar Deck impedirá que usuarios que no formen parte de esos grupos creen sus propios tableros. Los usuarios todavía podrán trabajar en tableros que hayan sido compartidos con ellos.",
|
||||||
|
|||||||
@@ -181,10 +181,8 @@
|
|||||||
"Failed to transfer the board to {user}" : "Failed to transfer the board to {user}",
|
"Failed to transfer the board to {user}" : "Failed to transfer the board to {user}",
|
||||||
"Add a new list" : "Añadir una lista nueva",
|
"Add a new list" : "Añadir una lista nueva",
|
||||||
"Archive all cards" : "Archivar todas las tarjetas",
|
"Archive all cards" : "Archivar todas las tarjetas",
|
||||||
"Unarchive all cards" : "Desarchivar todas las tarjetas",
|
|
||||||
"Delete list" : "Eliminar lista",
|
"Delete list" : "Eliminar lista",
|
||||||
"Archive all cards in this list" : "Archivar todas las tarjetas en esta lista",
|
"Archive all cards in this list" : "Archivar todas las tarjetas en esta lista",
|
||||||
"Unarchive all cards in this list" : "Desarchivar todas las tarjetas en esta lista",
|
|
||||||
"Add a new card" : "Añadir una nueva tarjeta",
|
"Add a new card" : "Añadir una nueva tarjeta",
|
||||||
"Card name" : "Nombre de la tarjeta",
|
"Card name" : "Nombre de la tarjeta",
|
||||||
"List deleted" : "Lista borrada",
|
"List deleted" : "Lista borrada",
|
||||||
@@ -260,7 +258,6 @@
|
|||||||
"Shared with you" : "Compartido contigo",
|
"Shared with you" : "Compartido contigo",
|
||||||
"Deck settings" : "Configuración del tablero",
|
"Deck settings" : "Configuración del tablero",
|
||||||
"Use bigger card view" : "Usar vista de tarjeta mayor",
|
"Use bigger card view" : "Usar vista de tarjeta mayor",
|
||||||
"Show card ID badge" : "Mostrar insignia de la ID de tarjeta",
|
|
||||||
"Show boards in calendar/tasks" : "Mostrar tableros en calendario/tareas",
|
"Show boards in calendar/tasks" : "Mostrar tableros en calendario/tareas",
|
||||||
"Limit deck usage of groups" : "Limitar el uso de Deck a grupos",
|
"Limit deck usage of groups" : "Limitar el uso de Deck a grupos",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Limitar Deck impedirá que usuarios que no formen parte de esos grupos creen sus propios tableros. Los usuarios todavía podrán trabajar en tableros que hayan sido compartidos con ellos.",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Limitar Deck impedirá que usuarios que no formen parte de esos grupos creen sus propios tableros. Los usuarios todavía podrán trabajar en tableros que hayan sido compartidos con ellos.",
|
||||||
|
|||||||
@@ -183,10 +183,8 @@ OC.L10N.register(
|
|||||||
"Failed to transfer the board to {user}" : "Échec du transfert du tableau à {user}",
|
"Failed to transfer the board to {user}" : "Échec du transfert du tableau à {user}",
|
||||||
"Add a new list" : "Ajouter une nouvelle liste",
|
"Add a new list" : "Ajouter une nouvelle liste",
|
||||||
"Archive all cards" : "Archiver toutes les cartes",
|
"Archive all cards" : "Archiver toutes les cartes",
|
||||||
"Unarchive all cards" : "Désarchiver toutes les cartes",
|
|
||||||
"Delete list" : "Supprimer la liste",
|
"Delete list" : "Supprimer la liste",
|
||||||
"Archive all cards in this list" : "Archiver toutes les cartes de cette liste",
|
"Archive all cards in this list" : "Archiver toutes les cartes de cette liste",
|
||||||
"Unarchive all cards in this list" : "Désarchiver toutes les cartes de cette liste",
|
|
||||||
"Add a new card" : "Ajouter une nouvelle carte",
|
"Add a new card" : "Ajouter une nouvelle carte",
|
||||||
"Card name" : "Nom de la carte",
|
"Card name" : "Nom de la carte",
|
||||||
"List deleted" : "Liste supprimée",
|
"List deleted" : "Liste supprimée",
|
||||||
@@ -262,7 +260,6 @@ OC.L10N.register(
|
|||||||
"Shared with you" : "Partagés avec vous",
|
"Shared with you" : "Partagés avec vous",
|
||||||
"Deck settings" : "Paramètres de Deck",
|
"Deck settings" : "Paramètres de Deck",
|
||||||
"Use bigger card view" : "Utiliser la vue large des cartes",
|
"Use bigger card view" : "Utiliser la vue large des cartes",
|
||||||
"Show card ID badge" : "Afficher la carte d'identité du badge",
|
|
||||||
"Show boards in calendar/tasks" : "Afficher les tableaux dans les agendas/tâches",
|
"Show boards in calendar/tasks" : "Afficher les tableaux dans les agendas/tâches",
|
||||||
"Limit deck usage of groups" : "Limiter l'utilisation du tableau aux groupes",
|
"Limit deck usage of groups" : "Limiter l'utilisation du tableau aux groupes",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Limiter Deck empêchera les utilisateurs ne faisant pas partie de ces groupes de créer leurs propres tableaux. Ces utilisateurs pourront toujours travailler sur les tableaux qui ont été partagés avec eux.",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Limiter Deck empêchera les utilisateurs ne faisant pas partie de ces groupes de créer leurs propres tableaux. Ces utilisateurs pourront toujours travailler sur les tableaux qui ont été partagés avec eux.",
|
||||||
|
|||||||
@@ -181,10 +181,8 @@
|
|||||||
"Failed to transfer the board to {user}" : "Échec du transfert du tableau à {user}",
|
"Failed to transfer the board to {user}" : "Échec du transfert du tableau à {user}",
|
||||||
"Add a new list" : "Ajouter une nouvelle liste",
|
"Add a new list" : "Ajouter une nouvelle liste",
|
||||||
"Archive all cards" : "Archiver toutes les cartes",
|
"Archive all cards" : "Archiver toutes les cartes",
|
||||||
"Unarchive all cards" : "Désarchiver toutes les cartes",
|
|
||||||
"Delete list" : "Supprimer la liste",
|
"Delete list" : "Supprimer la liste",
|
||||||
"Archive all cards in this list" : "Archiver toutes les cartes de cette liste",
|
"Archive all cards in this list" : "Archiver toutes les cartes de cette liste",
|
||||||
"Unarchive all cards in this list" : "Désarchiver toutes les cartes de cette liste",
|
|
||||||
"Add a new card" : "Ajouter une nouvelle carte",
|
"Add a new card" : "Ajouter une nouvelle carte",
|
||||||
"Card name" : "Nom de la carte",
|
"Card name" : "Nom de la carte",
|
||||||
"List deleted" : "Liste supprimée",
|
"List deleted" : "Liste supprimée",
|
||||||
@@ -260,7 +258,6 @@
|
|||||||
"Shared with you" : "Partagés avec vous",
|
"Shared with you" : "Partagés avec vous",
|
||||||
"Deck settings" : "Paramètres de Deck",
|
"Deck settings" : "Paramètres de Deck",
|
||||||
"Use bigger card view" : "Utiliser la vue large des cartes",
|
"Use bigger card view" : "Utiliser la vue large des cartes",
|
||||||
"Show card ID badge" : "Afficher la carte d'identité du badge",
|
|
||||||
"Show boards in calendar/tasks" : "Afficher les tableaux dans les agendas/tâches",
|
"Show boards in calendar/tasks" : "Afficher les tableaux dans les agendas/tâches",
|
||||||
"Limit deck usage of groups" : "Limiter l'utilisation du tableau aux groupes",
|
"Limit deck usage of groups" : "Limiter l'utilisation du tableau aux groupes",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Limiter Deck empêchera les utilisateurs ne faisant pas partie de ces groupes de créer leurs propres tableaux. Ces utilisateurs pourront toujours travailler sur les tableaux qui ont été partagés avec eux.",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Limiter Deck empêchera les utilisateurs ne faisant pas partie de ces groupes de créer leurs propres tableaux. Ces utilisateurs pourront toujours travailler sur les tableaux qui ont été partagés avec eux.",
|
||||||
|
|||||||
@@ -183,10 +183,8 @@ OC.L10N.register(
|
|||||||
"Failed to transfer the board to {user}" : "A tábla átadása {user} számára sikertelen",
|
"Failed to transfer the board to {user}" : "A tábla átadása {user} számára sikertelen",
|
||||||
"Add a new list" : "Új lista hozzáadása",
|
"Add a new list" : "Új lista hozzáadása",
|
||||||
"Archive all cards" : "Az összes kártya archiválása",
|
"Archive all cards" : "Az összes kártya archiválása",
|
||||||
"Unarchive all cards" : "Az összes kártya archiválásának visszavonása",
|
|
||||||
"Delete list" : "Lista törlése",
|
"Delete list" : "Lista törlése",
|
||||||
"Archive all cards in this list" : "Az összes kártya archiválása ebben a listában",
|
"Archive all cards in this list" : "Az összes kártya archiválása ebben a listában",
|
||||||
"Unarchive all cards in this list" : "Az összes kártya archiválásának visszavonása ebben a listában",
|
|
||||||
"Add a new card" : "Új kártya hozzáadása",
|
"Add a new card" : "Új kártya hozzáadása",
|
||||||
"Card name" : "Kártya neve",
|
"Card name" : "Kártya neve",
|
||||||
"List deleted" : "Lista törölve",
|
"List deleted" : "Lista törölve",
|
||||||
@@ -262,7 +260,6 @@ OC.L10N.register(
|
|||||||
"Shared with you" : "Megosztva Önnel",
|
"Shared with you" : "Megosztva Önnel",
|
||||||
"Deck settings" : "Kártyák beállításai",
|
"Deck settings" : "Kártyák beállításai",
|
||||||
"Use bigger card view" : "Nagyobb kártyanézet használata",
|
"Use bigger card view" : "Nagyobb kártyanézet használata",
|
||||||
"Show card ID badge" : "Kártyaazonosító jelvény megjelenítése",
|
|
||||||
"Show boards in calendar/tasks" : "Táblák megjelenítése a naptárak/teendők között",
|
"Show boards in calendar/tasks" : "Táblák megjelenítése a naptárak/teendők között",
|
||||||
"Limit deck usage of groups" : "A kártyák használatának csoportokra korlátozása",
|
"Limit deck usage of groups" : "A kártyák használatának csoportokra korlátozása",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "A Kártyák korlátozása blokkolja a saját táblák létrehozását azoknál a felhasználóknál, akik nem tagjai a megadott csoportoknak. A felhasználók továbbra is tudnak dolgozni a velük megosztott táblákon.",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "A Kártyák korlátozása blokkolja a saját táblák létrehozását azoknál a felhasználóknál, akik nem tagjai a megadott csoportoknak. A felhasználók továbbra is tudnak dolgozni a velük megosztott táblákon.",
|
||||||
@@ -289,7 +286,6 @@ OC.L10N.register(
|
|||||||
"Search for {searchQuery} in all boards" : "Keresés a(z) {searchQuery} kifejezésre az összes táblában",
|
"Search for {searchQuery} in all boards" : "Keresés a(z) {searchQuery} kifejezésre az összes táblában",
|
||||||
"No results found" : "Nincs találat",
|
"No results found" : "Nincs találat",
|
||||||
"{stack} in {board}" : "{stack} itt: {board}",
|
"{stack} in {board}" : "{stack} itt: {board}",
|
||||||
"Click to expand description" : "Kattintson a leírás kibontásához",
|
|
||||||
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Létrehozva: {created}\n* Utoljára módosítva: {lastMod}\n* {nbAttachments} melléklet\n* {nbComments} megjegyzés",
|
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Létrehozva: {created}\n* Utoljára módosítva: {lastMod}\n* {nbAttachments} melléklet\n* {nbComments} megjegyzés",
|
||||||
"{nbCards} cards" : "{nbCards} kártya",
|
"{nbCards} cards" : "{nbCards} kártya",
|
||||||
"No upcoming cards" : "Nincsenek közelgő kártyák",
|
"No upcoming cards" : "Nincsenek közelgő kártyák",
|
||||||
|
|||||||
@@ -181,10 +181,8 @@
|
|||||||
"Failed to transfer the board to {user}" : "A tábla átadása {user} számára sikertelen",
|
"Failed to transfer the board to {user}" : "A tábla átadása {user} számára sikertelen",
|
||||||
"Add a new list" : "Új lista hozzáadása",
|
"Add a new list" : "Új lista hozzáadása",
|
||||||
"Archive all cards" : "Az összes kártya archiválása",
|
"Archive all cards" : "Az összes kártya archiválása",
|
||||||
"Unarchive all cards" : "Az összes kártya archiválásának visszavonása",
|
|
||||||
"Delete list" : "Lista törlése",
|
"Delete list" : "Lista törlése",
|
||||||
"Archive all cards in this list" : "Az összes kártya archiválása ebben a listában",
|
"Archive all cards in this list" : "Az összes kártya archiválása ebben a listában",
|
||||||
"Unarchive all cards in this list" : "Az összes kártya archiválásának visszavonása ebben a listában",
|
|
||||||
"Add a new card" : "Új kártya hozzáadása",
|
"Add a new card" : "Új kártya hozzáadása",
|
||||||
"Card name" : "Kártya neve",
|
"Card name" : "Kártya neve",
|
||||||
"List deleted" : "Lista törölve",
|
"List deleted" : "Lista törölve",
|
||||||
@@ -260,7 +258,6 @@
|
|||||||
"Shared with you" : "Megosztva Önnel",
|
"Shared with you" : "Megosztva Önnel",
|
||||||
"Deck settings" : "Kártyák beállításai",
|
"Deck settings" : "Kártyák beállításai",
|
||||||
"Use bigger card view" : "Nagyobb kártyanézet használata",
|
"Use bigger card view" : "Nagyobb kártyanézet használata",
|
||||||
"Show card ID badge" : "Kártyaazonosító jelvény megjelenítése",
|
|
||||||
"Show boards in calendar/tasks" : "Táblák megjelenítése a naptárak/teendők között",
|
"Show boards in calendar/tasks" : "Táblák megjelenítése a naptárak/teendők között",
|
||||||
"Limit deck usage of groups" : "A kártyák használatának csoportokra korlátozása",
|
"Limit deck usage of groups" : "A kártyák használatának csoportokra korlátozása",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "A Kártyák korlátozása blokkolja a saját táblák létrehozását azoknál a felhasználóknál, akik nem tagjai a megadott csoportoknak. A felhasználók továbbra is tudnak dolgozni a velük megosztott táblákon.",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "A Kártyák korlátozása blokkolja a saját táblák létrehozását azoknál a felhasználóknál, akik nem tagjai a megadott csoportoknak. A felhasználók továbbra is tudnak dolgozni a velük megosztott táblákon.",
|
||||||
@@ -287,7 +284,6 @@
|
|||||||
"Search for {searchQuery} in all boards" : "Keresés a(z) {searchQuery} kifejezésre az összes táblában",
|
"Search for {searchQuery} in all boards" : "Keresés a(z) {searchQuery} kifejezésre az összes táblában",
|
||||||
"No results found" : "Nincs találat",
|
"No results found" : "Nincs találat",
|
||||||
"{stack} in {board}" : "{stack} itt: {board}",
|
"{stack} in {board}" : "{stack} itt: {board}",
|
||||||
"Click to expand description" : "Kattintson a leírás kibontásához",
|
|
||||||
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Létrehozva: {created}\n* Utoljára módosítva: {lastMod}\n* {nbAttachments} melléklet\n* {nbComments} megjegyzés",
|
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Létrehozva: {created}\n* Utoljára módosítva: {lastMod}\n* {nbAttachments} melléklet\n* {nbComments} megjegyzés",
|
||||||
"{nbCards} cards" : "{nbCards} kártya",
|
"{nbCards} cards" : "{nbCards} kártya",
|
||||||
"No upcoming cards" : "Nincsenek közelgő kártyák",
|
"No upcoming cards" : "Nincsenek közelgő kártyák",
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ OC.L10N.register(
|
|||||||
"Personal" : "Asmeniniai",
|
"Personal" : "Asmeniniai",
|
||||||
"The card \"%s\" on \"%s\" has been assigned to you by %s." : "Kortelę \"%s\" ties \"%s\" priskyrė jums %s.",
|
"The card \"%s\" on \"%s\" has been assigned to you by %s." : "Kortelę \"%s\" ties \"%s\" priskyrė jums %s.",
|
||||||
"The card \"%s\" on \"%s\" has reached its due date." : "Kortelė „%s“, esanti lentoje „%s“, pasiekė savo galutinį terminą.",
|
"The card \"%s\" on \"%s\" has reached its due date." : "Kortelė „%s“, esanti lentoje „%s“, pasiekė savo galutinį terminą.",
|
||||||
"The card {deck-card} on {deck-board} has reached its due date." : "Kortelė {deck-card}, esanti lentoje {deck-board} pasiekė savo galutinio termino datą.",
|
|
||||||
"%s has mentioned you in a comment on \"%s\"." : "%s paminėjo jus komentare ties \"%s\".",
|
"%s has mentioned you in a comment on \"%s\"." : "%s paminėjo jus komentare ties \"%s\".",
|
||||||
"The board \"%s\" has been shared with you by %s." : "Lentą \"%s\" su jumis bendrina %s.",
|
"The board \"%s\" has been shared with you by %s." : "Lentą \"%s\" su jumis bendrina %s.",
|
||||||
"%s on %s" : "%s ant %s",
|
"%s on %s" : "%s ant %s",
|
||||||
@@ -201,9 +200,9 @@ OC.L10N.register(
|
|||||||
"Assign to users" : "Priskirti naudotojams",
|
"Assign to users" : "Priskirti naudotojams",
|
||||||
"Assign to users/groups/circles" : "Priskirti naudotojams/grupėms/ratams",
|
"Assign to users/groups/circles" : "Priskirti naudotojams/grupėms/ratams",
|
||||||
"Assign a user to this card…" : "Priskirti šiai kortelei naudotoją…",
|
"Assign a user to this card…" : "Priskirti šiai kortelei naudotoją…",
|
||||||
"Due date" : "Galutinio termino data",
|
"Due date" : "Terminas",
|
||||||
"Set a due date" : "Nustatyti galutinį terminą",
|
"Set a due date" : "Nustatyti galutinį terminą",
|
||||||
"Remove due date" : "Šalinti galutinio termino datą",
|
"Remove due date" : "Pašalinti terminą",
|
||||||
"Select Date" : "Pasirinkti datą",
|
"Select Date" : "Pasirinkti datą",
|
||||||
"Today" : "Šiandien",
|
"Today" : "Šiandien",
|
||||||
"Tomorrow" : "Rytoj",
|
"Tomorrow" : "Rytoj",
|
||||||
@@ -244,9 +243,9 @@ OC.L10N.register(
|
|||||||
"Clone board" : "Dubliuoti lentą",
|
"Clone board" : "Dubliuoti lentą",
|
||||||
"Unarchive board" : "Išarchyvuoti lentą",
|
"Unarchive board" : "Išarchyvuoti lentą",
|
||||||
"Archive board" : "Archyvuoti lentą",
|
"Archive board" : "Archyvuoti lentą",
|
||||||
"Turn on due date reminders" : "Įjungti priminimus apie galutinio termino datą",
|
"Turn on due date reminders" : "Įjungti priminimus apie galutinį terminą",
|
||||||
"Turn off due date reminders" : "Išjungti priminimus apie galutinio termino datą",
|
"Turn off due date reminders" : "Išjungti priminimus apie galutinį terminą",
|
||||||
"Due date reminders" : "Priminimai apie galutinio termino datą",
|
"Due date reminders" : "Priminimai apie galutinį terminą",
|
||||||
"All cards" : "Visos kortelės",
|
"All cards" : "Visos kortelės",
|
||||||
"Assigned cards" : "Priskirtos kortelės",
|
"Assigned cards" : "Priskirtos kortelės",
|
||||||
"No notifications" : "Pranešimų nėra",
|
"No notifications" : "Pranešimų nėra",
|
||||||
@@ -258,7 +257,6 @@ OC.L10N.register(
|
|||||||
"Delete the board?" : "Ištrinti lentą?",
|
"Delete the board?" : "Ištrinti lentą?",
|
||||||
"No due" : "Be galutinio termino",
|
"No due" : "Be galutinio termino",
|
||||||
"No results found" : "Nerasta jokių rezultatų",
|
"No results found" : "Nerasta jokių rezultatų",
|
||||||
"Due on {date}" : "Galutinis terminas {date}",
|
|
||||||
"Link to a board" : "Susieti su lenta",
|
"Link to a board" : "Susieti su lenta",
|
||||||
"Link to a card" : "Susieti su kortele",
|
"Link to a card" : "Susieti su kortele",
|
||||||
"Create a card" : "Sukurti kortelę",
|
"Create a card" : "Sukurti kortelę",
|
||||||
|
|||||||
@@ -68,7 +68,6 @@
|
|||||||
"Personal" : "Asmeniniai",
|
"Personal" : "Asmeniniai",
|
||||||
"The card \"%s\" on \"%s\" has been assigned to you by %s." : "Kortelę \"%s\" ties \"%s\" priskyrė jums %s.",
|
"The card \"%s\" on \"%s\" has been assigned to you by %s." : "Kortelę \"%s\" ties \"%s\" priskyrė jums %s.",
|
||||||
"The card \"%s\" on \"%s\" has reached its due date." : "Kortelė „%s“, esanti lentoje „%s“, pasiekė savo galutinį terminą.",
|
"The card \"%s\" on \"%s\" has reached its due date." : "Kortelė „%s“, esanti lentoje „%s“, pasiekė savo galutinį terminą.",
|
||||||
"The card {deck-card} on {deck-board} has reached its due date." : "Kortelė {deck-card}, esanti lentoje {deck-board} pasiekė savo galutinio termino datą.",
|
|
||||||
"%s has mentioned you in a comment on \"%s\"." : "%s paminėjo jus komentare ties \"%s\".",
|
"%s has mentioned you in a comment on \"%s\"." : "%s paminėjo jus komentare ties \"%s\".",
|
||||||
"The board \"%s\" has been shared with you by %s." : "Lentą \"%s\" su jumis bendrina %s.",
|
"The board \"%s\" has been shared with you by %s." : "Lentą \"%s\" su jumis bendrina %s.",
|
||||||
"%s on %s" : "%s ant %s",
|
"%s on %s" : "%s ant %s",
|
||||||
@@ -199,9 +198,9 @@
|
|||||||
"Assign to users" : "Priskirti naudotojams",
|
"Assign to users" : "Priskirti naudotojams",
|
||||||
"Assign to users/groups/circles" : "Priskirti naudotojams/grupėms/ratams",
|
"Assign to users/groups/circles" : "Priskirti naudotojams/grupėms/ratams",
|
||||||
"Assign a user to this card…" : "Priskirti šiai kortelei naudotoją…",
|
"Assign a user to this card…" : "Priskirti šiai kortelei naudotoją…",
|
||||||
"Due date" : "Galutinio termino data",
|
"Due date" : "Terminas",
|
||||||
"Set a due date" : "Nustatyti galutinį terminą",
|
"Set a due date" : "Nustatyti galutinį terminą",
|
||||||
"Remove due date" : "Šalinti galutinio termino datą",
|
"Remove due date" : "Pašalinti terminą",
|
||||||
"Select Date" : "Pasirinkti datą",
|
"Select Date" : "Pasirinkti datą",
|
||||||
"Today" : "Šiandien",
|
"Today" : "Šiandien",
|
||||||
"Tomorrow" : "Rytoj",
|
"Tomorrow" : "Rytoj",
|
||||||
@@ -242,9 +241,9 @@
|
|||||||
"Clone board" : "Dubliuoti lentą",
|
"Clone board" : "Dubliuoti lentą",
|
||||||
"Unarchive board" : "Išarchyvuoti lentą",
|
"Unarchive board" : "Išarchyvuoti lentą",
|
||||||
"Archive board" : "Archyvuoti lentą",
|
"Archive board" : "Archyvuoti lentą",
|
||||||
"Turn on due date reminders" : "Įjungti priminimus apie galutinio termino datą",
|
"Turn on due date reminders" : "Įjungti priminimus apie galutinį terminą",
|
||||||
"Turn off due date reminders" : "Išjungti priminimus apie galutinio termino datą",
|
"Turn off due date reminders" : "Išjungti priminimus apie galutinį terminą",
|
||||||
"Due date reminders" : "Priminimai apie galutinio termino datą",
|
"Due date reminders" : "Priminimai apie galutinį terminą",
|
||||||
"All cards" : "Visos kortelės",
|
"All cards" : "Visos kortelės",
|
||||||
"Assigned cards" : "Priskirtos kortelės",
|
"Assigned cards" : "Priskirtos kortelės",
|
||||||
"No notifications" : "Pranešimų nėra",
|
"No notifications" : "Pranešimų nėra",
|
||||||
@@ -256,7 +255,6 @@
|
|||||||
"Delete the board?" : "Ištrinti lentą?",
|
"Delete the board?" : "Ištrinti lentą?",
|
||||||
"No due" : "Be galutinio termino",
|
"No due" : "Be galutinio termino",
|
||||||
"No results found" : "Nerasta jokių rezultatų",
|
"No results found" : "Nerasta jokių rezultatų",
|
||||||
"Due on {date}" : "Galutinis terminas {date}",
|
|
||||||
"Link to a board" : "Susieti su lenta",
|
"Link to a board" : "Susieti su lenta",
|
||||||
"Link to a card" : "Susieti su kortele",
|
"Link to a card" : "Susieti su kortele",
|
||||||
"Create a card" : "Sukurti kortelę",
|
"Create a card" : "Sukurti kortelę",
|
||||||
|
|||||||
@@ -183,10 +183,8 @@ OC.L10N.register(
|
|||||||
"Failed to transfer the board to {user}" : "Nie udało się przenieść tablicy do {user}",
|
"Failed to transfer the board to {user}" : "Nie udało się przenieść tablicy do {user}",
|
||||||
"Add a new list" : "Dodaj nową listę",
|
"Add a new list" : "Dodaj nową listę",
|
||||||
"Archive all cards" : "Zarchiwizuj wszystkie karty",
|
"Archive all cards" : "Zarchiwizuj wszystkie karty",
|
||||||
"Unarchive all cards" : "Przywróć wszystkie karty z archiwum",
|
|
||||||
"Delete list" : "Usuń listę",
|
"Delete list" : "Usuń listę",
|
||||||
"Archive all cards in this list" : "Zarchiwizuj wszystkie karty na tej liście",
|
"Archive all cards in this list" : "Zarchiwizuj wszystkie karty na tej liście",
|
||||||
"Unarchive all cards in this list" : "Cofnij archiwizację wszystkich kart z tej listy",
|
|
||||||
"Add a new card" : "Dodaj nową kartę",
|
"Add a new card" : "Dodaj nową kartę",
|
||||||
"Card name" : "Nazwa karty",
|
"Card name" : "Nazwa karty",
|
||||||
"List deleted" : "Lista usunięta",
|
"List deleted" : "Lista usunięta",
|
||||||
@@ -262,7 +260,6 @@ OC.L10N.register(
|
|||||||
"Shared with you" : "Udostępnione Tobie",
|
"Shared with you" : "Udostępnione Tobie",
|
||||||
"Deck settings" : "Ustawienia Tablicy",
|
"Deck settings" : "Ustawienia Tablicy",
|
||||||
"Use bigger card view" : "Użyj większego widoku karty",
|
"Use bigger card view" : "Użyj większego widoku karty",
|
||||||
"Show card ID badge" : "Pokaż ID karty",
|
|
||||||
"Show boards in calendar/tasks" : "Pokaż tablice w kalendarzu/zadaniach",
|
"Show boards in calendar/tasks" : "Pokaż tablice w kalendarzu/zadaniach",
|
||||||
"Limit deck usage of groups" : "Ogranicz użycie tablic dla grup",
|
"Limit deck usage of groups" : "Ogranicz użycie tablic dla grup",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Ograniczenie Tablicy zablokuje użytkownikom z tych grup możliwość tworzenia własnych tablic. Użytkownicy nadal będą mogli pracować na tablicach, które zostały im udostępnione.",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Ograniczenie Tablicy zablokuje użytkownikom z tych grup możliwość tworzenia własnych tablic. Użytkownicy nadal będą mogli pracować na tablicach, które zostały im udostępnione.",
|
||||||
|
|||||||
@@ -181,10 +181,8 @@
|
|||||||
"Failed to transfer the board to {user}" : "Nie udało się przenieść tablicy do {user}",
|
"Failed to transfer the board to {user}" : "Nie udało się przenieść tablicy do {user}",
|
||||||
"Add a new list" : "Dodaj nową listę",
|
"Add a new list" : "Dodaj nową listę",
|
||||||
"Archive all cards" : "Zarchiwizuj wszystkie karty",
|
"Archive all cards" : "Zarchiwizuj wszystkie karty",
|
||||||
"Unarchive all cards" : "Przywróć wszystkie karty z archiwum",
|
|
||||||
"Delete list" : "Usuń listę",
|
"Delete list" : "Usuń listę",
|
||||||
"Archive all cards in this list" : "Zarchiwizuj wszystkie karty na tej liście",
|
"Archive all cards in this list" : "Zarchiwizuj wszystkie karty na tej liście",
|
||||||
"Unarchive all cards in this list" : "Cofnij archiwizację wszystkich kart z tej listy",
|
|
||||||
"Add a new card" : "Dodaj nową kartę",
|
"Add a new card" : "Dodaj nową kartę",
|
||||||
"Card name" : "Nazwa karty",
|
"Card name" : "Nazwa karty",
|
||||||
"List deleted" : "Lista usunięta",
|
"List deleted" : "Lista usunięta",
|
||||||
@@ -260,7 +258,6 @@
|
|||||||
"Shared with you" : "Udostępnione Tobie",
|
"Shared with you" : "Udostępnione Tobie",
|
||||||
"Deck settings" : "Ustawienia Tablicy",
|
"Deck settings" : "Ustawienia Tablicy",
|
||||||
"Use bigger card view" : "Użyj większego widoku karty",
|
"Use bigger card view" : "Użyj większego widoku karty",
|
||||||
"Show card ID badge" : "Pokaż ID karty",
|
|
||||||
"Show boards in calendar/tasks" : "Pokaż tablice w kalendarzu/zadaniach",
|
"Show boards in calendar/tasks" : "Pokaż tablice w kalendarzu/zadaniach",
|
||||||
"Limit deck usage of groups" : "Ogranicz użycie tablic dla grup",
|
"Limit deck usage of groups" : "Ogranicz użycie tablic dla grup",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Ograniczenie Tablicy zablokuje użytkownikom z tych grup możliwość tworzenia własnych tablic. Użytkownicy nadal będą mogli pracować na tablicach, które zostały im udostępnione.",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Ograniczenie Tablicy zablokuje użytkownikom z tych grup możliwość tworzenia własnych tablic. Użytkownicy nadal będą mogli pracować na tablicach, które zostały im udostępnione.",
|
||||||
|
|||||||
@@ -183,10 +183,8 @@ OC.L10N.register(
|
|||||||
"Failed to transfer the board to {user}" : "Chyba pri presune nástenky na {user}",
|
"Failed to transfer the board to {user}" : "Chyba pri presune nástenky na {user}",
|
||||||
"Add a new list" : "Pridať nový zoznam",
|
"Add a new list" : "Pridať nový zoznam",
|
||||||
"Archive all cards" : "Archivovať všetky karty",
|
"Archive all cards" : "Archivovať všetky karty",
|
||||||
"Unarchive all cards" : "Zrušiť archiváciu všetkých kariet",
|
|
||||||
"Delete list" : "Vymazať zoznam",
|
"Delete list" : "Vymazať zoznam",
|
||||||
"Archive all cards in this list" : "Archivovať všetky karty v tomto zozname",
|
"Archive all cards in this list" : "Archivovať všetky karty v tomto zozname",
|
||||||
"Unarchive all cards in this list" : "Zrušiť archiváciu všetkých kariet v tomto zozname",
|
|
||||||
"Add a new card" : "Pridať novú kartu",
|
"Add a new card" : "Pridať novú kartu",
|
||||||
"Card name" : "Názov karty",
|
"Card name" : "Názov karty",
|
||||||
"List deleted" : "Zoznam bol vymazaný",
|
"List deleted" : "Zoznam bol vymazaný",
|
||||||
@@ -262,7 +260,6 @@ OC.L10N.register(
|
|||||||
"Shared with you" : "Vám sprístupnené",
|
"Shared with you" : "Vám sprístupnené",
|
||||||
"Deck settings" : "Nastavenia paluby",
|
"Deck settings" : "Nastavenia paluby",
|
||||||
"Use bigger card view" : "Použiť väčšie zobrazenie karty",
|
"Use bigger card view" : "Použiť väčšie zobrazenie karty",
|
||||||
"Show card ID badge" : "Ukázať ID karty",
|
|
||||||
"Show boards in calendar/tasks" : "Zobrazovať nástenky v kalendári/úlohách",
|
"Show boards in calendar/tasks" : "Zobrazovať nástenky v kalendári/úlohách",
|
||||||
"Limit deck usage of groups" : "Obmedziť použitie Deck na skupiny",
|
"Limit deck usage of groups" : "Obmedziť použitie Deck na skupiny",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Obmedzenie Násteniek bráni používateľom, ktorí nie sú súčasťou týchto skupín, aby si vytvárali vlastné nástenky. Môžu však stále pracovať na nástenkách, ktoré im niekto sprístupní.",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Obmedzenie Násteniek bráni používateľom, ktorí nie sú súčasťou týchto skupín, aby si vytvárali vlastné nástenky. Môžu však stále pracovať na nástenkách, ktoré im niekto sprístupní.",
|
||||||
|
|||||||
@@ -181,10 +181,8 @@
|
|||||||
"Failed to transfer the board to {user}" : "Chyba pri presune nástenky na {user}",
|
"Failed to transfer the board to {user}" : "Chyba pri presune nástenky na {user}",
|
||||||
"Add a new list" : "Pridať nový zoznam",
|
"Add a new list" : "Pridať nový zoznam",
|
||||||
"Archive all cards" : "Archivovať všetky karty",
|
"Archive all cards" : "Archivovať všetky karty",
|
||||||
"Unarchive all cards" : "Zrušiť archiváciu všetkých kariet",
|
|
||||||
"Delete list" : "Vymazať zoznam",
|
"Delete list" : "Vymazať zoznam",
|
||||||
"Archive all cards in this list" : "Archivovať všetky karty v tomto zozname",
|
"Archive all cards in this list" : "Archivovať všetky karty v tomto zozname",
|
||||||
"Unarchive all cards in this list" : "Zrušiť archiváciu všetkých kariet v tomto zozname",
|
|
||||||
"Add a new card" : "Pridať novú kartu",
|
"Add a new card" : "Pridať novú kartu",
|
||||||
"Card name" : "Názov karty",
|
"Card name" : "Názov karty",
|
||||||
"List deleted" : "Zoznam bol vymazaný",
|
"List deleted" : "Zoznam bol vymazaný",
|
||||||
@@ -260,7 +258,6 @@
|
|||||||
"Shared with you" : "Vám sprístupnené",
|
"Shared with you" : "Vám sprístupnené",
|
||||||
"Deck settings" : "Nastavenia paluby",
|
"Deck settings" : "Nastavenia paluby",
|
||||||
"Use bigger card view" : "Použiť väčšie zobrazenie karty",
|
"Use bigger card view" : "Použiť väčšie zobrazenie karty",
|
||||||
"Show card ID badge" : "Ukázať ID karty",
|
|
||||||
"Show boards in calendar/tasks" : "Zobrazovať nástenky v kalendári/úlohách",
|
"Show boards in calendar/tasks" : "Zobrazovať nástenky v kalendári/úlohách",
|
||||||
"Limit deck usage of groups" : "Obmedziť použitie Deck na skupiny",
|
"Limit deck usage of groups" : "Obmedziť použitie Deck na skupiny",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Obmedzenie Násteniek bráni používateľom, ktorí nie sú súčasťou týchto skupín, aby si vytvárali vlastné nástenky. Môžu však stále pracovať na nástenkách, ktoré im niekto sprístupní.",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Obmedzenie Násteniek bráni používateľom, ktorí nie sú súčasťou týchto skupín, aby si vytvárali vlastné nástenky. Môžu však stále pracovať na nástenkách, ktoré im niekto sprístupní.",
|
||||||
|
|||||||
23
l10n/sv.js
@@ -136,7 +136,6 @@ OC.L10N.register(
|
|||||||
"Archived cards" : "Arkiverade kort",
|
"Archived cards" : "Arkiverade kort",
|
||||||
"Add list" : "Lägg till lista...",
|
"Add list" : "Lägg till lista...",
|
||||||
"List name" : "Namn på lista",
|
"List name" : "Namn på lista",
|
||||||
"Active filters" : "Aktiva filter",
|
|
||||||
"Apply filter" : "Tillämpa filter",
|
"Apply filter" : "Tillämpa filter",
|
||||||
"Filter by tag" : "Filtrera efter tagg",
|
"Filter by tag" : "Filtrera efter tagg",
|
||||||
"Filter by assigned user" : "Filtrera efter tilldelad användare",
|
"Filter by assigned user" : "Filtrera efter tilldelad användare",
|
||||||
@@ -176,17 +175,11 @@ OC.L10N.register(
|
|||||||
"Owner" : "Ägare",
|
"Owner" : "Ägare",
|
||||||
"Delete" : "Ta bort",
|
"Delete" : "Ta bort",
|
||||||
"Failed to create share with {displayName}" : "Kunde inte skapa delning med {displayName}",
|
"Failed to create share with {displayName}" : "Kunde inte skapa delning med {displayName}",
|
||||||
"Are you sure you want to transfer the board {title} to {user}?" : "Är du säker att du vill överföra tavlan {title} till {user}?",
|
|
||||||
"Transfer the board." : "Överför tavlan.",
|
|
||||||
"Transfer" : "Överför",
|
"Transfer" : "Överför",
|
||||||
"The board has been transferred to {user}" : "Tavlan har överförts till {user}",
|
|
||||||
"Failed to transfer the board to {user}" : "Kunde inte överföra tavlan till {user}",
|
|
||||||
"Add a new list" : "Lägg till en ny lista",
|
"Add a new list" : "Lägg till en ny lista",
|
||||||
"Archive all cards" : "Arkivera alla kort",
|
"Archive all cards" : "Arkivera alla kort",
|
||||||
"Unarchive all cards" : "Ta ut alla kort ur arkivet",
|
|
||||||
"Delete list" : "Ta bort lista",
|
"Delete list" : "Ta bort lista",
|
||||||
"Archive all cards in this list" : "Arkivera alla kort i denna lista",
|
"Archive all cards in this list" : "Arkivera alla kort i denna lista",
|
||||||
"Unarchive all cards in this list" : "Ta ut alla kort i denna lista ur arkivet",
|
|
||||||
"Add a new card" : "Lägg till ett nytt kort",
|
"Add a new card" : "Lägg till ett nytt kort",
|
||||||
"Card name" : "Kortets namn",
|
"Card name" : "Kortets namn",
|
||||||
"List deleted" : "Listan har raderats",
|
"List deleted" : "Listan har raderats",
|
||||||
@@ -244,9 +237,7 @@ OC.L10N.register(
|
|||||||
"Write a description …" : "Ange en beskrivning ...",
|
"Write a description …" : "Ange en beskrivning ...",
|
||||||
"Choose attachment" : "Välj bilaga",
|
"Choose attachment" : "Välj bilaga",
|
||||||
"(group)" : " (grupp)",
|
"(group)" : " (grupp)",
|
||||||
"Todo items" : "Todo saker",
|
|
||||||
"{count} comments, {unread} unread" : "{count} kommentarer, {unread} olästa",
|
"{count} comments, {unread} unread" : "{count} kommentarer, {unread} olästa",
|
||||||
"Edit card title" : "Ändra korttitel",
|
|
||||||
"Assign to me" : "Tilldela till mig",
|
"Assign to me" : "Tilldela till mig",
|
||||||
"Unassign myself" : "Ta bort från mig själv",
|
"Unassign myself" : "Ta bort från mig själv",
|
||||||
"Move card" : "Flytta kort",
|
"Move card" : "Flytta kort",
|
||||||
@@ -260,9 +251,7 @@ OC.L10N.register(
|
|||||||
"All boards" : "Alla tavlor",
|
"All boards" : "Alla tavlor",
|
||||||
"Archived boards" : "Arkiverade tavlor",
|
"Archived boards" : "Arkiverade tavlor",
|
||||||
"Shared with you" : "Delad med dig",
|
"Shared with you" : "Delad med dig",
|
||||||
"Deck settings" : "Deck-inställningar",
|
|
||||||
"Use bigger card view" : "Visa större kort",
|
"Use bigger card view" : "Visa större kort",
|
||||||
"Show card ID badge" : "Visa kortets ID-märke",
|
|
||||||
"Show boards in calendar/tasks" : "Visa tavlor i kalender / uppgifter",
|
"Show boards in calendar/tasks" : "Visa tavlor i kalender / uppgifter",
|
||||||
"Limit deck usage of groups" : "Begränsa användningen av grupper",
|
"Limit deck usage of groups" : "Begränsa användningen av grupper",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Begränsning av Deck blockerar användare som inte ingår i dessa grupper från att skapa egna tavlor. Användare kan dock fortfarande integrera med tavlor som har delats med dem.",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Begränsning av Deck blockerar användare som inte ingår i dessa grupper från att skapa egna tavlor. Användare kan dock fortfarande integrera med tavlor som har delats med dem.",
|
||||||
@@ -282,19 +271,13 @@ OC.L10N.register(
|
|||||||
"Only assigned cards" : "Bara tilldelade kort",
|
"Only assigned cards" : "Bara tilldelade kort",
|
||||||
"No reminder" : "Ingen påminnelse",
|
"No reminder" : "Ingen påminnelse",
|
||||||
"An error occurred" : "Ett fel uppstod",
|
"An error occurred" : "Ett fel uppstod",
|
||||||
"Are you sure you want to delete the board {title}? This will delete all the data of this board including archived cards." : "Är du säker på att du vill radera brädet {title}? Detta kommer radera all data som tillhör brädet inklusive arkiverade kort.",
|
|
||||||
"Delete the board?" : "Ta bort tavlan?",
|
"Delete the board?" : "Ta bort tavlan?",
|
||||||
"Loading filtered view" : "Laddar filtrerad vy",
|
"Loading filtered view" : "Laddar filtrerad vy",
|
||||||
"No due" : "Inget slut",
|
"No due" : "Inget slut",
|
||||||
"Search for {searchQuery} in all boards" : "Sök efter {searchQuery} i alla tavlor",
|
"Search for {searchQuery} in all boards" : "Sök efter {searchQuery} i alla tavlor",
|
||||||
"No results found" : "Inga resultat funna",
|
"No results found" : "Inga resultat funna",
|
||||||
"{stack} in {board}" : "{stack} i {board}",
|
|
||||||
"Click to expand description" : "Klicka för att utöka beskrivningen",
|
|
||||||
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Skapades {created}\n* Ändrades senast {lastMod}\n* {nbAttachments} bilagor\n* {nbComments} kommentarer",
|
|
||||||
"{nbCards} cards" : "{nbCards} kort",
|
|
||||||
"No upcoming cards" : "Inga kommande kort",
|
"No upcoming cards" : "Inga kommande kort",
|
||||||
"upcoming cards" : "kommande kort",
|
"upcoming cards" : "kommande kort",
|
||||||
"Due on {date}" : "Går ut {date}",
|
|
||||||
"Link to a board" : "Länka till en tavla",
|
"Link to a board" : "Länka till en tavla",
|
||||||
"Link to a card" : "Länka till ett kort",
|
"Link to a card" : "Länka till ett kort",
|
||||||
"Create a card" : "Skapa ett kort",
|
"Create a card" : "Skapa ett kort",
|
||||||
@@ -307,11 +290,7 @@ OC.L10N.register(
|
|||||||
"Share {file} with a Deck card" : "Dela {file} med ett Deck-kort",
|
"Share {file} with a Deck card" : "Dela {file} med ett Deck-kort",
|
||||||
"Share" : "Dela",
|
"Share" : "Dela",
|
||||||
"Deck is a kanban style organization tool aimed at personal planning and project organization for teams integrated with Nextcloud.\n\n\n- 📥 Add your tasks to cards and put them in order\n- 📄 Write down additional notes in markdown\n- 🔖 Assign labels for even better organization\n- 👥 Share with your team, friends or family\n- 📎 Attach files and embed them in your markdown description\n- 💬 Discuss with your team using comments\n- ⚡ Keep track of changes in the activity stream\n- 🚀 Get your project organized" : "Deck är en kanban-liknande projekt- och organiseringsapp för arbetsgrupper i Nextcloud.\n\n\n- 📥 Lägg till uppgifter på kort och ordna dem\n- 📄 Skriv anteckningar i markdown\n- 🔖 Tilldela etiketter för organisering\n- 👥 Dela med arbetsgruppen, vänner eller familj\n- 📎 Bifoga filer och bädda in dem i markdown-anteckningarna\n- 💬 Diskutera i arbetsgruppen genom kommentarer\n- ⚡ Håll koll på ändringar i aktivitetsflödet\n- 🚀 Börja organisera din arbetsgrupp nu!",
|
"Deck is a kanban style organization tool aimed at personal planning and project organization for teams integrated with Nextcloud.\n\n\n- 📥 Add your tasks to cards and put them in order\n- 📄 Write down additional notes in markdown\n- 🔖 Assign labels for even better organization\n- 👥 Share with your team, friends or family\n- 📎 Attach files and embed them in your markdown description\n- 💬 Discuss with your team using comments\n- ⚡ Keep track of changes in the activity stream\n- 🚀 Get your project organized" : "Deck är en kanban-liknande projekt- och organiseringsapp för arbetsgrupper i Nextcloud.\n\n\n- 📥 Lägg till uppgifter på kort och ordna dem\n- 📄 Skriv anteckningar i markdown\n- 🔖 Tilldela etiketter för organisering\n- 👥 Dela med arbetsgruppen, vänner eller familj\n- 📎 Bifoga filer och bädda in dem i markdown-anteckningarna\n- 💬 Diskutera i arbetsgruppen genom kommentarer\n- ⚡ Håll koll på ändringar i aktivitetsflödet\n- 🚀 Börja organisera din arbetsgrupp nu!",
|
||||||
"Are you sure you want to transfer the board {title} for {user} ?" : "Är du säker på att du vill överföra brädet {title} för {user}?",
|
|
||||||
"Transfer the board for {user} successfully" : "Överförde brädet för {user}",
|
|
||||||
"Failed to transfer the board for {user}" : "Misslyckades med att överföra brädet för {user}",
|
|
||||||
"Are you sure you want to delete the board {title}? This will delete all the data of this board." : "Är du säker på att du vill radera tavla {title}? Detta kommer att radera all information från denna tavla.",
|
"Are you sure you want to delete the board {title}? This will delete all the data of this board." : "Är du säker på att du vill radera tavla {title}? Detta kommer att radera all information från denna tavla.",
|
||||||
"This week" : "Denna vecka",
|
"This week" : "Denna vecka"
|
||||||
"Are you sure you want to transfer the board {title} for {user}?" : "Är du säker på att du vill överföra brädet {title} för {user}?"
|
|
||||||
},
|
},
|
||||||
"nplurals=2; plural=(n != 1);");
|
"nplurals=2; plural=(n != 1);");
|
||||||
|
|||||||
23
l10n/sv.json
@@ -134,7 +134,6 @@
|
|||||||
"Archived cards" : "Arkiverade kort",
|
"Archived cards" : "Arkiverade kort",
|
||||||
"Add list" : "Lägg till lista...",
|
"Add list" : "Lägg till lista...",
|
||||||
"List name" : "Namn på lista",
|
"List name" : "Namn på lista",
|
||||||
"Active filters" : "Aktiva filter",
|
|
||||||
"Apply filter" : "Tillämpa filter",
|
"Apply filter" : "Tillämpa filter",
|
||||||
"Filter by tag" : "Filtrera efter tagg",
|
"Filter by tag" : "Filtrera efter tagg",
|
||||||
"Filter by assigned user" : "Filtrera efter tilldelad användare",
|
"Filter by assigned user" : "Filtrera efter tilldelad användare",
|
||||||
@@ -174,17 +173,11 @@
|
|||||||
"Owner" : "Ägare",
|
"Owner" : "Ägare",
|
||||||
"Delete" : "Ta bort",
|
"Delete" : "Ta bort",
|
||||||
"Failed to create share with {displayName}" : "Kunde inte skapa delning med {displayName}",
|
"Failed to create share with {displayName}" : "Kunde inte skapa delning med {displayName}",
|
||||||
"Are you sure you want to transfer the board {title} to {user}?" : "Är du säker att du vill överföra tavlan {title} till {user}?",
|
|
||||||
"Transfer the board." : "Överför tavlan.",
|
|
||||||
"Transfer" : "Överför",
|
"Transfer" : "Överför",
|
||||||
"The board has been transferred to {user}" : "Tavlan har överförts till {user}",
|
|
||||||
"Failed to transfer the board to {user}" : "Kunde inte överföra tavlan till {user}",
|
|
||||||
"Add a new list" : "Lägg till en ny lista",
|
"Add a new list" : "Lägg till en ny lista",
|
||||||
"Archive all cards" : "Arkivera alla kort",
|
"Archive all cards" : "Arkivera alla kort",
|
||||||
"Unarchive all cards" : "Ta ut alla kort ur arkivet",
|
|
||||||
"Delete list" : "Ta bort lista",
|
"Delete list" : "Ta bort lista",
|
||||||
"Archive all cards in this list" : "Arkivera alla kort i denna lista",
|
"Archive all cards in this list" : "Arkivera alla kort i denna lista",
|
||||||
"Unarchive all cards in this list" : "Ta ut alla kort i denna lista ur arkivet",
|
|
||||||
"Add a new card" : "Lägg till ett nytt kort",
|
"Add a new card" : "Lägg till ett nytt kort",
|
||||||
"Card name" : "Kortets namn",
|
"Card name" : "Kortets namn",
|
||||||
"List deleted" : "Listan har raderats",
|
"List deleted" : "Listan har raderats",
|
||||||
@@ -242,9 +235,7 @@
|
|||||||
"Write a description …" : "Ange en beskrivning ...",
|
"Write a description …" : "Ange en beskrivning ...",
|
||||||
"Choose attachment" : "Välj bilaga",
|
"Choose attachment" : "Välj bilaga",
|
||||||
"(group)" : " (grupp)",
|
"(group)" : " (grupp)",
|
||||||
"Todo items" : "Todo saker",
|
|
||||||
"{count} comments, {unread} unread" : "{count} kommentarer, {unread} olästa",
|
"{count} comments, {unread} unread" : "{count} kommentarer, {unread} olästa",
|
||||||
"Edit card title" : "Ändra korttitel",
|
|
||||||
"Assign to me" : "Tilldela till mig",
|
"Assign to me" : "Tilldela till mig",
|
||||||
"Unassign myself" : "Ta bort från mig själv",
|
"Unassign myself" : "Ta bort från mig själv",
|
||||||
"Move card" : "Flytta kort",
|
"Move card" : "Flytta kort",
|
||||||
@@ -258,9 +249,7 @@
|
|||||||
"All boards" : "Alla tavlor",
|
"All boards" : "Alla tavlor",
|
||||||
"Archived boards" : "Arkiverade tavlor",
|
"Archived boards" : "Arkiverade tavlor",
|
||||||
"Shared with you" : "Delad med dig",
|
"Shared with you" : "Delad med dig",
|
||||||
"Deck settings" : "Deck-inställningar",
|
|
||||||
"Use bigger card view" : "Visa större kort",
|
"Use bigger card view" : "Visa större kort",
|
||||||
"Show card ID badge" : "Visa kortets ID-märke",
|
|
||||||
"Show boards in calendar/tasks" : "Visa tavlor i kalender / uppgifter",
|
"Show boards in calendar/tasks" : "Visa tavlor i kalender / uppgifter",
|
||||||
"Limit deck usage of groups" : "Begränsa användningen av grupper",
|
"Limit deck usage of groups" : "Begränsa användningen av grupper",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Begränsning av Deck blockerar användare som inte ingår i dessa grupper från att skapa egna tavlor. Användare kan dock fortfarande integrera med tavlor som har delats med dem.",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Begränsning av Deck blockerar användare som inte ingår i dessa grupper från att skapa egna tavlor. Användare kan dock fortfarande integrera med tavlor som har delats med dem.",
|
||||||
@@ -280,19 +269,13 @@
|
|||||||
"Only assigned cards" : "Bara tilldelade kort",
|
"Only assigned cards" : "Bara tilldelade kort",
|
||||||
"No reminder" : "Ingen påminnelse",
|
"No reminder" : "Ingen påminnelse",
|
||||||
"An error occurred" : "Ett fel uppstod",
|
"An error occurred" : "Ett fel uppstod",
|
||||||
"Are you sure you want to delete the board {title}? This will delete all the data of this board including archived cards." : "Är du säker på att du vill radera brädet {title}? Detta kommer radera all data som tillhör brädet inklusive arkiverade kort.",
|
|
||||||
"Delete the board?" : "Ta bort tavlan?",
|
"Delete the board?" : "Ta bort tavlan?",
|
||||||
"Loading filtered view" : "Laddar filtrerad vy",
|
"Loading filtered view" : "Laddar filtrerad vy",
|
||||||
"No due" : "Inget slut",
|
"No due" : "Inget slut",
|
||||||
"Search for {searchQuery} in all boards" : "Sök efter {searchQuery} i alla tavlor",
|
"Search for {searchQuery} in all boards" : "Sök efter {searchQuery} i alla tavlor",
|
||||||
"No results found" : "Inga resultat funna",
|
"No results found" : "Inga resultat funna",
|
||||||
"{stack} in {board}" : "{stack} i {board}",
|
|
||||||
"Click to expand description" : "Klicka för att utöka beskrivningen",
|
|
||||||
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Skapades {created}\n* Ändrades senast {lastMod}\n* {nbAttachments} bilagor\n* {nbComments} kommentarer",
|
|
||||||
"{nbCards} cards" : "{nbCards} kort",
|
|
||||||
"No upcoming cards" : "Inga kommande kort",
|
"No upcoming cards" : "Inga kommande kort",
|
||||||
"upcoming cards" : "kommande kort",
|
"upcoming cards" : "kommande kort",
|
||||||
"Due on {date}" : "Går ut {date}",
|
|
||||||
"Link to a board" : "Länka till en tavla",
|
"Link to a board" : "Länka till en tavla",
|
||||||
"Link to a card" : "Länka till ett kort",
|
"Link to a card" : "Länka till ett kort",
|
||||||
"Create a card" : "Skapa ett kort",
|
"Create a card" : "Skapa ett kort",
|
||||||
@@ -305,11 +288,7 @@
|
|||||||
"Share {file} with a Deck card" : "Dela {file} med ett Deck-kort",
|
"Share {file} with a Deck card" : "Dela {file} med ett Deck-kort",
|
||||||
"Share" : "Dela",
|
"Share" : "Dela",
|
||||||
"Deck is a kanban style organization tool aimed at personal planning and project organization for teams integrated with Nextcloud.\n\n\n- 📥 Add your tasks to cards and put them in order\n- 📄 Write down additional notes in markdown\n- 🔖 Assign labels for even better organization\n- 👥 Share with your team, friends or family\n- 📎 Attach files and embed them in your markdown description\n- 💬 Discuss with your team using comments\n- ⚡ Keep track of changes in the activity stream\n- 🚀 Get your project organized" : "Deck är en kanban-liknande projekt- och organiseringsapp för arbetsgrupper i Nextcloud.\n\n\n- 📥 Lägg till uppgifter på kort och ordna dem\n- 📄 Skriv anteckningar i markdown\n- 🔖 Tilldela etiketter för organisering\n- 👥 Dela med arbetsgruppen, vänner eller familj\n- 📎 Bifoga filer och bädda in dem i markdown-anteckningarna\n- 💬 Diskutera i arbetsgruppen genom kommentarer\n- ⚡ Håll koll på ändringar i aktivitetsflödet\n- 🚀 Börja organisera din arbetsgrupp nu!",
|
"Deck is a kanban style organization tool aimed at personal planning and project organization for teams integrated with Nextcloud.\n\n\n- 📥 Add your tasks to cards and put them in order\n- 📄 Write down additional notes in markdown\n- 🔖 Assign labels for even better organization\n- 👥 Share with your team, friends or family\n- 📎 Attach files and embed them in your markdown description\n- 💬 Discuss with your team using comments\n- ⚡ Keep track of changes in the activity stream\n- 🚀 Get your project organized" : "Deck är en kanban-liknande projekt- och organiseringsapp för arbetsgrupper i Nextcloud.\n\n\n- 📥 Lägg till uppgifter på kort och ordna dem\n- 📄 Skriv anteckningar i markdown\n- 🔖 Tilldela etiketter för organisering\n- 👥 Dela med arbetsgruppen, vänner eller familj\n- 📎 Bifoga filer och bädda in dem i markdown-anteckningarna\n- 💬 Diskutera i arbetsgruppen genom kommentarer\n- ⚡ Håll koll på ändringar i aktivitetsflödet\n- 🚀 Börja organisera din arbetsgrupp nu!",
|
||||||
"Are you sure you want to transfer the board {title} for {user} ?" : "Är du säker på att du vill överföra brädet {title} för {user}?",
|
|
||||||
"Transfer the board for {user} successfully" : "Överförde brädet för {user}",
|
|
||||||
"Failed to transfer the board for {user}" : "Misslyckades med att överföra brädet för {user}",
|
|
||||||
"Are you sure you want to delete the board {title}? This will delete all the data of this board." : "Är du säker på att du vill radera tavla {title}? Detta kommer att radera all information från denna tavla.",
|
"Are you sure you want to delete the board {title}? This will delete all the data of this board." : "Är du säker på att du vill radera tavla {title}? Detta kommer att radera all information från denna tavla.",
|
||||||
"This week" : "Denna vecka",
|
"This week" : "Denna vecka"
|
||||||
"Are you sure you want to transfer the board {title} for {user}?" : "Är du säker på att du vill överföra brädet {title} för {user}?"
|
|
||||||
},"pluralForm" :"nplurals=2; plural=(n != 1);"
|
},"pluralForm" :"nplurals=2; plural=(n != 1);"
|
||||||
}
|
}
|
||||||
@@ -183,10 +183,8 @@ OC.L10N.register(
|
|||||||
"Failed to transfer the board to {user}" : "Pano {user} kullanıcısına aktarılamadı",
|
"Failed to transfer the board to {user}" : "Pano {user} kullanıcısına aktarılamadı",
|
||||||
"Add a new list" : "Yeni liste ekle",
|
"Add a new list" : "Yeni liste ekle",
|
||||||
"Archive all cards" : "Tüm kartları arşivle",
|
"Archive all cards" : "Tüm kartları arşivle",
|
||||||
"Unarchive all cards" : "Tüm kartları arşivden çıkar",
|
|
||||||
"Delete list" : "Listeyi sil",
|
"Delete list" : "Listeyi sil",
|
||||||
"Archive all cards in this list" : "Bu listedeki tüm kartları arşivle",
|
"Archive all cards in this list" : "Bu listedeki tüm kartları arşivle",
|
||||||
"Unarchive all cards in this list" : "Bu listedeki tüm kartları arşivden çıkar",
|
|
||||||
"Add a new card" : "Yeni kart ekle",
|
"Add a new card" : "Yeni kart ekle",
|
||||||
"Card name" : "Kart adı",
|
"Card name" : "Kart adı",
|
||||||
"List deleted" : "Liste silindi",
|
"List deleted" : "Liste silindi",
|
||||||
@@ -262,7 +260,6 @@ OC.L10N.register(
|
|||||||
"Shared with you" : "Sizinle paylaşıldı",
|
"Shared with you" : "Sizinle paylaşıldı",
|
||||||
"Deck settings" : "Tahta ayarları",
|
"Deck settings" : "Tahta ayarları",
|
||||||
"Use bigger card view" : "Daha büyük kart görünümü kullanılsın",
|
"Use bigger card view" : "Daha büyük kart görünümü kullanılsın",
|
||||||
"Show card ID badge" : "Kart kodu etiketi görüntülensin",
|
|
||||||
"Show boards in calendar/tasks" : "Takvimler ve görevlerde panolar görüntülensin",
|
"Show boards in calendar/tasks" : "Takvimler ve görevlerde panolar görüntülensin",
|
||||||
"Limit deck usage of groups" : "Tahtayı şu gruplar kullanabilsin",
|
"Limit deck usage of groups" : "Tahtayı şu gruplar kullanabilsin",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Tahta kullanımı gruplar ile sınırlandığında belirtilen grupların üyesi olmayan kişiler kendi tahtalarını oluşturamaz. Bu kullanıcılar ancak kendileri ile paylaşılan tahtalar üzerinde çalışabilir.",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Tahta kullanımı gruplar ile sınırlandığında belirtilen grupların üyesi olmayan kişiler kendi tahtalarını oluşturamaz. Bu kullanıcılar ancak kendileri ile paylaşılan tahtalar üzerinde çalışabilir.",
|
||||||
|
|||||||
@@ -181,10 +181,8 @@
|
|||||||
"Failed to transfer the board to {user}" : "Pano {user} kullanıcısına aktarılamadı",
|
"Failed to transfer the board to {user}" : "Pano {user} kullanıcısına aktarılamadı",
|
||||||
"Add a new list" : "Yeni liste ekle",
|
"Add a new list" : "Yeni liste ekle",
|
||||||
"Archive all cards" : "Tüm kartları arşivle",
|
"Archive all cards" : "Tüm kartları arşivle",
|
||||||
"Unarchive all cards" : "Tüm kartları arşivden çıkar",
|
|
||||||
"Delete list" : "Listeyi sil",
|
"Delete list" : "Listeyi sil",
|
||||||
"Archive all cards in this list" : "Bu listedeki tüm kartları arşivle",
|
"Archive all cards in this list" : "Bu listedeki tüm kartları arşivle",
|
||||||
"Unarchive all cards in this list" : "Bu listedeki tüm kartları arşivden çıkar",
|
|
||||||
"Add a new card" : "Yeni kart ekle",
|
"Add a new card" : "Yeni kart ekle",
|
||||||
"Card name" : "Kart adı",
|
"Card name" : "Kart adı",
|
||||||
"List deleted" : "Liste silindi",
|
"List deleted" : "Liste silindi",
|
||||||
@@ -260,7 +258,6 @@
|
|||||||
"Shared with you" : "Sizinle paylaşıldı",
|
"Shared with you" : "Sizinle paylaşıldı",
|
||||||
"Deck settings" : "Tahta ayarları",
|
"Deck settings" : "Tahta ayarları",
|
||||||
"Use bigger card view" : "Daha büyük kart görünümü kullanılsın",
|
"Use bigger card view" : "Daha büyük kart görünümü kullanılsın",
|
||||||
"Show card ID badge" : "Kart kodu etiketi görüntülensin",
|
|
||||||
"Show boards in calendar/tasks" : "Takvimler ve görevlerde panolar görüntülensin",
|
"Show boards in calendar/tasks" : "Takvimler ve görevlerde panolar görüntülensin",
|
||||||
"Limit deck usage of groups" : "Tahtayı şu gruplar kullanabilsin",
|
"Limit deck usage of groups" : "Tahtayı şu gruplar kullanabilsin",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Tahta kullanımı gruplar ile sınırlandığında belirtilen grupların üyesi olmayan kişiler kendi tahtalarını oluşturamaz. Bu kullanıcılar ancak kendileri ile paylaşılan tahtalar üzerinde çalışabilir.",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Tahta kullanımı gruplar ile sınırlandığında belirtilen grupların üyesi olmayan kişiler kendi tahtalarını oluşturamaz. Bu kullanıcılar ancak kendileri ile paylaşılan tahtalar üzerinde çalışabilir.",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ OC.L10N.register(
|
|||||||
"{user} has shared the board {board} with {acl}" : "{user} поділився дошкою {board} з {acl}",
|
"{user} has shared the board {board} with {acl}" : "{user} поділився дошкою {board} з {acl}",
|
||||||
"You have removed {acl} from the board {board}" : "Ви вилучили {acl} з дошки {board}",
|
"You have removed {acl} from the board {board}" : "Ви вилучили {acl} з дошки {board}",
|
||||||
"{user} has removed {acl} from the board {board}" : "{user} вилучив {acl} з дошки {board}",
|
"{user} has removed {acl} from the board {board}" : "{user} вилучив {acl} з дошки {board}",
|
||||||
"You have renamed the board {before} to {board}" : "Ви перейменували дошку з {before} на {board}",
|
"You have renamed the board {before} to {board}" : "Ви перейменували дошку з {before} у {board}",
|
||||||
"{user} has renamed the board {before} to {board}" : "{user} змінив назву дошки {before} на {board}",
|
"{user} has renamed the board {before} to {board}" : "{user} змінив назву дошки {before} на {board}",
|
||||||
"You have archived the board {board}" : "Ви заархівували дошку {board}",
|
"You have archived the board {board}" : "Ви заархівували дошку {board}",
|
||||||
"{user} has archived the board {before}" : "{user} заархівував дошку {before}",
|
"{user} has archived the board {before}" : "{user} заархівував дошку {before}",
|
||||||
@@ -190,7 +190,7 @@ OC.L10N.register(
|
|||||||
"Something went wrong" : "От халепа!",
|
"Something went wrong" : "От халепа!",
|
||||||
"Maximum file size of {size} exceeded" : "Досягнуто максимальний розмір файлу {size}",
|
"Maximum file size of {size} exceeded" : "Досягнуто максимальний розмір файлу {size}",
|
||||||
"Error creating the share" : "Помилка створення спільного доступу",
|
"Error creating the share" : "Помилка створення спільного доступу",
|
||||||
"Share" : "Спільний доступ",
|
"Share" : "Поділитися",
|
||||||
"This week" : "Цього тижня"
|
"This week" : "Цього тижня"
|
||||||
},
|
},
|
||||||
"nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);");
|
"nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);");
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
"{user} has shared the board {board} with {acl}" : "{user} поділився дошкою {board} з {acl}",
|
"{user} has shared the board {board} with {acl}" : "{user} поділився дошкою {board} з {acl}",
|
||||||
"You have removed {acl} from the board {board}" : "Ви вилучили {acl} з дошки {board}",
|
"You have removed {acl} from the board {board}" : "Ви вилучили {acl} з дошки {board}",
|
||||||
"{user} has removed {acl} from the board {board}" : "{user} вилучив {acl} з дошки {board}",
|
"{user} has removed {acl} from the board {board}" : "{user} вилучив {acl} з дошки {board}",
|
||||||
"You have renamed the board {before} to {board}" : "Ви перейменували дошку з {before} на {board}",
|
"You have renamed the board {before} to {board}" : "Ви перейменували дошку з {before} у {board}",
|
||||||
"{user} has renamed the board {before} to {board}" : "{user} змінив назву дошки {before} на {board}",
|
"{user} has renamed the board {before} to {board}" : "{user} змінив назву дошки {before} на {board}",
|
||||||
"You have archived the board {board}" : "Ви заархівували дошку {board}",
|
"You have archived the board {board}" : "Ви заархівували дошку {board}",
|
||||||
"{user} has archived the board {before}" : "{user} заархівував дошку {before}",
|
"{user} has archived the board {before}" : "{user} заархівував дошку {before}",
|
||||||
@@ -188,7 +188,7 @@
|
|||||||
"Something went wrong" : "От халепа!",
|
"Something went wrong" : "От халепа!",
|
||||||
"Maximum file size of {size} exceeded" : "Досягнуто максимальний розмір файлу {size}",
|
"Maximum file size of {size} exceeded" : "Досягнуто максимальний розмір файлу {size}",
|
||||||
"Error creating the share" : "Помилка створення спільного доступу",
|
"Error creating the share" : "Помилка створення спільного доступу",
|
||||||
"Share" : "Спільний доступ",
|
"Share" : "Поділитися",
|
||||||
"This week" : "Цього тижня"
|
"This week" : "Цього тижня"
|
||||||
},"pluralForm" :"nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);"
|
},"pluralForm" :"nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);"
|
||||||
}
|
}
|
||||||
@@ -183,10 +183,8 @@ OC.L10N.register(
|
|||||||
"Failed to transfer the board to {user}" : "未能將面板轉移給 {user}",
|
"Failed to transfer the board to {user}" : "未能將面板轉移給 {user}",
|
||||||
"Add a new list" : "添加一張新清單",
|
"Add a new list" : "添加一張新清單",
|
||||||
"Archive all cards" : "封存所有卡片",
|
"Archive all cards" : "封存所有卡片",
|
||||||
"Unarchive all cards" : "解除封存所有卡片",
|
|
||||||
"Delete list" : "刪除清單",
|
"Delete list" : "刪除清單",
|
||||||
"Archive all cards in this list" : "封存此清單內的所有卡片",
|
"Archive all cards in this list" : "封存此清單內的所有卡片",
|
||||||
"Unarchive all cards in this list" : "解除封存所有此列表中的卡片",
|
|
||||||
"Add a new card" : "添加一張新卡片",
|
"Add a new card" : "添加一張新卡片",
|
||||||
"Card name" : "卡片名稱",
|
"Card name" : "卡片名稱",
|
||||||
"List deleted" : "清單已被刪除",
|
"List deleted" : "清單已被刪除",
|
||||||
@@ -262,7 +260,6 @@ OC.L10N.register(
|
|||||||
"Shared with you" : "收到的分享",
|
"Shared with you" : "收到的分享",
|
||||||
"Deck settings" : "看板設定",
|
"Deck settings" : "看板設定",
|
||||||
"Use bigger card view" : "使用較大的卡片視圖",
|
"Use bigger card view" : "使用較大的卡片視圖",
|
||||||
"Show card ID badge" : "顯示卡片 ID 徽章",
|
|
||||||
"Show boards in calendar/tasks" : "在日曆/任務中顯示面板",
|
"Show boards in calendar/tasks" : "在日曆/任務中顯示面板",
|
||||||
"Limit deck usage of groups" : "限制群組使用 Deck",
|
"Limit deck usage of groups" : "限制群組使用 Deck",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "限制 Deck 將阻止不屬於這些群組的用戶創建自己的面板。用戶仍然可以在與他們的面板上工作。",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "限制 Deck 將阻止不屬於這些群組的用戶創建自己的面板。用戶仍然可以在與他們的面板上工作。",
|
||||||
|
|||||||
@@ -181,10 +181,8 @@
|
|||||||
"Failed to transfer the board to {user}" : "未能將面板轉移給 {user}",
|
"Failed to transfer the board to {user}" : "未能將面板轉移給 {user}",
|
||||||
"Add a new list" : "添加一張新清單",
|
"Add a new list" : "添加一張新清單",
|
||||||
"Archive all cards" : "封存所有卡片",
|
"Archive all cards" : "封存所有卡片",
|
||||||
"Unarchive all cards" : "解除封存所有卡片",
|
|
||||||
"Delete list" : "刪除清單",
|
"Delete list" : "刪除清單",
|
||||||
"Archive all cards in this list" : "封存此清單內的所有卡片",
|
"Archive all cards in this list" : "封存此清單內的所有卡片",
|
||||||
"Unarchive all cards in this list" : "解除封存所有此列表中的卡片",
|
|
||||||
"Add a new card" : "添加一張新卡片",
|
"Add a new card" : "添加一張新卡片",
|
||||||
"Card name" : "卡片名稱",
|
"Card name" : "卡片名稱",
|
||||||
"List deleted" : "清單已被刪除",
|
"List deleted" : "清單已被刪除",
|
||||||
@@ -260,7 +258,6 @@
|
|||||||
"Shared with you" : "收到的分享",
|
"Shared with you" : "收到的分享",
|
||||||
"Deck settings" : "看板設定",
|
"Deck settings" : "看板設定",
|
||||||
"Use bigger card view" : "使用較大的卡片視圖",
|
"Use bigger card view" : "使用較大的卡片視圖",
|
||||||
"Show card ID badge" : "顯示卡片 ID 徽章",
|
|
||||||
"Show boards in calendar/tasks" : "在日曆/任務中顯示面板",
|
"Show boards in calendar/tasks" : "在日曆/任務中顯示面板",
|
||||||
"Limit deck usage of groups" : "限制群組使用 Deck",
|
"Limit deck usage of groups" : "限制群組使用 Deck",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "限制 Deck 將阻止不屬於這些群組的用戶創建自己的面板。用戶仍然可以在與他們的面板上工作。",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "限制 Deck 將阻止不屬於這些群組的用戶創建自己的面板。用戶仍然可以在與他們的面板上工作。",
|
||||||
|
|||||||
@@ -183,10 +183,8 @@ OC.L10N.register(
|
|||||||
"Failed to transfer the board to {user}" : "轉移看板給 {user} 失敗",
|
"Failed to transfer the board to {user}" : "轉移看板給 {user} 失敗",
|
||||||
"Add a new list" : "新增列表",
|
"Add a new list" : "新增列表",
|
||||||
"Archive all cards" : "封存所有卡片",
|
"Archive all cards" : "封存所有卡片",
|
||||||
"Unarchive all cards" : "解除封存所有卡片",
|
|
||||||
"Delete list" : "刪除列表",
|
"Delete list" : "刪除列表",
|
||||||
"Archive all cards in this list" : "封存此列表中的所有卡片",
|
"Archive all cards in this list" : "封存此列表中的所有卡片",
|
||||||
"Unarchive all cards in this list" : "解除封存所有此列表中的卡片",
|
|
||||||
"Add a new card" : "新增卡片",
|
"Add a new card" : "新增卡片",
|
||||||
"Card name" : "卡片名稱",
|
"Card name" : "卡片名稱",
|
||||||
"List deleted" : "列表已刪除",
|
"List deleted" : "列表已刪除",
|
||||||
@@ -262,7 +260,6 @@ OC.L10N.register(
|
|||||||
"Shared with you" : "與您分享",
|
"Shared with you" : "與您分享",
|
||||||
"Deck settings" : "Deck 設定",
|
"Deck settings" : "Deck 設定",
|
||||||
"Use bigger card view" : "使用較大的卡片檢視",
|
"Use bigger card view" : "使用較大的卡片檢視",
|
||||||
"Show card ID badge" : "顯示卡片 ID 徽章",
|
|
||||||
"Show boards in calendar/tasks" : "在日曆/工作項目中顯示佈告欄",
|
"Show boards in calendar/tasks" : "在日曆/工作項目中顯示佈告欄",
|
||||||
"Limit deck usage of groups" : "限制群組的 Deck 使用",
|
"Limit deck usage of groups" : "限制群組的 Deck 使用",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "限制 Deck 將會阻止不屬於這些群組的使用者建立自己的佈告欄。使用者仍然可以在與他們分享的佈告欄上工作。",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "限制 Deck 將會阻止不屬於這些群組的使用者建立自己的佈告欄。使用者仍然可以在與他們分享的佈告欄上工作。",
|
||||||
|
|||||||
@@ -181,10 +181,8 @@
|
|||||||
"Failed to transfer the board to {user}" : "轉移看板給 {user} 失敗",
|
"Failed to transfer the board to {user}" : "轉移看板給 {user} 失敗",
|
||||||
"Add a new list" : "新增列表",
|
"Add a new list" : "新增列表",
|
||||||
"Archive all cards" : "封存所有卡片",
|
"Archive all cards" : "封存所有卡片",
|
||||||
"Unarchive all cards" : "解除封存所有卡片",
|
|
||||||
"Delete list" : "刪除列表",
|
"Delete list" : "刪除列表",
|
||||||
"Archive all cards in this list" : "封存此列表中的所有卡片",
|
"Archive all cards in this list" : "封存此列表中的所有卡片",
|
||||||
"Unarchive all cards in this list" : "解除封存所有此列表中的卡片",
|
|
||||||
"Add a new card" : "新增卡片",
|
"Add a new card" : "新增卡片",
|
||||||
"Card name" : "卡片名稱",
|
"Card name" : "卡片名稱",
|
||||||
"List deleted" : "列表已刪除",
|
"List deleted" : "列表已刪除",
|
||||||
@@ -260,7 +258,6 @@
|
|||||||
"Shared with you" : "與您分享",
|
"Shared with you" : "與您分享",
|
||||||
"Deck settings" : "Deck 設定",
|
"Deck settings" : "Deck 設定",
|
||||||
"Use bigger card view" : "使用較大的卡片檢視",
|
"Use bigger card view" : "使用較大的卡片檢視",
|
||||||
"Show card ID badge" : "顯示卡片 ID 徽章",
|
|
||||||
"Show boards in calendar/tasks" : "在日曆/工作項目中顯示佈告欄",
|
"Show boards in calendar/tasks" : "在日曆/工作項目中顯示佈告欄",
|
||||||
"Limit deck usage of groups" : "限制群組的 Deck 使用",
|
"Limit deck usage of groups" : "限制群組的 Deck 使用",
|
||||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "限制 Deck 將會阻止不屬於這些群組的使用者建立自己的佈告欄。使用者仍然可以在與他們分享的佈告欄上工作。",
|
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "限制 Deck 將會阻止不屬於這些群組的使用者建立自己的佈告欄。使用者仍然可以在與他們分享的佈告欄上工作。",
|
||||||
|
|||||||
@@ -45,7 +45,9 @@ use OCP\AppFramework\Db\DoesNotExistException;
|
|||||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||||
use OCP\Comments\IComment;
|
use OCP\Comments\IComment;
|
||||||
use OCP\IUser;
|
use OCP\IUser;
|
||||||
|
use OCP\Server;
|
||||||
use OCP\L10N\IFactory;
|
use OCP\L10N\IFactory;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
class ActivityManager {
|
class ActivityManager {
|
||||||
public const DECK_NOAUTHOR_COMMENT_SYSTEM_ENFORCED = 'DECK_NOAUTHOR_COMMENT_SYSTEM_ENFORCED';
|
public const DECK_NOAUTHOR_COMMENT_SYSTEM_ENFORCED = 'DECK_NOAUTHOR_COMMENT_SYSTEM_ENFORCED';
|
||||||
@@ -53,14 +55,14 @@ class ActivityManager {
|
|||||||
public const SUBJECT_PARAMS_MAX_LENGTH = 4000;
|
public const SUBJECT_PARAMS_MAX_LENGTH = 4000;
|
||||||
public const SHORTENED_DESCRIPTION_MAX_LENGTH = 2000;
|
public const SHORTENED_DESCRIPTION_MAX_LENGTH = 2000;
|
||||||
|
|
||||||
private $manager;
|
private IManager $manager;
|
||||||
private $userId;
|
private ?string $userId;
|
||||||
private $permissionService;
|
private PermissionService $permissionService;
|
||||||
private $boardMapper;
|
private BoardMapper $boardMapper;
|
||||||
private $cardMapper;
|
private CardMapper $cardMapper;
|
||||||
private $aclMapper;
|
private AclMapper $aclMapper;
|
||||||
private $stackMapper;
|
private StackMapper $stackMapper;
|
||||||
private $l10nFactory;
|
private IFactory $l10nFactory;
|
||||||
|
|
||||||
public const DECK_OBJECT_BOARD = 'deck_board';
|
public const DECK_OBJECT_BOARD = 'deck_board';
|
||||||
public const DECK_OBJECT_CARD = 'deck_card';
|
public const DECK_OBJECT_CARD = 'deck_card';
|
||||||
@@ -114,7 +116,7 @@ class ActivityManager {
|
|||||||
StackMapper $stackMapper,
|
StackMapper $stackMapper,
|
||||||
AclMapper $aclMapper,
|
AclMapper $aclMapper,
|
||||||
IFactory $l10nFactory,
|
IFactory $l10nFactory,
|
||||||
$userId
|
?string $userId
|
||||||
) {
|
) {
|
||||||
$this->manager = $manager;
|
$this->manager = $manager;
|
||||||
$this->permissionService = $permissionsService;
|
$this->permissionService = $permissionsService;
|
||||||
@@ -310,10 +312,10 @@ class ActivityManager {
|
|||||||
try {
|
try {
|
||||||
$object = $this->findObjectForEntity($objectType, $entity);
|
$object = $this->findObjectForEntity($objectType, $entity);
|
||||||
} catch (DoesNotExistException $e) {
|
} catch (DoesNotExistException $e) {
|
||||||
\OC::$server->getLogger()->error('Could not create activity entry for ' . $subject . '. Entity not found.', (array)$entity);
|
Server::get(LoggerInterface::class)->error('Could not create activity entry for ' . $subject . '. Entity not found.', (array)$entity);
|
||||||
return null;
|
return null;
|
||||||
} catch (MultipleObjectsReturnedException $e) {
|
} catch (MultipleObjectsReturnedException $e) {
|
||||||
\OC::$server->getLogger()->error('Could not create activity entry for ' . $subject . '. Entity not found.', (array)$entity);
|
Server::get(LoggerInterface::class)->error('Could not create activity entry for ' . $subject . '. Entity not found.', (array)$entity);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,7 +367,15 @@ class ActivityManager {
|
|||||||
case self::SUBJECT_CARD_USER_ASSIGN:
|
case self::SUBJECT_CARD_USER_ASSIGN:
|
||||||
case self::SUBJECT_CARD_USER_UNASSIGN:
|
case self::SUBJECT_CARD_USER_UNASSIGN:
|
||||||
$subjectParams = $this->findDetailsForCard($entity->getId(), $subject);
|
$subjectParams = $this->findDetailsForCard($entity->getId(), $subject);
|
||||||
break;
|
|
||||||
|
if (isset($additionalParams['after']) && $additionalParams['after'] instanceof \DateTimeInterface) {
|
||||||
|
$additionalParams['after'] = $additionalParams['after']->format('c');
|
||||||
|
}
|
||||||
|
if (isset($additionalParams['before']) && $additionalParams['before'] instanceof \DateTimeInterface) {
|
||||||
|
$additionalParams['before'] = $additionalParams['before']->format('c');
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
case self::SUBJECT_ATTACHMENT_CREATE:
|
case self::SUBJECT_ATTACHMENT_CREATE:
|
||||||
case self::SUBJECT_ATTACHMENT_UPDATE:
|
case self::SUBJECT_ATTACHMENT_UPDATE:
|
||||||
case self::SUBJECT_ATTACHMENT_DELETE:
|
case self::SUBJECT_ATTACHMENT_DELETE:
|
||||||
|
|||||||
@@ -312,12 +312,19 @@ class DeckProvider implements IProvider {
|
|||||||
$userLanguage = $this->config->getUserValue($event->getAuthor(), 'core', 'lang', $this->l10nFactory->findLanguage());
|
$userLanguage = $this->config->getUserValue($event->getAuthor(), 'core', 'lang', $this->l10nFactory->findLanguage());
|
||||||
$userLocale = $this->config->getUserValue($event->getAuthor(), 'core', 'locale', $this->l10nFactory->findLocale());
|
$userLocale = $this->config->getUserValue($event->getAuthor(), 'core', 'locale', $this->l10nFactory->findLocale());
|
||||||
$l10n = $this->l10nFactory->get('deck', $userLanguage, $userLocale);
|
$l10n = $this->l10nFactory->get('deck', $userLanguage, $userLocale);
|
||||||
$date = new \DateTime($subjectParams['after']);
|
if (is_array($subjectParams['after'])) {
|
||||||
$date->setTimezone(new \DateTimeZone(\date_default_timezone_get()));
|
// Unluckily there was a time when we stored jsonSerialized date objects in the database
|
||||||
|
// Broken in 1.8.0 and fixed again in 1.8.1
|
||||||
|
$date = new \DateTime($subjectParams['after']['date']);
|
||||||
|
$date->setTimezone(new \DateTimeZone(\date_default_timezone_get()));
|
||||||
|
} else {
|
||||||
|
$date = new \DateTime($subjectParams['after']);
|
||||||
|
$date->setTimezone(new \DateTimeZone(\date_default_timezone_get()));
|
||||||
|
}
|
||||||
$params['after'] = [
|
$params['after'] = [
|
||||||
'type' => 'highlight',
|
'type' => 'highlight',
|
||||||
'id' => 'dt:' . $subjectParams['after'],
|
'id' => 'dt:' . $subjectParams['after'],
|
||||||
'name' => $l10n->l('datetime', $date)
|
'name' => $l10n->l('datetime', $date),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
return $params;
|
return $params;
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ use OCA\Deck\Listeners\FullTextSearchEventListener;
|
|||||||
use OCA\Deck\Middleware\DefaultBoardMiddleware;
|
use OCA\Deck\Middleware\DefaultBoardMiddleware;
|
||||||
use OCA\Deck\Middleware\ExceptionMiddleware;
|
use OCA\Deck\Middleware\ExceptionMiddleware;
|
||||||
use OCA\Deck\Notification\Notifier;
|
use OCA\Deck\Notification\Notifier;
|
||||||
|
use OCA\Deck\Reference\CardReferenceProvider;
|
||||||
use OCA\Deck\Search\CardCommentProvider;
|
use OCA\Deck\Search\CardCommentProvider;
|
||||||
use OCA\Deck\Search\DeckProvider;
|
use OCA\Deck\Search\DeckProvider;
|
||||||
use OCA\Deck\Service\PermissionService;
|
use OCA\Deck\Service\PermissionService;
|
||||||
@@ -57,20 +58,22 @@ use OCP\AppFramework\Bootstrap\IBootContext;
|
|||||||
use OCP\AppFramework\Bootstrap\IBootstrap;
|
use OCP\AppFramework\Bootstrap\IBootstrap;
|
||||||
use OCP\AppFramework\Bootstrap\IRegistrationContext;
|
use OCP\AppFramework\Bootstrap\IRegistrationContext;
|
||||||
use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent;
|
use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent;
|
||||||
|
use OCP\Collaboration\Reference\RenderReferenceEvent;
|
||||||
use OCP\Collaboration\Resources\IProviderManager;
|
use OCP\Collaboration\Resources\IProviderManager;
|
||||||
use OCP\Comments\CommentsEntityEvent;
|
use OCP\Comments\CommentsEntityEvent;
|
||||||
use OCP\Comments\ICommentsManager;
|
use OCP\Comments\ICommentsManager;
|
||||||
use OCP\EventDispatcher\Event;
|
use OCP\EventDispatcher\Event;
|
||||||
use OCP\EventDispatcher\IEventDispatcher;
|
use OCP\EventDispatcher\IEventDispatcher;
|
||||||
|
use OCP\Group\Events\GroupDeletedEvent;
|
||||||
use OCP\IConfig;
|
use OCP\IConfig;
|
||||||
use OCP\IDBConnection;
|
use OCP\IDBConnection;
|
||||||
use OCP\IGroup;
|
|
||||||
use OCP\IGroupManager;
|
use OCP\IGroupManager;
|
||||||
use OCP\IServerContainer;
|
use OCP\IRequest;
|
||||||
use OCP\IUser;
|
use OCP\Server;
|
||||||
use OCP\IUserManager;
|
use OCP\IUserManager;
|
||||||
use OCP\Notification\IManager as NotificationManager;
|
use OCP\Notification\IManager as NotificationManager;
|
||||||
use OCP\Share\IManager;
|
use OCP\Share\IManager;
|
||||||
|
use OCP\User\Events\UserDeletedEvent;
|
||||||
use OCP\Util;
|
use OCP\Util;
|
||||||
use Psr\Container\ContainerInterface;
|
use Psr\Container\ContainerInterface;
|
||||||
|
|
||||||
@@ -79,13 +82,16 @@ class Application extends App implements IBootstrap {
|
|||||||
|
|
||||||
public const COMMENT_ENTITY_TYPE = 'deckCard';
|
public const COMMENT_ENTITY_TYPE = 'deckCard';
|
||||||
|
|
||||||
/** @var IServerContainer */
|
|
||||||
private $server;
|
|
||||||
|
|
||||||
public function __construct(array $urlParams = []) {
|
public function __construct(array $urlParams = []) {
|
||||||
parent::__construct(self::APP_ID, $urlParams);
|
parent::__construct(self::APP_ID, $urlParams);
|
||||||
|
|
||||||
$this->server = \OC::$server;
|
// TODO move this back to ::register after fixing the autoload issue
|
||||||
|
// (and use a listener class)
|
||||||
|
$container = $this->getContainer();
|
||||||
|
$eventDispatcher = $container->get(IEventDispatcher::class);
|
||||||
|
$eventDispatcher->addListener(RenderReferenceEvent::class, function () {
|
||||||
|
Util::addScript(self::APP_ID, self::APP_ID . '-card-reference');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function boot(IBootContext $context): void {
|
public function boot(IBootContext $context): void {
|
||||||
@@ -124,8 +130,12 @@ class Application extends App implements IBootstrap {
|
|||||||
$context->registerSearchProvider(CardCommentProvider::class);
|
$context->registerSearchProvider(CardCommentProvider::class);
|
||||||
$context->registerDashboardWidget(DeckWidget::class);
|
$context->registerDashboardWidget(DeckWidget::class);
|
||||||
|
|
||||||
|
// reference widget
|
||||||
|
$context->registerReferenceProvider(CardReferenceProvider::class);
|
||||||
|
// $context->registerEventListener(RenderReferenceEvent::class, CardReferenceListener::class);
|
||||||
|
|
||||||
$context->registerEventListener(BeforeTemplateRenderedEvent::class, BeforeTemplateRenderedListener::class);
|
$context->registerEventListener(BeforeTemplateRenderedEvent::class, BeforeTemplateRenderedListener::class);
|
||||||
|
|
||||||
// Event listening for full text search indexing
|
// Event listening for full text search indexing
|
||||||
$context->registerEventListener(CardCreatedEvent::class, FullTextSearchEventListener::class);
|
$context->registerEventListener(CardCreatedEvent::class, FullTextSearchEventListener::class);
|
||||||
$context->registerEventListener(CardUpdatedEvent::class, FullTextSearchEventListener::class);
|
$context->registerEventListener(CardUpdatedEvent::class, FullTextSearchEventListener::class);
|
||||||
@@ -141,33 +151,43 @@ class Application extends App implements IBootstrap {
|
|||||||
|
|
||||||
private function registerUserGroupHooks(IUserManager $userManager, IGroupManager $groupManager): void {
|
private function registerUserGroupHooks(IUserManager $userManager, IGroupManager $groupManager): void {
|
||||||
$container = $this->getContainer();
|
$container = $this->getContainer();
|
||||||
|
/** @var IEventDispatcher $eventDispatcher */
|
||||||
|
$eventDispatcher = $container->get(IEventDispatcher::class);
|
||||||
// Delete user/group acl entries when they get deleted
|
// Delete user/group acl entries when they get deleted
|
||||||
$userManager->listen('\OC\User', 'postDelete', static function (IUser $user) use ($container) {
|
$eventDispatcher->addListener(UserDeletedEvent::class, static function (Event $event) use ($container): void {
|
||||||
|
if (!($event instanceof UserDeletedEvent)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$user = $event->getUser();
|
||||||
// delete existing acl entries for deleted user
|
// delete existing acl entries for deleted user
|
||||||
/** @var AclMapper $aclMapper */
|
/** @var AclMapper $aclMapper */
|
||||||
$aclMapper = $container->query(AclMapper::class);
|
$aclMapper = $container->get(AclMapper::class);
|
||||||
$acls = $aclMapper->findByParticipant(Acl::PERMISSION_TYPE_USER, $user->getUID());
|
$acls = $aclMapper->findByParticipant(Acl::PERMISSION_TYPE_USER, $user->getUID());
|
||||||
foreach ($acls as $acl) {
|
foreach ($acls as $acl) {
|
||||||
$aclMapper->delete($acl);
|
$aclMapper->delete($acl);
|
||||||
}
|
}
|
||||||
// delete existing user assignments
|
// delete existing user assignments
|
||||||
$assignmentMapper = $container->query(AssignmentMapper::class);
|
$assignmentMapper = $container->get(AssignmentMapper::class);
|
||||||
$assignments = $assignmentMapper->findByParticipant($user->getUID());
|
$assignments = $assignmentMapper->findByParticipant($user->getUID());
|
||||||
foreach ($assignments as $assignment) {
|
foreach ($assignments as $assignment) {
|
||||||
$assignmentMapper->delete($assignment);
|
$assignmentMapper->delete($assignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var BoardMapper $boardMapper */
|
/** @var BoardMapper $boardMapper */
|
||||||
$boardMapper = $container->query(BoardMapper::class);
|
$boardMapper = $container->get(BoardMapper::class);
|
||||||
$boards = $boardMapper->findAllByOwner($user->getUID());
|
$boards = $boardMapper->findAllByOwner($user->getUID());
|
||||||
foreach ($boards as $board) {
|
foreach ($boards as $board) {
|
||||||
$boardMapper->delete($board);
|
$boardMapper->delete($board);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$groupManager->listen('\OC\Group', 'postDelete', static function (IGroup $group) use ($container) {
|
$eventDispatcher->addListener(GroupDeletedEvent::class, static function (Event $event) use ($container): void {
|
||||||
|
if (!($event instanceof GroupDeletedEvent)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$group = $event->getGroup();
|
||||||
/** @var AclMapper $aclMapper */
|
/** @var AclMapper $aclMapper */
|
||||||
$aclMapper = $container->query(AclMapper::class);
|
$aclMapper = $container->get(AclMapper::class);
|
||||||
$aclMapper->findByParticipant(Acl::PERMISSION_TYPE_GROUP, $group->getGID());
|
$aclMapper->findByParticipant(Acl::PERMISSION_TYPE_GROUP, $group->getGID());
|
||||||
$acls = $aclMapper->findByParticipant(Acl::PERMISSION_TYPE_GROUP, $group->getGID());
|
$acls = $aclMapper->findByParticipant(Acl::PERMISSION_TYPE_GROUP, $group->getGID());
|
||||||
foreach ($acls as $acl) {
|
foreach ($acls as $acl) {
|
||||||
@@ -181,6 +201,7 @@ class Application extends App implements IBootstrap {
|
|||||||
$event->addEntityCollection(self::COMMENT_ENTITY_TYPE, function ($name) {
|
$event->addEntityCollection(self::COMMENT_ENTITY_TYPE, function ($name) {
|
||||||
/** @var CardMapper */
|
/** @var CardMapper */
|
||||||
$cardMapper = $this->getContainer()->get(CardMapper::class);
|
$cardMapper = $this->getContainer()->get(CardMapper::class);
|
||||||
|
/** @var PermissionService $permissionService */
|
||||||
$permissionService = $this->getContainer()->get(PermissionService::class);
|
$permissionService = $this->getContainer()->get(PermissionService::class);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -203,7 +224,7 @@ class Application extends App implements IBootstrap {
|
|||||||
$resourceManager->registerResourceProvider(ResourceProviderCard::class);
|
$resourceManager->registerResourceProvider(ResourceProviderCard::class);
|
||||||
|
|
||||||
$symfonyAdapter->addListener('\OCP\Collaboration\Resources::loadAdditionalScripts', static function () {
|
$symfonyAdapter->addListener('\OCP\Collaboration\Resources::loadAdditionalScripts', static function () {
|
||||||
if (strpos(\OC::$server->getRequest()->getPathInfo(), '/call/') === 0) {
|
if (strpos(Server::get(IRequest::class)->getPathInfo(), '/call/') === 0) {
|
||||||
// Talk integration has its own entrypoint which already includes collections handling
|
// Talk integration has its own entrypoint which already includes collections handling
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,20 +32,23 @@ use OCP\AppFramework\QueryException;
|
|||||||
use OCP\Collaboration\Resources\IManager;
|
use OCP\Collaboration\Resources\IManager;
|
||||||
use OCP\Collaboration\Resources\IProvider;
|
use OCP\Collaboration\Resources\IProvider;
|
||||||
use OCP\Collaboration\Resources\IResource;
|
use OCP\Collaboration\Resources\IResource;
|
||||||
|
use OCP\IURLGenerator;
|
||||||
use OCP\IUser;
|
use OCP\IUser;
|
||||||
|
use OCP\Server;
|
||||||
|
|
||||||
class ResourceProvider implements IProvider {
|
class ResourceProvider implements IProvider {
|
||||||
public const RESOURCE_TYPE = 'deck';
|
public const RESOURCE_TYPE = 'deck';
|
||||||
|
|
||||||
private $boardMapper;
|
private BoardMapper $boardMapper;
|
||||||
private $permissionService;
|
private PermissionService $permissionService;
|
||||||
|
private IURLGenerator $urlGenerator;
|
||||||
|
|
||||||
/** @var array */
|
protected array $nodes = [];
|
||||||
protected $nodes = [];
|
|
||||||
|
|
||||||
public function __construct(BoardMapper $boardMapper, PermissionService $permissionService) {
|
public function __construct(BoardMapper $boardMapper, PermissionService $permissionService, IURLGenerator $urlGenerator) {
|
||||||
$this->boardMapper = $boardMapper;
|
$this->boardMapper = $boardMapper;
|
||||||
$this->permissionService = $permissionService;
|
$this->permissionService = $permissionService;
|
||||||
|
$this->urlGenerator = $urlGenerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,14 +73,14 @@ class ResourceProvider implements IProvider {
|
|||||||
*/
|
*/
|
||||||
public function getResourceRichObject(IResource $resource): array {
|
public function getResourceRichObject(IResource $resource): array {
|
||||||
$board = $this->getBoard($resource);
|
$board = $this->getBoard($resource);
|
||||||
$link = \OC::$server->getURLGenerator()->linkToRoute('deck.page.index') . '#/board/' . $resource->getId();
|
$link = $this->urlGenerator->linkToRoute('deck.page.index') . '#/board/' . $resource->getId();
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'type' => self::RESOURCE_TYPE,
|
'type' => self::RESOURCE_TYPE,
|
||||||
'id' => $resource->getId(),
|
'id' => $resource->getId(),
|
||||||
'name' => $board->getTitle(),
|
'name' => $board->getTitle(),
|
||||||
'link' => $link,
|
'link' => $link,
|
||||||
'iconUrl' => \OC::$server->getURLGenerator()->imagePath('deck', 'deck-dark.svg')
|
'iconUrl' => $this->urlGenerator->imagePath('deck', 'deck-dark.svg')
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +121,7 @@ class ResourceProvider implements IProvider {
|
|||||||
public function invalidateAccessCache($boardId = null) {
|
public function invalidateAccessCache($boardId = null) {
|
||||||
try {
|
try {
|
||||||
/** @var IManager $resourceManager */
|
/** @var IManager $resourceManager */
|
||||||
$resourceManager = \OC::$server->query(IManager::class);
|
$resourceManager = Server::get(IManager::class);
|
||||||
} catch (QueryException $e) {
|
} catch (QueryException $e) {
|
||||||
}
|
}
|
||||||
if ($boardId !== null) {
|
if ($boardId !== null) {
|
||||||
|
|||||||
@@ -37,24 +37,16 @@ use OCP\Collaboration\Resources\IResource;
|
|||||||
use OCP\Collaboration\Resources\ResourceException;
|
use OCP\Collaboration\Resources\ResourceException;
|
||||||
use OCP\IURLGenerator;
|
use OCP\IURLGenerator;
|
||||||
use OCP\IUser;
|
use OCP\IUser;
|
||||||
|
use OCP\Server;
|
||||||
|
|
||||||
class ResourceProviderCard implements IProvider {
|
class ResourceProviderCard implements IProvider {
|
||||||
public const RESOURCE_TYPE = 'deck-card';
|
public const RESOURCE_TYPE = 'deck-card';
|
||||||
|
|
||||||
/** @var CardMapper */
|
private CardMapper $cardMapper;
|
||||||
private $cardMapper;
|
private BoardMapper $boardMapper;
|
||||||
|
private PermissionService $permissionService;
|
||||||
/** @var BoardMapper */
|
private IURLGenerator $urlGenerator;
|
||||||
private $boardMapper;
|
protected array $nodes = [];
|
||||||
|
|
||||||
/** @var PermissionService */
|
|
||||||
private $permissionService;
|
|
||||||
|
|
||||||
/** @var IURLGenerator */
|
|
||||||
private $urlGenerator;
|
|
||||||
|
|
||||||
/** @var array */
|
|
||||||
protected $nodes = [];
|
|
||||||
|
|
||||||
public function __construct(CardMapper $cardMapper, BoardMapper $boardMapper, PermissionService $permissionService, IURLGenerator $urlGenerator) {
|
public function __construct(CardMapper $cardMapper, BoardMapper $boardMapper, PermissionService $permissionService, IURLGenerator $urlGenerator) {
|
||||||
$this->cardMapper = $cardMapper;
|
$this->cardMapper = $cardMapper;
|
||||||
@@ -147,7 +139,7 @@ class ResourceProviderCard implements IProvider {
|
|||||||
public function invalidateAccessCache($cardId = null) {
|
public function invalidateAccessCache($cardId = null) {
|
||||||
try {
|
try {
|
||||||
/** @var IManager $resourceManager */
|
/** @var IManager $resourceManager */
|
||||||
$resourceManager = \OC::$server->query(IManager::class);
|
$resourceManager = Server::get(IManager::class);
|
||||||
} catch (QueryException $e) {
|
} catch (QueryException $e) {
|
||||||
}
|
}
|
||||||
if ($cardId !== null) {
|
if ($cardId !== null) {
|
||||||
|
|||||||
@@ -30,8 +30,7 @@ use Symfony\Component\Console\Input\InputOption;
|
|||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
class BoardImport extends Command {
|
class BoardImport extends Command {
|
||||||
/** @var BoardImportCommandService */
|
private BoardImportCommandService $boardImportCommandService;
|
||||||
private $boardImportCommandService;
|
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
BoardImportCommandService $boardImportCommandService
|
BoardImportCommandService $boardImportCommandService
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ use OCA\Deck\Db\AssignmentMapper;
|
|||||||
use OCA\Deck\Db\BoardMapper;
|
use OCA\Deck\Db\BoardMapper;
|
||||||
use OCA\Deck\Db\CardMapper;
|
use OCA\Deck\Db\CardMapper;
|
||||||
use OCA\Deck\Db\StackMapper;
|
use OCA\Deck\Db\StackMapper;
|
||||||
|
use OCA\Deck\Model\CardDetails;
|
||||||
use OCA\Deck\Service\BoardService;
|
use OCA\Deck\Service\BoardService;
|
||||||
use OCP\AppFramework\Db\DoesNotExistException;
|
use OCP\AppFramework\Db\DoesNotExistException;
|
||||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||||
@@ -101,7 +102,9 @@ class UserExport extends Command {
|
|||||||
$fullCard = $this->cardMapper->find($card->getId());
|
$fullCard = $this->cardMapper->find($card->getId());
|
||||||
$assignedUsers = $this->assignedUsersMapper->findAll($card->getId());
|
$assignedUsers = $this->assignedUsersMapper->findAll($card->getId());
|
||||||
$fullCard->setAssignedUsers($assignedUsers);
|
$fullCard->setAssignedUsers($assignedUsers);
|
||||||
$data[$board->getId()]['stacks'][$stack->getId()]['cards'][] = (array)$fullCard->jsonSerialize();
|
|
||||||
|
$cardDetails = new CardDetails($fullCard, $fullBoard);
|
||||||
|
$data[$board->getId()]['stacks'][$stack->getId()]['cards'][] = $cardDetails->jsonSerialize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ use OCA\Deck\Service\PermissionService;
|
|||||||
use OCA\Files\Event\LoadSidebar;
|
use OCA\Files\Event\LoadSidebar;
|
||||||
use OCA\Viewer\Event\LoadViewer;
|
use OCA\Viewer\Event\LoadViewer;
|
||||||
use OCP\AppFramework\Http\ContentSecurityPolicy;
|
use OCP\AppFramework\Http\ContentSecurityPolicy;
|
||||||
|
use OCP\Collaboration\Resources\LoadAdditionalScriptsEvent as CollaborationResourcesEvent;
|
||||||
use OCP\EventDispatcher\IEventDispatcher;
|
use OCP\EventDispatcher\IEventDispatcher;
|
||||||
|
use OCP\IConfig;
|
||||||
use OCP\IInitialStateService;
|
use OCP\IInitialStateService;
|
||||||
use OCP\IRequest;
|
use OCP\IRequest;
|
||||||
use OCP\AppFramework\Http\TemplateResponse;
|
use OCP\AppFramework\Http\TemplateResponse;
|
||||||
@@ -41,16 +43,17 @@ use OCA\Deck\Db\Acl;
|
|||||||
use OCA\Deck\Service\CardService;
|
use OCA\Deck\Service\CardService;
|
||||||
|
|
||||||
class PageController extends Controller {
|
class PageController extends Controller {
|
||||||
private $permissionService;
|
private PermissionService $permissionService;
|
||||||
private $initialState;
|
private IInitialStateService $initialState;
|
||||||
private $configService;
|
private ConfigService $configService;
|
||||||
private $eventDispatcher;
|
private IEventDispatcher $eventDispatcher;
|
||||||
private $cardMapper;
|
private CardMapper $cardMapper;
|
||||||
private $urlGenerator;
|
private IURLGenerator $urlGenerator;
|
||||||
private $cardService;
|
private CardService $cardService;
|
||||||
|
private IConfig $config;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
$AppName,
|
string $AppName,
|
||||||
IRequest $request,
|
IRequest $request,
|
||||||
PermissionService $permissionService,
|
PermissionService $permissionService,
|
||||||
IInitialStateService $initialStateService,
|
IInitialStateService $initialStateService,
|
||||||
@@ -58,7 +61,8 @@ class PageController extends Controller {
|
|||||||
IEventDispatcher $eventDispatcher,
|
IEventDispatcher $eventDispatcher,
|
||||||
CardMapper $cardMapper,
|
CardMapper $cardMapper,
|
||||||
IURLGenerator $urlGenerator,
|
IURLGenerator $urlGenerator,
|
||||||
CardService $cardService
|
CardService $cardService,
|
||||||
|
IConfig $config
|
||||||
) {
|
) {
|
||||||
parent::__construct($AppName, $request);
|
parent::__construct($AppName, $request);
|
||||||
|
|
||||||
@@ -69,6 +73,7 @@ class PageController extends Controller {
|
|||||||
$this->cardMapper = $cardMapper;
|
$this->cardMapper = $cardMapper;
|
||||||
$this->urlGenerator = $urlGenerator;
|
$this->urlGenerator = $urlGenerator;
|
||||||
$this->cardService = $cardService;
|
$this->cardService = $cardService;
|
||||||
|
$this->config = $config;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,13 +89,17 @@ class PageController extends Controller {
|
|||||||
$this->initialState->provideInitialState(Application::APP_ID, 'config', $this->configService->getAll());
|
$this->initialState->provideInitialState(Application::APP_ID, 'config', $this->configService->getAll());
|
||||||
|
|
||||||
$this->eventDispatcher->dispatchTyped(new LoadSidebar());
|
$this->eventDispatcher->dispatchTyped(new LoadSidebar());
|
||||||
|
$this->eventDispatcher->dispatchTyped(new CollaborationResourcesEvent());
|
||||||
if (class_exists(LoadViewer::class)) {
|
if (class_exists(LoadViewer::class)) {
|
||||||
$this->eventDispatcher->dispatchTyped(new LoadViewer());
|
$this->eventDispatcher->dispatchTyped(new LoadViewer());
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = new TemplateResponse('deck', 'main');
|
$response = new TemplateResponse('deck', 'main', [
|
||||||
|
'id-app-content' => '#app-content-vue',
|
||||||
|
'id-app-navigation' => '#app-navigation-vue',
|
||||||
|
]);
|
||||||
|
|
||||||
if (\OC::$server->getConfig()->getSystemValueBool('debug', false)) {
|
if ($this->config->getSystemValueBool('debug', false)) {
|
||||||
$csp = new ContentSecurityPolicy();
|
$csp = new ContentSecurityPolicy();
|
||||||
$csp->addAllowedConnectDomain('*');
|
$csp->addAllowedConnectDomain('*');
|
||||||
$csp->addAllowedScriptDomain('*');
|
$csp->addAllowedScriptDomain('*');
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ declare(strict_types=1);
|
|||||||
namespace OCA\Deck\Controller;
|
namespace OCA\Deck\Controller;
|
||||||
|
|
||||||
use OCA\Deck\Db\Card;
|
use OCA\Deck\Db\Card;
|
||||||
|
use OCA\Deck\Model\CardDetails;
|
||||||
use OCA\Deck\Service\SearchService;
|
use OCA\Deck\Service\SearchService;
|
||||||
use OCP\AppFramework\Http\DataResponse;
|
use OCP\AppFramework\Http\DataResponse;
|
||||||
use OCP\AppFramework\OCSController;
|
use OCP\AppFramework\OCSController;
|
||||||
@@ -50,9 +51,12 @@ class SearchController extends OCSController {
|
|||||||
public function search(string $term, ?int $limit = null, ?int $cursor = null): DataResponse {
|
public function search(string $term, ?int $limit = null, ?int $cursor = null): DataResponse {
|
||||||
$cards = $this->searchService->searchCards($term, $limit, $cursor);
|
$cards = $this->searchService->searchCards($term, $limit, $cursor);
|
||||||
return new DataResponse(array_map(function (Card $card) {
|
return new DataResponse(array_map(function (Card $card) {
|
||||||
$json = $card->jsonSerialize();
|
$board = $card->getRelatedBoard();
|
||||||
|
$json = (new CardDetails($card, $board))->jsonSerialize();
|
||||||
|
|
||||||
|
$json['relatedBoard'] = $board;
|
||||||
$json['relatedStack'] = $card->getRelatedStack();
|
$json['relatedStack'] = $card->getRelatedStack();
|
||||||
$json['relatedBoard'] = $card->getRelatedBoard();
|
|
||||||
return $json;
|
return $json;
|
||||||
}, $cards));
|
}, $cards));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,18 +26,34 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace OCA\Deck\Dashboard;
|
namespace OCA\Deck\Dashboard;
|
||||||
|
|
||||||
use OCP\Dashboard\IWidget;
|
use DateTime;
|
||||||
|
use OCA\Deck\AppInfo\Application;
|
||||||
|
use OCA\Deck\Db\Label;
|
||||||
|
use OCA\Deck\Service\OverviewService;
|
||||||
|
use OCP\Dashboard\IAPIWidget;
|
||||||
|
use OCP\Dashboard\IButtonWidget;
|
||||||
|
use OCP\Dashboard\IIconWidget;
|
||||||
|
use OCP\Dashboard\Model\WidgetButton;
|
||||||
|
use OCP\Dashboard\Model\WidgetItem;
|
||||||
|
use OCP\IDateTimeFormatter;
|
||||||
use OCP\IL10N;
|
use OCP\IL10N;
|
||||||
|
use OCP\IURLGenerator;
|
||||||
|
use OCP\Util;
|
||||||
|
|
||||||
class DeckWidget implements IWidget {
|
class DeckWidget implements IAPIWidget, IButtonWidget, IIconWidget {
|
||||||
|
private IL10N $l10n;
|
||||||
|
private OverviewService $dashboardService;
|
||||||
|
private IURLGenerator $urlGenerator;
|
||||||
|
private IDateTimeFormatter $dateTimeFormatter;
|
||||||
|
|
||||||
/**
|
public function __construct(IL10N $l10n,
|
||||||
* @var IL10N
|
OverviewService $dashboardService,
|
||||||
*/
|
IDateTimeFormatter $dateTimeFormatter,
|
||||||
private $l10n;
|
IURLGenerator $urlGenerator) {
|
||||||
|
|
||||||
public function __construct(IL10N $l10n) {
|
|
||||||
$this->l10n = $l10n;
|
$this->l10n = $l10n;
|
||||||
|
$this->dashboardService = $dashboardService;
|
||||||
|
$this->urlGenerator = $urlGenerator;
|
||||||
|
$this->dateTimeFormatter = $dateTimeFormatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -68,17 +84,88 @@ class DeckWidget implements IWidget {
|
|||||||
return 'icon-deck';
|
return 'icon-deck';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getIconUrl(): string {
|
||||||
|
return $this->urlGenerator->getAbsoluteURL(
|
||||||
|
$this->urlGenerator->imagePath(Application::APP_ID, 'deck-dark.svg')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
public function getUrl(): ?string {
|
public function getUrl(): ?string {
|
||||||
return null;
|
return $this->urlGenerator->getAbsoluteURL(
|
||||||
|
$this->urlGenerator->linkToRoute(Application::APP_ID . '.page.index')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
public function load(): void {
|
public function load(): void {
|
||||||
\OCP\Util::addScript('deck', 'deck-dashboard');
|
Util::addScript('deck', 'deck-dashboard');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getItems(string $userId, ?string $since = null, int $limit = 7): array {
|
||||||
|
$upcomingCards = $this->dashboardService->findUpcomingCards($userId);
|
||||||
|
$nowTimestamp = (new Datetime())->getTimestamp();
|
||||||
|
$sinceTimestamp = $since !== null ? (new Datetime($since))->getTimestamp() : null;
|
||||||
|
$upcomingCards = array_filter($upcomingCards, static function (array $card) use ($nowTimestamp, $sinceTimestamp) {
|
||||||
|
if ($card['duedate']) {
|
||||||
|
$ts = (new Datetime($card['duedate']))->getTimestamp();
|
||||||
|
return $ts > $nowTimestamp && ($sinceTimestamp === null || $ts > $sinceTimestamp);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
usort($upcomingCards, static function ($a, $b) {
|
||||||
|
$a = new Datetime($a['duedate']);
|
||||||
|
$ta = $a->getTimestamp();
|
||||||
|
$b = new Datetime($b['duedate']);
|
||||||
|
$tb = $b->getTimestamp();
|
||||||
|
return ($ta > $tb) ? 1 : -1;
|
||||||
|
});
|
||||||
|
$upcomingCards = array_slice($upcomingCards, 0, $limit);
|
||||||
|
$urlGenerator = $this->urlGenerator;
|
||||||
|
$dateTimeFormatter = $this->dateTimeFormatter;
|
||||||
|
return array_map(static function (array $card) use ($urlGenerator, $dateTimeFormatter) {
|
||||||
|
$formattedDueDate = $dateTimeFormatter->formatDateTime(new DateTime($card['duedate']));
|
||||||
|
return new WidgetItem(
|
||||||
|
$card['title'] . ' (' . $formattedDueDate . ')',
|
||||||
|
implode(
|
||||||
|
', ',
|
||||||
|
array_map(static function (Label $label) {
|
||||||
|
return $label->jsonSerialize()['title'];
|
||||||
|
}, $card['labels'])
|
||||||
|
),
|
||||||
|
$urlGenerator->getAbsoluteURL(
|
||||||
|
$urlGenerator->linkToRoute(Application::APP_ID . '.page.redirectToCard', ['cardId' => $card['id']])
|
||||||
|
),
|
||||||
|
$urlGenerator->getAbsoluteURL(
|
||||||
|
$urlGenerator->imagePath(Application::APP_ID, 'deck-dark.svg')
|
||||||
|
),
|
||||||
|
$card['duedate']
|
||||||
|
);
|
||||||
|
}, $upcomingCards);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getWidgetButtons(string $userId): array {
|
||||||
|
return [
|
||||||
|
new WidgetButton(
|
||||||
|
WidgetButton::TYPE_MORE,
|
||||||
|
$this->urlGenerator->getAbsoluteURL(
|
||||||
|
$this->urlGenerator->linkToRoute(Application::APP_ID . '.page.index')
|
||||||
|
),
|
||||||
|
$this->l10n->t('Load more')
|
||||||
|
),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,18 +33,46 @@ class AclMapper extends DeckMapper implements IPermissionMapper {
|
|||||||
parent::__construct($db, 'deck_board_acl', Acl::class);
|
parent::__construct($db, 'deck_board_acl', Acl::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param numeric $boardId
|
||||||
|
* @param int|null $limit
|
||||||
|
* @param int|null $offset
|
||||||
|
* @return Acl[]
|
||||||
|
* @throws \OCP\DB\Exception
|
||||||
|
*/
|
||||||
public function findAll($boardId, $limit = null, $offset = null) {
|
public function findAll($boardId, $limit = null, $offset = null) {
|
||||||
$sql = 'SELECT id, board_id, type, participant, permission_edit, permission_share, permission_manage FROM `*PREFIX*deck_board_acl` WHERE `board_id` = ? ';
|
$qb = $this->db->getQueryBuilder();
|
||||||
return $this->findEntities($sql, [$boardId], $limit, $offset);
|
$qb->select('id', 'board_id', 'type', 'participant', 'permission_edit', 'permission_share', 'permission_manage')
|
||||||
|
->from('deck_board_acl')
|
||||||
|
->where($qb->expr()->eq('board_id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
|
||||||
|
->setMaxResults($limit)
|
||||||
|
->setFirstResult($offset);
|
||||||
|
|
||||||
|
return $this->findEntities($qb);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isOwner($userId, $aclId): bool {
|
/**
|
||||||
$sql = 'SELECT owner FROM `*PREFIX*deck_boards` WHERE `id` IN (SELECT board_id FROM `*PREFIX*deck_board_acl` WHERE id = ?)';
|
* @param numeric $userId
|
||||||
$stmt = $this->execute($sql, [$aclId]);
|
* @param numeric $id
|
||||||
$row = $stmt->fetch();
|
* @return bool
|
||||||
return ($row['owner'] === $userId);
|
* @throws \OCP\DB\Exception
|
||||||
|
*/
|
||||||
|
public function isOwner($userId, $id): bool {
|
||||||
|
$aclId = $id;
|
||||||
|
$qb = $this->db->getQueryBuilder();
|
||||||
|
$qb->select('acl.id')
|
||||||
|
->from($this->getTableName(), 'acl')
|
||||||
|
->innerJoin('acl', 'deck_boards', 'b', 'acl.board_id = b.id')
|
||||||
|
->where($qb->expr()->eq('owner', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)))
|
||||||
|
->andWhere($qb->expr()->eq('acl.id', $qb->createNamedParameter($aclId, IQueryBuilder::PARAM_INT)));
|
||||||
|
|
||||||
|
return count($qb->executeQuery()->fetchAll()) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param numeric $id
|
||||||
|
* @return int|null
|
||||||
|
*/
|
||||||
public function findBoardId($id): ?int {
|
public function findBoardId($id): ?int {
|
||||||
try {
|
try {
|
||||||
$entity = $this->find($id);
|
$entity = $this->find($id);
|
||||||
@@ -54,9 +82,21 @@ class AclMapper extends DeckMapper implements IPermissionMapper {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $type
|
||||||
|
* @param string $participant
|
||||||
|
* @return Acl[]
|
||||||
|
* @throws \OCP\DB\Exception
|
||||||
|
*/
|
||||||
public function findByParticipant($type, $participant): array {
|
public function findByParticipant($type, $participant): array {
|
||||||
$sql = 'SELECT * from *PREFIX*deck_board_acl WHERE type = ? AND participant = ?';
|
$qb = $this->db->getQueryBuilder();
|
||||||
return $this->findEntities($sql, [$type, $participant]);
|
|
||||||
|
$qb->select('*')
|
||||||
|
->from($this->getTableName())
|
||||||
|
->where($qb->expr()->eq('type', $qb->createNamedParameter($type, IQueryBuilder::PARAM_INT)))
|
||||||
|
->andWhere($qb->expr()->eq('participant', $qb->createNamedParameter($participant, IQueryBuilder::PARAM_STR)));
|
||||||
|
|
||||||
|
return $this->findEntities($qb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -55,9 +55,6 @@ class AssignmentMapper extends QBMapper implements IPermissionMapper {
|
|||||||
$this->circleService = $circleService;
|
$this->circleService = $circleService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Assignment[]
|
|
||||||
*/
|
|
||||||
public function findAll(int $cardId): array {
|
public function findAll(int $cardId): array {
|
||||||
$qb = $this->db->getQueryBuilder();
|
$qb = $this->db->getQueryBuilder();
|
||||||
$qb->select('*')
|
$qb->select('*')
|
||||||
@@ -80,8 +77,8 @@ class AssignmentMapper extends QBMapper implements IPermissionMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function isOwner($userId, $cardId): bool {
|
public function isOwner($userId, $id): bool {
|
||||||
return $this->cardMapper->isOwner($userId, $cardId);
|
return $this->cardMapper->isOwner($userId, $id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findBoardId($id): ?int {
|
public function findBoardId($id): ?int {
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
|||||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||||
use OCP\IDBConnection;
|
use OCP\IDBConnection;
|
||||||
use OCP\IUserManager;
|
use OCP\IUserManager;
|
||||||
use PDO;
|
|
||||||
|
|
||||||
class AttachmentMapper extends DeckMapper implements IPermissionMapper {
|
class AttachmentMapper extends DeckMapper implements IPermissionMapper {
|
||||||
private $cardMapper;
|
private $cardMapper;
|
||||||
@@ -52,70 +51,53 @@ class AttachmentMapper extends DeckMapper implements IPermissionMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $id
|
* @param int $id
|
||||||
* @return Entity|Attachment
|
* @return Attachment
|
||||||
* @throws \OCP\AppFramework\Db\DoesNotExistException
|
* @throws DoesNotExistException
|
||||||
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
|
* @throws MultipleObjectsReturnedException
|
||||||
|
* @throws \OCP\DB\Exception
|
||||||
*/
|
*/
|
||||||
public function find($id) {
|
public function find($id) {
|
||||||
$qb = $this->db->getQueryBuilder();
|
$qb = $this->db->getQueryBuilder();
|
||||||
$qb->select('*')
|
$qb->select('*')
|
||||||
->from('deck_attachment')
|
->from($this->getTableName())
|
||||||
->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)));
|
->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)));
|
||||||
|
|
||||||
$cursor = $qb->execute();
|
return $this->findEntity($qb);
|
||||||
$row = $cursor->fetch(PDO::FETCH_ASSOC);
|
}
|
||||||
if ($row === false) {
|
|
||||||
$cursor->closeCursor();
|
/**
|
||||||
throw new DoesNotExistException('Did expect one result but found none when executing query: ' . $qb->getSQL());
|
* @param int $cardId
|
||||||
}
|
* @param string $data
|
||||||
|
* @return Attachment
|
||||||
$row2 = $cursor->fetch();
|
* @throws DoesNotExistException
|
||||||
$cursor->closeCursor();
|
* @throws MultipleObjectsReturnedException
|
||||||
if ($row2 !== false) {
|
* @throws \OCP\DB\Exception
|
||||||
throw new MultipleObjectsReturnedException('Did not expect more than one result when executing query: ' . $qb->getSQL());
|
*/
|
||||||
}
|
public function findByData($cardId, $data) {
|
||||||
|
$qb = $this->db->getQueryBuilder();
|
||||||
return $this->mapRowToEntity($row);
|
$qb->select('*')
|
||||||
}
|
->from($this->getTableName())
|
||||||
|
->where($qb->expr()->eq('card_id', $qb->createNamedParameter($cardId, IQueryBuilder::PARAM_INT)))
|
||||||
public function findByData($cardId, $data) {
|
->andWhere($qb->expr()->eq('data', $qb->createNamedParameter($data, IQueryBuilder::PARAM_STR)));
|
||||||
$qb = $this->db->getQueryBuilder();
|
|
||||||
$qb->select('*')
|
return $this->findEntity($qb);
|
||||||
->from('deck_attachment')
|
|
||||||
->where($qb->expr()->eq('card_id', $qb->createNamedParameter($cardId, IQueryBuilder::PARAM_INT)))
|
|
||||||
->andWhere($qb->expr()->eq('data', $qb->createNamedParameter($data, IQueryBuilder::PARAM_STR)));
|
|
||||||
$cursor = $qb->execute();
|
|
||||||
$row = $cursor->fetch(PDO::FETCH_ASSOC);
|
|
||||||
if ($row === false) {
|
|
||||||
$cursor->closeCursor();
|
|
||||||
throw new DoesNotExistException('Did expect one result but found none when executing query: ' . $qb->getSQL());
|
|
||||||
}
|
|
||||||
$cursor->closeCursor();
|
|
||||||
return $this->mapRowToEntity($row);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find all attachments for a card
|
|
||||||
*
|
|
||||||
* @param $cardId
|
* @param $cardId
|
||||||
* @return array
|
* @return Entity[]
|
||||||
|
* @throws \OCP\DB\Exception
|
||||||
*/
|
*/
|
||||||
public function findAll($cardId) {
|
public function findAll($cardId) {
|
||||||
$qb = $this->db->getQueryBuilder();
|
$qb = $this->db->getQueryBuilder();
|
||||||
$qb->select('*')
|
$qb->select('*')
|
||||||
->from('deck_attachment')
|
->from($this->getTableName())
|
||||||
->where($qb->expr()->eq('card_id', $qb->createNamedParameter($cardId, IQueryBuilder::PARAM_INT)))
|
->where($qb->expr()->eq('card_id', $qb->createNamedParameter($cardId, IQueryBuilder::PARAM_INT)))
|
||||||
->andWhere($qb->expr()->eq('deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)));
|
->andWhere($qb->expr()->eq('deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)));
|
||||||
|
|
||||||
|
|
||||||
$entities = [];
|
return $this->findEntities($qb);
|
||||||
$cursor = $qb->execute();
|
|
||||||
while ($row = $cursor->fetch()) {
|
|
||||||
$entities[] = $this->mapRowToEntity($row);
|
|
||||||
}
|
|
||||||
$cursor->closeCursor();
|
|
||||||
return $entities;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -128,7 +110,7 @@ class AttachmentMapper extends DeckMapper implements IPermissionMapper {
|
|||||||
$timeLimit = time() - (60 * 5);
|
$timeLimit = time() - (60 * 5);
|
||||||
$qb = $this->db->getQueryBuilder();
|
$qb = $this->db->getQueryBuilder();
|
||||||
$qb->select('*')
|
$qb->select('*')
|
||||||
->from('deck_attachment')
|
->from($this->getTableName())
|
||||||
->where($qb->expr()->gt('deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)));
|
->where($qb->expr()->gt('deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)));
|
||||||
if ($withOffset) {
|
if ($withOffset) {
|
||||||
$qb
|
$qb
|
||||||
@@ -139,13 +121,7 @@ class AttachmentMapper extends DeckMapper implements IPermissionMapper {
|
|||||||
->andWhere($qb->expr()->eq('card_id', $qb->createNamedParameter($cardId, IQueryBuilder::PARAM_INT)));
|
->andWhere($qb->expr()->eq('card_id', $qb->createNamedParameter($cardId, IQueryBuilder::PARAM_INT)));
|
||||||
}
|
}
|
||||||
|
|
||||||
$entities = [];
|
return $this->findEntities($qb);
|
||||||
$cursor = $qb->execute();
|
|
||||||
while ($row = $cursor->fetch()) {
|
|
||||||
$entities[] = $this->mapRowToEntity($row);
|
|
||||||
}
|
|
||||||
$cursor->closeCursor();
|
|
||||||
return $entities;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,14 @@
|
|||||||
|
|
||||||
namespace OCA\Deck\Db;
|
namespace OCA\Deck\Db;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @method int getId()
|
||||||
|
* @method string getTitle()
|
||||||
|
* @method int getShared()
|
||||||
|
* @method bool getArchived()
|
||||||
|
* @method int getDeletedAt()
|
||||||
|
* @method int getLastModified()
|
||||||
|
*/
|
||||||
class Board extends RelationalEntity {
|
class Board extends RelationalEntity {
|
||||||
protected $title;
|
protected $title;
|
||||||
protected $owner;
|
protected $owner;
|
||||||
|
|||||||
@@ -42,9 +42,9 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
|
|||||||
private $circlesService;
|
private $circlesService;
|
||||||
private $logger;
|
private $logger;
|
||||||
|
|
||||||
/** @var CappedMemoryCache */
|
/** @var CappedMemoryCache<Board[]> */
|
||||||
private $userBoardCache;
|
private $userBoardCache;
|
||||||
/** @var CappedMemoryCache */
|
/** @var CappedMemoryCache<Board> */
|
||||||
private $boardCache;
|
private $boardCache;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
@@ -107,6 +107,47 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
|
|||||||
return $this->boardCache[$id];
|
return $this->boardCache[$id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function findBoardIds(string $userId): array {
|
||||||
|
$qb = $this->db->getQueryBuilder();
|
||||||
|
$qb->selectDistinct('b.id')
|
||||||
|
->from($this->getTableName(), 'b')
|
||||||
|
->leftJoin('b', 'deck_board_acl', 'acl', $qb->expr()->eq('b.id', 'acl.board_id'));
|
||||||
|
|
||||||
|
// Owned by the user
|
||||||
|
$qb->where($qb->expr()->andX(
|
||||||
|
$qb->expr()->eq('owner', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)),
|
||||||
|
));
|
||||||
|
|
||||||
|
// Shared to the user
|
||||||
|
$qb->orWhere($qb->expr()->andX(
|
||||||
|
$qb->expr()->eq('acl.participant', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)),
|
||||||
|
$qb->expr()->eq('acl.type', $qb->createNamedParameter(Acl::PERMISSION_TYPE_USER, IQueryBuilder::PARAM_INT)),
|
||||||
|
));
|
||||||
|
|
||||||
|
// Shared to user groups of the user
|
||||||
|
$groupIds = $this->groupManager->getUserGroupIds($this->userManager->get($userId));
|
||||||
|
if (count($groupIds) !== 0) {
|
||||||
|
$qb->orWhere($qb->expr()->andX(
|
||||||
|
$qb->expr()->in('acl.participant', $qb->createNamedParameter($groupIds, IQueryBuilder::PARAM_STR_ARRAY)),
|
||||||
|
$qb->expr()->eq('acl.type', $qb->createNamedParameter(Acl::PERMISSION_TYPE_GROUP, IQueryBuilder::PARAM_INT)),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shared to circles of the user
|
||||||
|
$circles = $this->circlesService->getUserCircles($userId);
|
||||||
|
if (count($circles) !== 0) {
|
||||||
|
$qb->orWhere($qb->expr()->andX(
|
||||||
|
$qb->expr()->in('acl.participant', $qb->createNamedParameter($circles, IQueryBuilder::PARAM_STR_ARRAY)),
|
||||||
|
$qb->expr()->eq('acl.type', $qb->createNamedParameter(Acl::PERMISSION_TYPE_CIRCLE, IQueryBuilder::PARAM_INT)),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $qb->executeQuery();
|
||||||
|
return array_map(function (string $id) {
|
||||||
|
return (int)$id;
|
||||||
|
}, $result->fetchAll(\PDO::FETCH_COLUMN));
|
||||||
|
}
|
||||||
|
|
||||||
public function findAllForUser(string $userId, ?int $since = null, bool $includeArchived = true, ?int $before = null,
|
public function findAllForUser(string $userId, ?int $since = null, bool $includeArchived = true, ?int $before = null,
|
||||||
?string $term = null): array {
|
?string $term = null): array {
|
||||||
$useCache = ($since === -1 && $includeArchived === true && $before === null && $term === null);
|
$useCache = ($since === -1 && $includeArchived === true && $before === null && $term === null);
|
||||||
@@ -131,14 +172,9 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Find all boards for a given user
|
* Find all boards for a given user
|
||||||
*
|
|
||||||
* @param $userId
|
|
||||||
* @param null $limit
|
|
||||||
* @param null $offset
|
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
public function findAllByUser(string $userId, ?int $limit = null, ?int $offset = null, ?int $since = null,
|
public function findAllByUser(string $userId, ?int $limit = null, ?int $offset = null, ?int $since = null,
|
||||||
bool $includeArchived = true, ?int $before = null, ?string $term = null) {
|
bool $includeArchived = true, ?int $before = null, ?string $term = null): array {
|
||||||
// FIXME this used to be a UNION to get boards owned by $userId and the user shares in one single query
|
// FIXME this used to be a UNION to get boards owned by $userId and the user shares in one single query
|
||||||
// Is it possible with the query builder?
|
// Is it possible with the query builder?
|
||||||
$qb = $this->db->getQueryBuilder();
|
$qb = $this->db->getQueryBuilder();
|
||||||
@@ -247,15 +283,9 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Find all boards for a given user
|
* Find all boards for a given user
|
||||||
*
|
|
||||||
* @param $userId
|
|
||||||
* @param $groups
|
|
||||||
* @param null $limit
|
|
||||||
* @param null $offset
|
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
public function findAllByGroups(string $userId, array $groups, ?int $limit = null, ?int $offset = null, ?int $since = null,
|
public function findAllByGroups(string $userId, array $groups, ?int $limit = null, ?int $offset = null, ?int $since = null,
|
||||||
bool $includeArchived = true, ?int $before = null, ?string $term = null) {
|
bool $includeArchived = true, ?int $before = null, ?string $term = null): array {
|
||||||
if (count($groups) <= 0) {
|
if (count($groups) <= 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -414,8 +444,8 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
|
|||||||
return parent::delete($entity);
|
return parent::delete($entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isOwner($userId, $boardId): bool {
|
public function isOwner($userId, $id): bool {
|
||||||
$board = $this->find($boardId);
|
$board = $this->find($id);
|
||||||
return ($board->getOwner() === $userId);
|
return ($board->getOwner() === $userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,44 @@ use DateTime;
|
|||||||
use DateTimeZone;
|
use DateTimeZone;
|
||||||
use Sabre\VObject\Component\VCalendar;
|
use Sabre\VObject\Component\VCalendar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @method string getTitle()
|
||||||
|
* @method string getDescription()
|
||||||
|
* @method string getDescriptionPrev()
|
||||||
|
* @method int getStackId()
|
||||||
|
* @method int getOrder()
|
||||||
|
* @method int getLastModified()
|
||||||
|
* @method int getCreatedAt()
|
||||||
|
* @method bool getArchived()
|
||||||
|
* @method bool getNotified()
|
||||||
|
*
|
||||||
|
* @method void setLabels(Label[] $labels)
|
||||||
|
* @method null|Label[] getLabels()
|
||||||
|
*
|
||||||
|
* @method void setAssignedUsers(Assignment[] $users)
|
||||||
|
* @method null|User[] getAssignedUsers()
|
||||||
|
*
|
||||||
|
* @method void setAttachments(Attachment[] $attachments)
|
||||||
|
* @method null|Attachment[] getAttachments()
|
||||||
|
*
|
||||||
|
* @method void setAttachmentCount(int $count)
|
||||||
|
* @method null|int getAttachmentCount()
|
||||||
|
*
|
||||||
|
* @method void setCommentsUnread(int $count)
|
||||||
|
* @method null|int getCommentsUnread()
|
||||||
|
*
|
||||||
|
* @method void setCommentsCount(int $count)
|
||||||
|
* @method null|int getCommentsCount()
|
||||||
|
*
|
||||||
|
* @method void setOwner(string $user)
|
||||||
|
* @method null|string getOwner()
|
||||||
|
*
|
||||||
|
* @method void setRelatedStack(Stack $stack)
|
||||||
|
* @method null|Stack getRelatedStack()
|
||||||
|
*
|
||||||
|
* @method void setRelatedBoard(Board $board)
|
||||||
|
* @method null|Board getRelatedBoard()
|
||||||
|
*/
|
||||||
class Card extends RelationalEntity {
|
class Card extends RelationalEntity {
|
||||||
public const TITLE_MAX_LENGTH = 255;
|
public const TITLE_MAX_LENGTH = 255;
|
||||||
|
|
||||||
@@ -70,6 +108,7 @@ class Card extends RelationalEntity {
|
|||||||
$this->addType('archived', 'boolean');
|
$this->addType('archived', 'boolean');
|
||||||
$this->addType('notified', 'boolean');
|
$this->addType('notified', 'boolean');
|
||||||
$this->addType('deletedAt', 'integer');
|
$this->addType('deletedAt', 'integer');
|
||||||
|
$this->addType('duedate', 'datetime');
|
||||||
$this->addRelation('labels');
|
$this->addRelation('labels');
|
||||||
$this->addRelation('assignedUsers');
|
$this->addRelation('assignedUsers');
|
||||||
$this->addRelation('attachments');
|
$this->addRelation('attachments');
|
||||||
@@ -87,50 +126,6 @@ class Card extends RelationalEntity {
|
|||||||
$this->databaseType = $type;
|
$this->databaseType = $type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDuedate($isoFormat = false) {
|
|
||||||
if ($this->duedate === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$dt = new DateTime($this->duedate);
|
|
||||||
if (!$isoFormat && $this->databaseType === 'mysql') {
|
|
||||||
return $dt->format('Y-m-d H:i:s');
|
|
||||||
}
|
|
||||||
return $dt->format('c');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function jsonSerialize(): array {
|
|
||||||
$json = parent::jsonSerialize();
|
|
||||||
$json['overdue'] = self::DUEDATE_FUTURE;
|
|
||||||
$due = $this->duedate ? strtotime($this->duedate) : false;
|
|
||||||
if ($due !== false) {
|
|
||||||
$today = new DateTime();
|
|
||||||
$today->setTime(0, 0);
|
|
||||||
|
|
||||||
$match_date = new DateTime($this->duedate);
|
|
||||||
|
|
||||||
$match_date->setTime(0, 0);
|
|
||||||
|
|
||||||
$diff = $today->diff($match_date);
|
|
||||||
$diffDays = (integer) $diff->format('%R%a'); // Extract days count in interval
|
|
||||||
|
|
||||||
if ($diffDays === 1) {
|
|
||||||
$json['overdue'] = self::DUEDATE_NEXT;
|
|
||||||
}
|
|
||||||
if ($diffDays === 0) {
|
|
||||||
$json['overdue'] = self::DUEDATE_NOW;
|
|
||||||
}
|
|
||||||
if ($diffDays < 0) {
|
|
||||||
$json['overdue'] = self::DUEDATE_OVERDUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$json['duedate'] = $this->getDuedate(true);
|
|
||||||
unset($json['notified']);
|
|
||||||
unset($json['descriptionPrev']);
|
|
||||||
unset($json['relatedStack']);
|
|
||||||
unset($json['relatedBoard']);
|
|
||||||
return $json;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCalendarObject(): VCalendar {
|
public function getCalendarObject(): VCalendar {
|
||||||
$calendar = new VCalendar();
|
$calendar = new VCalendar();
|
||||||
$event = $calendar->createComponent('VTODO');
|
$event = $calendar->createComponent('VTODO');
|
||||||
@@ -139,7 +134,7 @@ class Card extends RelationalEntity {
|
|||||||
$creationDate = new DateTime();
|
$creationDate = new DateTime();
|
||||||
$creationDate->setTimestamp($this->createdAt);
|
$creationDate->setTimestamp($this->createdAt);
|
||||||
$event->DTSTAMP = $creationDate;
|
$event->DTSTAMP = $creationDate;
|
||||||
$event->DUE = new DateTime($this->getDuedate(true), new DateTimeZone('UTC'));
|
$event->DUE = new DateTime($this->getDuedate()->format('c'), new DateTimeZone('UTC'));
|
||||||
}
|
}
|
||||||
$event->add('RELATED-TO', 'deck-stack-' . $this->getStackId());
|
$event->add('RELATED-TO', 'deck-stack-' . $this->getStackId());
|
||||||
|
|
||||||
|
|||||||
@@ -227,6 +227,21 @@ class CardMapper extends QBMapper implements IPermissionMapper {
|
|||||||
return $this->findEntities($qb);
|
return $this->findEntities($qb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function findAllByBoardId(int $boardId, ?int $limit = null, ?int $offset = null): array {
|
||||||
|
$qb = $this->db->getQueryBuilder();
|
||||||
|
$qb->select('c.*')
|
||||||
|
->from('deck_cards', 'c')
|
||||||
|
->innerJoin('c', 'deck_stacks', 's', 's.id = c.stack_id')
|
||||||
|
->innerJoin('s', 'deck_boards', 'b', 'b.id = s.board_id')
|
||||||
|
->where($qb->expr()->eq('board_id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
|
||||||
|
->andWhere($qb->expr()->eq('archived', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)))
|
||||||
|
->setMaxResults($limit)
|
||||||
|
->setFirstResult($offset)
|
||||||
|
->orderBy('c.lastmodified')
|
||||||
|
->addOrderBy('c.id');
|
||||||
|
return $this->findEntities($qb);
|
||||||
|
}
|
||||||
|
|
||||||
public function findAllWithDue($boardId) {
|
public function findAllWithDue($boardId) {
|
||||||
$qb = $this->db->getQueryBuilder();
|
$qb = $this->db->getQueryBuilder();
|
||||||
$qb->select('c.*')
|
$qb->select('c.*')
|
||||||
@@ -549,10 +564,10 @@ class CardMapper extends QBMapper implements IPermissionMapper {
|
|||||||
$qb->execute();
|
$qb->execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isOwner($userId, $cardId): bool {
|
public function isOwner($userId, $id): bool {
|
||||||
$sql = 'SELECT owner FROM `*PREFIX*deck_boards` WHERE `id` IN (SELECT board_id FROM `*PREFIX*deck_stacks` WHERE id IN (SELECT stack_id FROM `*PREFIX*deck_cards` WHERE id = ?))';
|
$sql = 'SELECT owner FROM `*PREFIX*deck_boards` WHERE `id` IN (SELECT board_id FROM `*PREFIX*deck_stacks` WHERE id IN (SELECT stack_id FROM `*PREFIX*deck_cards` WHERE id = ?))';
|
||||||
$stmt = $this->db->prepare($sql);
|
$stmt = $this->db->prepare($sql);
|
||||||
$stmt->bindParam(1, $cardId, \PDO::PARAM_INT, 0);
|
$stmt->bindParam(1, $id, \PDO::PARAM_INT, 0);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
$row = $stmt->fetch();
|
$row = $stmt->fetch();
|
||||||
return ($row['owner'] === $userId);
|
return ($row['owner'] === $userId);
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
namespace OCA\Deck\Db;
|
namespace OCA\Deck\Db;
|
||||||
|
|
||||||
use OCP\ICacheFactory;
|
use OCP\ICacheFactory;
|
||||||
|
use OCP\ICache;
|
||||||
use OCP\IDBConnection;
|
use OCP\IDBConnection;
|
||||||
use OCP\IRequest;
|
use OCP\IRequest;
|
||||||
|
|
||||||
@@ -31,13 +32,16 @@ class ChangeHelper {
|
|||||||
public const TYPE_BOARD = 'boardChanged';
|
public const TYPE_BOARD = 'boardChanged';
|
||||||
public const TYPE_CARD = 'cardChanged';
|
public const TYPE_CARD = 'cardChanged';
|
||||||
|
|
||||||
private $db;
|
private IDBConnection $db;
|
||||||
|
private ICache $cache;
|
||||||
|
private IRequest $request;
|
||||||
|
private ?string $userId;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
IDBConnection $db,
|
IDBConnection $db,
|
||||||
ICacheFactory $cacheFactory,
|
ICacheFactory $cacheFactory,
|
||||||
IRequest $request,
|
IRequest $request,
|
||||||
$userId
|
?string $userId
|
||||||
) {
|
) {
|
||||||
$this->db = $db;
|
$this->db = $db;
|
||||||
$this->cache = $cacheFactory->createDistributed('deck_changes');
|
$this->cache = $cacheFactory->createDistributed('deck_changes');
|
||||||
|
|||||||
@@ -23,17 +23,15 @@
|
|||||||
|
|
||||||
namespace OCA\Deck\Db;
|
namespace OCA\Deck\Db;
|
||||||
|
|
||||||
use OCP\AppFramework\Db\Mapper;
|
use OCP\AppFramework\Db\QBMapper;
|
||||||
|
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class DeckMapper
|
* Class DeckMapper
|
||||||
*
|
*
|
||||||
* @package OCA\Deck\Db
|
* @package OCA\Deck\Db
|
||||||
* @deprecated use QBMapper
|
|
||||||
*
|
|
||||||
* TODO: Move to QBMapper once Nextcloud 14 is a minimum requirement
|
|
||||||
*/
|
*/
|
||||||
class DeckMapper extends Mapper {
|
class DeckMapper extends QBMapper {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $id
|
* @param $id
|
||||||
@@ -42,11 +40,11 @@ class DeckMapper extends Mapper {
|
|||||||
* @throws \OCP\AppFramework\Db\DoesNotExistException
|
* @throws \OCP\AppFramework\Db\DoesNotExistException
|
||||||
*/
|
*/
|
||||||
public function find($id) {
|
public function find($id) {
|
||||||
$sql = 'SELECT * FROM `' . $this->tableName . '` ' . 'WHERE `id` = ?';
|
$qb = $this->db->getQueryBuilder();
|
||||||
return $this->findEntity($sql, [$id]);
|
$qb->select('*')
|
||||||
}
|
->from($this->getTableName())
|
||||||
|
->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)));
|
||||||
|
|
||||||
protected function execute($sql, array $params = [], $limit = null, $offset = null) {
|
return $this->findEntity($qb);
|
||||||
return parent::execute($sql, $params, $limit, $offset);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ namespace OCA\Deck\Db;
|
|||||||
use OCP\AppFramework\Db\DoesNotExistException;
|
use OCP\AppFramework\Db\DoesNotExistException;
|
||||||
use OCP\AppFramework\Db\Entity;
|
use OCP\AppFramework\Db\Entity;
|
||||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||||
|
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||||
use OCP\IDBConnection;
|
use OCP\IDBConnection;
|
||||||
|
|
||||||
class LabelMapper extends DeckMapper implements IPermissionMapper {
|
class LabelMapper extends DeckMapper implements IPermissionMapper {
|
||||||
@@ -33,41 +34,105 @@ class LabelMapper extends DeckMapper implements IPermissionMapper {
|
|||||||
parent::__construct($db, 'deck_labels', Label::class);
|
parent::__construct($db, 'deck_labels', Label::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findAll($boardId, $limit = null, $offset = null) {
|
/**
|
||||||
$sql = 'SELECT * FROM `*PREFIX*deck_labels` WHERE `board_id` = ? ORDER BY `id`';
|
* @param numeric $boardId
|
||||||
return $this->findEntities($sql, [$boardId], $limit, $offset);
|
* @param int|null $limit
|
||||||
|
* @param int|null $offset
|
||||||
|
* @return Label[]
|
||||||
|
* @throws \OCP\DB\Exception
|
||||||
|
*/
|
||||||
|
public function findAll($boardId, $limit = null, $offset = null): array {
|
||||||
|
$qb = $this->db->getQueryBuilder();
|
||||||
|
$qb->select('*')
|
||||||
|
->from($this->getTableName())
|
||||||
|
->where($qb->expr()->eq('board_id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
|
||||||
|
->setMaxResults($limit)
|
||||||
|
->setFirstResult($offset);
|
||||||
|
return $this->findEntities($qb);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(\OCP\AppFramework\Db\Entity $entity) {
|
/**
|
||||||
|
* @param Entity $entity
|
||||||
|
* @return Entity
|
||||||
|
* @throws \OCP\DB\Exception
|
||||||
|
*/
|
||||||
|
public function delete(Entity $entity): Entity {
|
||||||
// delete assigned labels
|
// delete assigned labels
|
||||||
$this->deleteLabelAssignments($entity->getId());
|
$this->deleteLabelAssignments($entity->getId());
|
||||||
// delete label
|
// delete label
|
||||||
return parent::delete($entity);
|
return parent::delete($entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findAssignedLabelsForCard($cardId, $limit = null, $offset = null) {
|
/**
|
||||||
$sql = 'SELECT l.*,card_id FROM `*PREFIX*deck_assigned_labels` as al INNER JOIN *PREFIX*deck_labels as l ON l.id = al.label_id WHERE `card_id` = ? ORDER BY l.id';
|
* @param numeric $cardId
|
||||||
return $this->findEntities($sql, [$cardId], $limit, $offset);
|
* @param int|null $limit
|
||||||
}
|
* @param int|null $offset
|
||||||
public function findAssignedLabelsForBoard($boardId, $limit = null, $offset = null) {
|
* @return Label[]
|
||||||
$sql = 'SELECT c.id as card_id, l.id as id, l.title as title, l.color as color FROM `*PREFIX*deck_cards` as c ' .
|
* @throws \OCP\DB\Exception
|
||||||
' INNER JOIN `*PREFIX*deck_assigned_labels` as al ON al.card_id = c.id INNER JOIN `*PREFIX*deck_labels` as l ON al.label_id = l.id WHERE board_id=? ORDER BY l.id';
|
*/
|
||||||
return $this->findEntities($sql, [$boardId], $limit, $offset);
|
public function findAssignedLabelsForCard($cardId, $limit = null, $offset = null): array {
|
||||||
|
$qb = $this->db->getQueryBuilder();
|
||||||
|
$qb->select('l.*', 'card_id')
|
||||||
|
->from($this->getTableName(), 'l')
|
||||||
|
->innerJoin('l', 'deck_assigned_labels', 'al', 'l.id = al.label_id')
|
||||||
|
->where($qb->expr()->eq('card_id', $qb->createNamedParameter($cardId, IQueryBuilder::PARAM_INT)))
|
||||||
|
->orderBy('l.id')
|
||||||
|
->setMaxResults($limit)
|
||||||
|
->setFirstResult($offset);
|
||||||
|
|
||||||
|
return $this->findEntities($qb);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function insert(Entity $entity) {
|
/**
|
||||||
|
* @param numeric $boardId
|
||||||
|
* @param int|null $limit
|
||||||
|
* @param int|null $offset
|
||||||
|
* @return Label[]
|
||||||
|
* @throws \OCP\DB\Exception
|
||||||
|
*/
|
||||||
|
public function findAssignedLabelsForBoard($boardId, $limit = null, $offset = null): array {
|
||||||
|
$qb = $this->db->getQueryBuilder();
|
||||||
|
$qb->select('l.id as id', 'l.title as title', 'l.color as color')
|
||||||
|
->selectAlias('c.id', 'card_id')
|
||||||
|
->from($this->getTableName(), 'l')
|
||||||
|
->innerJoin('l', 'deck_assigned_labels', 'al', 'al.label_id = l.id')
|
||||||
|
->innerJoin('l', 'deck_cards', 'c', 'al.card_id = c.id')
|
||||||
|
->where($qb->expr()->eq('board_id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
|
||||||
|
->orderBy('l.id')
|
||||||
|
->setMaxResults($limit)
|
||||||
|
->setFirstResult($offset);
|
||||||
|
|
||||||
|
return $this->findEntities($qb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Entity $entity
|
||||||
|
* @return Entity
|
||||||
|
* @throws \OCP\DB\Exception
|
||||||
|
*/
|
||||||
|
public function insert(Entity $entity): Entity {
|
||||||
$entity->setLastModified(time());
|
$entity->setLastModified(time());
|
||||||
return parent::insert($entity);
|
return parent::insert($entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(Entity $entity, $updateModified = true) {
|
/**
|
||||||
|
* @param Entity $entity
|
||||||
|
* @param bool $updateModified
|
||||||
|
* @return Entity
|
||||||
|
* @throws \OCP\DB\Exception
|
||||||
|
*/
|
||||||
|
public function update(Entity $entity, $updateModified = true): Entity {
|
||||||
if ($updateModified) {
|
if ($updateModified) {
|
||||||
$entity->setLastModified(time());
|
$entity->setLastModified(time());
|
||||||
}
|
}
|
||||||
return parent::update($entity);
|
return parent::update($entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param numeric $boardId
|
||||||
|
* @return array
|
||||||
|
* @throws \OCP\DB\Exception
|
||||||
|
*/
|
||||||
public function getAssignedLabelsForBoard($boardId) {
|
public function getAssignedLabelsForBoard($boardId) {
|
||||||
$labels = $this->findAssignedLabelsForBoard($boardId);
|
$labels = $this->findAssignedLabelsForBoard($boardId);
|
||||||
$result = [];
|
$result = [];
|
||||||
@@ -80,27 +145,51 @@ class LabelMapper extends DeckMapper implements IPermissionMapper {
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param numeric $labelId
|
||||||
|
* @return void
|
||||||
|
* @throws \OCP\DB\Exception
|
||||||
|
*/
|
||||||
public function deleteLabelAssignments($labelId) {
|
public function deleteLabelAssignments($labelId) {
|
||||||
$sql = 'DELETE FROM `*PREFIX*deck_assigned_labels` WHERE label_id = ?';
|
$qb = $this->db->getQueryBuilder();
|
||||||
$stmt = $this->db->prepare($sql);
|
$qb->delete('deck_assigned_labels')
|
||||||
$stmt->bindParam(1, $labelId, \PDO::PARAM_INT, 0);
|
->where($qb->expr()->eq('label_id', $qb->createNamedParameter($labelId, IQueryBuilder::PARAM_INT)));
|
||||||
$stmt->execute();
|
$qb->executeStatement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param numeric $cardId
|
||||||
|
* @return void
|
||||||
|
* @throws \OCP\DB\Exception
|
||||||
|
*/
|
||||||
public function deleteLabelAssignmentsForCard($cardId) {
|
public function deleteLabelAssignmentsForCard($cardId) {
|
||||||
$sql = 'DELETE FROM `*PREFIX*deck_assigned_labels` WHERE card_id = ?';
|
$qb = $this->db->getQueryBuilder();
|
||||||
$stmt = $this->db->prepare($sql);
|
$qb->delete('deck_assigned_labels')
|
||||||
$stmt->bindParam(1, $cardId, \PDO::PARAM_INT, 0);
|
->where($qb->expr()->eq('card_id', $qb->createNamedParameter($cardId, IQueryBuilder::PARAM_INT)));
|
||||||
$stmt->execute();
|
$qb->executeStatement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $userId
|
||||||
|
* @param numeric $labelId
|
||||||
|
* @return bool
|
||||||
|
* @throws \OCP\DB\Exception
|
||||||
|
*/
|
||||||
public function isOwner($userId, $labelId): bool {
|
public function isOwner($userId, $labelId): bool {
|
||||||
$sql = 'SELECT owner FROM `*PREFIX*deck_boards` WHERE `id` IN (SELECT board_id FROM `*PREFIX*deck_labels` WHERE id = ?)';
|
$qb = $this->db->getQueryBuilder();
|
||||||
$stmt = $this->execute($sql, [$labelId]);
|
$qb->select('l.id')
|
||||||
$row = $stmt->fetch();
|
->from($this->getTableName(), 'l')
|
||||||
return ($row['owner'] === $userId);
|
->innerJoin('l', 'deck_boards', 'b', 'l.board_id = b.id')
|
||||||
|
->where($qb->expr()->eq('l.id', $qb->createNamedParameter($labelId, IQueryBuilder::PARAM_INT)))
|
||||||
|
->andWhere($qb->expr()->eq('b.owner', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)));
|
||||||
|
|
||||||
|
return count($qb->executeQuery()->fetchAll()) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param numeric $id
|
||||||
|
* @return int|null
|
||||||
|
*/
|
||||||
public function findBoardId($id): ?int {
|
public function findBoardId($id): ?int {
|
||||||
try {
|
try {
|
||||||
$entity = $this->find($id);
|
$entity = $this->find($id);
|
||||||
|
|||||||
@@ -72,6 +72,9 @@ class RelationalEntity extends Entity implements \JsonSerializable {
|
|||||||
$propertyReflection = $reflection->getProperty($property);
|
$propertyReflection = $reflection->getProperty($property);
|
||||||
if (!$propertyReflection->isPrivate() && !in_array($property, $this->_resolvedProperties, true)) {
|
if (!$propertyReflection->isPrivate() && !in_array($property, $this->_resolvedProperties, true)) {
|
||||||
$json[$property] = $this->getter($property);
|
$json[$property] = $this->getter($property);
|
||||||
|
if ($json[$property] instanceof \DateTimeInterface) {
|
||||||
|
$json[$property] = $json[$property]->format('c');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ namespace OCA\Deck\Db;
|
|||||||
use OCP\AppFramework\Db\DoesNotExistException;
|
use OCP\AppFramework\Db\DoesNotExistException;
|
||||||
use OCP\AppFramework\Db\Entity;
|
use OCP\AppFramework\Db\Entity;
|
||||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||||
|
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||||
use OCP\IDBConnection;
|
use OCP\IDBConnection;
|
||||||
|
|
||||||
class StackMapper extends DeckMapper implements IPermissionMapper {
|
class StackMapper extends DeckMapper implements IPermissionMapper {
|
||||||
@@ -38,62 +39,112 @@ class StackMapper extends DeckMapper implements IPermissionMapper {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $id
|
* @param numeric $id
|
||||||
* @throws MultipleObjectsReturnedException
|
* @return Stack
|
||||||
* @throws DoesNotExistException
|
* @throws DoesNotExistException
|
||||||
|
* @throws MultipleObjectsReturnedException
|
||||||
|
* @throws \OCP\DB\Exception
|
||||||
*/
|
*/
|
||||||
public function find($id): Stack {
|
public function find($id): Stack {
|
||||||
$sql = 'SELECT * FROM `*PREFIX*deck_stacks` ' .
|
$qb = $this->db->getQueryBuilder();
|
||||||
'WHERE `id` = ?';
|
$qb->select('*')
|
||||||
return $this->findEntity($sql, [$id]);
|
->from($this->getTableName())
|
||||||
|
->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)));
|
||||||
|
|
||||||
|
return $this->findEntity($qb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $cardId
|
* @param $cardId
|
||||||
* @return Stack|null
|
* @return Stack|null
|
||||||
|
* @throws \OCP\DB\Exception
|
||||||
*/
|
*/
|
||||||
public function findStackFromCardId($cardId): ?Stack {
|
public function findStackFromCardId($cardId): ?Stack {
|
||||||
$sql = <<<SQL
|
$qb = $this->db->getQueryBuilder();
|
||||||
SELECT s.*
|
$qb->select('s.*')
|
||||||
FROM `*PREFIX*deck_stacks` as `s`
|
->from($this->getTableName(), 's')
|
||||||
INNER JOIN `*PREFIX*deck_cards` as `c` ON s.id = c.stack_id
|
->innerJoin('s', 'deck_cards', 'c', 's.id = c.stack_id')
|
||||||
WHERE c.id = ?
|
->where($qb->expr()->eq('c.id', $qb->createNamedParameter($cardId, IQueryBuilder::PARAM_INT)));
|
||||||
SQL;
|
|
||||||
try {
|
try {
|
||||||
return $this->findEntity($sql, [$cardId]);
|
return $this->findEntity($qb);
|
||||||
} catch (MultipleObjectsReturnedException|DoesNotExistException $e) {
|
} catch (MultipleObjectsReturnedException|DoesNotExistException $e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param numeric $boardId
|
||||||
|
* @param int|null $limit
|
||||||
|
* @param int|null $offset
|
||||||
|
* @return Stack[]
|
||||||
|
* @throws \OCP\DB\Exception
|
||||||
|
*/
|
||||||
|
public function findAll($boardId, $limit = null, $offset = null): array {
|
||||||
|
$qb = $this->db->getQueryBuilder();
|
||||||
|
$qb->select('*')
|
||||||
|
->from($this->getTableName())
|
||||||
|
->where($qb->expr()->eq('board_id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
|
||||||
|
->andWhere($qb->expr()->eq('deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)))
|
||||||
|
->setFirstResult($offset)
|
||||||
|
->setMaxResults($limit);
|
||||||
|
|
||||||
public function findAll($boardId, $limit = null, $offset = null) {
|
return $this->findEntities($qb);
|
||||||
$sql = 'SELECT * FROM `*PREFIX*deck_stacks` WHERE `board_id` = ? AND deleted_at = 0 ORDER BY `order`, `id`';
|
|
||||||
return $this->findEntities($sql, [$boardId], $limit, $offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param numeric $boardId
|
||||||
|
* @param int|null $limit
|
||||||
|
* @param int|null $offset
|
||||||
|
* @return Stack[]
|
||||||
|
* @throws \OCP\DB\Exception
|
||||||
|
*/
|
||||||
public function findDeleted($boardId, $limit = null, $offset = null) {
|
public function findDeleted($boardId, $limit = null, $offset = null) {
|
||||||
$sql = 'SELECT * FROM `*PREFIX*deck_stacks` s
|
$qb = $this->db->getQueryBuilder();
|
||||||
WHERE `s`.`board_id` = ? AND NOT s.deleted_at = 0';
|
$qb->select('*')
|
||||||
return $this->findEntities($sql, [$boardId], $limit, $offset);
|
->from($this->getTableName())
|
||||||
|
->where($qb->expr()->eq('board_id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
|
||||||
|
->andWhere($qb->expr()->neq('deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)))
|
||||||
|
->setFirstResult($offset)
|
||||||
|
->setMaxResults($limit);
|
||||||
|
|
||||||
|
return $this->findEntities($qb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
public function delete(Entity $entity) {
|
* @param Entity $entity
|
||||||
|
* @return Entity
|
||||||
|
* @throws \OCP\DB\Exception
|
||||||
|
*/
|
||||||
|
public function delete(Entity $entity): Entity {
|
||||||
// delete cards on stack
|
// delete cards on stack
|
||||||
$this->cardMapper->deleteByStack($entity->getId());
|
$this->cardMapper->deleteByStack($entity->getId());
|
||||||
return parent::delete($entity);
|
return parent::delete($entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isOwner($userId, $stackId): bool {
|
/**
|
||||||
$sql = 'SELECT owner FROM `*PREFIX*deck_boards` WHERE `id` IN (SELECT board_id FROM `*PREFIX*deck_stacks` WHERE id = ?)';
|
* @param numeric $userId
|
||||||
$stmt = $this->execute($sql, [$stackId]);
|
* @param numeric $stackId
|
||||||
$row = $stmt->fetch();
|
* @return bool
|
||||||
return ($row['owner'] === $userId);
|
* @throws \OCP\DB\Exception
|
||||||
|
*/
|
||||||
|
public function isOwner($userId, $id): bool {
|
||||||
|
$qb = $this->db->getQueryBuilder();
|
||||||
|
$qb->select('s.id')
|
||||||
|
->from($this->getTableName(), 's')
|
||||||
|
->innerJoin('s', 'deck_boards', 'b', 'b.id = s.board_id')
|
||||||
|
->where($qb->expr()->eq('s.id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)))
|
||||||
|
->andWhere($qb->expr()->eq('owner', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)));
|
||||||
|
|
||||||
|
return count($qb->executeQuery()->fetchAll()) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param numeric $id
|
||||||
|
* @return int|null
|
||||||
|
* @throws \OCP\DB\Exception
|
||||||
|
*/
|
||||||
public function findBoardId($id): ?int {
|
public function findBoardId($id): ?int {
|
||||||
try {
|
try {
|
||||||
$entity = $this->find($id);
|
$entity = $this->find($id);
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ use OCP\AppFramework\OCS\OCSException;
|
|||||||
use OCP\AppFramework\OCSController;
|
use OCP\AppFramework\OCSController;
|
||||||
use OCP\ILogger;
|
use OCP\ILogger;
|
||||||
use OCP\IRequest;
|
use OCP\IRequest;
|
||||||
use OCP\Util;
|
|
||||||
use OCP\IConfig;
|
use OCP\IConfig;
|
||||||
|
|
||||||
class ExceptionMiddleware extends Middleware {
|
class ExceptionMiddleware extends Middleware {
|
||||||
@@ -85,9 +84,9 @@ class ExceptionMiddleware extends Middleware {
|
|||||||
'message' => 'Permission denied'
|
'message' => 'Permission denied'
|
||||||
], 403);
|
], 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($exception instanceof StatusException) {
|
if ($exception instanceof StatusException) {
|
||||||
if ($this->config->getSystemValue('loglevel', Util::WARN) === Util::DEBUG) {
|
if ($this->config->getSystemValue('loglevel', ILogger::WARN) === ILogger::DEBUG) {
|
||||||
$this->logger->logException($exception);
|
$this->logger->logException($exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* @copyright Copyright (c) 2016 Julius Härtl <jus@bitgrid.net>
|
* @copyright Copyright (c) 2022 Raul Ferreira Fuentes <raul@nextcloud.com>
|
||||||
*
|
*
|
||||||
* @author Julius Härtl <jus@bitgrid.net>
|
* @author Raul Ferreira Fuentes <raul@nextcloud.com>
|
||||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
|
||||||
* @author Luka Trovic <luka.trovic@nextcloud.com>
|
|
||||||
*
|
*
|
||||||
* @license GNU AGPL version 3 or any later version
|
* @license GNU AGPL version 3 or any later version
|
||||||
*
|
*
|
||||||
@@ -22,16 +20,26 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
namespace OCA\Deck\Model;
|
||||||
|
|
||||||
declare(strict_types=1);
|
use OCA\Deck\Db\Board;
|
||||||
|
|
||||||
namespace OCA\Deck\Validators;
|
class BoardSummary extends Board {
|
||||||
|
private Board $board;
|
||||||
|
|
||||||
class AssignmentServiceValidator extends BaseValidator {
|
public function __construct(Board $board) {
|
||||||
public function rules() {
|
parent::__construct();
|
||||||
|
$this->board = $board;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function jsonSerialize(): array {
|
||||||
return [
|
return [
|
||||||
'cardId' => ['numeric'],
|
'id' => $this->getId(),
|
||||||
'userId' => ['not_empty', 'not_null', 'not_false', 'max:64'],
|
'title' => $this->getTitle()
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function __call($name, $arguments) {
|
||||||
|
return $this->board->__call($name, $arguments);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
92
lib/Model/CardDetails.php
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2022 Raul Ferreira Fuentes <raul@nextcloud.com>
|
||||||
|
*
|
||||||
|
* @author Raul Ferreira Fuentes <raul@nextcloud.com>
|
||||||
|
*
|
||||||
|
* @license GNU AGPL version 3 or any later version
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace OCA\Deck\Model;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
use OCA\Deck\Db\Board;
|
||||||
|
use OCA\Deck\Db\Card;
|
||||||
|
|
||||||
|
class CardDetails extends Card {
|
||||||
|
private Card $card;
|
||||||
|
private ?Board $board;
|
||||||
|
|
||||||
|
public function __construct(Card $card, ?Board $board = null) {
|
||||||
|
parent::__construct();
|
||||||
|
$this->card = $card;
|
||||||
|
$this->board = $board;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBoard(?Board $board): void {
|
||||||
|
$this->board = $board;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function jsonSerialize(array $extras = []): array {
|
||||||
|
$array = $this->card->jsonSerialize();
|
||||||
|
unset($array['notified'], $array['descriptionPrev'], $array['relatedStack'], $array['relatedBoard']);
|
||||||
|
|
||||||
|
$array['overdue'] = $this->getDueStatus();
|
||||||
|
$this->appendBoardDetails($array);
|
||||||
|
|
||||||
|
return $array;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getDueStatus(): int {
|
||||||
|
$today = new DateTime();
|
||||||
|
$today->setTime(0, 0);
|
||||||
|
|
||||||
|
$match_date = $this->card->getDuedate();
|
||||||
|
if (!$match_date) {
|
||||||
|
return Card::DUEDATE_FUTURE;
|
||||||
|
}
|
||||||
|
$match_date->setTime(0, 0);
|
||||||
|
|
||||||
|
$diff = $today->diff($match_date);
|
||||||
|
$diffDays = (int) $diff->format('%R%a'); // Extract days count in interval
|
||||||
|
|
||||||
|
|
||||||
|
if ($diffDays === 1) {
|
||||||
|
return Card::DUEDATE_NEXT;
|
||||||
|
}
|
||||||
|
if ($diffDays === 0) {
|
||||||
|
return Card::DUEDATE_NOW;
|
||||||
|
}
|
||||||
|
if ($diffDays < 0) {
|
||||||
|
return Card::DUEDATE_OVERDUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Card::DUEDATE_FUTURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function appendBoardDetails(&$array): void {
|
||||||
|
if (!$this->board) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$array['boardId'] = $this->board->id;
|
||||||
|
$array['board'] = (new BoardSummary($this->board))->jsonSerialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __call($name, $arguments) {
|
||||||
|
return $this->card->__call($name, $arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -129,7 +129,7 @@ class NotificationHelper {
|
|||||||
->setSubject('card-overdue', [
|
->setSubject('card-overdue', [
|
||||||
$card->getTitle(), $board->getTitle()
|
$card->getTitle(), $board->getTitle()
|
||||||
])
|
])
|
||||||
->setDateTime(new DateTime($card->getDuedate()));
|
->setDateTime($card->getDuedate());
|
||||||
$this->notificationManager->notify($notification);
|
$this->notificationManager->notify($notification);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -242,7 +242,7 @@ class NotificationHelper {
|
|||||||
}
|
}
|
||||||
return $this->boards[$boardId];
|
return $this->boards[$boardId];
|
||||||
}
|
}
|
||||||
|
|
||||||
private function generateBoardShared(Board $board, string $userId): INotification {
|
private function generateBoardShared(Board $board, string $userId): INotification {
|
||||||
$notification = $this->notificationManager->createNotification();
|
$notification = $this->notificationManager->createNotification();
|
||||||
$notification
|
$notification
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ class Notifier implements INotifier {
|
|||||||
$dn = $params[2];
|
$dn = $params[2];
|
||||||
}
|
}
|
||||||
$notification->setParsedSubject(
|
$notification->setParsedSubject(
|
||||||
(string) $l->t('The card "%s" on "%s" has been assigned to you by %s.', [$params[0], $params[1], $dn])
|
$l->t('The card "%s" on "%s" has been assigned to you by %s.', [$params[0], $params[1], $dn])
|
||||||
);
|
);
|
||||||
$notification->setRichSubject(
|
$notification->setRichSubject(
|
||||||
$l->t('{user} has assigned the card {deck-card} on {deck-board} to you.'),
|
$l->t('{user} has assigned the card {deck-card} on {deck-board} to you.'),
|
||||||
@@ -151,7 +151,7 @@ class Notifier implements INotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$notification->setParsedSubject(
|
$notification->setParsedSubject(
|
||||||
(string) $l->t('The card "%s" on "%s" has reached its due date.', $params)
|
$l->t('The card "%s" on "%s" has reached its due date.', $params)
|
||||||
);
|
);
|
||||||
$notification->setRichSubject(
|
$notification->setRichSubject(
|
||||||
$l->t('The card {deck-card} on {deck-board} has reached its due date.'),
|
$l->t('The card {deck-card} on {deck-board} has reached its due date.'),
|
||||||
@@ -189,7 +189,7 @@ class Notifier implements INotifier {
|
|||||||
$dn = $params[2];
|
$dn = $params[2];
|
||||||
}
|
}
|
||||||
$notification->setParsedSubject(
|
$notification->setParsedSubject(
|
||||||
(string) $l->t('%s has mentioned you in a comment on "%s".', [$dn, $params[0]])
|
$l->t('%s has mentioned you in a comment on "%s".', [$dn, $params[0]])
|
||||||
);
|
);
|
||||||
$notification->setRichSubject(
|
$notification->setRichSubject(
|
||||||
$l->t('{user} has mentioned you in a comment on {deck-card}.'),
|
$l->t('{user} has mentioned you in a comment on {deck-card}.'),
|
||||||
@@ -226,7 +226,7 @@ class Notifier implements INotifier {
|
|||||||
$dn = $params[1];
|
$dn = $params[1];
|
||||||
}
|
}
|
||||||
$notification->setParsedSubject(
|
$notification->setParsedSubject(
|
||||||
(string) $l->t('The board "%s" has been shared with you by %s.', [$params[0], $dn])
|
$l->t('The board "%s" has been shared with you by %s.', [$params[0], $dn])
|
||||||
);
|
);
|
||||||
$notification->setRichSubject(
|
$notification->setRichSubject(
|
||||||
$l->t('{user} has shared {deck-board} with you.'),
|
$l->t('{user} has shared {deck-board} with you.'),
|
||||||
|
|||||||
@@ -54,22 +54,11 @@ use OCP\IURLGenerator;
|
|||||||
class DeckProvider implements IFullTextSearchProvider {
|
class DeckProvider implements IFullTextSearchProvider {
|
||||||
public const DECK_PROVIDER_ID = 'deck';
|
public const DECK_PROVIDER_ID = 'deck';
|
||||||
|
|
||||||
|
private IL10N $l10n;
|
||||||
/** @var IL10N */
|
private IUrlGenerator $urlGenerator;
|
||||||
private $l10n;
|
private FullTextSearchService $fullTextSearchService;
|
||||||
|
private ?IRunner $runner = null;
|
||||||
/** @var IUrlGenerator */
|
private ?IIndexOptions $indexOptions = null;
|
||||||
private $urlGenerator;
|
|
||||||
|
|
||||||
/** @var FullTextSearchService */
|
|
||||||
private $fullTextSearchService;
|
|
||||||
|
|
||||||
|
|
||||||
/** @var IRunner */
|
|
||||||
private $runner;
|
|
||||||
|
|
||||||
/** @var IIndexOptions */
|
|
||||||
private $indexOptions = [];
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
167
lib/Reference/CardReferenceProvider.php
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2022 Julien Veyssier <eneiluj@posteo.net>
|
||||||
|
*
|
||||||
|
* @author Julien Veyssier <eneiluj@posteo.net>
|
||||||
|
*
|
||||||
|
* @license GNU AGPL version 3 or any later version
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace OCA\Deck\Reference;
|
||||||
|
|
||||||
|
use OCA\Deck\AppInfo\Application;
|
||||||
|
use OCA\Deck\Db\Assignment;
|
||||||
|
use OCA\Deck\Db\Attachment;
|
||||||
|
use OCA\Deck\Db\Label;
|
||||||
|
use OCA\Deck\Model\CardDetails;
|
||||||
|
use OCA\Deck\Service\BoardService;
|
||||||
|
use OCA\Deck\Service\CardService;
|
||||||
|
use OCA\Deck\Service\StackService;
|
||||||
|
use OCP\Collaboration\Reference\IReference;
|
||||||
|
use OCP\Collaboration\Reference\IReferenceProvider;
|
||||||
|
use OCP\Collaboration\Reference\Reference;
|
||||||
|
use OCP\IURLGenerator;
|
||||||
|
|
||||||
|
class CardReferenceProvider implements IReferenceProvider {
|
||||||
|
private CardService $cardService;
|
||||||
|
private IURLGenerator $urlGenerator;
|
||||||
|
private BoardService $boardService;
|
||||||
|
private StackService $stackService;
|
||||||
|
|
||||||
|
public function __construct(CardService $cardService,
|
||||||
|
BoardService $boardService,
|
||||||
|
StackService $stackService,
|
||||||
|
IURLGenerator $urlGenerator,
|
||||||
|
?string $userId) {
|
||||||
|
$this->cardService = $cardService;
|
||||||
|
$this->urlGenerator = $urlGenerator;
|
||||||
|
$this->boardService = $boardService;
|
||||||
|
$this->stackService = $stackService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function matchReference(string $referenceText): bool {
|
||||||
|
$start = $this->urlGenerator->getAbsoluteURL('/apps/' . Application::APP_ID);
|
||||||
|
$startIndex = $this->urlGenerator->getAbsoluteURL('/index.php/apps/' . Application::APP_ID);
|
||||||
|
|
||||||
|
// link example: https://nextcloud.local/index.php/apps/deck/#/board/2/card/11
|
||||||
|
$noIndexMatch = preg_match('/^' . preg_quote($start, '/') . '\/#\/board\/[0-9]+\/card\/[0-9]+$/', $referenceText) === 1;
|
||||||
|
$indexMatch = preg_match('/^' . preg_quote($startIndex, '/') . '\/#\/board\/[0-9]+\/card\/[0-9]+$/', $referenceText) === 1;
|
||||||
|
|
||||||
|
return $noIndexMatch || $indexMatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function resolveReference(string $referenceText): ?IReference {
|
||||||
|
if ($this->matchReference($referenceText)) {
|
||||||
|
$ids = $this->getBoardCardId($referenceText);
|
||||||
|
if ($ids !== null) {
|
||||||
|
[$boardId, $cardId] = $ids;
|
||||||
|
$card = $this->cardService->find((int) $cardId)->jsonSerialize();
|
||||||
|
$board = $this->boardService->find((int) $boardId)->jsonSerialize();
|
||||||
|
$stack = $this->stackService->find((int) $card['stackId'])->jsonSerialize();
|
||||||
|
|
||||||
|
$card = $this->sanitizeSerializedCard($card);
|
||||||
|
$board = $this->sanitizeSerializedBoard($board);
|
||||||
|
$stack = $this->sanitizeSerializedStack($stack);
|
||||||
|
/** @var IReference $reference */
|
||||||
|
$reference = new Reference($referenceText);
|
||||||
|
$reference->setRichObject(Application::APP_ID . '-card', [
|
||||||
|
'id' => $boardId . '/' . $cardId,
|
||||||
|
'card' => $card,
|
||||||
|
'board' => $board,
|
||||||
|
'stack' => $stack,
|
||||||
|
]);
|
||||||
|
return $reference;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sanitizeSerializedStack(array $stack): array {
|
||||||
|
$stack['cards'] = array_map(function (CardDetails $cardDetails) {
|
||||||
|
$result = $cardDetails->jsonSerialize();
|
||||||
|
unset($result['assignedUsers']);
|
||||||
|
return $result;
|
||||||
|
}, $stack['cards']);
|
||||||
|
|
||||||
|
return $stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sanitizeSerializedBoard(array $board): array {
|
||||||
|
unset($board['labels']);
|
||||||
|
$board['owner'] = $board['owner']->jsonSerialize();
|
||||||
|
unset($board['acl']);
|
||||||
|
unset($board['users']);
|
||||||
|
|
||||||
|
return $board;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sanitizeSerializedCard(array $card): array {
|
||||||
|
$card['labels'] = array_map(function (Label $label) {
|
||||||
|
return $label->jsonSerialize();
|
||||||
|
}, $card['labels']);
|
||||||
|
$card['assignedUsers'] = array_map(function (Assignment $assignment) {
|
||||||
|
$result = $assignment->jsonSerialize();
|
||||||
|
$result['participant'] = $result['participant']->jsonSerialize();
|
||||||
|
return $result;
|
||||||
|
}, $card['assignedUsers']);
|
||||||
|
$card['owner'] = $card['owner']->jsonSerialize();
|
||||||
|
unset($card['relatedStack']);
|
||||||
|
unset($card['relatedBoard']);
|
||||||
|
$card['attachments'] = array_map(function (Attachment $attachment) {
|
||||||
|
return $attachment->jsonSerialize();
|
||||||
|
}, $card['attachments']);
|
||||||
|
|
||||||
|
return $card;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getBoardCardId(string $url): ?array {
|
||||||
|
$start = $this->urlGenerator->getAbsoluteURL('/apps/' . Application::APP_ID);
|
||||||
|
$startIndex = $this->urlGenerator->getAbsoluteURL('/index.php/apps/' . Application::APP_ID);
|
||||||
|
|
||||||
|
preg_match('/^' . preg_quote($start, '/') . '\/#\/board\/([0-9]+)\/card\/([0-9]+)$/', $url, $matches);
|
||||||
|
if ($matches && count($matches) > 2) {
|
||||||
|
return [$matches[1], $matches[2]];
|
||||||
|
}
|
||||||
|
|
||||||
|
preg_match('/^' . preg_quote($startIndex, '/') . '\/#\/board\/([0-9]+)\/card\/([0-9]+)$/', $url, $matches2);
|
||||||
|
if ($matches2 && count($matches2) > 2) {
|
||||||
|
return [$matches2[1], $matches2[2]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCachePrefix(string $referenceId): string {
|
||||||
|
$ids = $this->getBoardCardId($referenceId);
|
||||||
|
if ($ids !== null) {
|
||||||
|
[$boardId, $cardId] = $ids;
|
||||||
|
return $boardId . '/' . $cardId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $referenceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCacheKey(string $referenceId): ?string {
|
||||||
|
return $this->userId ?? '';
|
||||||
|
}
|
||||||
|
}
|
||||||