glpi-python-client 0.1.3__py3-none-any.whl → 0.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. glpi_python_client/__init__.py +111 -22
  2. glpi_python_client/auth/__init__.py +5 -3
  3. glpi_python_client/{clients/api_v1_session.py → auth/_v1_session.py} +47 -216
  4. glpi_python_client/auth/tests/test_v1_session.py +283 -0
  5. glpi_python_client/clients/__init__.py +7 -12
  6. glpi_python_client/clients/api/__init__.py +40 -0
  7. glpi_python_client/clients/api/administration/__init__.py +12 -0
  8. glpi_python_client/clients/api/administration/_entity.py +172 -0
  9. glpi_python_client/clients/api/administration/_user.py +176 -0
  10. glpi_python_client/clients/api/assistance/__init__.py +8 -0
  11. glpi_python_client/clients/api/assistance/_team.py +121 -0
  12. glpi_python_client/clients/api/assistance/_ticket.py +185 -0
  13. glpi_python_client/clients/api/assistance/timeline/__init__.py +23 -0
  14. glpi_python_client/clients/api/assistance/timeline/_document.py +221 -0
  15. glpi_python_client/clients/api/assistance/timeline/_followup.py +203 -0
  16. glpi_python_client/clients/api/assistance/timeline/_solution.py +200 -0
  17. glpi_python_client/clients/api/assistance/timeline/_task.py +193 -0
  18. glpi_python_client/clients/api/dropdowns/__init__.py +7 -0
  19. glpi_python_client/clients/api/dropdowns/_location.py +166 -0
  20. glpi_python_client/clients/api/management/__init__.py +7 -0
  21. glpi_python_client/clients/api/management/_document.py +286 -0
  22. glpi_python_client/clients/commons/__init__.py +9 -0
  23. glpi_python_client/clients/{v2/common/client_config.py → commons/_config.py} +43 -29
  24. glpi_python_client/clients/commons/_constants.py +50 -0
  25. glpi_python_client/clients/{v2/common/errors.py → commons/_errors.py} +7 -3
  26. glpi_python_client/clients/commons/_filters.py +94 -0
  27. glpi_python_client/clients/{v2/common/request_http.py → commons/_http.py} +88 -43
  28. glpi_python_client/clients/commons/_payloads.py +42 -0
  29. glpi_python_client/clients/commons/_transport.py +494 -0
  30. glpi_python_client/clients/commons/tests/__init__.py +5 -0
  31. glpi_python_client/clients/commons/tests/test_errors.py +41 -0
  32. glpi_python_client/clients/commons/tests/test_filters.py +49 -0
  33. glpi_python_client/clients/commons/tests/test_http.py +131 -0
  34. glpi_python_client/clients/commons/tests/test_payloads.py +64 -0
  35. glpi_python_client/clients/custom/__init__.py +15 -0
  36. glpi_python_client/clients/custom/_statistics.py +264 -0
  37. glpi_python_client/clients/custom/_ticket_context.py +66 -0
  38. glpi_python_client/clients/custom/tests/test_statistics.py +196 -0
  39. glpi_python_client/clients/glpi_client.py +262 -0
  40. glpi_python_client/clients/tests/__init__.py +1 -5
  41. glpi_python_client/clients/tests/test_api_coverage.py +707 -0
  42. glpi_python_client/clients/tests/test_glpi_client.py +266 -0
  43. glpi_python_client/clients/tests/test_smoke.py +259 -0
  44. glpi_python_client/models/__init__.py +129 -20
  45. glpi_python_client/models/_base.py +43 -4
  46. glpi_python_client/models/api_schema/__init__.py +16 -0
  47. glpi_python_client/models/api_schema/_common.py +67 -0
  48. glpi_python_client/models/api_schema/_content.py +74 -0
  49. glpi_python_client/models/api_schema/administration/__init__.py +30 -0
  50. glpi_python_client/models/api_schema/administration/_entity.py +55 -0
  51. glpi_python_client/models/api_schema/administration/_user.py +132 -0
  52. glpi_python_client/models/api_schema/administration/tests/__init__.py +1 -0
  53. glpi_python_client/models/api_schema/administration/tests/test_administration_schemas.py +114 -0
  54. glpi_python_client/models/api_schema/assistance/__init__.py +30 -0
  55. glpi_python_client/models/api_schema/assistance/_team.py +59 -0
  56. glpi_python_client/models/api_schema/assistance/_ticket.py +156 -0
  57. glpi_python_client/models/api_schema/assistance/tests/__init__.py +1 -0
  58. glpi_python_client/models/api_schema/assistance/tests/test_assistance_schemas.py +108 -0
  59. glpi_python_client/models/api_schema/assistance/tests/test_content_roundtrip.py +102 -0
  60. glpi_python_client/models/api_schema/assistance/timeline/__init__.py +49 -0
  61. glpi_python_client/models/api_schema/assistance/timeline/_document.py +60 -0
  62. glpi_python_client/models/api_schema/assistance/timeline/_followup.py +78 -0
  63. glpi_python_client/models/api_schema/assistance/timeline/_solution.py +76 -0
  64. glpi_python_client/models/api_schema/assistance/timeline/_task.py +97 -0
  65. glpi_python_client/models/api_schema/assistance/timeline/tests/__init__.py +1 -0
  66. glpi_python_client/models/api_schema/assistance/timeline/tests/test_timeline_schemas.py +147 -0
  67. glpi_python_client/models/api_schema/dropdowns/__init__.py +15 -0
  68. glpi_python_client/models/api_schema/dropdowns/_location.py +86 -0
  69. glpi_python_client/models/api_schema/dropdowns/tests/__init__.py +1 -0
  70. glpi_python_client/models/api_schema/dropdowns/tests/test_dropdowns_schemas.py +61 -0
  71. glpi_python_client/models/api_schema/enums.py +156 -0
  72. glpi_python_client/models/api_schema/management/__init__.py +15 -0
  73. glpi_python_client/models/api_schema/management/_document.py +67 -0
  74. glpi_python_client/models/api_schema/management/tests/__init__.py +1 -0
  75. glpi_python_client/models/api_schema/management/tests/test_management_schemas.py +50 -0
  76. glpi_python_client/models/custom_schema/__init__.py +13 -0
  77. glpi_python_client/models/custom_schema/_ticket_context.py +239 -0
  78. glpi_python_client/models/custom_schema/tests/__init__.py +1 -0
  79. glpi_python_client/models/custom_schema/tests/test_ticket_context.py +210 -0
  80. glpi_python_client/testing/__init__.py +0 -4
  81. glpi_python_client/testing/fixtures.py +6 -32
  82. glpi_python_client/testing/utils.py +1 -42
  83. {glpi_python_client-0.1.3.dist-info → glpi_python_client-0.2.1.dist-info}/METADATA +61 -34
  84. glpi_python_client-0.2.1.dist-info/RECORD +93 -0
  85. glpi_python_client/clients/api_v2_client.py +0 -317
  86. glpi_python_client/clients/async_api_v2_client.py +0 -236
  87. glpi_python_client/clients/tests/test_api_v1_session.py +0 -85
  88. glpi_python_client/clients/tests/test_api_v2_client.py +0 -349
  89. glpi_python_client/clients/tests/test_async_api_v2_client.py +0 -257
  90. glpi_python_client/clients/v2/__init__.py +0 -8
  91. glpi_python_client/clients/v2/async_/__init__.py +0 -12
  92. glpi_python_client/clients/v2/async_/api.py +0 -29
  93. glpi_python_client/clients/v2/async_/directory.py +0 -88
  94. glpi_python_client/clients/v2/async_/documents.py +0 -144
  95. glpi_python_client/clients/v2/async_/team.py +0 -125
  96. glpi_python_client/clients/v2/async_/tests/__init__.py +0 -5
  97. glpi_python_client/clients/v2/async_/tests/test_directory.py +0 -43
  98. glpi_python_client/clients/v2/async_/tests/test_documents.py +0 -41
  99. glpi_python_client/clients/v2/async_/tests/test_team.py +0 -44
  100. glpi_python_client/clients/v2/async_/tests/test_tickets.py +0 -174
  101. glpi_python_client/clients/v2/async_/tests/test_timeline.py +0 -126
  102. glpi_python_client/clients/v2/async_/tickets.py +0 -312
  103. glpi_python_client/clients/v2/async_/timeline.py +0 -312
  104. glpi_python_client/clients/v2/async_/transport.py +0 -251
  105. glpi_python_client/clients/v2/common/__init__.py +0 -6
  106. glpi_python_client/clients/v2/common/constants.py +0 -45
  107. glpi_python_client/clients/v2/common/filters.py +0 -30
  108. glpi_python_client/clients/v2/common/payloads.py +0 -57
  109. glpi_python_client/clients/v2/common/response_payloads.py +0 -76
  110. glpi_python_client/clients/v2/common/ticket_search.py +0 -113
  111. glpi_python_client/clients/v2/sync/__init__.py +0 -12
  112. glpi_python_client/clients/v2/sync/api.py +0 -29
  113. glpi_python_client/clients/v2/sync/directory.py +0 -90
  114. glpi_python_client/clients/v2/sync/documents.py +0 -144
  115. glpi_python_client/clients/v2/sync/team.py +0 -125
  116. glpi_python_client/clients/v2/sync/tests/__init__.py +0 -5
  117. glpi_python_client/clients/v2/sync/tests/test_directory.py +0 -57
  118. glpi_python_client/clients/v2/sync/tests/test_documents.py +0 -99
  119. glpi_python_client/clients/v2/sync/tests/test_team.py +0 -64
  120. glpi_python_client/clients/v2/sync/tests/test_tickets.py +0 -430
  121. glpi_python_client/clients/v2/sync/tests/test_timeline.py +0 -77
  122. glpi_python_client/clients/v2/sync/tests/test_transport.py +0 -89
  123. glpi_python_client/clients/v2/sync/tickets.py +0 -312
  124. glpi_python_client/clients/v2/sync/timeline.py +0 -308
  125. glpi_python_client/clients/v2/sync/transport.py +0 -246
  126. glpi_python_client/content/records/__init__.py +0 -84
  127. glpi_python_client/content/records/core/__init__.py +0 -6
  128. glpi_python_client/content/records/core/document_links.py +0 -100
  129. glpi_python_client/content/records/core/normalization.py +0 -53
  130. glpi_python_client/content/records/core/references.py +0 -98
  131. glpi_python_client/content/records/core/scalars.py +0 -83
  132. glpi_python_client/content/records/parsers/__init__.py +0 -6
  133. glpi_python_client/content/records/parsers/directory.py +0 -62
  134. glpi_python_client/content/records/parsers/documents.py +0 -49
  135. glpi_python_client/content/records/parsers/team.py +0 -58
  136. glpi_python_client/content/records/parsers/tests/__init__.py +0 -5
  137. glpi_python_client/content/records/parsers/tests/test_tickets.py +0 -35
  138. glpi_python_client/content/records/parsers/tests/test_timeline.py +0 -20
  139. glpi_python_client/content/records/parsers/tickets.py +0 -96
  140. glpi_python_client/content/records/parsers/timeline.py +0 -119
  141. glpi_python_client/models/_payload.py +0 -79
  142. glpi_python_client/models/_shared.py +0 -37
  143. glpi_python_client/models/glpi/__init__.py +0 -27
  144. glpi_python_client/models/glpi/_document.py +0 -59
  145. glpi_python_client/models/glpi/_followup.py +0 -77
  146. glpi_python_client/models/glpi/_location.py +0 -53
  147. glpi_python_client/models/glpi/_solution.py +0 -57
  148. glpi_python_client/models/glpi/_task.py +0 -41
  149. glpi_python_client/models/glpi/_team_member.py +0 -33
  150. glpi_python_client/models/glpi/_ticket.py +0 -303
  151. glpi_python_client/models/glpi/_user.py +0 -92
  152. glpi_python_client/models/glpi/tests/__init__.py +0 -5
  153. glpi_python_client/models/glpi/tests/test__document.py +0 -12
  154. glpi_python_client/models/glpi/tests/test__followup.py +0 -31
  155. glpi_python_client/models/glpi/tests/test__location.py +0 -12
  156. glpi_python_client/models/glpi/tests/test__solution.py +0 -11
  157. glpi_python_client/models/glpi/tests/test__ticket.py +0 -59
  158. glpi_python_client/models/glpi/tests/test__user.py +0 -29
  159. glpi_python_client-0.1.3.dist-info/RECORD +0 -98
  160. {glpi_python_client-0.1.3.dist-info → glpi_python_client-0.2.1.dist-info}/WHEEL +0 -0
  161. {glpi_python_client-0.1.3.dist-info → glpi_python_client-0.2.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,36 +1,125 @@
1
1
  """Public import surface for the GLPI Python client package.
2
2
 
3
- This module re-exports the supported high-level clients and typed GLPI models
4
- so applications can import them from a single stable package root.
3
+ The package re-exports the asynchronous :class:`GlpiClient` and the
4
+ ``api_schema`` and ``custom_schema`` Pydantic models so downstream users
5
+ can import them from a single stable package root.
5
6
  """
6
7
 
7
8
  from __future__ import annotations
8
9
 
9
- from glpi_python_client.clients import AsyncGlpiClient, GlpiClient, GLPIV1Session
10
+ from glpi_python_client.clients import GlpiClient
10
11
  from glpi_python_client.models import (
11
- GlpiDocument,
12
- GlpiFollowup,
13
- GlpiLocation,
14
- GlpiSolution,
15
- GlpiTask,
16
- GlpiTeamMember,
17
- GlpiTicket,
18
- GlpiUser,
12
+ DeleteDocument,
13
+ DeleteEntity,
14
+ DeleteFollowup,
15
+ DeleteLocation,
16
+ DeleteSolution,
17
+ DeleteTeamMember,
18
+ DeleteTicket,
19
+ DeleteTicketTask,
20
+ DeleteTimelineDocument,
21
+ DeleteUser,
22
+ GetDocument,
23
+ GetEntity,
24
+ GetFollowup,
25
+ GetLocation,
26
+ GetSolution,
27
+ GetTeamMember,
28
+ GetTicket,
29
+ GetTicketTask,
30
+ GetTimelineDocument,
31
+ GetUser,
32
+ GlpiEnum,
33
+ GlpiGlobalValidation,
34
+ GlpiPriority,
35
+ GlpiSolutionStatus,
36
+ GlpiTaskState,
37
+ GlpiTicketContext,
38
+ GlpiTicketStatus,
39
+ GlpiTicketType,
40
+ GlpiTimelinePosition,
41
+ GlpiUserAuthType,
42
+ IdNameCompletenameRef,
43
+ IdNameRef,
44
+ IdRef,
45
+ PatchDocument,
46
+ PatchEntity,
47
+ PatchFollowup,
48
+ PatchLocation,
49
+ PatchSolution,
50
+ PatchTeamMember,
51
+ PatchTicket,
52
+ PatchTicketTask,
53
+ PatchTimelineDocument,
54
+ PatchUser,
55
+ PostDocument,
56
+ PostEntity,
57
+ PostFollowup,
58
+ PostLocation,
59
+ PostSolution,
60
+ PostTeamMember,
61
+ PostTicket,
62
+ PostTicketTask,
63
+ PostTimelineDocument,
64
+ PostUser,
19
65
  )
20
66
 
21
- __version__ = "0.1.3"
67
+ __version__ = "0.2.1"
22
68
 
23
69
  __all__ = [
24
- "AsyncGlpiClient",
25
- "GLPIV1Session",
70
+ "DeleteDocument",
71
+ "DeleteEntity",
72
+ "DeleteFollowup",
73
+ "DeleteLocation",
74
+ "DeleteSolution",
75
+ "DeleteTeamMember",
76
+ "DeleteTicket",
77
+ "DeleteTicketTask",
78
+ "DeleteTimelineDocument",
79
+ "DeleteUser",
80
+ "GetDocument",
81
+ "GetEntity",
82
+ "GetFollowup",
83
+ "GetLocation",
84
+ "GetSolution",
85
+ "GetTeamMember",
86
+ "GetTicket",
87
+ "GetTicketTask",
88
+ "GetTimelineDocument",
89
+ "GetUser",
26
90
  "GlpiClient",
27
- "GlpiDocument",
28
- "GlpiFollowup",
29
- "GlpiLocation",
30
- "GlpiSolution",
31
- "GlpiTask",
32
- "GlpiTeamMember",
33
- "GlpiTicket",
34
- "GlpiUser",
91
+ "GlpiEnum",
92
+ "GlpiGlobalValidation",
93
+ "GlpiPriority",
94
+ "GlpiSolutionStatus",
95
+ "GlpiTaskState",
96
+ "GlpiTicketContext",
97
+ "GlpiTicketStatus",
98
+ "GlpiTicketType",
99
+ "GlpiTimelinePosition",
100
+ "GlpiUserAuthType",
101
+ "IdNameCompletenameRef",
102
+ "IdNameRef",
103
+ "IdRef",
104
+ "PatchDocument",
105
+ "PatchEntity",
106
+ "PatchFollowup",
107
+ "PatchLocation",
108
+ "PatchSolution",
109
+ "PatchTeamMember",
110
+ "PatchTicket",
111
+ "PatchTicketTask",
112
+ "PatchTimelineDocument",
113
+ "PatchUser",
114
+ "PostDocument",
115
+ "PostEntity",
116
+ "PostFollowup",
117
+ "PostLocation",
118
+ "PostSolution",
119
+ "PostTeamMember",
120
+ "PostTicket",
121
+ "PostTicketTask",
122
+ "PostTimelineDocument",
123
+ "PostUser",
35
124
  "__version__",
36
125
  ]
@@ -1,11 +1,13 @@
1
1
  """Public authentication exports for the GLPI client package.
2
2
 
3
- The authentication package stays small on purpose and currently exposes the
4
- token manager used by the synchronous and asynchronous high-level clients.
3
+ The authentication package owns the OAuth2 token manager used by the
4
+ asynchronous ``GlpiClient`` and the legacy v1 session wrapper used solely by
5
+ the management document upload mixin.
5
6
  """
6
7
 
7
8
  from __future__ import annotations
8
9
 
10
+ from glpi_python_client.auth._v1_session import GLPIV1Session
9
11
  from glpi_python_client.auth.auth import GLPITokenManager
10
12
 
11
- __all__ = ["GLPITokenManager"]
13
+ __all__ = ["GLPITokenManager", "GLPIV1Session"]
@@ -1,8 +1,10 @@
1
- """Legacy GLPI v1 session management and document operations.
1
+ """GLPI v1 REST session used exclusively for document uploads.
2
2
 
3
- The high-level package still relies on selected v1 endpoints for document
4
- upload and linking workflows, so this module owns the authenticated v1 HTTP
5
- session and the retry logic around it.
3
+ The high-level async ``GlpiClient`` only relies on the legacy v1 API for the
4
+ ``POST /Document`` multipart upload endpoint. The session wrapper below owns
5
+ the authenticated v1 lifecycle (init, refresh, kill) and exposes a single
6
+ ``upload_document`` operation that the management mixin calls through
7
+ ``asyncio.to_thread`` at the blocking HTTP boundary.
6
8
  """
7
9
 
8
10
  from __future__ import annotations
@@ -22,20 +24,11 @@ _AUTH_FAILURE_STATUS_CODES = frozenset({401, 403})
22
24
 
23
25
 
24
26
  class GLPIV1Session:
25
- """Session manager for the GLPI v1 REST API.
26
-
27
- Parameters
28
- ----------
29
- base_url : str
30
- The v1 API base URL.
31
- user_token : str
32
- The ``user_token`` credential for v1 authentication.
33
- app_token : str
34
- The ``App-Token`` value.
35
- verify_ssl : bool, optional
36
- Whether to verify SSL certificates.
37
- session_refresh_interval_seconds : int, optional
38
- Maximum age of a v1 session token before it is renewed.
27
+ """Authenticated GLPI v1 REST session limited to document upload.
28
+
29
+ The session takes care of token initialisation, periodic refresh, retry on
30
+ auth failure, and best-effort cleanup. Only the upload endpoint is exposed
31
+ because the rest of the high-level client uses the v2 API exclusively.
39
32
  """
40
33
 
41
34
  def __init__(
@@ -68,17 +61,10 @@ class GLPIV1Session:
68
61
 
69
62
  @retry(stop=stop_after_attempt(3), wait=wait_fixed(3))
70
63
  def _init_session(self) -> None:
71
- """Call ``GET /initSession`` to obtain a session token.
72
-
73
- Returns
74
- -------
75
- None
76
- Stores the session token.
64
+ """Acquire one fresh GLPI v1 session token via ``GET /initSession``.
77
65
 
78
- Raises
79
- ------
80
- ValueError
81
- If the server does not return a valid session token.
66
+ The call replaces any existing session state and stores the
67
+ authentication timestamp used by the refresh-interval check.
82
68
  """
83
69
 
84
70
  headers: dict[str, str] = {
@@ -109,12 +95,10 @@ class GLPIV1Session:
109
95
  logger.info("GLPI v1 session initialised.")
110
96
 
111
97
  def _ensure_session(self) -> None:
112
- """Lazily initialise or renew the v1 session if needed.
98
+ """Lazily initialise or renew the v1 session when the token is stale.
113
99
 
114
- Returns
115
- -------
116
- None
117
- Ensures the session token exists.
100
+ The helper is called by every authenticated request before any header
101
+ construction so callers never have to manage the lifecycle directly.
118
102
  """
119
103
 
120
104
  if self._session_token is None:
@@ -125,13 +109,10 @@ class GLPIV1Session:
125
109
  self._renew_session()
126
110
 
127
111
  def _is_session_stale(self) -> bool:
128
- """Return whether the current v1 session should be renewed.
112
+ """Return whether the current v1 session token must be renewed.
129
113
 
130
- Returns
131
- -------
132
- bool
133
- ``True`` when the session age is beyond the configured refresh
134
- interval.
114
+ Stale tokens are determined by the configured refresh interval relative
115
+ to the timestamp the current token was acquired.
135
116
  """
136
117
 
137
118
  if self._session_started_at is None:
@@ -141,12 +122,10 @@ class GLPIV1Session:
141
122
  )
142
123
 
143
124
  def _session_headers(self) -> dict[str, str]:
144
- """Return headers for the current v1 session token.
125
+ """Return the GLPI v1 headers carrying the current session token.
145
126
 
146
- Returns
147
- -------
148
- dict[str, str]
149
- Headers including the current session token.
127
+ The helper assumes ``_ensure_session`` has already been called so the
128
+ session token state is valid.
150
129
  """
151
130
 
152
131
  headers: dict[str, str] = {
@@ -158,12 +137,10 @@ class GLPIV1Session:
158
137
  return headers
159
138
 
160
139
  def _renew_session(self) -> None:
161
- """Close the current v1 session token and initialise a new one.
140
+ """Drop the current GLPI v1 session token and acquire a new one.
162
141
 
163
- Returns
164
- -------
165
- None
166
- Mutates the stored session token.
142
+ The previous token is best-effort killed so the GLPI server can release
143
+ the associated session state immediately.
167
144
  """
168
145
 
169
146
  old_token = self._session_token
@@ -181,12 +158,10 @@ class GLPIV1Session:
181
158
  self._init_session()
182
159
 
183
160
  def _headers(self) -> dict[str, str]:
184
- """Return headers for an authenticated v1 request.
161
+ """Return ready-to-use authenticated GLPI v1 request headers.
185
162
 
186
- Returns
187
- -------
188
- dict[str, str]
189
- Headers including the session token.
163
+ The helper is the single header entry-point used by all authenticated
164
+ v1 calls so token lifecycle handling stays centralised.
190
165
  """
191
166
 
192
167
  self._ensure_session()
@@ -200,23 +175,10 @@ class GLPIV1Session:
200
175
  headers: dict[str, str] | None = None,
201
176
  **kwargs: object,
202
177
  ) -> requests.Response:
203
- """Execute one v1 request and retry once after auth rejection.
204
-
205
- Parameters
206
- ----------
207
- method : str
208
- HTTP method.
209
- url : str
210
- Absolute request URL.
211
- headers : dict[str, str] | None, optional
212
- Additional request headers.
213
- **kwargs : object
214
- Additional ``requests`` keyword arguments.
215
-
216
- Returns
217
- -------
218
- requests.Response
219
- Raw response from GLPI.
178
+ """Send one authenticated GLPI v1 request with one auth-failure retry.
179
+
180
+ When the GLPI server rejects the current token, the helper renews the
181
+ session and retries the request once before returning the response.
220
182
  """
221
183
 
222
184
  request_headers = {**self._headers(), **(headers or {})}
@@ -239,63 +201,11 @@ class GLPIV1Session:
239
201
  request_method(url, headers=request_headers, **kwargs),
240
202
  )
241
203
 
242
- @retry(stop=stop_after_attempt(3), wait=wait_fixed(3))
243
- def get_sub_items(
244
- self,
245
- itemtype: str,
246
- item_id: str | int,
247
- sub_itemtype: str,
248
- ) -> list[dict[str, object]]:
249
- """Fetch legacy GLPI sub-items for one parent item.
250
-
251
- Parameters
252
- ----------
253
- itemtype : str
254
- Parent GLPI itemtype.
255
- item_id : str | int
256
- Parent item identifier.
257
- sub_itemtype : str
258
- Child itemtype to fetch.
259
-
260
- Returns
261
- -------
262
- list[dict[str, object]]
263
- Raw sub-item payloads.
264
-
265
- Raises
266
- ------
267
- ValueError
268
- If the request fails or returns an unexpected payload shape.
269
- """
270
-
271
- response = self._authenticated_request(
272
- "GET",
273
- f"{self._base_url}/{itemtype}/{item_id}/{sub_itemtype}",
274
- timeout=30,
275
- )
276
- if response.status_code not in (200, 206):
277
- raise ValueError(
278
- "GLPI v1 sub-item fetch failed: "
279
- f"{response.status_code} {response.text[:300]}"
280
- )
281
-
282
- payload = response.json()
283
- if isinstance(payload, list):
284
- return [item for item in payload if isinstance(item, dict)]
285
- if isinstance(payload, dict):
286
- return [payload]
287
- raise ValueError(
288
- "GLPI v1 sub-item fetch returned unexpected payload: "
289
- f"{type(payload).__name__}"
290
- )
291
-
292
204
  def close(self) -> None:
293
- """Kill the v1 session and release resources.
205
+ """Kill the v1 session token and release the underlying HTTP session.
294
206
 
295
- Returns
296
- -------
297
- None
298
- Best-effort cleanup.
207
+ Cleanup is best-effort: any failure during ``killSession`` is logged
208
+ and the local session state is still cleared.
299
209
  """
300
210
 
301
211
  try:
@@ -324,32 +234,11 @@ class GLPIV1Session:
324
234
  ticket_id: int | None = None,
325
235
  entity_id: int | None = None,
326
236
  ) -> dict[str, object]:
327
- """Upload a document via ``POST /Document``.
328
-
329
- Parameters
330
- ----------
331
- filename : str
332
- File name.
333
- content : bytes
334
- Raw file bytes.
335
- mime_type : str
336
- MIME type.
337
- document_name : str | None, optional
338
- GLPI display name.
339
- ticket_id : int | None, optional
340
- GLPI ticket ID used to link the document during creation.
341
- entity_id : int | None, optional
342
- GLPI entity ID assigned to the created document.
343
-
344
- Returns
345
- -------
346
- dict[str, object]
347
- GLPI response payload.
348
-
349
- Raises
350
- ------
351
- ValueError
352
- If upload fails.
237
+ """Upload one binary document via ``POST /Document``.
238
+
239
+ The legacy v1 endpoint uses a multipart upload manifest so the GLPI
240
+ server can create the document, link it to the optional parent ticket,
241
+ and assign it to the provided entity in a single round-trip.
353
242
  """
354
243
 
355
244
  manifest_input: dict[str, object] = {
@@ -386,75 +275,17 @@ class GLPIV1Session:
386
275
  logger.info("GLPI v1 document uploaded: id=%s", payload.get("id"))
387
276
  return cast(dict[str, object], payload)
388
277
 
389
- @retry(stop=stop_after_attempt(3), wait=wait_fixed(3))
390
- def link_document_to_ticket(
391
- self, document_id: int, ticket_id: int
392
- ) -> dict[str, object]:
393
- """Link an existing document to a ticket.
394
-
395
- Parameters
396
- ----------
397
- document_id : int
398
- GLPI document ID.
399
- ticket_id : int
400
- GLPI ticket ID.
401
-
402
- Returns
403
- -------
404
- dict[str, object]
405
- GLPI response payload.
406
-
407
- Raises
408
- ------
409
- ValueError
410
- If the link creation fails.
411
- """
412
-
413
- payload = json.dumps(
414
- {
415
- "input": {
416
- "documents_id": document_id,
417
- "itemtype": "Ticket",
418
- "items_id": ticket_id,
419
- }
420
- }
421
- )
422
- response = self._authenticated_request(
423
- "POST",
424
- f"{self._base_url}/Document_Item",
425
- headers={"Content-Type": "application/json"},
426
- data=payload,
427
- timeout=30,
428
- )
429
- if response.status_code not in (200, 201):
430
- raise ValueError(
431
- "GLPI v1 Document_Item link failed: "
432
- f"{response.status_code} {response.text[:300]}"
433
- )
434
- result = response.json()
435
- if not isinstance(result, dict):
436
- raise ValueError(
437
- "GLPI v1 Document_Item link returned unexpected payload: "
438
- f"{type(result).__name__}"
439
- )
440
- logger.info("GLPI v1 document %d linked to ticket %d", document_id, ticket_id)
441
- return cast(dict[str, object], result)
442
-
443
278
 
444
279
  def _is_auth_failure_response(response: requests.Response) -> bool:
445
- """Return whether one GLPI v1 response means the session is invalid.
446
-
447
- Parameters
448
- ----------
449
- response : requests.Response
450
- Raw GLPI response.
280
+ """Return whether one GLPI v1 response means the session token is invalid.
451
281
 
452
- Returns
453
- -------
454
- bool
455
- ``True`` when the response indicates an expired or rejected v1 session.
282
+ Both HTTP-level rejection and the ``ERROR_SESSION_TOKEN_INVALID`` payload
283
+ marker emitted by the GLPI v1 API are considered auth failures.
456
284
  """
457
285
 
458
286
  if response.status_code in _AUTH_FAILURE_STATUS_CODES:
459
287
  return True
460
288
  return "ERROR_SESSION_TOKEN_INVALID" in str(response.text or "")
289
+
290
+
291
+ __all__ = ["GLPIV1Session"]