Skip to content

Commit 458a463

Browse files
committed
fix(dav): sync category changes outside card no-op updates
Signed-off-by: Jaggob <37583151+Jaggob@users.noreply.github.com>
1 parent 7f2d27e commit 458a463

2 files changed

Lines changed: 108 additions & 3 deletions

File tree

lib/DAV/DeckCalendarBackend.php

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,12 @@ private function updateCardFromCalendar(Card $sourceItem, string $data, bool $re
386386
}
387387
$done = $this->mapDoneFromTodo($todo, $card);
388388
$incomingDue = isset($todo->DUE) ? $todo->DUE->getDateTime() : null;
389+
$categories = $this->extractCategories($todo);
390+
if ($categories !== null) {
391+
$categories = $this->normalizeCategoriesForLabelSync($boardId, $categories, $mode);
392+
}
393+
$categoriesChanged = $categories !== null
394+
&& !$this->hasSameCategoryLabels($categories, $card);
389395

390396
$isNoopUpdate = $title === $card->getTitle()
391397
&& $stackId === $card->getStackId()
@@ -394,7 +400,11 @@ private function updateCardFromCalendar(Card $sourceItem, string $data, bool $re
394400
&& $this->isDateEqual($card->getDone(), $done->getValue())
395401
&& (!$restoreDeleted || $card->getDeletedAt() === 0);
396402

397-
if ($isNoopUpdate) {
403+
if ($isNoopUpdate && !$categoriesChanged) {
404+
return $card;
405+
}
406+
if ($isNoopUpdate && $categories !== null) {
407+
$this->syncCardCategories($card->getId(), $categories);
398408
return $card;
399409
}
400410

@@ -412,9 +422,7 @@ private function updateCardFromCalendar(Card $sourceItem, string $data, bool $re
412422
$done,
413423
$boardId
414424
);
415-
$categories = $this->extractCategories($todo);
416425
if ($categories !== null) {
417-
$categories = $this->normalizeCategoriesForLabelSync($boardId, $categories, $mode);
418426
$this->syncCardCategories($updatedCard->getId(), $categories);
419427
}
420428

@@ -896,6 +904,29 @@ private function normalizeDescriptionForCompare(string $value): string {
896904
return str_replace(["\r\n", "\r"], "\n", $value);
897905
}
898906

907+
/**
908+
* @param list<string> $categories
909+
*/
910+
private function hasSameCategoryLabels(array $categories, Card $card): bool {
911+
$incoming = [];
912+
foreach ($categories as $category) {
913+
$key = mb_strtolower(trim($category));
914+
if ($key !== '') {
915+
$incoming[$key] = true;
916+
}
917+
}
918+
919+
$current = [];
920+
foreach ($card->getLabels() ?? [] as $label) {
921+
$key = mb_strtolower(trim($label->getTitle()));
922+
if ($key !== '') {
923+
$current[$key] = true;
924+
}
925+
}
926+
927+
return array_keys($incoming) === array_keys($current);
928+
}
929+
899930
private function isDateEqual(?\DateTimeInterface $left, ?\DateTimeInterface $right): bool {
900931
if ($left === null && $right === null) {
901932
return true;

tests/unit/DAV/DeckCalendarBackendTest.php

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,80 @@ public function testUpdateCardSyncsAppleTagsToLabels(): void {
844844
$this->backend->updateCalendarObject($sourceCard, $calendarData);
845845
}
846846

847+
public function testUpdateCardSyncsCategoriesEvenWhenOtherFieldsAreUnchanged(): void {
848+
$sourceCard = new Card();
849+
$sourceCard->setId(123);
850+
851+
$existingCard = new Card();
852+
$existingCard->setId(123);
853+
$existingCard->setTitle('Card');
854+
$existingCard->setDescription('Description');
855+
$existingCard->setStackId(42);
856+
$existingCard->setType('plain');
857+
$existingCard->setOrder(0);
858+
$existingCard->setOwner('admin');
859+
$existingCard->setDeletedAt(0);
860+
$existingCard->setArchived(false);
861+
$existingCard->setDone(null);
862+
$existingCard->setLabels([]);
863+
864+
$this->cardService->expects($this->exactly(2))
865+
->method('find')
866+
->with(123)
867+
->willReturnOnConsecutiveCalls($existingCard, $existingCard);
868+
869+
$currentStack = new Stack();
870+
$currentStack->setId(42);
871+
$currentStack->setBoardId(12);
872+
$this->stackService->expects($this->once())
873+
->method('find')
874+
->with(42)
875+
->willReturn($currentStack);
876+
877+
$label = new Label();
878+
$label->setId(7);
879+
$label->setTitle('Test');
880+
$board = new Board();
881+
$board->setId(12);
882+
$board->setLabels([$label]);
883+
884+
$this->boardMapper->expects($this->once())
885+
->method('find')
886+
->with(12, true, false)
887+
->willReturn($board);
888+
889+
$this->permissionService->expects($this->once())
890+
->method('getPermissions')
891+
->with(12)
892+
->willReturn([
893+
\OCA\Deck\Db\Acl::PERMISSION_MANAGE => true,
894+
]);
895+
896+
$this->cardService->expects($this->never())
897+
->method('update');
898+
$this->labelService->expects($this->never())
899+
->method('create');
900+
$this->cardService->expects($this->once())
901+
->method('assignLabel')
902+
->with(123, 7);
903+
$this->cardService->expects($this->never())
904+
->method('removeLabel');
905+
906+
$calendarData = <<<ICS
907+
BEGIN:VCALENDAR
908+
VERSION:2.0
909+
BEGIN:VTODO
910+
UID:deck-card-123
911+
SUMMARY:Card
912+
DESCRIPTION:Description
913+
X-APPLE-TAGS:Test
914+
END:VTODO
915+
END:VCALENDAR
916+
ICS;
917+
918+
$this->backend->updateCalendarObject($sourceCard, $calendarData);
919+
}
920+
847921
public function testUpdateCardDoesNotAutoCreateLabelsWithoutManagePermission(): void {
848922
$sourceCard = new Card();
849923
$sourceCard->setId(123);

0 commit comments

Comments
 (0)