Compare commits
1 Commits
v1.9.0-bet
...
ci/query-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
011488d63b |
10
.github/workflows/integration.yml
vendored
10
.github/workflows/integration.yml
vendored
@@ -74,12 +74,11 @@ jobs:
|
||||
uses: shivammathur/setup-php@2.24.0
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
extensions: mbstring, iconv, fileinfo, intl, sqlite, pdo_sqlite, mysql, pdo_mysql, pgsql, pdo_pgsql, apcu
|
||||
ini-values:
|
||||
apc.enable_cli=on
|
||||
tools: phpunit
|
||||
extensions: mbstring, iconv, fileinfo, intl, sqlite, pdo_sqlite, mysql, pdo_mysql, pgsql, pdo_pgsql,
|
||||
coverage: none
|
||||
|
||||
- name: Set up dependencies
|
||||
- name: Set up PHPUnit
|
||||
working-directory: apps/${{ env.APP_NAME }}
|
||||
run: composer i --no-dev
|
||||
|
||||
@@ -92,9 +91,6 @@ jobs:
|
||||
fi
|
||||
mkdir data
|
||||
./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
|
||||
./occ config:system:set hashing_default_password --value=true --type=boolean
|
||||
./occ config:system:set memcache.local --value="\\OC\\Memcache\\APCu"
|
||||
./occ config:system:set memcache.distributed --value="\\OC\\Memcache\\APCu"
|
||||
cat config/config.php
|
||||
./occ user:list
|
||||
./occ app:enable --force ${{ env.APP_NAME }}
|
||||
|
||||
29
CHANGELOG.md
29
CHANGELOG.md
@@ -1,35 +1,6 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
|
||||
## 1.9.0-beta.1
|
||||
|
||||
### Added
|
||||
|
||||
- Export Board @david-loe [#3065](https://github.com/nextcloud/deck/pull/3065)
|
||||
- basic notify_push usage with session handling @alangecker [#3876](https://github.com/nextcloud/deck/pull/3876)
|
||||
- feat(Description): Use text as editor if available @juliushaertl [#4399](https://github.com/nextcloud/deck/pull/4399)
|
||||
- Improve reference provider and add reference widgets @julien-nc [#4422](https://github.com/nextcloud/deck/pull/4422)
|
||||
- live updates 🎉 @alangecker [#4273](https://github.com/nextcloud/deck/pull/4273)
|
||||
- Tag creation from card view @juliushaertl [#4344](https://github.com/nextcloud/deck/pull/4344)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix component renaming so that acl works on shares again @small1 [#4315](https://github.com/nextcloud/deck/pull/4315)
|
||||
- fix(Sidebar): Only close sidebar on v-click-outside for specific targets @juliushaertl [#4350](https://github.com/nextcloud/deck/pull/4350)
|
||||
- add basic e2e tests for stack title @shoetten [#4206](https://github.com/nextcloud/deck/pull/4206)
|
||||
- App metadata: add links to user and developer documentation @p-bo [#4356](https://github.com/nextcloud/deck/pull/4356)
|
||||
- Update signature of Entity::markFieldUpdated @nickvergessen [#4398](https://github.com/nextcloud/deck/pull/4398)
|
||||
- Remove updated nightly information @xf- [#4419](https://github.com/nextcloud/deck/pull/4419)
|
||||
- perf: Register notifier and resource listener lazy @juliushaertl [#4439](https://github.com/nextcloud/deck/pull/4439)
|
||||
- perf: Lazy load dashboard components @juliushaertl [#4440](https://github.com/nextcloud/deck/pull/4440)
|
||||
- Optimise upcomming overview creation @Raudius [#3793](https://github.com/nextcloud/deck/pull/3793)
|
||||
- Performance boost @juliushaertl [#4452](https://github.com/nextcloud/deck/pull/4452)
|
||||
|
||||
### Other
|
||||
- Dependency updates
|
||||
|
||||
|
||||
## 1.8.0-beta.1
|
||||
### Enhancements
|
||||
|
||||
|
||||
@@ -79,12 +79,8 @@ OC.L10N.register(
|
||||
"The board \"%s\" has been shared with you by %s." : "Таблото \"%s\" е споделено с вас от%s.",
|
||||
"{user} has shared {deck-board} with you." : "{user} сподели {deck-board} с Вас.",
|
||||
"Deck board" : "Deck табло",
|
||||
"Owned by %1$s" : "Притежаван от %1$s",
|
||||
"Deck boards, cards and comments" : "Табла, карти и коментари",
|
||||
"From %1$s, in %2$s/%3$s, owned by %4$s" : "От %1$s, в %2$s/%3$s, притежание на %4$s",
|
||||
"Card comments" : "Коментари на карти",
|
||||
"%s on %s" : "%s на %s",
|
||||
"Deck boards and cards" : "Табла и карти",
|
||||
"No data was provided to create an attachment." : "Не бяха предоставени данни за създаване на прикачен файл.",
|
||||
"Finished" : "Готово",
|
||||
"To review" : "За преглед",
|
||||
@@ -295,7 +291,6 @@ OC.L10N.register(
|
||||
"No due" : "Не се дължи",
|
||||
"Search for {searchQuery} in all boards" : "Търсене на {searchQuery} във всички табла",
|
||||
"No results found" : "Няма намерени резултати",
|
||||
"Deck board {name}\n* Last modified on {lastMod}" : "Табло {name}\n* Последна промяна на {lastMod}",
|
||||
"{stack} in {board}" : "{stack} в {board}",
|
||||
"Click to expand description" : "Кликване за разширяване на описанието",
|
||||
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Създаден на {created}\n* Последна промяна на {lastMod} \n* {nbAttachments} прикачени файлове \n* {nbComments} коментара",
|
||||
|
||||
@@ -77,12 +77,8 @@
|
||||
"The board \"%s\" has been shared with you by %s." : "Таблото \"%s\" е споделено с вас от%s.",
|
||||
"{user} has shared {deck-board} with you." : "{user} сподели {deck-board} с Вас.",
|
||||
"Deck board" : "Deck табло",
|
||||
"Owned by %1$s" : "Притежаван от %1$s",
|
||||
"Deck boards, cards and comments" : "Табла, карти и коментари",
|
||||
"From %1$s, in %2$s/%3$s, owned by %4$s" : "От %1$s, в %2$s/%3$s, притежание на %4$s",
|
||||
"Card comments" : "Коментари на карти",
|
||||
"%s on %s" : "%s на %s",
|
||||
"Deck boards and cards" : "Табла и карти",
|
||||
"No data was provided to create an attachment." : "Не бяха предоставени данни за създаване на прикачен файл.",
|
||||
"Finished" : "Готово",
|
||||
"To review" : "За преглед",
|
||||
@@ -293,7 +289,6 @@
|
||||
"No due" : "Не се дължи",
|
||||
"Search for {searchQuery} in all boards" : "Търсене на {searchQuery} във всички табла",
|
||||
"No results found" : "Няма намерени резултати",
|
||||
"Deck board {name}\n* Last modified on {lastMod}" : "Табло {name}\n* Последна промяна на {lastMod}",
|
||||
"{stack} in {board}" : "{stack} в {board}",
|
||||
"Click to expand description" : "Кликване за разширяване на описанието",
|
||||
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Създаден на {created}\n* Последна промяна на {lastMod} \n* {nbAttachments} прикачени файлове \n* {nbComments} коментара",
|
||||
|
||||
@@ -81,7 +81,6 @@ OC.L10N.register(
|
||||
"Deck board" : "Tableau",
|
||||
"Owned by %1$s" : "Assignée à %1$s",
|
||||
"Deck boards, cards and comments" : "Tableaux, cartes et commentaires",
|
||||
"From %1$s, in %2$s/%3$s, owned by %4$s" : "De %1$s, dans %2$s / %3$s, appartenant à %4$s",
|
||||
"Card comments" : "Commentaires de la carte",
|
||||
"%s on %s" : "%s sur %s",
|
||||
"Deck boards and cards" : "Tableaux et cartes",
|
||||
|
||||
@@ -79,7 +79,6 @@
|
||||
"Deck board" : "Tableau",
|
||||
"Owned by %1$s" : "Assignée à %1$s",
|
||||
"Deck boards, cards and comments" : "Tableaux, cartes et commentaires",
|
||||
"From %1$s, in %2$s/%3$s, owned by %4$s" : "De %1$s, dans %2$s / %3$s, appartenant à %4$s",
|
||||
"Card comments" : "Commentaires de la carte",
|
||||
"%s on %s" : "%s sur %s",
|
||||
"Deck boards and cards" : "Tableaux et cartes",
|
||||
|
||||
@@ -30,8 +30,6 @@ OC.L10N.register(
|
||||
"Created" : "Үүсгэсэн",
|
||||
"Today" : "өнөөдөр",
|
||||
"Tomorrow" : "маргааш",
|
||||
"Next week" : "Дараа 7 хоног",
|
||||
"Next month" : "Дараа сар",
|
||||
"Save" : "Хадгалах",
|
||||
"Reply" : "хариулт",
|
||||
"Update" : "Шинэчлэх",
|
||||
|
||||
@@ -28,8 +28,6 @@
|
||||
"Created" : "Үүсгэсэн",
|
||||
"Today" : "өнөөдөр",
|
||||
"Tomorrow" : "маргааш",
|
||||
"Next week" : "Дараа 7 хоног",
|
||||
"Next month" : "Дараа сар",
|
||||
"Save" : "Хадгалах",
|
||||
"Reply" : "хариулт",
|
||||
"Update" : "Шинэчлэх",
|
||||
|
||||
16
l10n/nb.js
16
l10n/nb.js
@@ -78,13 +78,9 @@ OC.L10N.register(
|
||||
"{user} has mentioned you in a comment on {deck-card}." : "{user} har nevnt deg i en kommentar på {deck-card}.",
|
||||
"The board \"%s\" has been shared with you by %s." : "Brettet \"%s\" har blitt delt med deg av %s.",
|
||||
"{user} has shared {deck-board} with you." : "{user} har delt brettet {deck-board} med deg.",
|
||||
"Deck board" : "Stokktavle",
|
||||
"Owned by %1$s" : "Eid av %1$s",
|
||||
"Deck boards, cards and comments" : "Stokktavler, kort og kommentarer",
|
||||
"From %1$s, in %2$s/%3$s, owned by %4$s" : "Fra %1$s, under %2$s/%3$s, eid av %4$s",
|
||||
"Deck board" : "Deck tavle",
|
||||
"Card comments" : "Kommentarer på kortet",
|
||||
"%s on %s" : "%s på %s",
|
||||
"Deck boards and cards" : "Stokktavler og kort",
|
||||
"No data was provided to create an attachment." : "Ingen data for å opprette vedlegg.",
|
||||
"Finished" : "Fullført",
|
||||
"To review" : "Til gjennomlesning",
|
||||
@@ -157,7 +153,6 @@ OC.L10N.register(
|
||||
"Toggle compact mode" : "Endre kompakt modus",
|
||||
"Open details" : "Åpne detaljer",
|
||||
"Details" : "Detaljer",
|
||||
"Currently present people" : "Tilstedeværende personer for øyeblikket",
|
||||
"Loading board" : "Laster tavle",
|
||||
"No lists available" : "Ingen stabler tilgjengelig",
|
||||
"Create a new list to add cards to this board" : "Lag en ny stabel for å legge til kort til denne tavlen",
|
||||
@@ -186,12 +181,9 @@ OC.L10N.register(
|
||||
"Transfer" : "Overfør",
|
||||
"The board has been transferred to {user}" : "Tavlen har blitt overført til {user}",
|
||||
"Failed to transfer the board to {user}" : "Klarte ikke overføre tavlen til {user}",
|
||||
"Edit list title" : "Rediger listetittel",
|
||||
"Archive all cards" : "Arkiver alle kort",
|
||||
"Unarchive all cards" : "Fjern alle kort fra arkiv",
|
||||
"Delete list" : "Slett listen",
|
||||
"Archive all cards in this list" : "Arkiver alle kort i en stabel",
|
||||
"Unarchive all cards in this list" : "Fjern alle kortene i denne listen fra arkiv",
|
||||
"Add a new card" : "Legg til nytt kort",
|
||||
"Card name" : "Navn på kort",
|
||||
"List deleted" : "Stabel slettet",
|
||||
@@ -268,7 +260,6 @@ OC.L10N.register(
|
||||
"Shared with you" : "Delt med deg",
|
||||
"Deck settings" : "Innstillinger for Stokk",
|
||||
"Use bigger card view" : "Bruk større visning på kort",
|
||||
"Show card ID badge" : "Vis ID-merke til kort",
|
||||
"Show boards in calendar/tasks" : "Vis tavler i kalender/oppgaver",
|
||||
"Limit deck usage of groups" : "Begrens stokk-bruk til 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." : "Begrensning av tavler vil hindre tilgang til de brukere som ikke er medlem av en gruppe fra å lage egne tavler. Bruker kan arbeide på de tavler som er delt med dem.",
|
||||
@@ -277,7 +268,6 @@ OC.L10N.register(
|
||||
"Clone board" : "Klon tavle",
|
||||
"Unarchive board" : "Aktiver tavle",
|
||||
"Archive board" : "Arkiver tavle",
|
||||
"Export board" : "Eksporter tavle",
|
||||
"Turn on due date reminders" : "Skru på påminnelser for forfallsdato",
|
||||
"Turn off due date reminders" : "Skru av påminnelser for forfallsdato",
|
||||
"Due date reminders" : "Påminnelser for forfallsdato",
|
||||
@@ -288,19 +278,17 @@ OC.L10N.register(
|
||||
"Board {0} deleted" : "Tavle {0} slettet",
|
||||
"Only assigned cards" : "Kun tildelte kort",
|
||||
"No reminder" : "Ingen varsel",
|
||||
"An error occurred" : "En feil oppsto",
|
||||
"An error occurred" : "En feil oppstod",
|
||||
"Are you sure you want to delete the board {title}? This will delete all the data of this board including archived cards." : "Are du sikker på sletting av tavlen {title}? Handlingen vil slette all data i denne tavlen, inkludert arkiverte kort.",
|
||||
"Delete the board?" : "Slett tavlen?",
|
||||
"Loading filtered view" : "Laster filtrert visning",
|
||||
"No due" : "Ingen forfall",
|
||||
"Search for {searchQuery} in all boards" : "Søk etter {searchQuery} i alle tavler",
|
||||
"No results found" : "Ingen resultater funnet",
|
||||
"Deck board {name}\n* Last modified on {lastMod}" : "Stokktavle {name}\n* Sist endret {lastMod}",
|
||||
"{stack} in {board}" : "{stack} i {board}",
|
||||
"Click to expand description" : "Klikk for å utvide beskrivelsen",
|
||||
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Opprettet {created}\n* Sist endret {lastMod}\n* {nbAttachments} vedlegg\n* {nbComments} kommentarer",
|
||||
"{nbCards} cards" : "{nbCards} kort",
|
||||
"Click to expand comment" : "Klikk for å utvide kommentaren",
|
||||
"No upcoming cards" : "Ingen kommende kort",
|
||||
"upcoming cards" : "kommende kort",
|
||||
"Due on {date}" : "Utløper {date}",
|
||||
|
||||
16
l10n/nb.json
16
l10n/nb.json
@@ -76,13 +76,9 @@
|
||||
"{user} has mentioned you in a comment on {deck-card}." : "{user} har nevnt deg i en kommentar på {deck-card}.",
|
||||
"The board \"%s\" has been shared with you by %s." : "Brettet \"%s\" har blitt delt med deg av %s.",
|
||||
"{user} has shared {deck-board} with you." : "{user} har delt brettet {deck-board} med deg.",
|
||||
"Deck board" : "Stokktavle",
|
||||
"Owned by %1$s" : "Eid av %1$s",
|
||||
"Deck boards, cards and comments" : "Stokktavler, kort og kommentarer",
|
||||
"From %1$s, in %2$s/%3$s, owned by %4$s" : "Fra %1$s, under %2$s/%3$s, eid av %4$s",
|
||||
"Deck board" : "Deck tavle",
|
||||
"Card comments" : "Kommentarer på kortet",
|
||||
"%s on %s" : "%s på %s",
|
||||
"Deck boards and cards" : "Stokktavler og kort",
|
||||
"No data was provided to create an attachment." : "Ingen data for å opprette vedlegg.",
|
||||
"Finished" : "Fullført",
|
||||
"To review" : "Til gjennomlesning",
|
||||
@@ -155,7 +151,6 @@
|
||||
"Toggle compact mode" : "Endre kompakt modus",
|
||||
"Open details" : "Åpne detaljer",
|
||||
"Details" : "Detaljer",
|
||||
"Currently present people" : "Tilstedeværende personer for øyeblikket",
|
||||
"Loading board" : "Laster tavle",
|
||||
"No lists available" : "Ingen stabler tilgjengelig",
|
||||
"Create a new list to add cards to this board" : "Lag en ny stabel for å legge til kort til denne tavlen",
|
||||
@@ -184,12 +179,9 @@
|
||||
"Transfer" : "Overfør",
|
||||
"The board has been transferred to {user}" : "Tavlen har blitt overført til {user}",
|
||||
"Failed to transfer the board to {user}" : "Klarte ikke overføre tavlen til {user}",
|
||||
"Edit list title" : "Rediger listetittel",
|
||||
"Archive all cards" : "Arkiver alle kort",
|
||||
"Unarchive all cards" : "Fjern alle kort fra arkiv",
|
||||
"Delete list" : "Slett listen",
|
||||
"Archive all cards in this list" : "Arkiver alle kort i en stabel",
|
||||
"Unarchive all cards in this list" : "Fjern alle kortene i denne listen fra arkiv",
|
||||
"Add a new card" : "Legg til nytt kort",
|
||||
"Card name" : "Navn på kort",
|
||||
"List deleted" : "Stabel slettet",
|
||||
@@ -266,7 +258,6 @@
|
||||
"Shared with you" : "Delt med deg",
|
||||
"Deck settings" : "Innstillinger for Stokk",
|
||||
"Use bigger card view" : "Bruk større visning på kort",
|
||||
"Show card ID badge" : "Vis ID-merke til kort",
|
||||
"Show boards in calendar/tasks" : "Vis tavler i kalender/oppgaver",
|
||||
"Limit deck usage of groups" : "Begrens stokk-bruk til 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." : "Begrensning av tavler vil hindre tilgang til de brukere som ikke er medlem av en gruppe fra å lage egne tavler. Bruker kan arbeide på de tavler som er delt med dem.",
|
||||
@@ -275,7 +266,6 @@
|
||||
"Clone board" : "Klon tavle",
|
||||
"Unarchive board" : "Aktiver tavle",
|
||||
"Archive board" : "Arkiver tavle",
|
||||
"Export board" : "Eksporter tavle",
|
||||
"Turn on due date reminders" : "Skru på påminnelser for forfallsdato",
|
||||
"Turn off due date reminders" : "Skru av påminnelser for forfallsdato",
|
||||
"Due date reminders" : "Påminnelser for forfallsdato",
|
||||
@@ -286,19 +276,17 @@
|
||||
"Board {0} deleted" : "Tavle {0} slettet",
|
||||
"Only assigned cards" : "Kun tildelte kort",
|
||||
"No reminder" : "Ingen varsel",
|
||||
"An error occurred" : "En feil oppsto",
|
||||
"An error occurred" : "En feil oppstod",
|
||||
"Are you sure you want to delete the board {title}? This will delete all the data of this board including archived cards." : "Are du sikker på sletting av tavlen {title}? Handlingen vil slette all data i denne tavlen, inkludert arkiverte kort.",
|
||||
"Delete the board?" : "Slett tavlen?",
|
||||
"Loading filtered view" : "Laster filtrert visning",
|
||||
"No due" : "Ingen forfall",
|
||||
"Search for {searchQuery} in all boards" : "Søk etter {searchQuery} i alle tavler",
|
||||
"No results found" : "Ingen resultater funnet",
|
||||
"Deck board {name}\n* Last modified on {lastMod}" : "Stokktavle {name}\n* Sist endret {lastMod}",
|
||||
"{stack} in {board}" : "{stack} i {board}",
|
||||
"Click to expand description" : "Klikk for å utvide beskrivelsen",
|
||||
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Opprettet {created}\n* Sist endret {lastMod}\n* {nbAttachments} vedlegg\n* {nbComments} kommentarer",
|
||||
"{nbCards} cards" : "{nbCards} kort",
|
||||
"Click to expand comment" : "Klikk for å utvide kommentaren",
|
||||
"No upcoming cards" : "Ingen kommende kort",
|
||||
"upcoming cards" : "kommende kort",
|
||||
"Due on {date}" : "Utløper {date}",
|
||||
|
||||
@@ -79,11 +79,8 @@ OC.L10N.register(
|
||||
"The board \"%s\" has been shared with you by %s." : "Вам предоставлен доступ к рабочей доске «%s» пользователем %s.",
|
||||
"{user} has shared {deck-board} with you." : "{user} предоставил(а) вам доступ к {deck-board}.",
|
||||
"Deck board" : "Доска",
|
||||
"Owned by %1$s" : "Владелец: %1$s",
|
||||
"Deck boards, cards and comments" : "Доски, карточки и комментарии",
|
||||
"Card comments" : "Комментарии карточки",
|
||||
"%s on %s" : "%s на %s",
|
||||
"Deck boards and cards" : "Доски и карточки",
|
||||
"No data was provided to create an attachment." : "Отсутствуют данные для создания вложения.",
|
||||
"Finished" : "Завершено",
|
||||
"To review" : "Проверить",
|
||||
@@ -184,7 +181,6 @@ OC.L10N.register(
|
||||
"Transfer" : "Передача",
|
||||
"The board has been transferred to {user}" : "Доска была передана пользователю {user}",
|
||||
"Failed to transfer the board to {user}" : "Не удалось передать доску пользователю {user}",
|
||||
"Edit list title" : "Изменить название списка",
|
||||
"Archive all cards" : "Переместить все карточки в архив",
|
||||
"Unarchive all cards" : "Восстановить все карточки из архива",
|
||||
"Delete list" : "Удалить список",
|
||||
@@ -275,7 +271,6 @@ OC.L10N.register(
|
||||
"Clone board" : "Скопировать доску",
|
||||
"Unarchive board" : "Восстановить доску из архива",
|
||||
"Archive board" : "Переместить доску в архив",
|
||||
"Export board" : "Экспортировать доску",
|
||||
"Turn on due date reminders" : "Включить напоминания о сроке выполнения",
|
||||
"Turn off due date reminders" : "Отключить напоминания о сроке выполнения",
|
||||
"Due date reminders" : "Напоминания о сроке выполнения",
|
||||
@@ -293,14 +288,11 @@ OC.L10N.register(
|
||||
"No due" : "Без назначенной даты",
|
||||
"Search for {searchQuery} in all boards" : "Искать {searchQuery} на всех досках",
|
||||
"No results found" : "Результаты отсутствуют",
|
||||
"Deck board {name}\n* Last modified on {lastMod}" : "Доска «{name}»\n* Последнее изменение: {lastMod}",
|
||||
"{stack} in {board}" : "«{stack}» с доски «{board}»",
|
||||
"Click to expand description" : "Нажмите, чтобы развернуть поле описания",
|
||||
"{nbCards} cards" : "карточек: {nbCards}",
|
||||
"Click to expand comment" : "Нажмите, чтобы развернуть комментарии",
|
||||
"No upcoming cards" : "Отсутствуют карточки, ожидающие выполнения",
|
||||
"upcoming cards" : "карточки, ожидающие выполнения",
|
||||
"Due on {date}" : "Дата исполнения: {date}",
|
||||
"Link to a board" : "Ссылка на доску",
|
||||
"Link to a card" : "Ссылка на карточку",
|
||||
"Create a card" : "Создать карточку",
|
||||
|
||||
@@ -77,11 +77,8 @@
|
||||
"The board \"%s\" has been shared with you by %s." : "Вам предоставлен доступ к рабочей доске «%s» пользователем %s.",
|
||||
"{user} has shared {deck-board} with you." : "{user} предоставил(а) вам доступ к {deck-board}.",
|
||||
"Deck board" : "Доска",
|
||||
"Owned by %1$s" : "Владелец: %1$s",
|
||||
"Deck boards, cards and comments" : "Доски, карточки и комментарии",
|
||||
"Card comments" : "Комментарии карточки",
|
||||
"%s on %s" : "%s на %s",
|
||||
"Deck boards and cards" : "Доски и карточки",
|
||||
"No data was provided to create an attachment." : "Отсутствуют данные для создания вложения.",
|
||||
"Finished" : "Завершено",
|
||||
"To review" : "Проверить",
|
||||
@@ -182,7 +179,6 @@
|
||||
"Transfer" : "Передача",
|
||||
"The board has been transferred to {user}" : "Доска была передана пользователю {user}",
|
||||
"Failed to transfer the board to {user}" : "Не удалось передать доску пользователю {user}",
|
||||
"Edit list title" : "Изменить название списка",
|
||||
"Archive all cards" : "Переместить все карточки в архив",
|
||||
"Unarchive all cards" : "Восстановить все карточки из архива",
|
||||
"Delete list" : "Удалить список",
|
||||
@@ -273,7 +269,6 @@
|
||||
"Clone board" : "Скопировать доску",
|
||||
"Unarchive board" : "Восстановить доску из архива",
|
||||
"Archive board" : "Переместить доску в архив",
|
||||
"Export board" : "Экспортировать доску",
|
||||
"Turn on due date reminders" : "Включить напоминания о сроке выполнения",
|
||||
"Turn off due date reminders" : "Отключить напоминания о сроке выполнения",
|
||||
"Due date reminders" : "Напоминания о сроке выполнения",
|
||||
@@ -291,14 +286,11 @@
|
||||
"No due" : "Без назначенной даты",
|
||||
"Search for {searchQuery} in all boards" : "Искать {searchQuery} на всех досках",
|
||||
"No results found" : "Результаты отсутствуют",
|
||||
"Deck board {name}\n* Last modified on {lastMod}" : "Доска «{name}»\n* Последнее изменение: {lastMod}",
|
||||
"{stack} in {board}" : "«{stack}» с доски «{board}»",
|
||||
"Click to expand description" : "Нажмите, чтобы развернуть поле описания",
|
||||
"{nbCards} cards" : "карточек: {nbCards}",
|
||||
"Click to expand comment" : "Нажмите, чтобы развернуть комментарии",
|
||||
"No upcoming cards" : "Отсутствуют карточки, ожидающие выполнения",
|
||||
"upcoming cards" : "карточки, ожидающие выполнения",
|
||||
"Due on {date}" : "Дата исполнения: {date}",
|
||||
"Link to a board" : "Ссылка на доску",
|
||||
"Link to a card" : "Ссылка на карточку",
|
||||
"Create a card" : "Создать карточку",
|
||||
|
||||
@@ -185,7 +185,6 @@ OC.L10N.register(
|
||||
"An error occurred" : "Виникла помилка",
|
||||
"Are you sure you want to delete the board {title}? This will delete all the data of this board including archived cards." : "Ви впевнені, що хочете вилучити дошку {title}? Це призведе до видалення всіх даних цієї дошки, включаючи архівні картки.",
|
||||
"Delete the board?" : "Вилучити дошку?",
|
||||
"Due on {date}" : "До {date}",
|
||||
"Link to a board" : "Прив'язати до дошки",
|
||||
"Link to a card" : "Прив'язати до картки",
|
||||
"Message from {author} in {conversationName}" : "Повідомлення від {author} у {conversationName}",
|
||||
|
||||
@@ -183,7 +183,6 @@
|
||||
"An error occurred" : "Виникла помилка",
|
||||
"Are you sure you want to delete the board {title}? This will delete all the data of this board including archived cards." : "Ви впевнені, що хочете вилучити дошку {title}? Це призведе до видалення всіх даних цієї дошки, включаючи архівні картки.",
|
||||
"Delete the board?" : "Вилучити дошку?",
|
||||
"Due on {date}" : "До {date}",
|
||||
"Link to a board" : "Прив'язати до дошки",
|
||||
"Link to a card" : "Прив'язати до картки",
|
||||
"Message from {author} in {conversationName}" : "Повідомлення від {author} у {conversationName}",
|
||||
|
||||
@@ -36,7 +36,6 @@ use OCA\Deck\Db\CardMapper;
|
||||
use OCA\Deck\Event\AclCreatedEvent;
|
||||
use OCA\Deck\Event\AclDeletedEvent;
|
||||
use OCA\Deck\Event\AclUpdatedEvent;
|
||||
use OCA\Deck\Event\BoardUpdatedEvent;
|
||||
use OCA\Deck\Event\CardCreatedEvent;
|
||||
use OCA\Deck\Event\CardDeletedEvent;
|
||||
use OCA\Deck\Event\CardUpdatedEvent;
|
||||
@@ -155,13 +154,6 @@ class Application extends App implements IBootstrap {
|
||||
// Event listening for realtime updates via notify_push
|
||||
$context->registerEventListener(SessionCreatedEvent::class, LiveUpdateListener::class);
|
||||
$context->registerEventListener(SessionClosedEvent::class, LiveUpdateListener::class);
|
||||
$context->registerEventListener(BoardUpdatedEvent::class, LiveUpdateListener::class);
|
||||
$context->registerEventListener(CardCreatedEvent::class, LiveUpdateListener::class);
|
||||
$context->registerEventListener(CardUpdatedEvent::class, LiveUpdateListener::class);
|
||||
$context->registerEventListener(CardDeletedEvent::class, LiveUpdateListener::class);
|
||||
$context->registerEventListener(AclCreatedEvent::class, LiveUpdateListener::class);
|
||||
$context->registerEventListener(AclUpdatedEvent::class, LiveUpdateListener::class);
|
||||
$context->registerEventListener(AclDeletedEvent::class, LiveUpdateListener::class);
|
||||
|
||||
$context->registerNotifierService(Notifier::class);
|
||||
$context->registerEventListener(LoadAdditionalScriptsEvent::class, ResourceAdditionalScriptsListener::class);
|
||||
|
||||
@@ -65,7 +65,7 @@ class BoardApiController extends ApiController {
|
||||
public function index($details = null) {
|
||||
$modified = $this->request->getHeader('If-Modified-Since');
|
||||
if ($modified === null || $modified === '') {
|
||||
$boards = $this->boardService->findAll(0, $details === true);
|
||||
$boards = $this->boardService->findAll(0, $details);
|
||||
} else {
|
||||
$date = Util::parseHTTPDate($modified);
|
||||
if (!$date) {
|
||||
|
||||
@@ -59,7 +59,7 @@ class DeckCalendarBackend {
|
||||
}
|
||||
|
||||
public function getBoards(): array {
|
||||
return $this->boardService->findAll(-1, false, false);
|
||||
return $this->boardService->findAll(-1, null, false);
|
||||
}
|
||||
|
||||
public function getBoard(int $id): Board {
|
||||
|
||||
@@ -52,20 +52,6 @@ class AclMapper extends DeckMapper implements IPermissionMapper {
|
||||
return $this->findEntities($qb);
|
||||
}
|
||||
|
||||
public function findIn(array $boardIds, ?int $limit = null, ?int $offset = null): array {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->select('id', 'board_id', 'type', 'participant', 'permission_edit', 'permission_share', 'permission_manage')
|
||||
->from('deck_board_acl')
|
||||
->where($qb->expr()->in('board_id', $qb->createParameter('boardIds')))
|
||||
->setMaxResults($limit)
|
||||
->setFirstResult($offset);
|
||||
|
||||
return iterator_to_array($this->chunkQuery($boardIds, function (array $ids) use ($qb) {
|
||||
$qb->setParameter('boardIds', $ids, IQueryBuilder::PARAM_INT_ARRAY);
|
||||
return $this->findEntities($qb);
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param numeric $userId
|
||||
* @param numeric $id
|
||||
|
||||
@@ -28,13 +28,15 @@ namespace OCA\Deck\Db;
|
||||
use OCA\Deck\NotFoundException;
|
||||
use OCA\Deck\Service\CirclesService;
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\AppFramework\Db\QBMapper;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\IUserManager;
|
||||
use PDO;
|
||||
|
||||
/** @template-extends DeckMapper<Assignment> */
|
||||
class AssignmentMapper extends DeckMapper implements IPermissionMapper {
|
||||
/** @template-extends QBMapper<Assignment> */
|
||||
class AssignmentMapper extends QBMapper implements IPermissionMapper {
|
||||
|
||||
/** @var CardMapper */
|
||||
private $cardMapper;
|
||||
@@ -58,7 +60,7 @@ class AssignmentMapper extends DeckMapper implements IPermissionMapper {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->select('*')
|
||||
->from('deck_assigned_users')
|
||||
->where($qb->expr()->eq('card_id', $qb->createNamedParameter($cardId, IQueryBuilder::PARAM_INT)));
|
||||
->where($qb->expr()->eq('card_id', $qb->createNamedParameter($cardId, PDO::PARAM_INT)));
|
||||
$users = $this->findEntities($qb);
|
||||
foreach ($users as $user) {
|
||||
$this->mapParticipant($user);
|
||||
@@ -66,29 +68,12 @@ class AssignmentMapper extends DeckMapper implements IPermissionMapper {
|
||||
return $users;
|
||||
}
|
||||
|
||||
public function findIn(array $cardIds): array {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->select('*')
|
||||
->from('deck_assigned_users')
|
||||
->where($qb->expr()->in('card_id', $qb->createParameter('cardIds')));
|
||||
|
||||
$users = iterator_to_array($this->chunkQuery($cardIds, function (array $ids) use ($qb) {
|
||||
$qb->setParameter('cardIds', $ids, IQueryBuilder::PARAM_INT_ARRAY);
|
||||
return $this->findEntities($qb);
|
||||
}));
|
||||
|
||||
foreach ($users as $user) {
|
||||
$this->mapParticipant($user);
|
||||
}
|
||||
return $users;
|
||||
}
|
||||
|
||||
public function findByParticipant(string $participant, $type = Assignment::TYPE_USER): array {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->select('*')
|
||||
->from('deck_assigned_users')
|
||||
->where($qb->expr()->eq('participant', $qb->createNamedParameter($participant, IQueryBuilder::PARAM_STR)))
|
||||
->andWhere($qb->expr()->eq('type', $qb->createNamedParameter($type, IQueryBuilder::PARAM_INT)));
|
||||
->where($qb->expr()->eq('participant', $qb->createNamedParameter($participant, PDO::PARAM_STR)))
|
||||
->andWhere($qb->expr()->eq('type', $qb->createNamedParameter($type, PDO::PARAM_INT)));
|
||||
return $this->findEntities($qb);
|
||||
}
|
||||
|
||||
@@ -147,8 +132,8 @@ class AssignmentMapper extends DeckMapper implements IPermissionMapper {
|
||||
|
||||
private function getOrigin(Assignment $assignment) {
|
||||
if ($assignment->getType() === Assignment::TYPE_USER) {
|
||||
$origin = $this->userManager->userExists($assignment->getParticipant());
|
||||
return $origin ? new User($assignment->getParticipant(), $this->userManager) : null;
|
||||
$origin = $this->userManager->get($assignment->getParticipant());
|
||||
return $origin ? new User($origin) : null;
|
||||
}
|
||||
if ($assignment->getType() === Assignment::TYPE_GROUP) {
|
||||
$origin = $this->groupManager->get($assignment->getParticipant());
|
||||
|
||||
@@ -90,6 +90,9 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
|
||||
$this->boardCache[$id] = $this->findEntity($qb);
|
||||
}
|
||||
|
||||
// FIXME is this necessary? it was NOT done with the old mapper
|
||||
// $this->mapOwner($board);
|
||||
|
||||
// Add labels
|
||||
if ($withLabels && $this->boardCache[$id]->getLabels() === null) {
|
||||
$labels = $this->labelMapper->findAll($id);
|
||||
@@ -157,20 +160,6 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
|
||||
$groupBoards = $this->findAllByGroups($userId, $groups, null, null, $since, $includeArchived, $before, $term);
|
||||
$circleBoards = $this->findAllByCircles($userId, null, null, $since, $includeArchived, $before, $term);
|
||||
$allBoards = array_unique(array_merge($userBoards, $groupBoards, $circleBoards));
|
||||
|
||||
// Could be moved outside
|
||||
$acls = $this->aclMapper->findIn(array_map(function ($board) {
|
||||
return $board->getId();
|
||||
}, $allBoards));
|
||||
|
||||
/* @var Board $entry */
|
||||
foreach ($allBoards as $entry) {
|
||||
$boardAcls = array_values(array_filter($acls, function ($acl) use ($entry) {
|
||||
return $acl->getBoardId() === $entry->getId();
|
||||
}));
|
||||
$entry->setAcl($boardAcls);
|
||||
}
|
||||
|
||||
foreach ($allBoards as $board) {
|
||||
$this->boardCache[$board->getId()] = $board;
|
||||
}
|
||||
@@ -270,7 +259,11 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
|
||||
$entry->setShared(1);
|
||||
}
|
||||
$entries = array_merge($entries, $sharedEntries);
|
||||
|
||||
/* @var Board $entry */
|
||||
foreach ($entries as $entry) {
|
||||
$acl = $this->aclMapper->findAll($entry->id);
|
||||
$entry->setAcl($acl);
|
||||
}
|
||||
return $entries;
|
||||
}
|
||||
|
||||
@@ -343,6 +336,11 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
|
||||
foreach ($entries as $entry) {
|
||||
$entry->setShared(2);
|
||||
}
|
||||
/* @var Board $entry */
|
||||
foreach ($entries as $entry) {
|
||||
$acl = $this->aclMapper->findAll($entry->id);
|
||||
$entry->setAcl($acl);
|
||||
}
|
||||
return $entries;
|
||||
}
|
||||
|
||||
@@ -399,6 +397,11 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
|
||||
foreach ($entries as $entry) {
|
||||
$entry->setShared(2);
|
||||
}
|
||||
/* @var Board $entry */
|
||||
foreach ($entries as $entry) {
|
||||
$acl = $this->aclMapper->findAll($entry->id);
|
||||
$entry->setAcl($acl);
|
||||
}
|
||||
return $entries;
|
||||
}
|
||||
|
||||
@@ -452,11 +455,13 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
|
||||
}
|
||||
|
||||
public function mapAcl(Acl &$acl) {
|
||||
$userManager = $this->userManager;
|
||||
$groupManager = $this->groupManager;
|
||||
$acl->resolveRelation('participant', function ($participant) use (&$acl, &$userManager, &$groupManager) {
|
||||
if ($acl->getType() === Acl::PERMISSION_TYPE_USER) {
|
||||
if ($this->userManager->userExists($acl->getParticipant())) {
|
||||
return new User($acl->getParticipant(), $this->userManager);
|
||||
$user = $userManager->get($participant);
|
||||
if ($user !== null) {
|
||||
return new User($user);
|
||||
}
|
||||
$this->logger->debug('User ' . $acl->getId() . ' not found when mapping acl ' . $acl->getParticipant());
|
||||
return null;
|
||||
@@ -494,8 +499,9 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
|
||||
public function mapOwner(Board &$board) {
|
||||
$userManager = $this->userManager;
|
||||
$board->resolveRelation('owner', function ($owner) use (&$userManager) {
|
||||
if ($this->userManager->userExists($owner)) {
|
||||
return new User($owner, $userManager);
|
||||
$user = $userManager->get($owner);
|
||||
if ($user !== null) {
|
||||
return new User($user);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
@@ -254,13 +254,13 @@ class CardMapper extends QBMapper implements IPermissionMapper {
|
||||
return $this->findEntities($qb);
|
||||
}
|
||||
|
||||
public function findAllWithDue(array $boardIds) {
|
||||
public function findAllWithDue($boardId) {
|
||||
$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()->in('s.board_id', $qb->createNamedParameter($boardIds, IQueryBuilder::PARAM_INT_ARRAY)))
|
||||
->where($qb->expr()->eq('s.board_id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
|
||||
->andWhere($qb->expr()->isNotNull('c.duedate'))
|
||||
->andWhere($qb->expr()->eq('c.archived', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)))
|
||||
->andWhere($qb->expr()->eq('c.deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)))
|
||||
@@ -270,14 +270,14 @@ class CardMapper extends QBMapper implements IPermissionMapper {
|
||||
return $this->findEntities($qb);
|
||||
}
|
||||
|
||||
public function findToMeOrNotAssignedCards(array $boardIds, string $username) {
|
||||
public function findToMeOrNotAssignedCards($boardId, $username) {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->select('c.*')
|
||||
->from('deck_cards', 'c')
|
||||
->innerJoin('c', 'deck_stacks', 's', 's.id = c.stack_id')
|
||||
->innerJoin('s', 'deck_boards', 'b', 'b.id = s.board_id')
|
||||
->leftJoin('c', 'deck_assigned_users', 'u', 'c.id = u.card_id')
|
||||
->where($qb->expr()->in('s.board_id', $qb->createNamedParameter($boardIds, IQueryBuilder::PARAM_INT_ARRAY)))
|
||||
->where($qb->expr()->eq('s.board_id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
|
||||
->andWhere($qb->expr()->orX(
|
||||
$qb->expr()->eq('u.participant', $qb->createNamedParameter($username, IQueryBuilder::PARAM_STR)),
|
||||
$qb->expr()->isNull('u.participant'))
|
||||
@@ -607,8 +607,9 @@ class CardMapper extends QBMapper implements IPermissionMapper {
|
||||
public function mapOwner(Card &$card) {
|
||||
$userManager = $this->userManager;
|
||||
$card->resolveRelation('owner', function ($owner) use (&$userManager) {
|
||||
if ($userManager->userExists($owner)) {
|
||||
return new User($owner, $this->userManager);
|
||||
$user = $userManager->get($owner);
|
||||
if ($user !== null) {
|
||||
return new User($user);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
namespace OCA\Deck\Db;
|
||||
|
||||
use Generator;
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\AppFramework\Db\QBMapper;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
@@ -36,7 +35,7 @@ abstract class DeckMapper extends QBMapper {
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @return T
|
||||
* @return \OCP\AppFramework\Db\Entity if not found
|
||||
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
|
||||
* @throws \OCP\AppFramework\Db\DoesNotExistException
|
||||
*/
|
||||
@@ -48,21 +47,4 @@ abstract class DeckMapper extends QBMapper {
|
||||
|
||||
return $this->findEntity($qb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to split passed array into chunks of 1000 elements and
|
||||
* call a given callback for fetching query results
|
||||
*
|
||||
* Can be useful to limit to 1000 results per query for oracle compatiblity
|
||||
* but still iterate over all results
|
||||
*/
|
||||
public function chunkQuery(array $ids, callable $callback): Generator {
|
||||
$limit = 1000;
|
||||
while (!empty($ids)) {
|
||||
$slice = array_splice($ids, 0, $limit);
|
||||
foreach ($callback($slice) as $item) {
|
||||
yield $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,19 +79,6 @@ class LabelMapper extends DeckMapper implements IPermissionMapper {
|
||||
return $this->findEntities($qb);
|
||||
}
|
||||
|
||||
public function findAssignedLabelsForCards($cardIds, $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()->in('card_id', $qb->createNamedParameter($cardIds, IQueryBuilder::PARAM_INT_ARRAY)))
|
||||
->orderBy('l.id')
|
||||
->setMaxResults($limit)
|
||||
->setFirstResult($offset);
|
||||
|
||||
return $this->findEntities($qb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param numeric $boardId
|
||||
* @param int|null $limit
|
||||
|
||||
@@ -33,7 +33,7 @@ class RelationalObject implements JsonSerializable {
|
||||
* RelationalObject constructor.
|
||||
*
|
||||
* @param $primaryKey string
|
||||
* @param callable|mixed $object
|
||||
* @param $object
|
||||
*/
|
||||
public function __construct($primaryKey, $object) {
|
||||
$this->primaryKey = $primaryKey;
|
||||
@@ -47,24 +47,16 @@ class RelationalObject implements JsonSerializable {
|
||||
);
|
||||
}
|
||||
|
||||
public function getObject() {
|
||||
if (is_callable($this->object)) {
|
||||
$this->object = call_user_func($this->object, $this);
|
||||
}
|
||||
|
||||
return $this->object;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should be overwritten if object doesn't implement \JsonSerializable
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getObjectSerialization() {
|
||||
if ($this->getObject() instanceof JsonSerializable) {
|
||||
return $this->getObject()->jsonSerialize();
|
||||
if ($this->object instanceof JsonSerializable) {
|
||||
return $this->object->jsonSerialize();
|
||||
} else {
|
||||
throw new \Exception('jsonSerialize is not implemented on ' . get_class($this->getObject()));
|
||||
throw new \Exception('jsonSerialize is not implemented on ' . get_class($this));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,27 +26,16 @@ namespace OCA\Deck\Db;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||
use OCP\Cache\CappedMemoryCache;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\ICache;
|
||||
use OCP\ICacheFactory;
|
||||
|
||||
/** @template-extends DeckMapper<Stack> */
|
||||
class StackMapper extends DeckMapper implements IPermissionMapper {
|
||||
private CappedMemoryCache $stackCache;
|
||||
private CardMapper $cardMapper;
|
||||
private ICache $cache;
|
||||
private $cardMapper;
|
||||
|
||||
public function __construct(
|
||||
IDBConnection $db,
|
||||
CardMapper $cardMapper,
|
||||
ICacheFactory $cacheFactory
|
||||
) {
|
||||
public function __construct(IDBConnection $db, CardMapper $cardMapper) {
|
||||
parent::__construct($db, 'deck_stacks', Stack::class);
|
||||
$this->cardMapper = $cardMapper;
|
||||
$this->stackCache = new CappedMemoryCache();
|
||||
$this->cache = $cacheFactory->createDistributed('deck-stackMapper');
|
||||
}
|
||||
|
||||
|
||||
@@ -58,17 +47,12 @@ class StackMapper extends DeckMapper implements IPermissionMapper {
|
||||
* @throws \OCP\DB\Exception
|
||||
*/
|
||||
public function find($id): Stack {
|
||||
if (isset($this->stackCache[(string)$id])) {
|
||||
return $this->stackCache[(string)$id];
|
||||
}
|
||||
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->select('*')
|
||||
->from($this->getTableName())
|
||||
->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)));
|
||||
|
||||
$this->stackCache[(string)$id] = $this->findEntity($qb);
|
||||
return $this->stackCache[(string)$id];
|
||||
return $this->findEntity($qb);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,16 +113,9 @@ class StackMapper extends DeckMapper implements IPermissionMapper {
|
||||
return $this->findEntities($qb);
|
||||
}
|
||||
|
||||
public function update(Entity $entity): Entity {
|
||||
$result = parent::update($entity);
|
||||
$this->stackCache[(string)$entity->getId()] = $result;
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function delete(Entity $entity): Entity {
|
||||
// delete cards on stack
|
||||
$this->cardMapper->deleteByStack($entity->getId());
|
||||
unset($this->stackCache[(string)$entity->getId()]);
|
||||
return parent::delete($entity);
|
||||
}
|
||||
|
||||
@@ -165,19 +142,12 @@ class StackMapper extends DeckMapper implements IPermissionMapper {
|
||||
* @throws \OCP\DB\Exception
|
||||
*/
|
||||
public function findBoardId($id): ?int {
|
||||
$result = $this->cache->get('findBoardId:' . $id);
|
||||
if ($result !== null) {
|
||||
return $result !== false ? $result : null;
|
||||
}
|
||||
try {
|
||||
$entity = $this->find($id);
|
||||
$result = $entity->getBoardId();
|
||||
return $entity->getBoardId();
|
||||
} catch (DoesNotExistException $e) {
|
||||
$result = false;
|
||||
} catch (MultipleObjectsReturnedException $e) {
|
||||
}
|
||||
$this->cache->set('findBoardId:' . $id, $result);
|
||||
|
||||
return $result !== false ? $result : null;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,30 +23,27 @@
|
||||
|
||||
namespace OCA\Deck\Db;
|
||||
|
||||
use OCP\IUserManager;
|
||||
use OCP\IUser;
|
||||
|
||||
class User extends RelationalObject {
|
||||
private IUserManager $userManager;
|
||||
public function __construct($uid, IUserManager $userManager) {
|
||||
$this->userManager = $userManager;
|
||||
parent::__construct($uid, function ($object) {
|
||||
return $this->userManager->get($object->getPrimaryKey());
|
||||
});
|
||||
public function __construct(IUser $user) {
|
||||
$primaryKey = $user->getUID();
|
||||
parent::__construct($primaryKey, $user);
|
||||
}
|
||||
|
||||
public function getObjectSerialization() {
|
||||
return [
|
||||
'uid' => $this->getObject()->getUID(),
|
||||
'displayname' => $this->getObject()->getDisplayName(),
|
||||
'type' => Acl::PERMISSION_TYPE_USER
|
||||
'uid' => $this->object->getUID(),
|
||||
'displayname' => $this->object->getDisplayName(),
|
||||
'type' => 0
|
||||
];
|
||||
}
|
||||
|
||||
public function getUID() {
|
||||
return $this->getPrimaryKey();
|
||||
return $this->object->getUID();
|
||||
}
|
||||
|
||||
public function getDisplayName() {
|
||||
return $this->userManager->getDisplayName($this->getPrimaryKey());
|
||||
return $this->object->getDisplayName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ use OCP\EventDispatcher\Event;
|
||||
|
||||
abstract class AAclEvent extends Event {
|
||||
private $acl;
|
||||
|
||||
|
||||
public function __construct(Acl $acl) {
|
||||
parent::__construct();
|
||||
|
||||
@@ -41,8 +41,4 @@ abstract class AAclEvent extends Event {
|
||||
public function getAcl(): Acl {
|
||||
return $this->acl;
|
||||
}
|
||||
|
||||
public function getBoardId(): int {
|
||||
return $this->acl->getBoardId();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (c) 2022 chandi Langecker <git@chandi.it>
|
||||
*
|
||||
* @author chandi Langecker <git@chandi.it>
|
||||
*
|
||||
* @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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
namespace OCA\Deck\Event;
|
||||
|
||||
use OCP\EventDispatcher\Event;
|
||||
|
||||
class BoardUpdatedEvent extends Event {
|
||||
private $boardId;
|
||||
|
||||
public function __construct(int $boardId) {
|
||||
parent::__construct();
|
||||
|
||||
$this->boardId = $boardId;
|
||||
}
|
||||
|
||||
public function getBoardId(): int {
|
||||
return $this->boardId;
|
||||
}
|
||||
}
|
||||
@@ -26,17 +26,5 @@ declare(strict_types=1);
|
||||
|
||||
namespace OCA\Deck\Event;
|
||||
|
||||
use OCA\Deck\Db\Card;
|
||||
|
||||
class CardUpdatedEvent extends ACardEvent {
|
||||
private $cardBefore;
|
||||
|
||||
public function __construct(Card $card, Card $before = null) {
|
||||
parent::__construct($card);
|
||||
$this->cardBefore = $before;
|
||||
}
|
||||
|
||||
public function getCardBefore() {
|
||||
return $this->cardBefore;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,12 +26,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace OCA\Deck\Listeners;
|
||||
|
||||
use OCA\Deck\Db\StackMapper;
|
||||
use OCA\Deck\NotifyPushEvents;
|
||||
use OCA\Deck\Event\AAclEvent;
|
||||
use OCA\Deck\Event\ACardEvent;
|
||||
use OCA\Deck\Event\BoardUpdatedEvent;
|
||||
use OCA\Deck\Event\CardUpdatedEvent;
|
||||
use OCA\Deck\Event\SessionClosedEvent;
|
||||
use OCA\Deck\Event\SessionCreatedEvent;
|
||||
use OCA\Deck\Service\SessionService;
|
||||
@@ -42,20 +37,18 @@ use OCP\IRequest;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/** @template-implements IEventListener<Event|SessionCreatedEvent|SessionClosedEvent|AAclEvent|ACardEvent|CardUpdatedEvent|BoardUpdatedEvent> */
|
||||
/** @template-implements IEventListener<Event|SessionCreatedEvent|SessionClosedEvent> */
|
||||
class LiveUpdateListener implements IEventListener {
|
||||
private LoggerInterface $logger;
|
||||
private SessionService $sessionService;
|
||||
private IRequest $request;
|
||||
private StackMapper $stackMapper;
|
||||
private $queue;
|
||||
|
||||
public function __construct(
|
||||
ContainerInterface $container,
|
||||
IRequest $request,
|
||||
LoggerInterface $logger,
|
||||
SessionService $sessionService,
|
||||
StackMapper $stackMapper
|
||||
SessionService $sessionService
|
||||
) {
|
||||
try {
|
||||
$this->queue = $container->get(IQueue::class);
|
||||
@@ -66,7 +59,6 @@ class LiveUpdateListener implements IEventListener {
|
||||
$this->logger = $logger;
|
||||
$this->sessionService = $sessionService;
|
||||
$this->request = $request;
|
||||
$this->stackMapper = $stackMapper;
|
||||
}
|
||||
|
||||
public function handle(Event $event): void {
|
||||
@@ -76,37 +68,17 @@ class LiveUpdateListener implements IEventListener {
|
||||
}
|
||||
|
||||
try {
|
||||
// the web frontend is adding the Session-ID as a header
|
||||
// the web frontend is adding the Session-ID as a header on every request
|
||||
// TODO: verify the token! this currently allows to spoof a token from someone
|
||||
// else, preventing this person from getting updates
|
||||
// else, preventing this person from getting any live updates
|
||||
$causingSessionToken = $this->request->getHeader('x-nc-deck-session');
|
||||
if (
|
||||
$event instanceof SessionCreatedEvent ||
|
||||
$event instanceof SessionClosedEvent ||
|
||||
$event instanceof BoardUpdatedEvent ||
|
||||
$event instanceof AAclEvent
|
||||
$event instanceof SessionClosedEvent
|
||||
) {
|
||||
$this->sessionService->notifyAllSessions($this->queue, $event->getBoardId(), NotifyPushEvents::DeckBoardUpdate, [
|
||||
'id' => $event->getBoardId()
|
||||
], $causingSessionToken);
|
||||
} elseif ($event instanceof ACardEvent) {
|
||||
$boardId = $this->stackMapper->findBoardId($event->getCard()->getStackId());
|
||||
$this->sessionService->notifyAllSessions($this->queue, $boardId, NotifyPushEvents::DeckCardUpdate, [
|
||||
'boardId' => $boardId,
|
||||
'cardId' => $event->getCard()->getId()
|
||||
], $causingSessionToken);
|
||||
|
||||
// if card got moved to a diferent board, we should notify
|
||||
// also sessions active on the previous board
|
||||
if ($event instanceof CardUpdatedEvent && $event->getCardBefore()) {
|
||||
$previousBoardId = $this->stackMapper->findBoardId($event->getCardBefore()->getStackId());
|
||||
if ($boardId !== $previousBoardId) {
|
||||
$this->sessionService->notifyAllSessions($this->queue, $previousBoardId, NotifyPushEvents::DeckCardUpdate, [
|
||||
'boardId' => $boardId,
|
||||
'cardId' => $event->getCard()->getId()
|
||||
], $causingSessionToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$this->logger->error('Error when handling live update event', ['exception' => $e]);
|
||||
|
||||
@@ -26,5 +26,4 @@ namespace OCA\Deck;
|
||||
|
||||
class NotifyPushEvents {
|
||||
public const DeckBoardUpdate = 'deck_board_update';
|
||||
public const DeckCardUpdate = 'deck_card_update';
|
||||
}
|
||||
|
||||
@@ -56,7 +56,6 @@ use OCA\Deck\Db\BoardMapper;
|
||||
use OCA\Deck\Db\LabelMapper;
|
||||
use OCP\IUserManager;
|
||||
use OCA\Deck\BadRequestException;
|
||||
use OCA\Deck\Event\BoardUpdatedEvent;
|
||||
use OCA\Deck\Validators\BoardServiceValidator;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\Server;
|
||||
@@ -80,8 +79,7 @@ class BoardService {
|
||||
private IEventDispatcher $eventDispatcher;
|
||||
private ChangeHelper $changeHelper;
|
||||
private CardMapper $cardMapper;
|
||||
private ?array $boardsCacheFull = null;
|
||||
private ?array $boardsCachePartial = null;
|
||||
private ?array $boardsCache = null;
|
||||
private IURLGenerator $urlGenerator;
|
||||
private IDBConnection $connection;
|
||||
private BoardServiceValidator $boardServiceValidator;
|
||||
@@ -149,45 +147,96 @@ class BoardService {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Board[]
|
||||
* @return array
|
||||
*/
|
||||
public function findAll(int $since = -1, bool $fullDetails = false, bool $includeArchived = true): array {
|
||||
if ($this->boardsCacheFull && $fullDetails) {
|
||||
return $this->boardsCacheFull;
|
||||
public function findAll($since = -1, $details = null, $includeArchived = true) {
|
||||
if ($this->boardsCache) {
|
||||
return $this->boardsCache;
|
||||
}
|
||||
|
||||
if ($this->boardsCachePartial && !$fullDetails) {
|
||||
return $this->boardsCachePartial;
|
||||
}
|
||||
|
||||
$complete = $this->getUserBoards($since, $includeArchived);
|
||||
return $this->enrichBoards($complete, $fullDetails);
|
||||
$result = [];
|
||||
/** @var Board $item */
|
||||
foreach ($complete as &$item) {
|
||||
$this->boardMapper->mapOwner($item);
|
||||
if ($item->getAcl() !== null) {
|
||||
foreach ($item->getAcl() as &$acl) {
|
||||
$this->boardMapper->mapAcl($acl);
|
||||
}
|
||||
}
|
||||
if ($details !== null) {
|
||||
$this->enrichWithStacks($item);
|
||||
$this->enrichWithLabels($item);
|
||||
$this->enrichWithUsers($item);
|
||||
}
|
||||
$permissions = $this->permissionService->matchPermissions($item);
|
||||
$item->setPermissions([
|
||||
'PERMISSION_READ' => $permissions[Acl::PERMISSION_READ] ?? false,
|
||||
'PERMISSION_EDIT' => $permissions[Acl::PERMISSION_EDIT] ?? false,
|
||||
'PERMISSION_MANAGE' => $permissions[Acl::PERMISSION_MANAGE] ?? false,
|
||||
'PERMISSION_SHARE' => $permissions[Acl::PERMISSION_SHARE] ?? false
|
||||
]);
|
||||
$this->enrichWithBoardSettings($item);
|
||||
$result[$item->getId()] = $item;
|
||||
}
|
||||
$this->boardsCache = $result;
|
||||
return array_values($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $boardId
|
||||
* @return Board
|
||||
* @throws DoesNotExistException
|
||||
* @throws \OCA\Deck\NoPermissionException
|
||||
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
|
||||
* @throws BadRequestException
|
||||
*/
|
||||
public function find(int $boardId, bool $fullDetails = true): Board {
|
||||
public function find($boardId) {
|
||||
$this->boardServiceValidator->check(compact('boardId'));
|
||||
|
||||
if (isset($this->boardsCacheFull[$boardId]) && $fullDetails) {
|
||||
return $this->boardsCacheFull[$boardId];
|
||||
if ($this->boardsCache && isset($this->boardsCache[$boardId])) {
|
||||
return $this->boardsCache[$boardId];
|
||||
}
|
||||
|
||||
if (isset($this->boardsCachePartial[$boardId]) && !$fullDetails) {
|
||||
return $this->boardsCachePartial[$boardId];
|
||||
if (is_numeric($boardId) === false) {
|
||||
throw new BadRequestException('board id must be a number');
|
||||
}
|
||||
|
||||
$this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_READ);
|
||||
/** @var Board $board */
|
||||
$board = $this->boardMapper->find($boardId, true, true);
|
||||
[$board] = $this->enrichBoards([$board], $fullDetails);
|
||||
$this->boardMapper->mapOwner($board);
|
||||
if ($board->getAcl() !== null) {
|
||||
foreach ($board->getAcl() as $acl) {
|
||||
if ($acl !== null) {
|
||||
$this->boardMapper->mapAcl($acl);
|
||||
}
|
||||
}
|
||||
}
|
||||
$permissions = $this->permissionService->matchPermissions($board);
|
||||
$board->setPermissions([
|
||||
'PERMISSION_READ' => $permissions[Acl::PERMISSION_READ] ?? false,
|
||||
'PERMISSION_EDIT' => $permissions[Acl::PERMISSION_EDIT] ?? false,
|
||||
'PERMISSION_MANAGE' => $permissions[Acl::PERMISSION_MANAGE] ?? false,
|
||||
'PERMISSION_SHARE' => $permissions[Acl::PERMISSION_SHARE] ?? false
|
||||
]);
|
||||
$this->enrichWithUsers($board);
|
||||
$this->enrichWithBoardSettings($board);
|
||||
$this->enrichWithActiveSessions($board);
|
||||
$this->boardsCache[$board->getId()] = $board;
|
||||
return $board;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getBoardPrerequisites() {
|
||||
$groups = $this->groupManager->getUserGroupIds(
|
||||
$this->userManager->get($this->userId)
|
||||
);
|
||||
return [
|
||||
'user' => $this->userId,
|
||||
'groups' => $groups
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $mapper
|
||||
* @param $id
|
||||
@@ -380,7 +429,6 @@ class BoardService {
|
||||
$this->boardMapper->mapOwner($board);
|
||||
$this->activityManager->triggerUpdateEvents(ActivityManager::DECK_OBJECT_BOARD, $changes, ActivityManager::SUBJECT_BOARD_UPDATE);
|
||||
$this->changeHelper->boardChanged($board->getId());
|
||||
$this->eventDispatcher->dispatchTyped(new BoardUpdatedEvent($board->getId()));
|
||||
|
||||
return $board;
|
||||
}
|
||||
@@ -408,7 +456,7 @@ class BoardService {
|
||||
|
||||
public function enrichWithActiveSessions(Board $board) {
|
||||
$sessions = $this->sessionMapper->findAllActive($board->getId());
|
||||
|
||||
|
||||
$board->setActiveSessions(array_values(
|
||||
array_unique(
|
||||
array_map(function (Session $session) {
|
||||
@@ -643,45 +691,6 @@ class BoardService {
|
||||
return $board;
|
||||
}
|
||||
|
||||
/** @param Board[] $boards */
|
||||
private function enrichBoards(array $boards, bool $fullDetails = true): array {
|
||||
$result = [];
|
||||
foreach ($boards as $board) {
|
||||
// FIXME The enrichment in here could make use of combined queries
|
||||
$this->boardMapper->mapOwner($board);
|
||||
if ($board->getAcl() !== null) {
|
||||
foreach ($board->getAcl() as &$acl) {
|
||||
$this->boardMapper->mapAcl($acl);
|
||||
}
|
||||
}
|
||||
|
||||
$permissions = $this->permissionService->matchPermissions($board);
|
||||
$board->setPermissions([
|
||||
'PERMISSION_READ' => $permissions[Acl::PERMISSION_READ] ?? false,
|
||||
'PERMISSION_EDIT' => $permissions[Acl::PERMISSION_EDIT] ?? false,
|
||||
'PERMISSION_MANAGE' => $permissions[Acl::PERMISSION_MANAGE] ?? false,
|
||||
'PERMISSION_SHARE' => $permissions[Acl::PERMISSION_SHARE] ?? false
|
||||
]);
|
||||
|
||||
if ($fullDetails) {
|
||||
$this->enrichWithStacks($board);
|
||||
$this->enrichWithLabels($board);
|
||||
$this->enrichWithUsers($board);
|
||||
$this->enrichWithBoardSettings($board);
|
||||
$this->enrichWithActiveSessions($board);
|
||||
}
|
||||
|
||||
// Cache for further usage
|
||||
if ($fullDetails) {
|
||||
$this->boardsCacheFull[$board->getId()] = $board;
|
||||
} else {
|
||||
$this->boardsCachePartial[$board->getId()] = $board;
|
||||
}
|
||||
}
|
||||
|
||||
return $boards;
|
||||
}
|
||||
|
||||
private function enrichWithStacks($board, $since = -1) {
|
||||
$stacks = $this->stackMapper->findAll($board->getId(), null, null, $since);
|
||||
|
||||
@@ -704,7 +713,7 @@ class BoardService {
|
||||
|
||||
private function enrichWithUsers($board, $since = -1) {
|
||||
$boardUsers = $this->permissionService->findUsers($board->getId());
|
||||
if ($boardUsers === null || \count($boardUsers) === 0) {
|
||||
if (\count($boardUsers) === 0) {
|
||||
return;
|
||||
}
|
||||
$board->setUsers(array_values($boardUsers));
|
||||
@@ -714,6 +723,10 @@ class BoardService {
|
||||
return $this->urlGenerator->linkToRouteAbsolute('deck.page.index') . '#' . $endpoint;
|
||||
}
|
||||
|
||||
private function clearBoardsCache() {
|
||||
$this->boardsCache = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean a given board data from the Cache
|
||||
*/
|
||||
@@ -722,8 +735,7 @@ class BoardService {
|
||||
$boardOwnerId = $board->getOwner();
|
||||
|
||||
$this->boardMapper->flushCache($boardId, $boardOwnerId);
|
||||
unset($this->boardsCacheFull[$boardId]);
|
||||
unset($this->boardsCachePartial[$boardId]);
|
||||
unset($this->boardsCache[$boardId]);
|
||||
}
|
||||
|
||||
private function enrichWithCards($board) {
|
||||
|
||||
@@ -28,13 +28,11 @@ namespace OCA\Deck\Service;
|
||||
|
||||
use OCA\Deck\Activity\ActivityManager;
|
||||
use OCA\Deck\Activity\ChangeSet;
|
||||
use OCA\Deck\Db\Assignment;
|
||||
use OCA\Deck\Db\AssignmentMapper;
|
||||
use OCA\Deck\Db\Card;
|
||||
use OCA\Deck\Db\CardMapper;
|
||||
use OCA\Deck\Db\Acl;
|
||||
use OCA\Deck\Db\ChangeHelper;
|
||||
use OCA\Deck\Db\Label;
|
||||
use OCA\Deck\Db\StackMapper;
|
||||
use OCA\Deck\Event\CardCreatedEvent;
|
||||
use OCA\Deck\Event\CardDeletedEvent;
|
||||
@@ -116,52 +114,32 @@ class CardService {
|
||||
$this->cardServiceValidator = $cardServiceValidator;
|
||||
}
|
||||
|
||||
public function enrichCards($cards) {
|
||||
public function enrich($card) {
|
||||
$cardId = $card->getId();
|
||||
$this->cardMapper->mapOwner($card);
|
||||
$card->setAssignedUsers($this->assignedUsersMapper->findAll($cardId));
|
||||
$card->setLabels($this->labelMapper->findAssignedLabelsForCard($cardId));
|
||||
$card->setAttachmentCount($this->attachmentService->count($cardId));
|
||||
$user = $this->userManager->get($this->currentUser);
|
||||
$lastRead = $this->commentsManager->getReadMark('deckCard', (string)$card->getId(), $user);
|
||||
$countUnreadComments = $this->commentsManager->getNumberOfCommentsForObject('deckCard', (string)$card->getId(), $lastRead);
|
||||
$countComments = $this->commentsManager->getNumberOfCommentsForObject('deckCard', (string)$card->getId());
|
||||
$card->setCommentsUnread($countUnreadComments);
|
||||
$card->setCommentsCount($countComments);
|
||||
|
||||
$cardIds = array_map(function (Card $card) use ($user) {
|
||||
// Everything done in here might be heavy as it is executed for every card
|
||||
$cardId = $card->getId();
|
||||
$this->cardMapper->mapOwner($card);
|
||||
|
||||
$card->setAttachmentCount($this->attachmentService->count($cardId));
|
||||
|
||||
// TODO We should find a better way just to get the comment count so we can save 1-3 queries per card here
|
||||
$countComments = $this->commentsManager->getNumberOfCommentsForObject('deckCard', (string)$card->getId());
|
||||
$lastRead = $countComments > 0 ? $this->commentsManager->getReadMark('deckCard', (string)$card->getId(), $user) : null;
|
||||
$countUnreadComments = $lastRead ? $this->commentsManager->getNumberOfCommentsForObject('deckCard', (string)$card->getId(), $lastRead) : 0;
|
||||
$card->setCommentsUnread($countUnreadComments);
|
||||
$card->setCommentsCount($countComments);
|
||||
|
||||
$stack = $this->stackMapper->find($card->getStackId());
|
||||
$board = $this->boardService->find($stack->getBoardId(), false);
|
||||
$card->setRelatedStack($stack);
|
||||
$card->setRelatedBoard($board);
|
||||
|
||||
return $card->getId();
|
||||
}, $cards);
|
||||
|
||||
$assignedLabels = $this->labelMapper->findAssignedLabelsForCards($cardIds);
|
||||
$assignedUsers = $this->assignedUsersMapper->findIn($cardIds);
|
||||
|
||||
foreach ($cards as $card) {
|
||||
$cardLabels = array_values(array_filter($assignedLabels, function (Label $label) use ($card) {
|
||||
return $label->getCardId() === $card->getId();
|
||||
}));
|
||||
$cardAssignedUsers = array_values(array_filter($assignedUsers, function (Assignment $assignment) use ($card) {
|
||||
return $assignment->getCardId() === $card->getId();
|
||||
}));
|
||||
$card->setLabels($cardLabels);
|
||||
$card->setAssignedUsers($cardAssignedUsers);
|
||||
}
|
||||
|
||||
return $cards;
|
||||
$stack = $this->stackMapper->find($card->getStackId());
|
||||
$board = $this->boardService->find($stack->getBoardId());
|
||||
$card->setRelatedStack($stack);
|
||||
$card->setRelatedBoard($board);
|
||||
}
|
||||
|
||||
public function fetchDeleted($boardId) {
|
||||
$this->cardServiceValidator->check(compact('boardId'));
|
||||
$this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_READ);
|
||||
$cards = $this->cardMapper->findDeleted($boardId);
|
||||
$this->enrichCards($cards);
|
||||
foreach ($cards as $card) {
|
||||
$this->enrich($card);
|
||||
}
|
||||
return $cards;
|
||||
}
|
||||
|
||||
@@ -175,17 +153,16 @@ class CardService {
|
||||
public function find(int $cardId) {
|
||||
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ);
|
||||
$card = $this->cardMapper->find($cardId);
|
||||
[$card] = $this->enrichCards([$card]);
|
||||
|
||||
// Attachments are only enriched on individual card fetching
|
||||
$assignedUsers = $this->assignedUsersMapper->findAll($card->getId());
|
||||
$attachments = $this->attachmentService->findAll($cardId, true);
|
||||
if ($this->request->getParam('apiVersion') === '1.0') {
|
||||
$attachments = array_filter($attachments, function ($attachment) {
|
||||
return $attachment->getType() === 'deck_file';
|
||||
});
|
||||
}
|
||||
$card->setAssignedUsers($assignedUsers);
|
||||
$card->setAttachments($attachments);
|
||||
|
||||
$this->enrich($card);
|
||||
return $card;
|
||||
}
|
||||
|
||||
@@ -197,7 +174,9 @@ class CardService {
|
||||
return [];
|
||||
}
|
||||
$cards = $this->cardMapper->findCalendarEntries($boardId);
|
||||
$this->enrichCards($cards);
|
||||
foreach ($cards as $card) {
|
||||
$this->enrich($card);
|
||||
}
|
||||
return $cards;
|
||||
}
|
||||
|
||||
@@ -353,7 +332,7 @@ class CardService {
|
||||
}
|
||||
$this->changeHelper->cardChanged($card->getId(), true);
|
||||
|
||||
$this->eventDispatcher->dispatchTyped(new CardUpdatedEvent($card, $changes->getBefore()));
|
||||
$this->eventDispatcher->dispatchTyped(new CardUpdatedEvent($card));
|
||||
|
||||
return $card;
|
||||
}
|
||||
@@ -443,8 +422,6 @@ class CardService {
|
||||
$result[$card->getOrder()] = $card;
|
||||
}
|
||||
$this->changeHelper->cardChanged($id, false);
|
||||
$this->eventDispatcher->dispatchTyped(new CardUpdatedEvent($card));
|
||||
|
||||
return array_values($result);
|
||||
}
|
||||
|
||||
|
||||
@@ -62,8 +62,9 @@ class DefaultBoardService {
|
||||
*/
|
||||
public function checkFirstRun($userId): bool {
|
||||
$firstRun = $this->config->getUserValue($userId, Application::APP_ID, 'firstRun', 'yes');
|
||||
$userBoards = $this->boardMapper->findAllByUser($userId);
|
||||
|
||||
if ($firstRun === 'yes') {
|
||||
if ($firstRun === 'yes' && count($userBoards) === 0) {
|
||||
try {
|
||||
$this->config->setUserValue($userId, Application::APP_ID, 'firstRun', 'no');
|
||||
} catch (PreConditionNotMetException $e) {
|
||||
|
||||
@@ -28,7 +28,7 @@ declare(strict_types=1);
|
||||
namespace OCA\Deck\Service;
|
||||
|
||||
use OCA\Deck\Db\AssignmentMapper;
|
||||
use OCA\Deck\Db\Board;
|
||||
use OCA\Deck\Db\Card;
|
||||
use OCA\Deck\Db\CardMapper;
|
||||
use OCA\Deck\Model\CardDetails;
|
||||
use OCP\Comments\ICommentsManager;
|
||||
@@ -37,7 +37,6 @@ use OCA\Deck\Db\LabelMapper;
|
||||
use OCP\IUserManager;
|
||||
|
||||
class OverviewService {
|
||||
private CardService $cardService;
|
||||
private BoardMapper $boardMapper;
|
||||
private LabelMapper $labelMapper;
|
||||
private CardMapper $cardMapper;
|
||||
@@ -47,7 +46,6 @@ class OverviewService {
|
||||
private AttachmentService $attachmentService;
|
||||
|
||||
public function __construct(
|
||||
CardService $cardService,
|
||||
BoardMapper $boardMapper,
|
||||
LabelMapper $labelMapper,
|
||||
CardMapper $cardMapper,
|
||||
@@ -56,7 +54,6 @@ class OverviewService {
|
||||
ICommentsManager $commentsManager,
|
||||
AttachmentService $attachmentService
|
||||
) {
|
||||
$this->cardService = $cardService;
|
||||
$this->boardMapper = $boardMapper;
|
||||
$this->labelMapper = $labelMapper;
|
||||
$this->cardMapper = $cardMapper;
|
||||
@@ -66,43 +63,66 @@ class OverviewService {
|
||||
$this->attachmentService = $attachmentService;
|
||||
}
|
||||
|
||||
public function enrich(Card $card, string $userId): void {
|
||||
$cardId = $card->getId();
|
||||
|
||||
$this->cardMapper->mapOwner($card);
|
||||
$card->setAssignedUsers($this->assignedUsersMapper->findAll($cardId));
|
||||
$card->setLabels($this->labelMapper->findAssignedLabelsForCard($cardId));
|
||||
$card->setAttachmentCount($this->attachmentService->count($cardId));
|
||||
|
||||
$user = $this->userManager->get($userId);
|
||||
if ($user !== null) {
|
||||
$lastRead = $this->commentsManager->getReadMark('deckCard', (string)$card->getId(), $user);
|
||||
$count = $this->commentsManager->getNumberOfCommentsForObject('deckCard', (string)$card->getId(), $lastRead);
|
||||
$card->setCommentsUnread($count);
|
||||
}
|
||||
}
|
||||
|
||||
public function findAllWithDue(string $userId): array {
|
||||
$userBoards = $this->boardMapper->findAllForUser($userId);
|
||||
$allDueCards = [];
|
||||
foreach ($userBoards as $userBoard) {
|
||||
$allDueCards[] = array_map(function ($card) use ($userBoard, $userId) {
|
||||
$this->enrich($card, $userId);
|
||||
return (new CardDetails($card, $userBoard))->jsonSerialize();
|
||||
}, $this->cardMapper->findAllWithDue($userBoard->getId()));
|
||||
}
|
||||
return array_merge(...$allDueCards);
|
||||
}
|
||||
|
||||
public function findUpcomingCards(string $userId): array {
|
||||
$userBoards = $this->boardMapper->findAllForUser($userId);
|
||||
|
||||
$boardOwnerIds = array_filter(array_map(function (Board $board) {
|
||||
return count($board->getAcl()) === 0 ? $board->getId() : null;
|
||||
}, $userBoards));
|
||||
$boardSharedIds = array_filter(array_map(function (Board $board) {
|
||||
return count($board->getAcl()) > 0 ? $board->getId() : null;
|
||||
}, $userBoards));
|
||||
|
||||
$foundCards = array_merge(
|
||||
// private board: get cards with due date
|
||||
$this->cardMapper->findAllWithDue($boardOwnerIds),
|
||||
// shared board: get all my assigned or unassigned cards
|
||||
$this->cardMapper->findToMeOrNotAssignedCards($boardSharedIds, $userId)
|
||||
);
|
||||
|
||||
$this->cardService->enrichCards($foundCards);
|
||||
$overview = [];
|
||||
foreach ($foundCards as $card) {
|
||||
$diffDays = $card->getDaysUntilDue();
|
||||
|
||||
$key = 'later';
|
||||
if ($diffDays === null) {
|
||||
$key = 'nodue';
|
||||
} elseif ($diffDays < 0) {
|
||||
$key = 'overdue';
|
||||
} elseif ($diffDays === 0) {
|
||||
$key = 'today';
|
||||
} elseif ($diffDays === 1) {
|
||||
$key = 'tomorrow';
|
||||
} elseif ($diffDays <= 7) {
|
||||
$key = 'nextSevenDays';
|
||||
foreach ($userBoards as $userBoard) {
|
||||
if (count($userBoard->getAcl()) === 0) {
|
||||
// private board: get cards with due date
|
||||
$cards = $this->cardMapper->findAllWithDue($userBoard->getId());
|
||||
} else {
|
||||
// shared board: get all my assigned or unassigned cards
|
||||
$cards = $this->cardMapper->findToMeOrNotAssignedCards($userBoard->getId(), $userId);
|
||||
}
|
||||
|
||||
$card = (new CardDetails($card, $card->getRelatedBoard()));
|
||||
$overview[$key][] = $card->jsonSerialize();
|
||||
foreach ($cards as $card) {
|
||||
$this->enrich($card, $userId);
|
||||
$diffDays = $card->getDaysUntilDue();
|
||||
|
||||
$key = 'later';
|
||||
if ($diffDays === null) {
|
||||
$key = 'nodue';
|
||||
} elseif ($diffDays < 0) {
|
||||
$key = 'overdue';
|
||||
} elseif ($diffDays === 0) {
|
||||
$key = 'today';
|
||||
} elseif ($diffDays === 1) {
|
||||
$key = 'tomorrow';
|
||||
} elseif ($diffDays <= 7) {
|
||||
$key = 'nextSevenDays';
|
||||
}
|
||||
|
||||
$card = (new CardDetails($card, $userBoard));
|
||||
$overview[$key][] = $card->jsonSerialize();
|
||||
}
|
||||
}
|
||||
return $overview;
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ class PermissionService {
|
||||
* @return bool
|
||||
* @throws NoPermissionException
|
||||
*/
|
||||
public function checkPermission($mapper, $id, $permission, $userId = null): bool {
|
||||
public function checkPermission($mapper, $id, $permission, $userId = null) {
|
||||
$boardId = $id;
|
||||
if ($mapper instanceof IPermissionMapper && !($mapper instanceof BoardMapper)) {
|
||||
$boardId = $mapper->findBoardId($id);
|
||||
@@ -153,11 +153,23 @@ class PermissionService {
|
||||
throw new NoPermissionException('Permission denied');
|
||||
}
|
||||
|
||||
$permissions = $this->getPermissions($boardId);
|
||||
if ($permissions[$permission] === true) {
|
||||
if ($permission === Acl::PERMISSION_SHARE && $this->shareManager->sharingDisabledForUser($this->userId)) {
|
||||
throw new NoPermissionException('Permission denied');
|
||||
}
|
||||
|
||||
if ($this->userIsBoardOwner($boardId, $userId)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
$acls = $this->getBoard($boardId)->getAcl() ?? [];
|
||||
$result = $this->userCan($acls, $permission, $userId);
|
||||
if ($result) {
|
||||
return true;
|
||||
}
|
||||
} catch (DoesNotExistException | MultipleObjectsReturnedException $e) {
|
||||
}
|
||||
|
||||
// Throw NoPermission to not leak information about existing entries
|
||||
throw new NoPermissionException('Permission denied');
|
||||
}
|
||||
@@ -248,20 +260,22 @@ class PermissionService {
|
||||
}
|
||||
|
||||
$users = [];
|
||||
if (!$this->userManager->userExists($board->getOwner())) {
|
||||
$owner = $this->userManager->get($board->getOwner());
|
||||
if ($owner === null) {
|
||||
$this->logger->info('No owner found for board ' . $board->getId());
|
||||
} else {
|
||||
$users[$board->getOwner()] = new User($board->getOwner(), $this->userManager);
|
||||
$users[$owner->getUID()] = new User($owner);
|
||||
}
|
||||
$acls = $this->aclMapper->findAll($boardId);
|
||||
/** @var Acl $acl */
|
||||
foreach ($acls as $acl) {
|
||||
if ($acl->getType() === Acl::PERMISSION_TYPE_USER) {
|
||||
if (!$this->userManager->userExists($acl->getParticipant())) {
|
||||
$user = $this->userManager->get($acl->getParticipant());
|
||||
if ($user === null) {
|
||||
$this->logger->info('No user found for acl rule ' . $acl->getId());
|
||||
continue;
|
||||
}
|
||||
$users[$acl->getParticipant()] = new User($acl->getParticipant(), $this->userManager);
|
||||
$users[$user->getUID()] = new User($user);
|
||||
}
|
||||
if ($acl->getType() === Acl::PERMISSION_TYPE_GROUP) {
|
||||
$group = $this->groupManager->get($acl->getParticipant());
|
||||
@@ -270,7 +284,7 @@ class PermissionService {
|
||||
continue;
|
||||
}
|
||||
foreach ($group->getUsers() as $user) {
|
||||
$users[$user->getUID()] = new User($user->getUID(), $this->userManager);
|
||||
$users[$user->getUID()] = new User($user);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,7 +305,7 @@ class PermissionService {
|
||||
if ($user === null) {
|
||||
$this->logger->info('No user found for circle member ' . $member->getUserId());
|
||||
} else {
|
||||
$users[$member->getUserId()] = new User($member->getUserId(), $this->userManager);
|
||||
$users[$member->getUserId()] = new User($user);
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
|
||||
@@ -82,7 +82,11 @@ class SearchService {
|
||||
}, $boards);
|
||||
$matchedCards = $this->cardMapper->search($boardIds, $this->filterStringParser->parse($term), $limit, $cursor);
|
||||
|
||||
return $this->cardService->enrichCards($matchedCards);
|
||||
$self = $this;
|
||||
return array_map(function (Card $card) use ($self) {
|
||||
$self->cardService->enrich($card);
|
||||
return $card;
|
||||
}, $matchedCards);
|
||||
}
|
||||
|
||||
public function searchBoards(string $term, ?int $limit, ?int $cursor): array {
|
||||
@@ -113,8 +117,7 @@ class SearchService {
|
||||
$comment = $this->commentsManager->get($cardRow['comment_id']);
|
||||
unset($cardRow['comment_id']);
|
||||
$card = Card::fromRow($cardRow);
|
||||
// TODO: Only perform one enrich call here
|
||||
$self->cardService->enrichCards([$card]);
|
||||
$self->cardService->enrich($card);
|
||||
$user = $this->userManager->get($comment->getActorId());
|
||||
$displayName = $user ? $user->getDisplayName() : '';
|
||||
return new CommentSearchResultEntry($comment->getId(), $comment->getMessage(), $displayName, $card, $this->urlGenerator, $this->l10n);
|
||||
|
||||
@@ -36,12 +36,10 @@ use OCA\Deck\Db\ChangeHelper;
|
||||
use OCA\Deck\Db\LabelMapper;
|
||||
use OCA\Deck\Db\Stack;
|
||||
use OCA\Deck\Db\StackMapper;
|
||||
use OCA\Deck\Event\BoardUpdatedEvent;
|
||||
use OCA\Deck\Model\CardDetails;
|
||||
use OCA\Deck\NoPermissionException;
|
||||
use OCA\Deck\StatusException;
|
||||
use OCA\Deck\Validators\StackServiceValidator;
|
||||
use OCP\EventDispatcher\IEventDispatcher;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class StackService {
|
||||
@@ -57,7 +55,6 @@ class StackService {
|
||||
private ActivityManager $activityManager;
|
||||
private ChangeHelper $changeHelper;
|
||||
private LoggerInterface $logger;
|
||||
private IEventDispatcher $eventDispatcher;
|
||||
private StackServiceValidator $stackServiceValidator;
|
||||
|
||||
public function __construct(
|
||||
@@ -73,7 +70,6 @@ class StackService {
|
||||
ActivityManager $activityManager,
|
||||
ChangeHelper $changeHelper,
|
||||
LoggerInterface $logger,
|
||||
IEventDispatcher $eventDispatcher,
|
||||
StackServiceValidator $stackServiceValidator
|
||||
) {
|
||||
$this->stackMapper = $stackMapper;
|
||||
@@ -88,7 +84,6 @@ class StackService {
|
||||
$this->activityManager = $activityManager;
|
||||
$this->changeHelper = $changeHelper;
|
||||
$this->logger = $logger;
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
$this->stackServiceValidator = $stackServiceValidator;
|
||||
}
|
||||
|
||||
@@ -99,9 +94,9 @@ class StackService {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->cardService->enrichCards($cards);
|
||||
$cards = array_map(
|
||||
function (Card $card): CardDetails {
|
||||
$this->cardService->enrich($card);
|
||||
return new CardDetails($card);
|
||||
},
|
||||
$cards
|
||||
@@ -242,7 +237,6 @@ class StackService {
|
||||
ActivityManager::DECK_OBJECT_BOARD, $stack, ActivityManager::SUBJECT_STACK_CREATE
|
||||
);
|
||||
$this->changeHelper->boardChanged($boardId);
|
||||
$this->eventDispatcher->dispatchTyped(new BoardUpdatedEvent($boardId));
|
||||
|
||||
return $stack;
|
||||
}
|
||||
@@ -271,7 +265,6 @@ class StackService {
|
||||
ActivityManager::DECK_OBJECT_BOARD, $stack, ActivityManager::SUBJECT_STACK_DELETE
|
||||
);
|
||||
$this->changeHelper->boardChanged($stack->getBoardId());
|
||||
$this->eventDispatcher->dispatchTyped(new BoardUpdatedEvent($stack->getBoardId()));
|
||||
$this->enrichStackWithCards($stack);
|
||||
|
||||
return $stack;
|
||||
@@ -313,7 +306,6 @@ class StackService {
|
||||
ActivityManager::DECK_OBJECT_BOARD, $changes, ActivityManager::SUBJECT_STACK_UPDATE
|
||||
);
|
||||
$this->changeHelper->boardChanged($stack->getBoardId());
|
||||
$this->eventDispatcher->dispatchTyped(new BoardUpdatedEvent($stack->getBoardId()));
|
||||
|
||||
return $stack;
|
||||
}
|
||||
@@ -353,7 +345,6 @@ class StackService {
|
||||
$result[$stack->getOrder()] = $stack;
|
||||
}
|
||||
$this->changeHelper->boardChanged($stackToSort->getBoardId());
|
||||
$this->eventDispatcher->dispatchTyped(new BoardUpdatedEvent($stackToSort->getBoardId()));
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
321
package-lock.json
generated
321
package-lock.json
generated
@@ -31,7 +31,7 @@
|
||||
"markdown-it-link-attributes": "^4.0.1",
|
||||
"markdown-it-task-checkbox": "^1.0.6",
|
||||
"moment": "^2.29.4",
|
||||
"nextcloud-vue-collections": "^0.11.0",
|
||||
"nextcloud-vue-collections": "^0.10.0",
|
||||
"p-queue": "^7.3.4",
|
||||
"url-search-params-polyfill": "^8.1.1",
|
||||
"vue": "^2.7.14",
|
||||
@@ -2933,7 +2933,6 @@
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/browserslist-config/-/browserslist-config-2.3.0.tgz",
|
||||
"integrity": "sha512-1Tpkof2e9Q0UicHWahQnXXrubJoqyiaqsH9G52v3cjGeVeH3BCfa1FOa41eBwBSFe2/Jxj/wCH2YVLgIXpWbBg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^16.0.0",
|
||||
"npm": "^7.0.0 || ^8.0.0"
|
||||
@@ -12984,11 +12983,6 @@
|
||||
"version": "4.17.21",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash-es": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
|
||||
},
|
||||
"node_modules/lodash.debounce": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
||||
@@ -13863,24 +13857,172 @@
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/nextcloud-vue-collections": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/nextcloud-vue-collections/-/nextcloud-vue-collections-0.11.0.tgz",
|
||||
"integrity": "sha512-sVeJzwVF7z/71n6TVk3RY+OewvF7gRRexYQ9ZRURbRUK9NIwByFNM7Y2S+U2LJFBsjM58twUhxwll9yWxYqdeA==",
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/nextcloud-vue-collections/-/nextcloud-vue-collections-0.10.0.tgz",
|
||||
"integrity": "sha512-vfGYCtAV0vQ9809VO9z2pQqmiduqhhI5jkVlKv+yYXPfR8G+9YmTYrjdjH3mARBzt8gxZYXtbSIWqWsH2/N0pA==",
|
||||
"dependencies": {
|
||||
"@nextcloud/axios": "^2.3.0",
|
||||
"@nextcloud/router": "^2.0.1",
|
||||
"@nextcloud/vue": "^7.5.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"vue": "^2.7.14"
|
||||
"@nextcloud/axios": "^1.9.0",
|
||||
"@nextcloud/browserslist-config": "^2.2.0",
|
||||
"@nextcloud/router": "^2.0.0",
|
||||
"@nextcloud/vue": "^3.10.2",
|
||||
"lodash": "^4.17.21",
|
||||
"vue": "^2.6.14"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nextcloud/vue": "^3.10.2",
|
||||
"vue": "^2.6.14"
|
||||
}
|
||||
},
|
||||
"node_modules/nextcloud-vue-collections/node_modules/@nextcloud/auth": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/auth/-/auth-1.3.0.tgz",
|
||||
"integrity": "sha512-GfwRM9W7hat4psNdAt74UHEV+drEXQ53klCVp6JpON66ZLPeK5eJ1LQuiQDkpUxZpqNeaumXjiB98h5cug/uQw==",
|
||||
"dependencies": {
|
||||
"@nextcloud/event-bus": "^1.1.3",
|
||||
"@nextcloud/typings": "^0.2.2",
|
||||
"core-js": "^3.6.4"
|
||||
}
|
||||
},
|
||||
"node_modules/nextcloud-vue-collections/node_modules/@nextcloud/axios": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/axios/-/axios-1.11.0.tgz",
|
||||
"integrity": "sha512-NyaiSC2GX2CPaH/MUGGMTTTza/TW9ZqWNGWq6LJ+pLER8nqZ9BQkwJ5kXUYGo+i3cka68PO+9WhcDv4fSABpuQ==",
|
||||
"dependencies": {
|
||||
"@nextcloud/auth": "^1.3.0",
|
||||
"axios": "^0.27.1",
|
||||
"core-js": "^3.6.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.0.0",
|
||||
"npm": "^8.0.0"
|
||||
"npm": "^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nextcloud-vue-collections/node_modules/@nextcloud/event-bus": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/event-bus/-/event-bus-1.3.0.tgz",
|
||||
"integrity": "sha512-+U5MnCvfnNWvf0lvdqJg8F+Nm8wN+s9ayuBjtiEQxTAcootv7lOnlMgfreqF3l2T0Wet2uZh4JbFVUWf8l3w7g==",
|
||||
"dependencies": {
|
||||
"@types/semver": "^7.3.5",
|
||||
"core-js": "^3.11.2",
|
||||
"semver": "^7.3.5"
|
||||
}
|
||||
},
|
||||
"node_modules/nextcloud-vue-collections/node_modules/@nextcloud/l10n": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/l10n/-/l10n-1.6.0.tgz",
|
||||
"integrity": "sha512-aKGlgrwN9OiafN791sYus0shfwNeU3PlrH6Oi9ISma6iJSvN6a8aJM8WGKCJ9pqBaTR5PrDuckuM/WnybBWb6A==",
|
||||
"dependencies": {
|
||||
"core-js": "^3.6.4",
|
||||
"node-gettext": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nextcloud-vue-collections/node_modules/@nextcloud/vue": {
|
||||
"version": "3.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-3.10.2.tgz",
|
||||
"integrity": "sha512-/8r2fE8V7nw9erjm06x3nCALC+6o9q2CzNSL0eDRfsKXCVySFoZ4bYX+zziQUStienisKDRXRhxh7RUAwkS2+w==",
|
||||
"dependencies": {
|
||||
"@nextcloud/auth": "^1.2.3",
|
||||
"@nextcloud/axios": "^1.3.2",
|
||||
"@nextcloud/browser-storage": "^0.1.1",
|
||||
"@nextcloud/capabilities": "^1.0.2",
|
||||
"@nextcloud/dialogs": "^3.0.0",
|
||||
"@nextcloud/event-bus": "^1.1.4",
|
||||
"@nextcloud/l10n": "^1.2.3",
|
||||
"@nextcloud/router": "^1.0.2",
|
||||
"core-js": "^3.6.5",
|
||||
"debounce": "1.2.1",
|
||||
"emoji-mart-vue-fast": "^7.0.7",
|
||||
"escape-html": "^1.0.3",
|
||||
"hammerjs": "^2.0.8",
|
||||
"linkifyjs": "~2.1.9",
|
||||
"md5": "^2.2.1",
|
||||
"regenerator-runtime": "^0.13.5",
|
||||
"string-length": "^4.0.1",
|
||||
"striptags": "^3.1.1",
|
||||
"style-loader": "^2.0.0",
|
||||
"tributejs": "^5.1.3",
|
||||
"v-click-outside": "^3.0.1",
|
||||
"v-tooltip": "^2.0.3",
|
||||
"vue": "^2.6.11",
|
||||
"vue-color": "^2.7.1",
|
||||
"vue-multiselect": "^2.1.6",
|
||||
"vue-visible": "^1.0.2",
|
||||
"vue2-datepicker": "^3.6.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nextcloud-vue-collections/node_modules/@nextcloud/vue/node_modules/@nextcloud/router": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/router/-/router-1.2.0.tgz",
|
||||
"integrity": "sha512-kn9QsL9LuhkIMaSSgdiqRL3SZ6PatuAjXUiyq343BbSnI99Oc5eJH8kU6cT2AHije7wKy/tK8Xe3VQuVO32SZQ==",
|
||||
"dependencies": {
|
||||
"core-js": "^3.6.4"
|
||||
}
|
||||
},
|
||||
"node_modules/nextcloud-vue-collections/node_modules/core-js": {
|
||||
"version": "3.22.4",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.22.4.tgz",
|
||||
"integrity": "sha512-1uLykR+iOfYja+6Jn/57743gc9n73EWiOnSJJ4ba3B4fOEYDBv25MagmEZBxTp5cWq4b/KPx/l77zgsp28ju4w==",
|
||||
"hasInstallScript": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/core-js"
|
||||
}
|
||||
},
|
||||
"node_modules/nextcloud-vue-collections/node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/nextcloud-vue-collections/node_modules/semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/nextcloud-vue-collections/node_modules/style-loader": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-2.0.0.tgz",
|
||||
"integrity": "sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ==",
|
||||
"dependencies": {
|
||||
"loader-utils": "^2.0.0",
|
||||
"schema-utils": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.13.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/webpack"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nextcloud/vue": "^7.5.0"
|
||||
"webpack": "^4.0.0 || ^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nextcloud-vue-collections/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||
@@ -20409,8 +20551,7 @@
|
||||
"@nextcloud/browserslist-config": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/browserslist-config/-/browserslist-config-2.3.0.tgz",
|
||||
"integrity": "sha512-1Tpkof2e9Q0UicHWahQnXXrubJoqyiaqsH9G52v3cjGeVeH3BCfa1FOa41eBwBSFe2/Jxj/wCH2YVLgIXpWbBg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-1Tpkof2e9Q0UicHWahQnXXrubJoqyiaqsH9G52v3cjGeVeH3BCfa1FOa41eBwBSFe2/Jxj/wCH2YVLgIXpWbBg=="
|
||||
},
|
||||
"@nextcloud/calendar-js": {
|
||||
"version": "5.0.3",
|
||||
@@ -27925,11 +28066,6 @@
|
||||
"lodash": {
|
||||
"version": "4.17.21"
|
||||
},
|
||||
"lodash-es": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
|
||||
},
|
||||
"lodash.debounce": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
||||
@@ -28572,15 +28708,136 @@
|
||||
"peer": true
|
||||
},
|
||||
"nextcloud-vue-collections": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/nextcloud-vue-collections/-/nextcloud-vue-collections-0.11.0.tgz",
|
||||
"integrity": "sha512-sVeJzwVF7z/71n6TVk3RY+OewvF7gRRexYQ9ZRURbRUK9NIwByFNM7Y2S+U2LJFBsjM58twUhxwll9yWxYqdeA==",
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/nextcloud-vue-collections/-/nextcloud-vue-collections-0.10.0.tgz",
|
||||
"integrity": "sha512-vfGYCtAV0vQ9809VO9z2pQqmiduqhhI5jkVlKv+yYXPfR8G+9YmTYrjdjH3mARBzt8gxZYXtbSIWqWsH2/N0pA==",
|
||||
"requires": {
|
||||
"@nextcloud/axios": "^2.3.0",
|
||||
"@nextcloud/router": "^2.0.1",
|
||||
"@nextcloud/vue": "^7.5.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"vue": "^2.7.14"
|
||||
"@nextcloud/axios": "^1.9.0",
|
||||
"@nextcloud/browserslist-config": "^2.2.0",
|
||||
"@nextcloud/router": "^2.0.0",
|
||||
"@nextcloud/vue": "^3.10.2",
|
||||
"lodash": "^4.17.21",
|
||||
"vue": "^2.6.14"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nextcloud/auth": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/auth/-/auth-1.3.0.tgz",
|
||||
"integrity": "sha512-GfwRM9W7hat4psNdAt74UHEV+drEXQ53klCVp6JpON66ZLPeK5eJ1LQuiQDkpUxZpqNeaumXjiB98h5cug/uQw==",
|
||||
"requires": {
|
||||
"@nextcloud/event-bus": "^1.1.3",
|
||||
"@nextcloud/typings": "^0.2.2",
|
||||
"core-js": "^3.6.4"
|
||||
}
|
||||
},
|
||||
"@nextcloud/axios": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/axios/-/axios-1.11.0.tgz",
|
||||
"integrity": "sha512-NyaiSC2GX2CPaH/MUGGMTTTza/TW9ZqWNGWq6LJ+pLER8nqZ9BQkwJ5kXUYGo+i3cka68PO+9WhcDv4fSABpuQ==",
|
||||
"requires": {
|
||||
"@nextcloud/auth": "^1.3.0",
|
||||
"axios": "^0.27.1",
|
||||
"core-js": "^3.6.4"
|
||||
}
|
||||
},
|
||||
"@nextcloud/event-bus": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/event-bus/-/event-bus-1.3.0.tgz",
|
||||
"integrity": "sha512-+U5MnCvfnNWvf0lvdqJg8F+Nm8wN+s9ayuBjtiEQxTAcootv7lOnlMgfreqF3l2T0Wet2uZh4JbFVUWf8l3w7g==",
|
||||
"requires": {
|
||||
"@types/semver": "^7.3.5",
|
||||
"core-js": "^3.11.2",
|
||||
"semver": "^7.3.5"
|
||||
}
|
||||
},
|
||||
"@nextcloud/l10n": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/l10n/-/l10n-1.6.0.tgz",
|
||||
"integrity": "sha512-aKGlgrwN9OiafN791sYus0shfwNeU3PlrH6Oi9ISma6iJSvN6a8aJM8WGKCJ9pqBaTR5PrDuckuM/WnybBWb6A==",
|
||||
"requires": {
|
||||
"core-js": "^3.6.4",
|
||||
"node-gettext": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"@nextcloud/vue": {
|
||||
"version": "3.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-3.10.2.tgz",
|
||||
"integrity": "sha512-/8r2fE8V7nw9erjm06x3nCALC+6o9q2CzNSL0eDRfsKXCVySFoZ4bYX+zziQUStienisKDRXRhxh7RUAwkS2+w==",
|
||||
"requires": {
|
||||
"@nextcloud/auth": "^1.2.3",
|
||||
"@nextcloud/axios": "^1.3.2",
|
||||
"@nextcloud/browser-storage": "^0.1.1",
|
||||
"@nextcloud/capabilities": "^1.0.2",
|
||||
"@nextcloud/dialogs": "^3.0.0",
|
||||
"@nextcloud/event-bus": "^1.1.4",
|
||||
"@nextcloud/l10n": "^1.2.3",
|
||||
"@nextcloud/router": "^1.0.2",
|
||||
"core-js": "^3.6.5",
|
||||
"debounce": "1.2.1",
|
||||
"emoji-mart-vue-fast": "^7.0.7",
|
||||
"escape-html": "^1.0.3",
|
||||
"hammerjs": "^2.0.8",
|
||||
"linkifyjs": "~2.1.9",
|
||||
"md5": "^2.2.1",
|
||||
"regenerator-runtime": "^0.13.5",
|
||||
"string-length": "^4.0.1",
|
||||
"striptags": "^3.1.1",
|
||||
"style-loader": "^2.0.0",
|
||||
"tributejs": "^5.1.3",
|
||||
"v-click-outside": "^3.0.1",
|
||||
"v-tooltip": "^2.0.3",
|
||||
"vue": "^2.6.11",
|
||||
"vue-color": "^2.7.1",
|
||||
"vue-multiselect": "^2.1.6",
|
||||
"vue-visible": "^1.0.2",
|
||||
"vue2-datepicker": "^3.6.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nextcloud/router": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/router/-/router-1.2.0.tgz",
|
||||
"integrity": "sha512-kn9QsL9LuhkIMaSSgdiqRL3SZ6PatuAjXUiyq343BbSnI99Oc5eJH8kU6cT2AHije7wKy/tK8Xe3VQuVO32SZQ==",
|
||||
"requires": {
|
||||
"core-js": "^3.6.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"core-js": {
|
||||
"version": "3.22.4",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.22.4.tgz",
|
||||
"integrity": "sha512-1uLykR+iOfYja+6Jn/57743gc9n73EWiOnSJJ4ba3B4fOEYDBv25MagmEZBxTp5cWq4b/KPx/l77zgsp28ju4w=="
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"style-loader": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-2.0.0.tgz",
|
||||
"integrity": "sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ==",
|
||||
"requires": {
|
||||
"loader-utils": "^2.0.0",
|
||||
"schema-utils": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
"markdown-it-link-attributes": "^4.0.1",
|
||||
"markdown-it-task-checkbox": "^1.0.6",
|
||||
"moment": "^2.29.4",
|
||||
"nextcloud-vue-collections": "^0.11.0",
|
||||
"nextcloud-vue-collections": "^0.10.0",
|
||||
"p-queue": "^7.3.4",
|
||||
"url-search-params-polyfill": "^8.1.1",
|
||||
"vue": "^2.7.14",
|
||||
|
||||
@@ -95,7 +95,8 @@ export default {
|
||||
.avatar-wrapper {
|
||||
background-color: #b9b9b9;
|
||||
border-radius: 50%;
|
||||
border: 1px solid var(--color-border-dark);
|
||||
border-width: 2px;
|
||||
border-style: solid;
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
text-align: center;
|
||||
|
||||
@@ -52,18 +52,6 @@ hasPush = listen('deck_board_update', (name, body) => {
|
||||
store.dispatch('refreshBoard', currentBoardId)
|
||||
})
|
||||
|
||||
listen('deck_card_update', (name, body) => {
|
||||
|
||||
// ignore update events which we have triggered ourselves
|
||||
if (isOurSessionToken(body._causingSessionToken)) return
|
||||
|
||||
// only handle update events for the currently open board
|
||||
const currentBoardId = store.state.currentBoard?.id
|
||||
if (body.boardId !== currentBoardId) return
|
||||
|
||||
store.dispatch('loadStacks', currentBoardId)
|
||||
})
|
||||
|
||||
/**
|
||||
* is the notify_push app active and can
|
||||
* provide us with real time updates?
|
||||
|
||||
@@ -273,17 +273,6 @@ export default {
|
||||
addNewCard(state, card) {
|
||||
state.cards.push(card)
|
||||
},
|
||||
setCards(state, cards) {
|
||||
const deletedCards = state.cards.filter(_card => {
|
||||
return cards.findIndex(c => _card.id === c.id) === -1
|
||||
})
|
||||
for (const card of deletedCards) {
|
||||
this.commit('deleteCard', card)
|
||||
}
|
||||
for (const card of cards) {
|
||||
this.commit('addCard', card)
|
||||
}
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async addCard({ commit }, card) {
|
||||
|
||||
@@ -333,15 +333,10 @@ export default new Vuex.Store({
|
||||
commit('setAssignableUsers', board.users)
|
||||
},
|
||||
|
||||
async refreshBoard({ commit, dispatch }, boardId) {
|
||||
async refreshBoard({ commit }, boardId) {
|
||||
const board = await apiClient.loadById(boardId)
|
||||
const etagHasChanged = board.ETag !== this.state.currentBoard.ETag
|
||||
commit('setCurrentBoard', board)
|
||||
commit('setAssignableUsers', board.users)
|
||||
|
||||
if (etagHasChanged) {
|
||||
dispatch('loadStacks', boardId)
|
||||
}
|
||||
},
|
||||
|
||||
toggleShowArchived({ commit }) {
|
||||
|
||||
@@ -84,16 +84,14 @@ export default {
|
||||
call = 'loadArchivedStacks'
|
||||
}
|
||||
const stacks = await apiClient[call](boardId)
|
||||
const cards = []
|
||||
for (const i in stacks) {
|
||||
const stack = stacks[i]
|
||||
for (const j in stack.cards) {
|
||||
cards.push(stack.cards[j])
|
||||
commit('addCard', stack.cards[j])
|
||||
}
|
||||
delete stack.cards
|
||||
commit('addStack', stack)
|
||||
}
|
||||
commit('setCards', cards)
|
||||
},
|
||||
createStack({ commit }, stack) {
|
||||
stack.boardId = this.state.currentBoard.id
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
namespace OCA\Deck\Db;
|
||||
|
||||
use OCP\IUser;
|
||||
use OCP\IUserManager;
|
||||
|
||||
class UserTest extends \Test\TestCase {
|
||||
public function testGroupObjectSerialize() {
|
||||
@@ -36,11 +35,7 @@ class UserTest extends \Test\TestCase {
|
||||
$user->expects($this->any())
|
||||
->method('getDisplayName')
|
||||
->willReturn('myuser displayname');
|
||||
$userManager = $this->createMock(IUserManager::class);
|
||||
$userManager->expects($this->any())
|
||||
->method('get')
|
||||
->willReturn($user);
|
||||
$userRelationalObject = new User('myuser', $userManager);
|
||||
$userRelationalObject = new User($user);
|
||||
$expected = [
|
||||
'uid' => 'myuser',
|
||||
'displayname' => 'myuser displayname',
|
||||
@@ -58,11 +53,7 @@ class UserTest extends \Test\TestCase {
|
||||
$user->expects($this->any())
|
||||
->method('getDisplayName')
|
||||
->willReturn('myuser displayname');
|
||||
$userManager = $this->createMock(IUserManager::class);
|
||||
$userManager->expects($this->any())
|
||||
->method('get')
|
||||
->willReturn($user);
|
||||
$userRelationalObject = new User('myuser', $userManager);
|
||||
$userRelationalObject = new User($user);
|
||||
$expected = [
|
||||
'uid' => 'myuser',
|
||||
'displayname' => 'myuser displayname',
|
||||
|
||||
@@ -37,7 +37,6 @@ use OCP\IConfig;
|
||||
use OCP\IGroup;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserManager;
|
||||
use OCP\Notification\IManager;
|
||||
use OCP\Notification\INotification;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
@@ -220,9 +219,8 @@ class NotificationHelperTest extends \Test\TestCase {
|
||||
'title' => 'MyCardTitle',
|
||||
'duedate' => '2020-12-24'
|
||||
]);
|
||||
$userManager = $this->createMock(IUserManager::class);
|
||||
$card->setAssignedUsers([
|
||||
new User($users[0]->getUID(), $userManager)
|
||||
new User($users[0])
|
||||
]);
|
||||
$this->cardMapper->expects($this->once())
|
||||
->method('findBoardId')
|
||||
@@ -310,9 +308,8 @@ class NotificationHelperTest extends \Test\TestCase {
|
||||
'title' => 'MyCardTitle',
|
||||
'duedate' => '2020-12-24'
|
||||
]);
|
||||
$userManager = $this->createMock(IUserManager::class);
|
||||
$card->setAssignedUsers([
|
||||
new User($users[0]->getUID(), $userManager)
|
||||
new User($users[0])
|
||||
]);
|
||||
$this->cardMapper->expects($this->once())
|
||||
->method('findBoardId')
|
||||
|
||||
@@ -219,7 +219,6 @@ class BoardServiceTest extends TestCase {
|
||||
|
||||
public function testUpdate() {
|
||||
$board = new Board();
|
||||
$board->setId(123);
|
||||
$board->setTitle('MyBoard');
|
||||
$board->setOwner('admin');
|
||||
$board->setColor('00ff00');
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
namespace OCA\Deck\Service;
|
||||
|
||||
use OCA\Deck\Activity\ActivityManager;
|
||||
use OCA\Deck\Db\Assignment;
|
||||
use OCA\Deck\Db\AssignmentMapper;
|
||||
use OCA\Deck\Db\Board;
|
||||
use OCA\Deck\Db\Card;
|
||||
@@ -156,8 +155,7 @@ class CardServiceTest extends TestCase {
|
||||
->method('getNumberOfCommentsForObject')
|
||||
->willReturn(0);
|
||||
$boardMock = $this->createMock(Board::class);
|
||||
$stackMock = new Stack();
|
||||
$stackMock->setBoardId(1234);
|
||||
$stackMock = $this->createMock(Stack::class);
|
||||
$this->stackMapper->expects($this->any())
|
||||
->method('find')
|
||||
->willReturn($stackMock);
|
||||
@@ -170,21 +168,13 @@ class CardServiceTest extends TestCase {
|
||||
->method('find')
|
||||
->with(123)
|
||||
->willReturn($card);
|
||||
$a1 = new Assignment();
|
||||
$a1->setCardId(1337);
|
||||
$a1->setType(0);
|
||||
$a1->setParticipant('user1');
|
||||
$a2 = new Assignment();
|
||||
$a2->setCardId(1337);
|
||||
$a2->setType(0);
|
||||
$a2->setParticipant('user2');
|
||||
$this->assignedUsersMapper->expects($this->any())
|
||||
->method('findIn')
|
||||
->with([1337])
|
||||
->willReturn([$a1, $a2]);
|
||||
->method('findAll')
|
||||
->with(1337)
|
||||
->willReturn(['user1', 'user2']);
|
||||
$cardExpected = new Card();
|
||||
$cardExpected->setId(1337);
|
||||
$cardExpected->setAssignedUsers([$a1, $a2]);
|
||||
$cardExpected->setAssignedUsers(['user1', 'user2']);
|
||||
$cardExpected->setRelatedBoard($boardMock);
|
||||
$cardExpected->setRelatedStack($stackMock);
|
||||
$cardExpected->setLabels([]);
|
||||
|
||||
@@ -83,6 +83,10 @@ class DefaultBoardServiceTest extends TestCase {
|
||||
->method('getUserValue')
|
||||
->willReturn('yes');
|
||||
|
||||
$this->boardMapper->expects($this->once())
|
||||
->method('findAllByUser')
|
||||
->willReturn($userBoards);
|
||||
|
||||
$this->config->expects($this->once())
|
||||
->method('setUserValue');
|
||||
|
||||
@@ -103,6 +107,10 @@ class DefaultBoardServiceTest extends TestCase {
|
||||
->method('getUserValue')
|
||||
->willReturn('no');
|
||||
|
||||
$this->boardMapper->expects($this->once())
|
||||
->method('findAllByUser')
|
||||
->willReturn($userBoards);
|
||||
|
||||
$result = $this->service->checkFirstRun($this->userId);
|
||||
$this->assertEquals($result, false);
|
||||
}
|
||||
|
||||
@@ -30,9 +30,6 @@ use OCP\IUserManager;
|
||||
use OCP\Server;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
||||
/**
|
||||
* @group DB
|
||||
*/
|
||||
class TrelloJsonServiceTest extends \Test\TestCase {
|
||||
private TrelloJsonService $service;
|
||||
/** @var IURLGenerator|MockObject */
|
||||
@@ -60,7 +57,7 @@ class TrelloJsonServiceTest extends \Test\TestCase {
|
||||
}
|
||||
|
||||
public function testValidateUsersWithInvalidUser() {
|
||||
$this->expectExceptionMessage('Trello user trello_user not found in property "members" of json data');
|
||||
$this->expectErrorMessage('Trello user trello_user not found in property "members" of json data');
|
||||
$importService = $this->createMock(BoardImportService::class);
|
||||
$importService
|
||||
->method('getConfig')
|
||||
|
||||
@@ -236,11 +236,6 @@ class PermissionServiceTest extends \Test\TestCase {
|
||||
$board->setAcl($this->getAcls($boardId));
|
||||
$this->boardMapper->expects($this->any())->method('find')->willReturn($board);
|
||||
|
||||
$this->aclMapper->expects($this->any())
|
||||
->method('findAll')
|
||||
->with($boardId)
|
||||
->willReturn($this->getAcls($boardId));
|
||||
|
||||
$this->shareManager->expects($this->any())
|
||||
->method('sharingDisabledForUser')
|
||||
->willReturn(false);
|
||||
@@ -267,17 +262,12 @@ class PermissionServiceTest extends \Test\TestCase {
|
||||
$this->boardMapper->expects($this->any())->method('find')->willReturn($board);
|
||||
}
|
||||
|
||||
$this->aclMapper->expects($this->any())
|
||||
->method('findAll')
|
||||
->with($boardId)
|
||||
->willReturn($this->getAcls($boardId));
|
||||
|
||||
if ($result) {
|
||||
$actual = $this->service->checkPermission($mapper, $boardId, $permission);
|
||||
$actual = $this->service->checkPermission($mapper, 1234, $permission);
|
||||
$this->assertTrue($actual);
|
||||
} else {
|
||||
$this->expectException(NoPermissionException::class);
|
||||
$this->service->checkPermission($mapper, $boardId, $permission);
|
||||
$this->service->checkPermission($mapper, 1234, $permission);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,7 +340,7 @@ class PermissionServiceTest extends \Test\TestCase {
|
||||
$aclGroup->setParticipant('group1');
|
||||
|
||||
$board = $this->createMock(Board::class);
|
||||
$board->expects($this->any())
|
||||
$board->expects($this->once())
|
||||
->method('__call')
|
||||
->with('getOwner', [])
|
||||
->willReturn('user1');
|
||||
@@ -362,8 +352,8 @@ class PermissionServiceTest extends \Test\TestCase {
|
||||
->method('find')
|
||||
->with(123)
|
||||
->willReturn($board);
|
||||
$this->userManager->expects($this->any())
|
||||
->method('userExists')
|
||||
$this->userManager->expects($this->exactly(2))
|
||||
->method('get')
|
||||
->withConsecutive(['user1'], ['user2'])
|
||||
->willReturnOnConsecutiveCalls($user1, $user2);
|
||||
|
||||
@@ -377,9 +367,9 @@ class PermissionServiceTest extends \Test\TestCase {
|
||||
->willReturn($group);
|
||||
$users = $this->service->findUsers(123);
|
||||
$this->assertEquals([
|
||||
'user1' => new User($user1->getUID(), $this->userManager),
|
||||
'user2' => new User($user2->getUID(), $this->userManager),
|
||||
'user3' => new User($user3->getUID(), $this->userManager),
|
||||
'user1' => new User($user1),
|
||||
'user2' => new User($user2),
|
||||
'user3' => new User($user3),
|
||||
], $users);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ use OCA\Deck\Db\LabelMapper;
|
||||
use OCA\Deck\Db\Stack;
|
||||
use OCA\Deck\Db\StackMapper;
|
||||
use OCA\Deck\Validators\StackServiceValidator;
|
||||
use OCP\EventDispatcher\IEventDispatcher;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use \Test\TestCase;
|
||||
|
||||
@@ -72,8 +71,6 @@ class StackServiceTest extends TestCase {
|
||||
private $changeHelper;
|
||||
/** @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject */
|
||||
private $logger;
|
||||
/** @var IEventDispatcher|\PHPUnit\Framework\MockObject\MockObject */
|
||||
private $eventDispatcher;
|
||||
/** @var StackServiceValidator|\PHPUnit\Framework\MockObject\MockObject */
|
||||
private $stackServiceValidator;
|
||||
|
||||
@@ -91,7 +88,6 @@ class StackServiceTest extends TestCase {
|
||||
$this->activityManager = $this->createMock(ActivityManager::class);
|
||||
$this->changeHelper = $this->createMock(ChangeHelper::class);
|
||||
$this->logger = $this->createMock(LoggerInterface::class);
|
||||
$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
|
||||
$this->stackServiceValidator = $this->createMock(StackServiceValidator::class);
|
||||
|
||||
$this->stackService = new StackService(
|
||||
@@ -107,7 +103,6 @@ class StackServiceTest extends TestCase {
|
||||
$this->activityManager,
|
||||
$this->changeHelper,
|
||||
$this->logger,
|
||||
$this->eventDispatcher,
|
||||
$this->stackServiceValidator
|
||||
);
|
||||
}
|
||||
@@ -115,12 +110,10 @@ class StackServiceTest extends TestCase {
|
||||
public function testFindAll() {
|
||||
$this->permissionService->expects($this->once())->method('checkPermission');
|
||||
$this->stackMapper->expects($this->once())->method('findAll')->willReturn($this->getStacks());
|
||||
$this->cardService->expects($this->atLeastOnce())->method('enrichCards')->will(
|
||||
$this->cardService->expects($this->atLeastOnce())->method('enrich')->will(
|
||||
$this->returnCallback(
|
||||
function ($cards) {
|
||||
foreach ($cards as $card) {
|
||||
$card->setLabels($this->getLabels()[$card->getId()]);
|
||||
}
|
||||
function ($card) {
|
||||
$card->setLabels($this->getLabels()[$card->getId()]);
|
||||
}
|
||||
)
|
||||
);
|
||||
@@ -203,7 +196,6 @@ class StackServiceTest extends TestCase {
|
||||
$this->permissionService->expects($this->once())->method('checkPermission');
|
||||
$stackToBeDeleted = new Stack();
|
||||
$stackToBeDeleted->setId(1);
|
||||
$stackToBeDeleted->setBoardId(1);
|
||||
$this->stackMapper->expects($this->once())->method('find')->willReturn($stackToBeDeleted);
|
||||
$this->stackMapper->expects($this->once())->method('update')->willReturn($stackToBeDeleted);
|
||||
$this->cardMapper->expects($this->once())->method('findAll')->willReturn([]);
|
||||
@@ -252,7 +244,6 @@ class StackServiceTest extends TestCase {
|
||||
private function createStack($id, $order) {
|
||||
$stack = new Stack();
|
||||
$stack->setId($id);
|
||||
$stack->setBoardId(1);
|
||||
$stack->setOrder($order);
|
||||
return $stack;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
namespace OCA\Deck\Controller;
|
||||
|
||||
use OCA\Deck\Db\Acl;
|
||||
use OCA\Deck\Db\Board;
|
||||
use OCP\IUser;
|
||||
|
||||
class BoardControllerTest extends \Test\TestCase {
|
||||
@@ -89,12 +88,11 @@ class BoardControllerTest extends \Test\TestCase {
|
||||
}
|
||||
|
||||
public function testRead() {
|
||||
$board = new Board();
|
||||
$this->boardService->expects($this->once())
|
||||
->method('find')
|
||||
->with(123)
|
||||
->willReturn($board);
|
||||
$this->assertEquals($board, $this->controller->read(123));
|
||||
->willReturn(1);
|
||||
$this->assertEquals(1, $this->controller->read(123));
|
||||
}
|
||||
|
||||
public function testCreate() {
|
||||
|
||||
Reference in New Issue
Block a user