6 Commits
Author SHA1 Message Date
gnilebein 28b4edc811 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.
2026-08-26 07:10:55 +02:00
Patrick Niebeling 0e66319a06 Let each workflow watch the due date or the start date
Build package / php-lint (8.4) (push) Successful in 39s
Build package / php-lint (8.5) (push) Successful in 43s
Build package / xml-lint (push) Successful in 13s
Build package / unit-tests (push) Failing after 39s
Build package / package (push) Skipped
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.
2026-08-25 15:28:30 +02:00
Patrick Niebeling 43648f3728 Use app.svg for the personal settings section icon
Was already pending in the working tree; committed unchanged.
2026-08-25 15:28:21 +02:00
Patrick Niebeling ce749e63a4 Fix overdue check to compare real timestamps, not whole calendar days
Build package / package (push) Successful in 57s
Build package / php-lint (8.4) (push) Successful in 44s
Build package / php-lint (8.5) (push) Successful in 35s
Build package / xml-lint (push) Successful in 11s
Build package / unit-tests (push) Successful in 37s
WorkflowRunner::isOverdue() took Card::getDaysUntilDue(), which Deck
computes by truncating both "now" and the due date to midnight before
diffing. A card due earlier today therefore reported 0 days until due -
not overdue - until the calendar date rolled over to the next day, so
a card due "this morning" sat unmoved for up to 24h while one due
"yesterday morning" moved immediately. isOverdue() now takes the due
date and $now directly and compares them as real timestamps, matching
what Deck's own UI shows.

Bump to 34.0.2.
2026-08-25 13:48:02 +02:00
Patrick Niebeling b203ba35f8 Align declared PHP compatibility with CI: require 8.4-8.5
Build package / php-lint (8.4) (push) Successful in 36s
Build package / php-lint (8.5) (push) Successful in 35s
Build package / xml-lint (push) Successful in 14s
Build package / unit-tests (push) Successful in 37s
Build package / package (push) Successful in 52s
Bump to 34.0.1.
2026-08-25 13:28:52 +02:00
Patrick Niebeling ef973af4b5 Drop PHP 8.2/8.3 from CI, test against 8.4/8.5 only
Build package / php-lint (8.4) (push) Successful in 36s
Build package / php-lint (8.5) (push) Successful in 33s
Build package / xml-lint (push) Successful in 11s
Build package / unit-tests (push) Successful in 39s
Build package / package (push) Successful in 52s
2026-08-25 13:14:02 +02:00
6 changed files with 39 additions and 14 deletions
+2 -2
View File
@@ -15,7 +15,7 @@ jobs:
runs-on: gitea-runner-server03
strategy:
matrix:
php-version: ['8.2', '8.3', '8.4', '8.5']
php-version: ['8.4', '8.5']
steps:
- uses: actions/checkout@v7
@@ -51,7 +51,7 @@ jobs:
- uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
php-version: '8.4'
extensions: sqlite, pdo_sqlite
coverage: none
+2 -2
View File
@@ -28,7 +28,7 @@ This app lets every user configure their own Deck automation workflows from Pers
A background job periodically evaluates all enabled workflows and moves cards whose due date has passed, using Deck's own internal PHP classes only (no HTTP/OCS calls).
]]></description>
<version>34.0.0</version>
<version>34.0.2</version>
<licence>agpl</licence>
<author mail="patrick@niebel.ing">Patrick Niebeling</author>
<namespace>WorkflowDeckAutomation</namespace>
@@ -36,7 +36,7 @@ A background job periodically evaluates all enabled workflows and moves cards wh
<category>tools</category>
<bugs>https://github.com/pniebeling/workflow_deck_automation/issues</bugs>
<dependencies>
<php min-version="8.2" max-version="8.5"/>
<php min-version="8.4" max-version="8.5"/>
<database min-version="9.4">pgsql</database>
<database>sqlite</database>
<database min-version="8.0">mysql</database>
+15 -3
View File
@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace OCA\WorkflowDeckAutomation\Service;
use DateTimeInterface;
use OCA\Deck\Db\Card;
use OCA\WorkflowDeckAutomation\Db\Workflow;
use OCA\WorkflowDeckAutomation\Db\WorkflowMapper;
@@ -165,8 +166,10 @@ class WorkflowRunner {
// and the workflow wants a mail — this is decoration, not a check.
$targets = null;
$now = $this->timeFactory->getDateTime();
foreach ($cards as $card) {
if (!self::isOverdue($card->getDaysUntilDue())) {
if (!self::isOverdue($card->getDuedate(), $now)) {
continue;
}
@@ -319,8 +322,17 @@ class WorkflowRunner {
}
}
public static function isOverdue(?int $daysUntilDue): bool {
return $daysUntilDue !== null && $daysUntilDue < 0;
/**
* 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.
*/
public static function isOverdue(?DateTimeInterface $duedate, DateTimeInterface $now): bool {
return $duedate !== null && $duedate < $now;
}
/**
+1 -1
View File
@@ -29,6 +29,6 @@ class PersonalSection implements IIconSection {
}
public function getIcon(): string {
return $this->urlGenerator->imagePath(Application::APP_ID, 'app-dark.svg');
return $this->urlGenerator->imagePath(Application::APP_ID, 'app.svg');
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "workflow_deck_automation",
"version": "34.0.0",
"version": "34.0.2",
"private": true,
"type": "module",
"description": "Automates moving overdue Deck cards between stacks, configurable per user.",
@@ -4,22 +4,35 @@ declare(strict_types=1);
namespace OCA\WorkflowDeckAutomation\Tests\Unit\Service;
use DateTimeImmutable;
use OCA\WorkflowDeckAutomation\Service\WorkflowRunner;
use PHPUnit\Framework\TestCase;
class WorkflowRunnerFilterTest extends TestCase {
public function testIsOverdueReturnsFalseWithoutDueDate(): void {
$this->assertFalse(WorkflowRunner::isOverdue(null));
$this->assertFalse(WorkflowRunner::isOverdue(null, new DateTimeImmutable('2026-01-15 12:00:00')));
}
public function testIsOverdueReturnsFalseForFutureDueDate(): void {
$this->assertFalse(WorkflowRunner::isOverdue(0));
$this->assertFalse(WorkflowRunner::isOverdue(3));
$now = new DateTimeImmutable('2026-01-15 12:00:00');
$this->assertFalse(WorkflowRunner::isOverdue($now->modify('+1 hour'), $now));
$this->assertFalse(WorkflowRunner::isOverdue($now->modify('+3 days'), $now));
}
public function testIsOverdueReturnsTrueForPastDueDate(): void {
$this->assertTrue(WorkflowRunner::isOverdue(-1));
$this->assertTrue(WorkflowRunner::isOverdue(-30));
$now = new DateTimeImmutable('2026-01-15 12:00:00');
$this->assertTrue(WorkflowRunner::isOverdue($now->modify('-1 hour'), $now));
$this->assertTrue(WorkflowRunner::isOverdue($now->modify('-30 days'), $now));
}
public function testIsOverdueReturnsTrueForADueTimeEarlierTheSameDay(): void {
// Regression: comparing whole calendar days (as Deck's own
// Card::getDaysUntilDue() does) reports a card due earlier today as
// "0 days until due", not overdue, until the calendar date rolls
// over - holding every card back for up to 24h after it actually
// fell due. isOverdue() must compare the real timestamps instead.
$now = new DateTimeImmutable('2026-01-15 12:00:00');
$this->assertTrue(WorkflowRunner::isOverdue(new DateTimeImmutable('2026-01-15 06:00:00'), $now));
}
public function testNoFiltersMatchesAnyCard(): void {