mtx-api-py 0.4.0__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.
- mtx_api/__init__.py +25 -0
- mtx_api/client/__init__.py +3 -0
- mtx_api/client/_auth_client.py +230 -0
- mtx_api/client/_base_client.py +50 -0
- mtx_api/client/_jurisdiction_client.py +74 -0
- mtx_api/client/_jurisdiction_elements_client.py +41 -0
- mtx_api/client/_location_client.py +61 -0
- mtx_api/client/_mtx_http_client.py +201 -0
- mtx_api/client/_request_client.py +374 -0
- mtx_api/client/_service_client.py +94 -0
- mtx_api/client/_typology_client.py +64 -0
- mtx_api/client/_user_client.py +135 -0
- mtx_api/client/mtx_client.py +51 -0
- mtx_api/models/__init__.py +0 -0
- mtx_api/models/additional_data.py +334 -0
- mtx_api/models/auth.py +84 -0
- mtx_api/models/base.py +26 -0
- mtx_api/models/common.py +103 -0
- mtx_api/models/errors.py +117 -0
- mtx_api/models/jurisdiction.py +101 -0
- mtx_api/models/medias.py +97 -0
- mtx_api/models/request.py +253 -0
- mtx_api/models/request_comment.py +53 -0
- mtx_api/models/request_media.py +32 -0
- mtx_api/models/service.py +207 -0
- mtx_api/models/typology.py +69 -0
- mtx_api/py.typed +0 -0
- mtx_api/settings.py +11 -0
- mtx_api_py-0.4.0.dist-info/METADATA +323 -0
- mtx_api_py-0.4.0.dist-info/RECORD +32 -0
- mtx_api_py-0.4.0.dist-info/WHEEL +4 -0
- mtx_api_py-0.4.0.dist-info/licenses/LICENSE.txt +21 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
|
|
5
|
+
from mtx_api.client._auth_client import AuthClient
|
|
6
|
+
from mtx_api.client._base_client import BaseClient
|
|
7
|
+
from mtx_api.client._jurisdiction_client import JurisdictionClient
|
|
8
|
+
from mtx_api.client._jurisdiction_elements_client import JurisdictionElementsClient
|
|
9
|
+
from mtx_api.client._location_client import LocationClient
|
|
10
|
+
from mtx_api.client._mtx_http_client import MtxHttpClient
|
|
11
|
+
from mtx_api.client._request_client import RequestClient
|
|
12
|
+
from mtx_api.client._service_client import ServiceClient
|
|
13
|
+
from mtx_api.client._typology_client import TypologyClient
|
|
14
|
+
from mtx_api.client._user_client import UserClient
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class MTXClient:
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
base_url: str | None = None,
|
|
21
|
+
client_id: str | None = None,
|
|
22
|
+
jwt_secret: str | None = None,
|
|
23
|
+
transport: httpx.AsyncBaseTransport | None = None,
|
|
24
|
+
) -> None:
|
|
25
|
+
self._http_client = MtxHttpClient(
|
|
26
|
+
base_url=base_url,
|
|
27
|
+
client_id=client_id,
|
|
28
|
+
jwt_secret=jwt_secret,
|
|
29
|
+
transport=transport,
|
|
30
|
+
)
|
|
31
|
+
self.base = BaseClient(self._http_client)
|
|
32
|
+
self.auth = AuthClient(self._http_client)
|
|
33
|
+
self.user = UserClient(self._http_client)
|
|
34
|
+
self.location = LocationClient(self._http_client)
|
|
35
|
+
self.services = ServiceClient(self._http_client)
|
|
36
|
+
self.typologies = TypologyClient(self._http_client)
|
|
37
|
+
self.jurisdictions = JurisdictionClient(self._http_client)
|
|
38
|
+
self.jurisdiction_elements = JurisdictionElementsClient(self._http_client)
|
|
39
|
+
self.requests = RequestClient(self._http_client)
|
|
40
|
+
|
|
41
|
+
async def __aenter__(self) -> MTXClient:
|
|
42
|
+
await self._http_client.__aenter__()
|
|
43
|
+
return self
|
|
44
|
+
|
|
45
|
+
async def __aexit__(
|
|
46
|
+
self,
|
|
47
|
+
exc_type: type[BaseException] | None,
|
|
48
|
+
exc: BaseException | None,
|
|
49
|
+
tb: object | None,
|
|
50
|
+
) -> None:
|
|
51
|
+
await self._http_client.__aexit__(exc_type, exc, tb)
|
|
File without changes
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
from abc import ABC
|
|
2
|
+
from collections.abc import Sequence
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from pydantic import AliasChoices, Field, RootModel, field_serializer
|
|
6
|
+
|
|
7
|
+
from mtx_api.models.base import DatetimeField, ImmutableBaseModel
|
|
8
|
+
from mtx_api.models.common import Location, Tag
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Question(ImmutableBaseModel):
|
|
12
|
+
"""
|
|
13
|
+
Represents a configurable question that can be asked when creating a request.
|
|
14
|
+
|
|
15
|
+
Questions are used to gather additional information from users during the request
|
|
16
|
+
creation process. They can have different types (label, text, number, etc.) and may include
|
|
17
|
+
predefined possible answers.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
type: str | None = Field(
|
|
21
|
+
default=None,
|
|
22
|
+
description="The type of question input (label, number, boolean, color, datetime, "
|
|
23
|
+
"position, singleValueList, multiValueList, url, signature, image, "
|
|
24
|
+
"imageGallery, audioClip or videoClip).",
|
|
25
|
+
)
|
|
26
|
+
active: bool | None = Field(
|
|
27
|
+
default=None,
|
|
28
|
+
description="Whether this question is currently active and should be used.",
|
|
29
|
+
)
|
|
30
|
+
code: str | None = Field(
|
|
31
|
+
default=None,
|
|
32
|
+
description="Unique code identifier for the question.",
|
|
33
|
+
)
|
|
34
|
+
help_text: str | None = Field(
|
|
35
|
+
default=None,
|
|
36
|
+
description="Additional help text or instructions given to the user.",
|
|
37
|
+
)
|
|
38
|
+
id: str | None = Field(
|
|
39
|
+
default=None,
|
|
40
|
+
description="Unique identifier for the question.",
|
|
41
|
+
)
|
|
42
|
+
question: str | None = Field(
|
|
43
|
+
default=None,
|
|
44
|
+
description="The question text given to the user.",
|
|
45
|
+
)
|
|
46
|
+
tags: list[Tag] | None = Field(
|
|
47
|
+
default=None,
|
|
48
|
+
description="Classification tags associated with this question.",
|
|
49
|
+
)
|
|
50
|
+
possible_answers: list["PossibleAnswer"] | None = Field(
|
|
51
|
+
default=None,
|
|
52
|
+
description=(
|
|
53
|
+
"List of predefined answer options for singleValueList or"
|
|
54
|
+
" multiValueList type questions."
|
|
55
|
+
),
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class ConfigurableQuestion(ImmutableBaseModel):
|
|
60
|
+
"""
|
|
61
|
+
Represents a question with its configuration settings.
|
|
62
|
+
|
|
63
|
+
This model extends a base question with additional metadata that controls
|
|
64
|
+
how and when the question is given in different contexts (forms, details...).
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
editable: bool | None = Field(
|
|
68
|
+
default=None,
|
|
69
|
+
description="Whether the answer to this question can be edited after initial submission.",
|
|
70
|
+
)
|
|
71
|
+
omit_in_detail: bool | None = Field(
|
|
72
|
+
default=None,
|
|
73
|
+
validation_alias=AliasChoices("omit_in_detail", "hidden_in_open010_detail"),
|
|
74
|
+
serialization_alias="hidden_in_open010_detail",
|
|
75
|
+
description=(
|
|
76
|
+
"Whether this question should be hidden when the request details. "
|
|
77
|
+
"When True, the question and its answer will not appear in the detail of a request."
|
|
78
|
+
),
|
|
79
|
+
)
|
|
80
|
+
omit_in_form: bool | None = Field(
|
|
81
|
+
default=None,
|
|
82
|
+
validation_alias=AliasChoices("omit_in_form", "hidden_in_open010_form"),
|
|
83
|
+
serialization_alias="hidden_in_open010_form",
|
|
84
|
+
description=(
|
|
85
|
+
"Whether this question should be hidden in the request. "
|
|
86
|
+
"When True, the question will not be given to users when creating a new request."
|
|
87
|
+
),
|
|
88
|
+
)
|
|
89
|
+
question: Question | None = Field(
|
|
90
|
+
default=None,
|
|
91
|
+
description="The underlying question definition with its content and options.",
|
|
92
|
+
)
|
|
93
|
+
required: bool | None = Field(
|
|
94
|
+
default=None,
|
|
95
|
+
description="Whether an answer to this question is mandatory for submission.",
|
|
96
|
+
)
|
|
97
|
+
default_value: str | None = Field(
|
|
98
|
+
default=None,
|
|
99
|
+
description="The default value pre-filled for this question.",
|
|
100
|
+
)
|
|
101
|
+
response_attribute: str | None = Field(
|
|
102
|
+
default=None,
|
|
103
|
+
description="The attribute name where the response should be stored.",
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class AdditionalData(ImmutableBaseModel):
|
|
108
|
+
"""
|
|
109
|
+
Represents a collection of additional data questions for a service.
|
|
110
|
+
|
|
111
|
+
This model defines a set of configurable questions that can be asked
|
|
112
|
+
when creating or updating requests, along with metadata about
|
|
113
|
+
required variables and platform integration.
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
required_variables: list[str] | None = Field(
|
|
117
|
+
default=None,
|
|
118
|
+
alias="requiredVariables",
|
|
119
|
+
description="List of variable names that must be provided to use this additional data set.",
|
|
120
|
+
)
|
|
121
|
+
configurable_questions: list[ConfigurableQuestion] | None = Field(
|
|
122
|
+
default=None,
|
|
123
|
+
description="List of questions with their configuration.",
|
|
124
|
+
)
|
|
125
|
+
id: str | None = Field(
|
|
126
|
+
default=None,
|
|
127
|
+
description="Unique identifier for the additional data set.",
|
|
128
|
+
)
|
|
129
|
+
name: str | None = Field(
|
|
130
|
+
default=None,
|
|
131
|
+
description="Name of the additional data set.",
|
|
132
|
+
)
|
|
133
|
+
description: str | None = Field(
|
|
134
|
+
default=None,
|
|
135
|
+
description="Description of what this additional data set is used for.",
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class PossibleAnswer(ImmutableBaseModel):
|
|
140
|
+
"""
|
|
141
|
+
Represents a possible answer option for a singleValueList-type or multiValueList-type question.
|
|
142
|
+
|
|
143
|
+
When a question has predefined answers, each option is represented by this model.
|
|
144
|
+
Selecting an answer may trigger additional questions based on the conditional logic.
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
value: str | None = Field(
|
|
148
|
+
default=None,
|
|
149
|
+
description="The value of the answer option.",
|
|
150
|
+
)
|
|
151
|
+
next_question_list: AdditionalData | None = Field(
|
|
152
|
+
default=None,
|
|
153
|
+
description="Additional questions if this answer is selected.",
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class AdditionalDataAnswer(ImmutableBaseModel):
|
|
158
|
+
"""
|
|
159
|
+
Represents an answer provided to an additional data question.
|
|
160
|
+
|
|
161
|
+
This model contains the user's response to a configurable question,
|
|
162
|
+
including the question details and the value provided.
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
type: str | None = Field(
|
|
166
|
+
default=None,
|
|
167
|
+
description=(
|
|
168
|
+
"The type of answer value (label, number, boolean, color, datetime, "
|
|
169
|
+
"position, singleValueList, multiValueList, url, signature, image, "
|
|
170
|
+
"imageGallery, audioClip or videoClip)."
|
|
171
|
+
),
|
|
172
|
+
)
|
|
173
|
+
value: Any | None = Field(
|
|
174
|
+
default=None,
|
|
175
|
+
description=(
|
|
176
|
+
"The answer value, which can be of various types depending on the question type."
|
|
177
|
+
),
|
|
178
|
+
)
|
|
179
|
+
question: Question | None = Field(
|
|
180
|
+
default=None,
|
|
181
|
+
description="The question that this answer corresponds to.",
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class AdditionalDataValue(ImmutableBaseModel, ABC):
|
|
186
|
+
"""
|
|
187
|
+
Base model for additional data values when creating or updating requests.
|
|
188
|
+
|
|
189
|
+
This abstract model provides the foundation for different types of additional
|
|
190
|
+
data values that can be submitted with requests.
|
|
191
|
+
"""
|
|
192
|
+
|
|
193
|
+
question_id: str = Field(
|
|
194
|
+
validation_alias=AliasChoices("question_id", "question"),
|
|
195
|
+
serialization_alias="question",
|
|
196
|
+
description="Unique identifier of the question this value answers.",
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class AdditionalDataSingleValue(AdditionalDataValue):
|
|
201
|
+
"""
|
|
202
|
+
Represents a single-value answer to an additional data question.
|
|
203
|
+
|
|
204
|
+
This model is used when submitting answers that accept a single text value.
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
value: str = Field(
|
|
208
|
+
description="The single text value answering the question.",
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class AdditionalDataMultivalue(AdditionalDataValue):
|
|
213
|
+
"""
|
|
214
|
+
Represents a multi-value answer to an additional data question.
|
|
215
|
+
|
|
216
|
+
This model is used when submitting answers that accept multiple values.
|
|
217
|
+
"""
|
|
218
|
+
|
|
219
|
+
value: Sequence[str] = Field(
|
|
220
|
+
description="List of selected values answering the question.",
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
class AdditionalDataDatetime(AdditionalDataValue):
|
|
225
|
+
"""
|
|
226
|
+
Represents a datetime answer to an additional data question.
|
|
227
|
+
|
|
228
|
+
This model is used when submitting date or datetime values as answers,
|
|
229
|
+
automatically serialized to ISO format with timezone.
|
|
230
|
+
"""
|
|
231
|
+
|
|
232
|
+
value: DatetimeField = Field(
|
|
233
|
+
description=(
|
|
234
|
+
"The datetime value answering the question, serialized in ISO format with timezone."
|
|
235
|
+
),
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class AdditionalDataLocation(AdditionalDataValue):
|
|
240
|
+
"""
|
|
241
|
+
Represents a geographic location answer to an additional data question.
|
|
242
|
+
|
|
243
|
+
This model is used when submitting location coordinates as answers.
|
|
244
|
+
The coordinates are stored separately but serialized as a nested object
|
|
245
|
+
in the value field.
|
|
246
|
+
"""
|
|
247
|
+
|
|
248
|
+
lat: float = Field(
|
|
249
|
+
exclude=True,
|
|
250
|
+
description="Latitude coordinate.",
|
|
251
|
+
)
|
|
252
|
+
lng: float = Field(
|
|
253
|
+
exclude=True,
|
|
254
|
+
description="Longitude coordinate.",
|
|
255
|
+
)
|
|
256
|
+
srs: str | None = Field(
|
|
257
|
+
default="3857",
|
|
258
|
+
exclude=True,
|
|
259
|
+
description="Spatial Reference System identifier, default is '3857'.",
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
def model_dump(self, *args: Any, **kwargs: Any) -> dict[str, Any]:
|
|
263
|
+
data = super().model_dump(*args, **kwargs)
|
|
264
|
+
data["value"] = {
|
|
265
|
+
"lat": self.lat,
|
|
266
|
+
"lng": self.lng,
|
|
267
|
+
"srs": self.srs,
|
|
268
|
+
}
|
|
269
|
+
return data
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
class AdditionalDataAudioClip(AdditionalDataValue):
|
|
273
|
+
"""
|
|
274
|
+
Represents an audio clip answer to an additional data question.
|
|
275
|
+
|
|
276
|
+
This model is used when submitting audio file references as answers.
|
|
277
|
+
"""
|
|
278
|
+
|
|
279
|
+
value: str = Field(
|
|
280
|
+
description="The audio clip URL to be submitted as the answer.",
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
@field_serializer("value")
|
|
284
|
+
def s(self, value: str) -> dict[str, dict[str, str]]:
|
|
285
|
+
return {"audio_clip": {"es": value}}
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
class AdditionalDataVideoClip(AdditionalDataValue):
|
|
289
|
+
"""
|
|
290
|
+
Represents a video clip answer to an additional data question.
|
|
291
|
+
|
|
292
|
+
This model is used when submitting video file references as answers.
|
|
293
|
+
"""
|
|
294
|
+
|
|
295
|
+
value: str = Field(
|
|
296
|
+
description="The video clip URL to be submitted as the answer.",
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
@field_serializer("value")
|
|
300
|
+
def s(self, value: str) -> dict[str, dict[str, str]]:
|
|
301
|
+
return {"video_clip": {"es": value}}
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
class LocationAdditionalData(ImmutableBaseModel):
|
|
305
|
+
"""
|
|
306
|
+
Represents location-specific additional data and questions.
|
|
307
|
+
|
|
308
|
+
This model contains additional data questions that are specific to a particular
|
|
309
|
+
location, including the formatted address and geographic coordinates.
|
|
310
|
+
"""
|
|
311
|
+
|
|
312
|
+
formatted_address: str | None = Field(
|
|
313
|
+
default=None,
|
|
314
|
+
description="The formatted address string of the location.",
|
|
315
|
+
)
|
|
316
|
+
data: list[AdditionalDataAnswer] | None = Field(
|
|
317
|
+
default=None,
|
|
318
|
+
description="List of additional data answers associated with this location.",
|
|
319
|
+
)
|
|
320
|
+
location: Location | None = Field(
|
|
321
|
+
default=None,
|
|
322
|
+
description="The geographic coordinates of the location.",
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
class LocationAdditionalDataList(RootModel[list[LocationAdditionalData]]):
|
|
327
|
+
"""
|
|
328
|
+
A collection of LocationAdditionalData objects.
|
|
329
|
+
|
|
330
|
+
This model represents a list of location-specific additional data returned
|
|
331
|
+
when querying location-based information for a jurisdiction element.
|
|
332
|
+
"""
|
|
333
|
+
|
|
334
|
+
pass
|
mtx_api/models/auth.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
3
|
+
from pydantic import AliasChoices, Field
|
|
4
|
+
|
|
5
|
+
from mtx_api.models.base import ImmutableBaseModel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Authentication(ImmutableBaseModel):
|
|
9
|
+
"""
|
|
10
|
+
Represents authentication credentials for a user session.
|
|
11
|
+
|
|
12
|
+
This model contains the tokens required to authenticate operations on the platform.
|
|
13
|
+
The access token is used for authorized operations, while the refresh token allows
|
|
14
|
+
obtaining a new access token when it expires.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
access_token: str = Field(
|
|
18
|
+
description="The bearer token used to authenticate operations on the platform.",
|
|
19
|
+
)
|
|
20
|
+
refresh_token: str = Field(
|
|
21
|
+
description="The token used to obtain a new access token when the current one expires.",
|
|
22
|
+
)
|
|
23
|
+
expires_in: int = Field(
|
|
24
|
+
description="The number of seconds until the access token expires.",
|
|
25
|
+
)
|
|
26
|
+
token_type: str = Field(
|
|
27
|
+
description="The type of token, typically 'bearer' for OAuth2 tokens.",
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
type Gender = Literal["male", "female", "other", "not_specified"]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class Profile(ImmutableBaseModel):
|
|
35
|
+
"""
|
|
36
|
+
Represents a user profile with personal information and account details.
|
|
37
|
+
|
|
38
|
+
This model contains all the personal and account information associated with
|
|
39
|
+
a user on the platform. It includes identification, contact information,
|
|
40
|
+
and demographic data.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
id: str | None = Field(
|
|
44
|
+
default=None,
|
|
45
|
+
description="Unique identifier for the user profile.",
|
|
46
|
+
)
|
|
47
|
+
email: str | None = Field(
|
|
48
|
+
default=None,
|
|
49
|
+
description="The user's email address used for contact and authentication.",
|
|
50
|
+
)
|
|
51
|
+
username: str | None = Field(
|
|
52
|
+
default=None,
|
|
53
|
+
description="The user's chosen username, typically their email address.",
|
|
54
|
+
)
|
|
55
|
+
first_name: str | None = Field(
|
|
56
|
+
default=None,
|
|
57
|
+
description="The user's first name or given name.",
|
|
58
|
+
)
|
|
59
|
+
last_name: str | None = Field(
|
|
60
|
+
default=None,
|
|
61
|
+
description="The user's last name or family name.",
|
|
62
|
+
)
|
|
63
|
+
twitter_nickname: str | None = Field(
|
|
64
|
+
default=None,
|
|
65
|
+
validation_alias=AliasChoices("twitter_nickname", "twitterNickname"),
|
|
66
|
+
serialization_alias="twitterNickname",
|
|
67
|
+
description="The user's Twitter handle or social media nickname visible to others.",
|
|
68
|
+
)
|
|
69
|
+
anonymous: bool | None = Field(
|
|
70
|
+
default=None,
|
|
71
|
+
description="Whether the user is logged in anonymously without a registered account.",
|
|
72
|
+
)
|
|
73
|
+
phone: str | None = Field(
|
|
74
|
+
default=None,
|
|
75
|
+
description="The user's primary phone number for contact purposes.",
|
|
76
|
+
)
|
|
77
|
+
gender: Gender | None = Field(
|
|
78
|
+
default=None,
|
|
79
|
+
description="The user's gender identification.",
|
|
80
|
+
)
|
|
81
|
+
birthday: str | None = Field(
|
|
82
|
+
default=None,
|
|
83
|
+
description="The user's date of birth in format YYYY-MM-DD.",
|
|
84
|
+
)
|
mtx_api/models/base.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from datetime import UTC, datetime
|
|
2
|
+
from typing import Annotated
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, PlainSerializer
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ImmutableBaseModel(BaseModel):
|
|
8
|
+
model_config = {
|
|
9
|
+
"frozen": True,
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class EmptyResponse(ImmutableBaseModel):
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class TextResponse(ImmutableBaseModel):
|
|
18
|
+
text: str
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
DatetimeField = Annotated[
|
|
22
|
+
datetime,
|
|
23
|
+
PlainSerializer(
|
|
24
|
+
lambda v: v.astimezone(UTC).isoformat() if v else None,
|
|
25
|
+
),
|
|
26
|
+
]
|
mtx_api/models/common.py
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pydantic import Field
|
|
4
|
+
|
|
5
|
+
from mtx_api.models.base import ImmutableBaseModel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Tag(ImmutableBaseModel):
|
|
9
|
+
"""
|
|
10
|
+
Represents a label or category tag for classification purposes.
|
|
11
|
+
|
|
12
|
+
Tags are used throughout the platform to categorize and filter various
|
|
13
|
+
entities such as questions, services, or other content items.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
name: str | None = Field(
|
|
17
|
+
default=None,
|
|
18
|
+
description="The name of the tag.",
|
|
19
|
+
)
|
|
20
|
+
id: str | None = Field(
|
|
21
|
+
default=None,
|
|
22
|
+
description="Unique identifier for the tag.",
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class User(ImmutableBaseModel):
|
|
27
|
+
"""
|
|
28
|
+
Represents a basic user reference with minimal information.
|
|
29
|
+
|
|
30
|
+
This simplified model is used when referencing a user in contexts where
|
|
31
|
+
only the identifier is needed, without full profile details.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
id: str | None = Field(
|
|
35
|
+
default=None,
|
|
36
|
+
description="Unique identifier for the user.",
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class Location(ImmutableBaseModel):
|
|
41
|
+
"""
|
|
42
|
+
Represents geographic coordinates for a location on Earth.
|
|
43
|
+
|
|
44
|
+
This model uses the standard GPS coordinates system
|
|
45
|
+
with latitude and longitude.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
lat: float | None = Field(
|
|
49
|
+
default=None,
|
|
50
|
+
description="Latitude coordinate.",
|
|
51
|
+
)
|
|
52
|
+
lng: float | None = Field(
|
|
53
|
+
default=None,
|
|
54
|
+
description="Longitude coordinate.",
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class LegalText(ImmutableBaseModel):
|
|
59
|
+
"""
|
|
60
|
+
Represents the legal documentation content required for platform usage.
|
|
61
|
+
|
|
62
|
+
This model encapsulates all legal text content that users must review and
|
|
63
|
+
accept to use the platform. Each field may contain plain text, formatted
|
|
64
|
+
text, or links to external legal documents.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
privacy_policy: str | None = Field(
|
|
68
|
+
default=None,
|
|
69
|
+
description=(
|
|
70
|
+
"The privacy policy content describing how user data is collected, "
|
|
71
|
+
"processed, and protected. May be plain text or a link to the full document."
|
|
72
|
+
),
|
|
73
|
+
)
|
|
74
|
+
terms_of_use: str | None = Field(
|
|
75
|
+
default=None,
|
|
76
|
+
description=(
|
|
77
|
+
"The terms of use content outlining the rules and conditions for using "
|
|
78
|
+
"the platform. May be plain text or a link to the full document."
|
|
79
|
+
),
|
|
80
|
+
)
|
|
81
|
+
cookies_policy: str | None = Field(
|
|
82
|
+
default=None,
|
|
83
|
+
description=(
|
|
84
|
+
"The cookies policy content explaining how cookies are used on the platform. "
|
|
85
|
+
"May be plain text or a link to the full document."
|
|
86
|
+
),
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class LegalTerms(ImmutableBaseModel):
|
|
91
|
+
"""
|
|
92
|
+
Container model for platform legal terms and conditions.
|
|
93
|
+
|
|
94
|
+
This model serves as a wrapper for all legal documentation that users must
|
|
95
|
+
accept before using the platform. It is typically retrieved when showing
|
|
96
|
+
legal information during registration or when terms have been updated.
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
legal_text: LegalText | None = Field(
|
|
100
|
+
default=None,
|
|
101
|
+
description="The complete legal documentation including privacy policy,"
|
|
102
|
+
" terms of use, and cookies policy.",
|
|
103
|
+
)
|