Compare commits

..

1 Commits

Author SHA1 Message Date
Julius Härtl
011488d63b ci: Add query count for integration tests
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2023-02-16 23:33:31 +01:00
54 changed files with 591 additions and 665 deletions

View File

@@ -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 }}

View File

@@ -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

View File

@@ -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} коментара",

View File

@@ -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} коментара",

View File

@@ -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",

View File

@@ -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",

View File

@@ -30,8 +30,6 @@ OC.L10N.register(
"Created" : "Үүсгэсэн",
"Today" : "өнөөдөр",
"Tomorrow" : "маргааш",
"Next week" : "Дараа 7 хоног",
"Next month" : "Дараа сар",
"Save" : "Хадгалах",
"Reply" : "хариулт",
"Update" : "Шинэчлэх",

View File

@@ -28,8 +28,6 @@
"Created" : "Үүсгэсэн",
"Today" : "өнөөдөр",
"Tomorrow" : "маргааш",
"Next week" : "Дараа 7 хоног",
"Next month" : "Дараа сар",
"Save" : "Хадгалах",
"Reply" : "хариулт",
"Update" : "Шинэчлэх",

View File

@@ -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}",

View File

@@ -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}",

View File

@@ -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" : "Создать карточку",

View File

@@ -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" : "Создать карточку",

View File

@@ -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}",

View File

@@ -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}",

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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

View File

@@ -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());

View File

@@ -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;
});

View File

@@ -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;
});

View File

@@ -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;
}
}
}
}

View File

@@ -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

View File

@@ -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));
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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]);

View File

@@ -26,5 +26,4 @@ namespace OCA\Deck;
class NotifyPushEvents {
public const DeckBoardUpdate = 'deck_board_update';
public const DeckCardUpdate = 'deck_card_update';
}

View File

@@ -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) {

View File

@@ -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);
}

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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
View File

@@ -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": {

View File

@@ -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",

View File

@@ -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;

View File

@@ -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?

View File

@@ -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) {

View File

@@ -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 }) {

View File

@@ -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

View File

@@ -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',

View File

@@ -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')

View File

@@ -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');

View File

@@ -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([]);

View File

@@ -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);
}

View File

@@ -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')

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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() {