Skip to content

feat(timeline): read the documents GLPI links to a followup (0.6.4) - #43

Merged
baraline merged 5 commits into
mainfrom
feat/followup-documents
Oct 12, 2026
Merged

baraline merged 5 commits into
mainfrom
feat/followup-documents

Conversation

@baraline

Copy link
Copy Markdown
Owner

Why

GLPI's editor links an image pasted into a followup to the followup (ITILFollowup), not to the ticket. list_ticket_timeline_documents uses the v2 timeline route, which returns only the ticket's own Document_Item links, so it never returns such an image. A caller that mirrors a ticket's followups therefore cannot resolve the images inside them. Measured on a live server: a description paste is linked to the ticket, and a followup paste is linked to the followup only.

The v1 sub-item route ITILFollowup/<id>/Document_Item does return those links. This release reads it.

What

  • list_item_documents(itemtype, items_id) lists one item's v1 Document_Item links as GetDocumentItem rows.
    • It needs the v1 session (v1_base_url, v1_user_token) and raises RuntimeError without one.
    • itemtype must match ^[A-Za-z][A-Za-z0-9_]*$ and the id must be positive, because both go into the URL path. Otherwise it raises GlpiValidationError before any call.
    • It sends range=0-999. GLPI was checked to honour range on a sub-item route. An answer of 1000 rows or more raises GlpiValidationError, because the page may be truncated, so a partial list is never returned.
    • {}, the v1 helper's empty-body result, gives []. Any other non-list answer raises.
  • list_ticket_followup_documents(ticket_id, *, include_private=False) walks a ticket's followups and returns one FollowupDocuments per kept followup: the followup itself and its links.
    • Entries come in ascending followup id, followups without links included.
    • Private followups, and followups whose is_private flag is missing, are dropped and never queried by default. include_private=True keeps every followup, and followup.is_private lets the caller classify each link.
    • A link row that does not name that followup as its item is dropped.
    • The fan-out goes through gather: concurrent on the async surface, sequential on the sync one.
  • GetDocumentItem is the v1 link row: id, documents_id, itemtype, items_id, entities_id, the three dates (localised) and timeline_position. Other keys (users_id, is_recursive, links) stay in extra_payload.
  • GlpiTimelinePosition.NO_TIMELINE is GLPI's own name for -1, an alias of INVALID. Existing uses are unchanged, and GlpiTimelinePosition(-1).name is still "INVALID". GLPI's editor writes -1 on the link of an image it embeds, and such a link is hidden from the ticket's Documents tab. An attachment upload is linked at 1.
  • FollowupDocuments and GetDocumentItem are exported from the package root.
  • User guide, API reference, the document-workflow and ticket-timeline skills, and the CHANGELOG are updated. The version is 0.6.4 (pyproject, __version__, skills).

Tasks and solutions are not walked, and their routes are not measured.

Verification

  • 26 new client test cases (18 functions, written once and generated into the sync tree) and 10 model tests.
  • 26 mutants of the new code, every one caught. They cover the itemtype and id checks, the range and the 1000-row refusal, {} handling, the session guard, the privacy default, the flag-less followup, the row filter, ordering, empty followups and failure propagation.
  • Full suite: 2056 passed, coverage 97.96%.
  • mypy (strict), ruff, ruff format, unasync_build.py --check and sphinx -W all clean.
  • No real ids, hostnames or names in the diff: tests use synthetic ids and example.invalid URLs.

🤖 Generated with Claude Code

baraline and others added 5 commits October 12, 2026 11:36
…TIMELINE for position -1

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…links

Reads <Itemtype>/<id>/Document_Item over the legacy v1 session and returns
GetDocumentItem rows. The itemtype and id are validated before any call, the
range 0-999 is sent, an empty body reads as no rows, any other non-list answer
raises, and a full page of 1000 rows or more raises rather than returning a
possibly truncated list. The followup route is the one measured live.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…wups for their document links

Lists each followup's Document_Item links through list_item_documents and
returns one FollowupDocuments (the followup and its links) per kept followup,
in ascending followup id. By default private and flag-less followups are
dropped and never queried; include_private=True keeps them, so a caller can
classify every link from followup.is_private. Link rows that do not name the
followup are dropped, a followup without an id raises, and a failed read
propagates rather than returning a partial list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… followup (0.6.4)

Bumps the version in pyproject.toml, the package and every skill, adds the
CHANGELOG entry, and describes list_item_documents,
list_ticket_followup_documents and NO_TIMELINE in the user guide.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d reflow the model list

list_ticket_followup_documents builds (id, followup) pairs with an explicit
None check, so mypy narrows the id instead of passing through Any. Its
docstring states one v1 request per kept followup. The user guide lists
GetDocumentItem and FollowupDocuments apart from the models with post /
patch / delete variants, the timeline skill points to the new method, and
a test pins that GlpiTimelinePosition(-1) still names INVALID.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.96%. Comparing base (a80fe01) to head (6ca37f8).
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #43      +/-   ##
==========================================
+ Coverage   97.92%   97.96%   +0.03%     
==========================================
  Files          90       91       +1     
  Lines        3476     3536      +60     
==========================================
+ Hits         3404     3464      +60     
  Misses         72       72              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@baraline
baraline merged commit e03d577 into main Oct 12, 2026
7 checks passed
@baraline
baraline deleted the feat/followup-documents branch October 12, 2026 13:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants