Only allow workflows on owned boards, and show the board in the table
Build package / php-lint (8.4) (push) Successful in 1m7s
Build package / php-lint (8.5) (push) Successful in 56s
Build package / xml-lint (push) Successful in 17s
Build package / unit-tests (push) Successful in 42s
Build package / package (push) Successful in 1m4s

The board list now only contains boards the current user owns, which
also makes the controller's board validation enforce the owner rule.

The workflow table gains a Board column (Board, Titel, Von Stapel,
Nach Stapel, Filter, E-Mail, Aktiv) and is sorted alphabetically by
those columns in that order.
This commit is contained in:
Patrick Niebeling committed 2026-09-30 09:16:09 +02:00
1 parent 7c7c52cb1c
commit ada16cb101
4 files changed
+85 -22

No files matched your search

+6
View File
@@ -40,6 +40,12 @@ The filter logic (`WorkflowRunner::cardMatchesFilters()`, `::isOverdue()`, `::fi
Archived boards deliberately do *not* trigger this (they stay readable, so `findStackIds()` succeeds), even though they're filtered out of the settings dropdowns.
## Workflows only on boards the user owns
A workflow can only be created or saved on a board whose Deck owner is the current user. `DeckIntegrationService::listBoardsForCurrentUser($uid)` returns **only owned boards** (`unwrapUid($board->getOwner()) === $uid`); boards merely shared with the user are dropped. Since `WorkflowController::validate()` checks the board id against that list, the same filter enforces the rule server-side — there is no separate ownership check.
Workflows created before this rule may still sit on a shared board. The runner does not check ownership, so they keep running; in the settings table their board is missing from the list, so the row is marked "Board nicht mehr vorhanden oder nicht dein eigenes" and saving it requires picking an owned board.
## Dead filters are surfaced, never disabled
`findBrokenTarget()` covers the board and the two stacks — **not** `filter_user_ids` / `filter_label_ids`. Those are plain id lists compared with `array_intersect()` in `cardMatchesFilters()`, so an entry that no longer exists simply stops matching. With three labels of which one was deleted that is exactly right, and disabling would be wrong.