Skip to content

Commit 59eccff

Browse files
committed
add ticket option object
1 parent 2b22fc0 commit 59eccff

7 files changed

Lines changed: 414 additions & 42 deletions

File tree

‎docs/api_reference.rst‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ Aggregated Models
2323
:undoc-members:
2424
:show-inheritance:
2525

26+
.. autoclass:: TicketMarkdownOptions
27+
:members:
28+
:undoc-members:
29+
:show-inheritance:
30+
2631
Common Reference Models
2732
-----------------------
2833

‎docs/user_guide.rst‎

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,74 @@ Example output::
697697
## Documents
698698
- diagnostic.txt
699699

700+
Customising the Markdown output
701+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
702+
703+
Pass a :class:`TicketMarkdownOptions` instance to select which sections
704+
and metadata fields appear in the output. All flags default to ``True``
705+
so the default call reproduces the full transcript shown above.
706+
707+
+-------------------------------+----------------------------------------------+
708+
| Flag | Controls |
709+
+===============================+==============================================+
710+
| ``include_description`` | ``## Description`` section |
711+
+-------------------------------+----------------------------------------------+
712+
| ``include_followups`` | Followup entries in ``## Timeline`` |
713+
+-------------------------------+----------------------------------------------+
714+
| ``include_tasks`` | Task entries in ``## Timeline`` |
715+
+-------------------------------+----------------------------------------------+
716+
| ``include_solutions`` | Solution entries in ``## Timeline`` |
717+
+-------------------------------+----------------------------------------------+
718+
| ``include_documents`` | ``## Documents`` section |
719+
+-------------------------------+----------------------------------------------+
720+
| ``show_status`` | ``Status`` in the ticket subtitle |
721+
+-------------------------------+----------------------------------------------+
722+
| ``show_requester`` | ``Requester`` in the ticket subtitle |
723+
+-------------------------------+----------------------------------------------+
724+
| ``show_editor`` | ``Last edited by`` in the ticket subtitle |
725+
+-------------------------------+----------------------------------------------+
726+
| ``show_dates`` | All ticket-level date fields |
727+
+-------------------------------+----------------------------------------------+
728+
| ``show_event_author`` | ``Created by`` in event subtitles |
729+
+-------------------------------+----------------------------------------------+
730+
| ``show_event_editor`` | ``Last edited by`` in event subtitles |
731+
+-------------------------------+----------------------------------------------+
732+
| ``show_event_dates`` | All date fields in event subtitles |
733+
+-------------------------------+----------------------------------------------+
734+
| ``show_event_state`` | ``State`` in event subtitles |
735+
+-------------------------------+----------------------------------------------+
736+
| ``show_event_status`` | ``Status`` in event subtitles |
737+
+-------------------------------+----------------------------------------------+
738+
| ``show_duration`` | ``Duration`` in task subtitles |
739+
+-------------------------------+----------------------------------------------+
740+
| ``show_technician`` | ``Technician`` / ``Technician group`` |
741+
+-------------------------------+----------------------------------------------+
742+
| ``show_approver`` | ``Approver`` in solution subtitles |
743+
+-------------------------------+----------------------------------------------+
744+
745+
Example — description and timeline only, no metadata fields:
746+
747+
.. code-block:: python
748+
749+
from glpi_python_client import TicketMarkdownOptions
750+
751+
opts = TicketMarkdownOptions(
752+
include_documents=False,
753+
show_status=False,
754+
show_requester=False,
755+
show_editor=False,
756+
show_dates=False,
757+
show_event_author=False,
758+
show_event_editor=False,
759+
show_event_dates=False,
760+
show_event_state=False,
761+
show_event_status=False,
762+
show_duration=False,
763+
show_technician=False,
764+
show_approver=False,
765+
)
766+
print(bundle.to_markdown(opts))
767+
700768
Reporting helpers
701769
~~~~~~~~~~~~~~~~~
702770

‎glpi_python_client/__init__.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
PostTicketTask,
6363
PostTimelineDocument,
6464
PostUser,
65+
TicketMarkdownOptions,
6566
)
6667

6768
__version__ = "0.2.1"
@@ -121,5 +122,6 @@
121122
"PostTicketTask",
122123
"PostTimelineDocument",
123124
"PostUser",
125+
"TicketMarkdownOptions",
124126
"__version__",
125127
]

‎glpi_python_client/models/__init__.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,10 @@
8080
PatchDocument,
8181
PostDocument,
8282
)
83-
from glpi_python_client.models.custom_schema import GlpiTicketContext
83+
from glpi_python_client.models.custom_schema import (
84+
GlpiTicketContext,
85+
TicketMarkdownOptions,
86+
)
8487

8588
__all__ = [
8689
"DeleteDocument",
@@ -136,4 +139,5 @@
136139
"PostTicketTask",
137140
"PostTimelineDocument",
138141
"PostUser",
142+
"TicketMarkdownOptions",
139143
]

‎glpi_python_client/models/custom_schema/__init__.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from glpi_python_client.models.custom_schema._ticket_context import (
1010
GlpiTicketContext,
11+
TicketMarkdownOptions,
1112
)
1213

13-
__all__ = ["GlpiTicketContext"]
14+
__all__ = ["GlpiTicketContext", "TicketMarkdownOptions"]

‎glpi_python_client/models/custom_schema/_ticket_context.py‎

Lines changed: 143 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from __future__ import annotations
1010

11+
from dataclasses import dataclass, field
1112
from datetime import datetime
1213
from enum import Enum
1314
from typing import Any
@@ -90,6 +91,73 @@ def _subtitle_line(*parts: tuple[str, object | None]) -> str | None:
9091
return f"> {' | '.join(rendered_parts)}"
9192

9293

94+
@dataclass
95+
class TicketMarkdownOptions:
96+
"""Options controlling which sections and fields appear in the Markdown export.
97+
98+
All flags default to ``True`` so that a bare ``to_markdown()`` call
99+
reproduces the original full output.
100+
101+
Parameters
102+
----------
103+
include_description : bool
104+
Emit the ``## Description`` section with the ticket body.
105+
include_followups : bool
106+
Include followup entries in the ``## Timeline`` section.
107+
include_tasks : bool
108+
Include task entries in the ``## Timeline`` section.
109+
include_solutions : bool
110+
Include solution entries in the ``## Timeline`` section.
111+
include_documents : bool
112+
Append the ``## Documents`` section with linked file references.
113+
show_status : bool
114+
Emit the ``Status`` field in the ticket subtitle line.
115+
show_requester : bool
116+
Emit the ``Requester`` field in the ticket subtitle line.
117+
show_editor : bool
118+
Emit the ``Last edited by`` field in the ticket subtitle line.
119+
show_dates : bool
120+
Emit all ticket-level date fields (created, updated, resolved,
121+
closed) in the ticket subtitle line.
122+
show_event_author : bool
123+
Emit the ``Created by`` field in timeline-entry subtitle lines.
124+
show_event_editor : bool
125+
Emit the ``Last edited by`` field in timeline-entry subtitle lines.
126+
show_event_dates : bool
127+
Emit date fields (created, updated, scheduled, planned start/end,
128+
approved) in timeline-entry subtitle lines.
129+
show_event_state : bool
130+
Emit the ``State`` field in timeline-entry subtitle lines.
131+
show_event_status : bool
132+
Emit the ``Status`` field in timeline-entry subtitle lines.
133+
show_duration : bool
134+
Emit the ``Duration`` field in task subtitle lines.
135+
show_technician : bool
136+
Emit the ``Technician`` and ``Technician group`` fields in task
137+
subtitle lines.
138+
show_approver : bool
139+
Emit the ``Approver`` field in solution subtitle lines.
140+
"""
141+
142+
include_description: bool = field(default=True)
143+
include_followups: bool = field(default=True)
144+
include_tasks: bool = field(default=True)
145+
include_solutions: bool = field(default=True)
146+
include_documents: bool = field(default=True)
147+
show_status: bool = field(default=True)
148+
show_requester: bool = field(default=True)
149+
show_editor: bool = field(default=True)
150+
show_dates: bool = field(default=True)
151+
show_event_author: bool = field(default=True)
152+
show_event_editor: bool = field(default=True)
153+
show_event_dates: bool = field(default=True)
154+
show_event_state: bool = field(default=True)
155+
show_event_status: bool = field(default=True)
156+
show_duration: bool = field(default=True)
157+
show_technician: bool = field(default=True)
158+
show_approver: bool = field(default=True)
159+
160+
93161
def _event_sort_key(event: Any) -> datetime:
94162
"""Compute the sort key used to order timeline events for rendering.
95163
@@ -126,7 +194,10 @@ class GlpiTicketContext(GlpiModel):
126194
solutions: list[GetSolution] = Field(default_factory=list)
127195
documents: list[GetTimelineDocument] = Field(default_factory=list)
128196

129-
def to_markdown(self) -> str:
197+
def to_markdown(
198+
self,
199+
options: TicketMarkdownOptions | None = None,
200+
) -> str:
130201
"""Render the ticket and its timeline as one Markdown transcript.
131202
132203
The rendering starts with the ticket title, then a compact
@@ -140,6 +211,14 @@ def to_markdown(self) -> str:
140211
dedicated section because the document-link payload does not
141212
expose the same authoring metadata.
142213
214+
Parameters
215+
----------
216+
options : TicketMarkdownOptions, optional
217+
Controls which sections and metadata fields are included in
218+
the output. When *None* (the default) a fresh
219+
:class:`TicketMarkdownOptions` is used, which enables all
220+
sections and fields.
221+
143222
Returns
144223
-------
145224
str
@@ -148,6 +227,8 @@ def to_markdown(self) -> str:
148227
never ends with trailing whitespace.
149228
"""
150229

230+
opts = options if options is not None else TicketMarkdownOptions()
231+
151232
lines: list[str] = []
152233
ticket = self.ticket
153234
ticket_label = ticket.name or "(unnamed ticket)"
@@ -156,28 +237,37 @@ def to_markdown(self) -> str:
156237
else:
157238
lines.append(f"# Ticket \u2014 {ticket_label}")
158239

159-
ticket_subtitle = _subtitle_line(
160-
("Status", ticket.status),
161-
("Requester", ticket.user_recipient),
162-
("Last edited by", ticket.user_editor),
163-
("Created at", ticket.date_creation),
164-
("Updated at", ticket.date_mod),
165-
("Resolved at", ticket.date_solve),
166-
("Closed at", ticket.date_close),
167-
)
240+
ticket_subtitle_parts: list[tuple[str, object | None]] = []
241+
if opts.show_status:
242+
ticket_subtitle_parts.append(("Status", ticket.status))
243+
if opts.show_requester:
244+
ticket_subtitle_parts.append(("Requester", ticket.user_recipient))
245+
if opts.show_editor:
246+
ticket_subtitle_parts.append(("Last edited by", ticket.user_editor))
247+
if opts.show_dates:
248+
ticket_subtitle_parts += [
249+
("Created at", ticket.date_creation),
250+
("Updated at", ticket.date_mod),
251+
("Resolved at", ticket.date_solve),
252+
("Closed at", ticket.date_close),
253+
]
254+
ticket_subtitle = _subtitle_line(*ticket_subtitle_parts)
168255
if ticket_subtitle is not None:
169256
lines.append(ticket_subtitle)
170257

171-
if ticket.content:
258+
if opts.include_description and ticket.content:
172259
lines.append("")
173260
lines.append("## Description")
174261
lines.append("")
175262
lines.append(ticket.content)
176263

177264
events: list[tuple[str, Any]] = []
178-
events.extend(("Followup", item) for item in self.followups)
179-
events.extend(("Task", item) for item in self.tasks)
180-
events.extend(("Solution", item) for item in self.solutions)
265+
if opts.include_followups:
266+
events.extend(("Followup", item) for item in self.followups)
267+
if opts.include_tasks:
268+
events.extend(("Task", item) for item in self.tasks)
269+
if opts.include_solutions:
270+
events.extend(("Solution", item) for item in self.solutions)
181271
events.sort(key=lambda pair: _event_sort_key(pair[1]))
182272

183273
if events:
@@ -192,29 +282,43 @@ def to_markdown(self) -> str:
192282
lines.append("")
193283
lines.append(heading)
194284

195-
event_subtitle = _subtitle_line(
196-
("Created by", getattr(event, "user", None)),
197-
("Last edited by", getattr(event, "user_editor", None)),
198-
("Created at", getattr(event, "date_creation", None)),
199-
("Updated at", getattr(event, "date_mod", None)),
200-
("Scheduled for", getattr(event, "date", None)),
201-
("Planned start", getattr(event, "planned_begin", None)),
202-
("Planned end", getattr(event, "planned_end", None)),
203-
("Approved at", getattr(event, "date_approval", None)),
204-
("State", getattr(event, "state", None)),
205-
("Status", getattr(event, "status", None)),
206-
(
207-
"Duration",
208-
(
209-
f"{duration}s"
210-
if (duration := getattr(event, "duration", None)) is not None
211-
else None
212-
),
213-
),
214-
("Technician", getattr(event, "user_tech", None)),
215-
("Technician group", getattr(event, "group_tech", None)),
216-
("Approver", getattr(event, "approver", None)),
217-
)
285+
event_subtitle_parts: list[tuple[str, object | None]] = []
286+
if opts.show_event_author:
287+
event_subtitle_parts.append(
288+
("Created by", getattr(event, "user", None))
289+
)
290+
if opts.show_event_editor:
291+
event_subtitle_parts.append(
292+
("Last edited by", getattr(event, "user_editor", None))
293+
)
294+
if opts.show_event_dates:
295+
event_subtitle_parts += [
296+
("Created at", getattr(event, "date_creation", None)),
297+
("Updated at", getattr(event, "date_mod", None)),
298+
("Scheduled for", getattr(event, "date", None)),
299+
("Planned start", getattr(event, "planned_begin", None)),
300+
("Planned end", getattr(event, "planned_end", None)),
301+
("Approved at", getattr(event, "date_approval", None)),
302+
]
303+
if opts.show_event_state:
304+
event_subtitle_parts.append(("State", getattr(event, "state", None)))
305+
if opts.show_event_status:
306+
event_subtitle_parts.append(("Status", getattr(event, "status", None)))
307+
if opts.show_duration:
308+
duration = getattr(event, "duration", None)
309+
event_subtitle_parts.append(
310+
("Duration", f"{duration}s" if duration is not None else None)
311+
)
312+
if opts.show_technician:
313+
event_subtitle_parts += [
314+
("Technician", getattr(event, "user_tech", None)),
315+
("Technician group", getattr(event, "group_tech", None)),
316+
]
317+
if opts.show_approver:
318+
event_subtitle_parts.append(
319+
("Approver", getattr(event, "approver", None))
320+
)
321+
event_subtitle = _subtitle_line(*event_subtitle_parts)
218322
if event_subtitle is not None:
219323
lines.append(event_subtitle)
220324

@@ -223,7 +327,7 @@ def to_markdown(self) -> str:
223327
lines.append("")
224328
lines.append(content)
225329

226-
if self.documents:
330+
if opts.include_documents and self.documents:
227331
lines.append("")
228332
lines.append("## Documents")
229333
for document in self.documents:
@@ -236,4 +340,4 @@ def to_markdown(self) -> str:
236340
return "\n".join(lines).rstrip()
237341

238342

239-
__all__ = ["GlpiTicketContext"]
343+
__all__ = ["GlpiTicketContext", "TicketMarkdownOptions"]

0 commit comments

Comments
 (0)