Release 1.0.0 - #22
Merged
Merged
Conversation
request. Added userId to timesheets and stopped resolving ticket status against the session project when a ticket has no project. Added PHPUnit setup and a Taskfile for running tests.
Leantime core does not maintain its `modified` column on every write path: timesheets saved through ON DUPLICATE KEY UPDATE leave it untouched, and tickets and milestones were filtered on `ticket.date` — the creation date — so edits to existing entities never reached consumers at all. The plugin now owns `itk_data_api_modified` on zp_projects, zp_tickets, zp_timesheets and zp_user, maintained by database triggers so no write path can bypass it. All modifiedAfter filtering and every `modified` value in a response come from that column; core's own column is left alone. Installing stamps existing rows, so the first sync after install returns everything once. The DDL moves out of the service into a SchemaRepository that executes one statement at a time, so a failure past the first is reported instead of swallowed, and is idempotent — reinstalling no longer throws on the delete triggers it left behind. Timestamps are written with UTC_TIMESTAMP() rather than NOW(), which would record the session timezone's clock; the delete triggers now stamp dateDeleted the same way. Users gain a `modified` field, and WorkerData accepts a null name — CONCAT of the first and last name is NULL for a user without a surname, which used to fail the whole /users response.
Allowed a missing worker name, and stopped returning a whitespace-only name for a worker whose firstname and lastname are both blank. Ticket status labels are looked up once per project instead of once per ticket, and the remaining implicit-nullable parameters are now explicit. Committed composer.lock and pinned illuminate/database and nesbot/carbon to the versions Leantime v3.9.7 locks, so the tests run against the code Leantime itself runs. PHPUnit moved to 12, the newest release that still runs on PHP 8.3. The pull request test job runs in the project's Docker Compose stack, so the PHP version comes from the Dockerfile rather than being repeated in the workflow. Releases no longer ship .claude, .idea or compose.yml.
The container ran as `deploy` (uid 1000) while the CI checkout belongs to the runner's uid, so composer could not create `vendor`. The compose user now comes from COMPOSE_USER, which the workflow sets to the checkout owner; the image carries a `runner` user at that uid, so it still has a writable home. Only `bin/create-release` needs the rsync the Dockerfile adds, so tests and linting run on itkdev/php8.3-fpm directly and no longer build an image. The built image moved to a `php-release` service, used by the release workflow alone.
Matches how itk-dev/economics does it, and drops a shell step.
An empty projectIds list was compared loosely, so it dropped the filter and answered with every row instead of none, while an empty ids list correctly matched nothing. Elements sent in array form are now trimmed like the comma separated form, so ?types[]=tickets%20 is no longer a 400 against the strict type comparison. types is required on the deleted endpoint, missing or empty. The endpoint has no limit, so defaulting it let a bare request return every deleted id ever recorded, and an empty list would answer 200 with nothing, which a sync client reads as "nothing was deleted". Renamed InvalidRequestException to BadRequestException, matching the 400 it turns into.
…lumn # Conflicts: # Model/WorkerData.php # Repositories/ApiDataRepository.php # tests/Model/WorkerDataTest.php # tests/Service/APIDataTest.php
Extracted the per-table install sequence into installStatements() so the order it depends on is pinned by a test rather than by a comment, and moved the index after the backfill — it was being built over an all-NULL column and then rewritten entry by entry. Gave the deletion tables a migration path. CREATE TABLE IF NOT EXISTS never reaches a database that already has the table, so changes now go in deletedTableAlterStatements(), which both populations run. First of them drops the dateDeleted default: the triggers make it unreachable, but the tables outlive an uninstall and the triggers do not. Wrote down the precondition the design rests on — install and update happen with the site down — and corrected the backfill docblock, which claimed to heal rows written while the triggers were absent when it only recovers inserts.
feat: allowed null values in API models
feat: validated request parameters, so malformed input answers 400 instead of 500
feat: own the sync watermark in an itk_data_api_modified column
The endpoint returned every type's whole deletion history in one unbounded response: it was the only query in ApiDataRepository with no orderBy, no limit and no offset, and `types` was required precisely because of that. It now serves one type per request, paged with start/limit like the entity endpoints. The cursor is the tracking table's own auto-increment id, exposed as `deletionId` next to the deleted entity's `id` — deletions are appended, so that is the one column that orders them and stays put while a client pages through. `results` becomes a flat list, which makes resultsCount === limit a meaningful "there may be more" signal.
It filters on a timestamp the same way `modifiedAfter` does on the entity endpoints, so it now carries the same name. The old `deleted` answers 400 instead of being ignored. Ignored, it would answer with the whole deletion history while the caller believes it asked for a window — which is exactly what happened to the consumer when it sent the timestamp under the name the endpoint did not read.
feat: paginated the deleted endpoint and narrowed it to one type
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.