revert 0e66319a06
Build package / php-lint (8.4) (push) Successful in 43s
Build package / php-lint (8.5) (push) Successful in 40s
Build package / xml-lint (push) Successful in 12s
Build package / unit-tests (push) Successful in 38s
Build package / package (push) Successful in 52s

revert Let each workflow watch the due date or the start date

Deck 1.18 added a start date to cards (Card::$startdate), so a workflow
no longer has to mean "overdue". Each rule now carries a date_field
('due' | 'start'), chosen in the settings form next to board and stacks.

Existing rules keep the due date: the new column's default supplies it
for every stored row, so there is no backfill step, and
Workflow::getDateFieldOrDue() covers entities that were never near the
database as well as hand-edited values. The controller is the one place
that rejects an unknown value instead of normalising it - a client
asking for a rule it would not get should hear about it.

The probe for the field is property_exists(), not method_exists():
Deck's entities declare no getter as real code - getStartdate(),
getDuedate(), even getId() all go through Entity::__call(), which
method_exists() ignores by definition. A method_exists() guard would
have been false on every Deck version and would have turned every
start-date rule into a silent no-op.

assertDeckAvailable() now also refuses Deck older than 1.18.0. That
floor cannot live in appinfo/info.xml - neither the server's nor the app
store's schema has an app-to-app dependency element - but
<nextcloud min-version="34"> already implies it, since 1.18.x is the
only Deck release line published for Nextcloud 34.

isOverdue() becomes hasPassed(): one function for both dates, since the
comparison and the argument against Deck's day-truncating
getDaysUntilDue() are identical for either.

Also carries a pending NcSelect icon-alignment fix that was already in
the working tree.

Bump to 34.1.0.
This commit is contained in:
2026-08-26 07:10:55 +02:00
parent 0e66319a06
commit 28b4edc811
13 changed files with 41 additions and 390 deletions
+7 -15
View File
@@ -17,8 +17,7 @@ use Psr\Log\LoggerInterface;
use Throwable;
/**
* Evaluates all enabled workflows and moves the cards whose watched date -
* Deck's due date or its start date, per workflow - has passed.
* Evaluates all enabled workflows and moves overdue cards.
*
* This runner has to evaluate rules for many different users within a
* single background-job process, so workflows are grouped by owner and
@@ -168,10 +167,9 @@ class WorkflowRunner {
$targets = null;
$now = $this->timeFactory->getDateTime();
$dateField = $workflow->getDateFieldOrDue();
foreach ($cards as $card) {
if (!self::hasPassed($this->deckService->getCardDate($card, $dateField), $now)) {
if (!self::isOverdue($card->getDuedate(), $now)) {
continue;
}
@@ -181,12 +179,11 @@ class WorkflowRunner {
continue;
}
$this->logger->info('Card {card} ("{title}") matches workflow {id} on its {dateField} date; moving to stack {target}.', [
$this->logger->info('Card {card} ("{title}") matches workflow {id}; moving to stack {target}.', [
'app' => 'workflow_deck_automation',
'card' => $card->getId(),
'title' => $card->getTitle(),
'id' => $workflow->getId(),
'dateField' => $dateField,
'target' => $workflow->getTargetStackId(),
]);
@@ -326,21 +323,16 @@ class WorkflowRunner {
}
/**
* Whether the card date a workflow watches - its due date or its start date,
* see Workflow::DATE_FIELD_* - lies in the past. A card without that date set
* is never picked up.
*
* Compares the card's actual timestamp against $now instead of Deck's own
* Compares the card's actual due timestamp against $now instead of Deck's own
* Card::getDaysUntilDue(), which truncates both sides to midnight before diffing
* (DateInterval's %a is a whole-day count) and therefore reports 0 - not overdue -
* for any card whose due time has already passed today. That silently held back
* every card for up to 24h after it actually fell due; comparing the raw datetime
* instead matches what Deck's own UI shows (e.g. "vor 2 Stunden") and has no
* day-rounding step to get wrong. The same reasoning applies unchanged to the
* start date, which is why this is one function and not two.
* day-rounding step to get wrong.
*/
public static function hasPassed(?DateTimeInterface $cardDate, DateTimeInterface $now): bool {
return $cardDate !== null && $cardDate < $now;
public static function isOverdue(?DateTimeInterface $duedate, DateTimeInterface $now): bool {
return $duedate !== null && $duedate < $now;
}
/**