Tapi 0.1.2__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.
- tapi/__init__.py +2 -0
- tapi/api/__init__.py +46 -0
- tapi/api/action/__init__.py +7 -0
- tapi/api/action/actions.py +106 -0
- tapi/api/action/events.py +33 -0
- tapi/api/action/logs.py +34 -0
- tapi/api/admin/__init__.py +12 -0
- tapi/api/admin/action_egress_control_rules.py +87 -0
- tapi/api/admin/admin.py +43 -0
- tapi/api/admin/ip_access_control.py +76 -0
- tapi/api/admin/job.py +42 -0
- tapi/api/admin/scim.py +27 -0
- tapi/api/admin/template.py +86 -0
- tapi/api/admin/user.py +104 -0
- tapi/api/audit_log/__init__.py +5 -0
- tapi/api/audit_log/audit_logs.py +24 -0
- tapi/api/case/__init__.py +20 -0
- tapi/api/case/actions.py +90 -0
- tapi/api/case/activities.py +35 -0
- tapi/api/case/assignees.py +21 -0
- tapi/api/case/blocks.py +112 -0
- tapi/api/case/cases.py +132 -0
- tapi/api/case/comments.py +102 -0
- tapi/api/case/fields.py +69 -0
- tapi/api/case/files.py +77 -0
- tapi/api/case/inputs.py +64 -0
- tapi/api/case/linked_cases.py +57 -0
- tapi/api/case/metadata.py +65 -0
- tapi/api/case/notes.py +78 -0
- tapi/api/case/records.py +54 -0
- tapi/api/case/subscribers.py +56 -0
- tapi/api/credential/__init__.py +1 -0
- tapi/api/credential/credentials.py +240 -0
- tapi/api/event/__init__.py +1 -0
- tapi/api/event/events.py +44 -0
- tapi/api/folder/__init__.py +1 -0
- tapi/api/folder/folders.py +71 -0
- tapi/api/note/__init__.py +5 -0
- tapi/api/note/notes.py +76 -0
- tapi/api/record/__init__.py +7 -0
- tapi/api/record/artifacts.py +17 -0
- tapi/api/record/records.py +85 -0
- tapi/api/record/types.py +52 -0
- tapi/api/report/__init__.py +5 -0
- tapi/api/report/reporting.py +41 -0
- tapi/api/resource/__init__.py +1 -0
- tapi/api/resource/resources.py +152 -0
- tapi/api/story/__init__.py +10 -0
- tapi/api/story/change_requests.py +64 -0
- tapi/api/story/drafts.py +45 -0
- tapi/api/story/groups.py +38 -0
- tapi/api/story/runs.py +43 -0
- tapi/api/story/stories.py +162 -0
- tapi/api/story/versions.py +65 -0
- tapi/api/team/__init__.py +4 -0
- tapi/api/team/members.py +62 -0
- tapi/api/team/teams.py +60 -0
- tapi/api/tenant.py +68 -0
- tapi/client/__init__.py +1 -0
- tapi/client/client.py +55 -0
- tapi/utils/helpers.py +9 -0
- tapi/utils/http.py +8 -0
- tapi/utils/testing_decorators.py +5 -0
- tapi/utils/types.py +300 -0
- tapi-0.1.2.dist-info/METADATA +2487 -0
- tapi-0.1.2.dist-info/RECORD +69 -0
- tapi-0.1.2.dist-info/WHEEL +5 -0
- tapi-0.1.2.dist-info/licenses/LICENSE +674 -0
- tapi-0.1.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
from tapi.client import Client
|
|
2
|
+
from typing import Literal, Optional, List, Dict, Any
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class CredentialsAPI(Client):
|
|
6
|
+
def __init__(self, domain: str, apiKey: str):
|
|
7
|
+
super().__init__(domain, apiKey)
|
|
8
|
+
self.base_endpoint = "user_credentials"
|
|
9
|
+
|
|
10
|
+
def create_aws(
|
|
11
|
+
self,
|
|
12
|
+
name: str,
|
|
13
|
+
team_id: int,
|
|
14
|
+
aws_authentication_type: Literal["KEY", "ROLE", "INSTANCE_PROFILE"],
|
|
15
|
+
aws_access_key: str,
|
|
16
|
+
aws_secret_key: str,
|
|
17
|
+
aws_assumed_role_arn: Optional[str] = None,
|
|
18
|
+
folder_id: Optional[int] = None,
|
|
19
|
+
read_access: Literal["TEAM", "GLOBAL", "SPECIFIC_TEAMS"] = "TEAM",
|
|
20
|
+
shared_team_slugs: Optional[List[str]] = None,
|
|
21
|
+
description: Optional[str] = None,
|
|
22
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
23
|
+
allowed_hosts: Optional[List[str]] = None,
|
|
24
|
+
live_credential_id: Optional[int] = None
|
|
25
|
+
):
|
|
26
|
+
data = {key: value for key, value in locals().items() if value is not None and key != "self"}
|
|
27
|
+
data.update({"mode": "AWS"})
|
|
28
|
+
|
|
29
|
+
return self._http_request(
|
|
30
|
+
"POST",
|
|
31
|
+
self.base_endpoint,
|
|
32
|
+
json = data
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
def create_http_request(
|
|
36
|
+
self,
|
|
37
|
+
name: str,
|
|
38
|
+
team_id: int,
|
|
39
|
+
http_request_options: Dict[str, Any],
|
|
40
|
+
http_request_location_of_token: str,
|
|
41
|
+
http_request_secret: Optional[str] = None,
|
|
42
|
+
http_request_ttl: Optional[int] = None,
|
|
43
|
+
content_type: Optional[str] = None,
|
|
44
|
+
folder_id: Optional[int] = None,
|
|
45
|
+
read_access: Literal["TEAM", "GLOBAL", "SPECIFIC_TEAMS"] = "TEAM",
|
|
46
|
+
shared_team_slugs: Optional[List[str]] = None,
|
|
47
|
+
description: Optional[str] = None,
|
|
48
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
49
|
+
allowed_hosts: Optional[List[str]] = None,
|
|
50
|
+
live_credential_id: Optional[int] = None
|
|
51
|
+
):
|
|
52
|
+
data = {key: value for key, value in locals().items() if value is not None and key != "self"}
|
|
53
|
+
data.update({"mode": "HTTP_REQUEST_AGENT"})
|
|
54
|
+
|
|
55
|
+
return self._http_request(
|
|
56
|
+
"POST",
|
|
57
|
+
self.base_endpoint,
|
|
58
|
+
json = data
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
def create_jwt(
|
|
62
|
+
self,
|
|
63
|
+
name: str,
|
|
64
|
+
team_id: int,
|
|
65
|
+
jwt_algorithm: str,
|
|
66
|
+
jwt_payload: Dict[str, str],
|
|
67
|
+
jwt_auto_generate_time_claims: bool,
|
|
68
|
+
jwt_private_key: str,
|
|
69
|
+
folder_id: Optional[int] = None,
|
|
70
|
+
read_access: Literal["TEAM", "GLOBAL", "SPECIFIC_TEAMS"] = "TEAM",
|
|
71
|
+
shared_team_slugs: Optional[List[str]] = None,
|
|
72
|
+
description: Optional[str] = None,
|
|
73
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
74
|
+
allowed_hosts: Optional[List[str]] = None,
|
|
75
|
+
live_credential_id: Optional[int] = None
|
|
76
|
+
):
|
|
77
|
+
data = {key: value for key, value in locals().items() if value is not None and key != "self"}
|
|
78
|
+
data.update({"mode": "JWT"})
|
|
79
|
+
|
|
80
|
+
return self._http_request(
|
|
81
|
+
"POST",
|
|
82
|
+
self.base_endpoint,
|
|
83
|
+
json = data
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def create_mtls(
|
|
88
|
+
self,
|
|
89
|
+
name: str,
|
|
90
|
+
team_id: int,
|
|
91
|
+
mtls_client_certificate: str,
|
|
92
|
+
mtls_client_private_key: str,
|
|
93
|
+
mtls_root_certificate: str,
|
|
94
|
+
folder_id: Optional[int] = None,
|
|
95
|
+
read_access: Literal["TEAM", "GLOBAL", "SPECIFIC_TEAMS"] = "TEAM",
|
|
96
|
+
shared_team_slugs: Optional[List[str]] = None,
|
|
97
|
+
description: Optional[str] = None,
|
|
98
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
99
|
+
allowed_hosts: Optional[List[str]] = None,
|
|
100
|
+
live_credential_id: Optional[int] = None
|
|
101
|
+
):
|
|
102
|
+
data = {key: value for key, value in locals().items() if value is not None and key != "self"}
|
|
103
|
+
data.update({"mode": "MTLS"})
|
|
104
|
+
|
|
105
|
+
return self._http_request(
|
|
106
|
+
"POST",
|
|
107
|
+
self.base_endpoint,
|
|
108
|
+
json = data
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
def create_multi_request(
|
|
112
|
+
self,
|
|
113
|
+
name: str,
|
|
114
|
+
team_id: int,
|
|
115
|
+
http_request_location_of_token: str,
|
|
116
|
+
credential_requests: List[Dict[str, Any]],
|
|
117
|
+
http_request_ttl: Optional[int] = None,
|
|
118
|
+
content_type: Optional[str] = None,
|
|
119
|
+
folder_id: Optional[int] = None,
|
|
120
|
+
read_access: Literal["TEAM", "GLOBAL", "SPECIFIC_TEAMS"] = "TEAM",
|
|
121
|
+
shared_team_slugs: Optional[List[str]] = None,
|
|
122
|
+
description: Optional[str] = None,
|
|
123
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
124
|
+
allowed_hosts: Optional[List[str]] = None,
|
|
125
|
+
live_credential_id: Optional[int] = None
|
|
126
|
+
):
|
|
127
|
+
data = {key: value for key, value in locals().items() if value is not None and key != "self"}
|
|
128
|
+
data.update({"mode": "MULTI_REQUEST"})
|
|
129
|
+
|
|
130
|
+
return self._http_request(
|
|
131
|
+
"POST",
|
|
132
|
+
self.base_endpoint,
|
|
133
|
+
json = data
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
def create_oauth(
|
|
137
|
+
self,
|
|
138
|
+
name: str,
|
|
139
|
+
team_id: int,
|
|
140
|
+
oauth_url: str,
|
|
141
|
+
oauth_token_url: str,
|
|
142
|
+
oauth_client_id: str,
|
|
143
|
+
oauth_client_secret: str,
|
|
144
|
+
oauth_scope: str,
|
|
145
|
+
oauth_grant_type: Literal["client_credentials", "authorization_code"],
|
|
146
|
+
oauthPkceCodeChallengeMethod: Optional[Literal["S256", "plain"]] = None,
|
|
147
|
+
folder_id: Optional[int] = None,
|
|
148
|
+
read_access: Literal["TEAM", "GLOBAL", "SPECIFIC_TEAMS"] = "TEAM",
|
|
149
|
+
shared_team_slugs: Optional[List[str]] = None,
|
|
150
|
+
description: Optional[str] = None,
|
|
151
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
152
|
+
allowed_hosts: Optional[List[str]] = None,
|
|
153
|
+
live_credential_id: Optional[int] = None
|
|
154
|
+
):
|
|
155
|
+
data = {key: value for key, value in locals().items() if value is not None and key != "self"}
|
|
156
|
+
data.update({"mode": "OAUTH"})
|
|
157
|
+
|
|
158
|
+
return self._http_request(
|
|
159
|
+
"POST",
|
|
160
|
+
self.base_endpoint,
|
|
161
|
+
json = data
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
def create_text(
|
|
165
|
+
self,
|
|
166
|
+
name: str,
|
|
167
|
+
team_id: int,
|
|
168
|
+
value: str,
|
|
169
|
+
folder_id: Optional[int] = None,
|
|
170
|
+
read_access: Literal["TEAM", "GLOBAL", "SPECIFIC_TEAMS"] = "TEAM",
|
|
171
|
+
shared_team_slugs: Optional[List[str]] = None,
|
|
172
|
+
description: Optional[str] = None,
|
|
173
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
174
|
+
allowed_hosts: Optional[List[str]] = None,
|
|
175
|
+
live_credential_id: Optional[int] = None
|
|
176
|
+
):
|
|
177
|
+
data = {key: value for key, value in locals().items() if value is not None and key != "self"}
|
|
178
|
+
data.update({"mode": "TEXT"})
|
|
179
|
+
|
|
180
|
+
return self._http_request(
|
|
181
|
+
"POST",
|
|
182
|
+
self.base_endpoint,
|
|
183
|
+
json = data
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
def update(
|
|
187
|
+
self,
|
|
188
|
+
mode: Literal["TEXT", "JWT", "OAUTH", "AWS", "MTLS", "HTTP_REQUEST_AGENT", "MULTI_REQUEST"],
|
|
189
|
+
credential_id: int,
|
|
190
|
+
name: Optional[str] = None,
|
|
191
|
+
folder_id: Optional[int] = None,
|
|
192
|
+
read_access: Literal["TEAM", "GLOBAL", "SPECIFIC_TEAMS"] = None,
|
|
193
|
+
shared_team_slugs: Optional[List[str]] = None,
|
|
194
|
+
description: Optional[str] = None,
|
|
195
|
+
metadata: Optional[Dict[str, str]] = None,
|
|
196
|
+
allowed_hosts: Optional[List[str]] = None,
|
|
197
|
+
test_credential_enabled: Optional[bool] = None,
|
|
198
|
+
is_test: Optional[bool] = None,
|
|
199
|
+
**options
|
|
200
|
+
):
|
|
201
|
+
data = {key: value for key, value in locals().items() if value is not None and key not in ("self", "credential_id", "options")}
|
|
202
|
+
data = {**data, **locals()["options"]}
|
|
203
|
+
|
|
204
|
+
return self._http_request(
|
|
205
|
+
"PUT",
|
|
206
|
+
f"{self.base_endpoint}/{credential_id}",
|
|
207
|
+
json = data
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
def get(
|
|
211
|
+
self,
|
|
212
|
+
credential_id: int
|
|
213
|
+
):
|
|
214
|
+
return self._http_request(
|
|
215
|
+
"GET",
|
|
216
|
+
f"{self.base_endpoint}/{credential_id}"
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
def list(
|
|
220
|
+
self,
|
|
221
|
+
folder_id: Optional[int] = None,
|
|
222
|
+
team_id: Optional[int] = None,
|
|
223
|
+
per_page: int = 10,
|
|
224
|
+
page: int = 1
|
|
225
|
+
):
|
|
226
|
+
return self._http_request(
|
|
227
|
+
"GET",
|
|
228
|
+
self.base_endpoint,
|
|
229
|
+
params={key: value for key, value in locals().items() if value is not None and key != "self"}
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
def delete(
|
|
233
|
+
self,
|
|
234
|
+
credential_id: int
|
|
235
|
+
):
|
|
236
|
+
return self._http_request(
|
|
237
|
+
"DELETE",
|
|
238
|
+
f"{self.base_endpoint}/{credential_id}"
|
|
239
|
+
)
|
|
240
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .events import EventsAPI
|
tapi/api/event/events.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from tapi.client import Client
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class EventsAPI(Client):
|
|
6
|
+
def __init__(self, domain: str, apiKey: str):
|
|
7
|
+
super().__init__(domain, apiKey)
|
|
8
|
+
self.base_endpoint = "events"
|
|
9
|
+
|
|
10
|
+
def get(
|
|
11
|
+
self,
|
|
12
|
+
event_id: int
|
|
13
|
+
):
|
|
14
|
+
return self._http_request(
|
|
15
|
+
"GET",
|
|
16
|
+
f"{self.base_endpoint}/{event_id}"
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
def list(
|
|
20
|
+
self,
|
|
21
|
+
since_id: Optional[int] = None,
|
|
22
|
+
until_id: Optional[int] = None,
|
|
23
|
+
since: Optional[str] = None,
|
|
24
|
+
until: Optional[str] = None,
|
|
25
|
+
team_id: Optional[int] = None,
|
|
26
|
+
story_id: Optional[int] = None,
|
|
27
|
+
include_groups: Optional[bool] = None,
|
|
28
|
+
per_page: int = 10,
|
|
29
|
+
page: int = 1,
|
|
30
|
+
):
|
|
31
|
+
return self._http_request(
|
|
32
|
+
"GET",
|
|
33
|
+
self.base_endpoint,
|
|
34
|
+
params = {key: value for key, value in locals().items() if value is not None and key != "self"}
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
def re_emit(
|
|
38
|
+
self,
|
|
39
|
+
event_id: int
|
|
40
|
+
):
|
|
41
|
+
return self._http_request(
|
|
42
|
+
"POST",
|
|
43
|
+
f"{self.base_endpoint}/{event_id}/reemit"
|
|
44
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .folders import FoldersAPI
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
from tapi.client import Client
|
|
2
|
+
from typing import Optional, Literal
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class FoldersAPI(Client):
|
|
6
|
+
def __init__(self, domain: str, apiKey: str):
|
|
7
|
+
super().__init__(domain, apiKey)
|
|
8
|
+
self.base_endpoint = "folders"
|
|
9
|
+
|
|
10
|
+
def create(
|
|
11
|
+
self,
|
|
12
|
+
name: str,
|
|
13
|
+
content_type: Literal["CREDENTIAL", "RESOURCE", "STORY"],
|
|
14
|
+
team_id: int
|
|
15
|
+
):
|
|
16
|
+
return self._http_request(
|
|
17
|
+
"POST",
|
|
18
|
+
self.base_endpoint,
|
|
19
|
+
json = {
|
|
20
|
+
"name": name,
|
|
21
|
+
"content_type": content_type,
|
|
22
|
+
"team_id": team_id
|
|
23
|
+
}
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
def get(
|
|
27
|
+
self,
|
|
28
|
+
folder_id: int
|
|
29
|
+
):
|
|
30
|
+
return self._http_request(
|
|
31
|
+
"GET",
|
|
32
|
+
f"{self.base_endpoint}/{folder_id}"
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
def update(
|
|
36
|
+
self,
|
|
37
|
+
folder_id: int,
|
|
38
|
+
name: str
|
|
39
|
+
):
|
|
40
|
+
return self._http_request(
|
|
41
|
+
"PUT",
|
|
42
|
+
f"{self.base_endpoint}/{folder_id}",
|
|
43
|
+
json = {"name": name}
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
def list(
|
|
47
|
+
self,
|
|
48
|
+
team_id: Optional[int] = None,
|
|
49
|
+
content_type: Literal["CREDENTIAL", "RESOURCE", "STORY"] = "STORY",
|
|
50
|
+
per_page: int = 10,
|
|
51
|
+
page: int = 1
|
|
52
|
+
):
|
|
53
|
+
return self._http_request(
|
|
54
|
+
"GET",
|
|
55
|
+
self.base_endpoint,
|
|
56
|
+
params = {
|
|
57
|
+
"team_id": team_id,
|
|
58
|
+
"content_type": content_type,
|
|
59
|
+
"per_page": per_page,
|
|
60
|
+
"page": page
|
|
61
|
+
}
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
def delete(
|
|
65
|
+
self,
|
|
66
|
+
folder_id: int
|
|
67
|
+
):
|
|
68
|
+
return self._http_request(
|
|
69
|
+
"DELETE",
|
|
70
|
+
f"{self.base_endpoint}/{folder_id}"
|
|
71
|
+
)
|
tapi/api/note/notes.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from tapi.client import Client
|
|
2
|
+
from tapi.utils.types import StoryMode
|
|
3
|
+
from typing import Optional, Dict, Union
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class NotesAPI(Client):
|
|
7
|
+
def __init__(self, domain: str, apiKey: str):
|
|
8
|
+
super().__init__(domain, apiKey)
|
|
9
|
+
self.base_endpoint = "notes"
|
|
10
|
+
|
|
11
|
+
def create(
|
|
12
|
+
self,
|
|
13
|
+
content: str,
|
|
14
|
+
story_id: Optional[int] = None,
|
|
15
|
+
group_id: Optional[int] = None,
|
|
16
|
+
position: Optional[Dict[str, int]] = None,
|
|
17
|
+
draft_id: Optional[int] = None
|
|
18
|
+
):
|
|
19
|
+
if not (story_id or group_id):
|
|
20
|
+
raise ValueError("Story ID or Group ID must be specified.")
|
|
21
|
+
|
|
22
|
+
if story_id and group_id:
|
|
23
|
+
raise ValueError("Story ID or Group ID must be specified but not both.")
|
|
24
|
+
|
|
25
|
+
return self._http_request(
|
|
26
|
+
"POST",
|
|
27
|
+
self.base_endpoint,
|
|
28
|
+
json = {key: value for key, value in locals().items() if value is not None and key != "self"}
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
def get(
|
|
32
|
+
self,
|
|
33
|
+
note_id: int
|
|
34
|
+
):
|
|
35
|
+
return self._http_request(
|
|
36
|
+
"GET",
|
|
37
|
+
f"{self.base_endpoint}/{note_id}"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def update(
|
|
41
|
+
self,
|
|
42
|
+
note_id: int,
|
|
43
|
+
content: Optional[str] = None,
|
|
44
|
+
position: Optional[Dict[str, int]] = None
|
|
45
|
+
):
|
|
46
|
+
return self._http_request(
|
|
47
|
+
"PUT",
|
|
48
|
+
f"{self.base_endpoint}/{note_id}",
|
|
49
|
+
json = {key: value for key, value in locals().items()
|
|
50
|
+
if value is not None and key not in ("self", "note_id")}
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
def list(
|
|
54
|
+
self,
|
|
55
|
+
story_id: Optional[int] = None,
|
|
56
|
+
mode: Optional[Union[StoryMode, str]] = None,
|
|
57
|
+
team_id: Optional[int] = None,
|
|
58
|
+
group_id: Optional[int] = None,
|
|
59
|
+
draft_id: Optional[int] = None,
|
|
60
|
+
per_page: int = 10,
|
|
61
|
+
page: int = 1
|
|
62
|
+
):
|
|
63
|
+
return self._http_request(
|
|
64
|
+
"GET",
|
|
65
|
+
self.base_endpoint,
|
|
66
|
+
json = {key: value for key, value in locals().items() if value is not None and key != "self"}
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def delete(
|
|
70
|
+
self,
|
|
71
|
+
note_id: int
|
|
72
|
+
):
|
|
73
|
+
return self._http_request(
|
|
74
|
+
"DELETE",
|
|
75
|
+
f"{self.base_endpoint}/{note_id}"
|
|
76
|
+
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from tapi.client import Client
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class RecordArtifactsAPI(Client):
|
|
5
|
+
def __init__(self, domain: str, apiKey: str):
|
|
6
|
+
super().__init__(domain, apiKey)
|
|
7
|
+
self.base_endpoint = "records"
|
|
8
|
+
|
|
9
|
+
def get(
|
|
10
|
+
self,
|
|
11
|
+
record_id: int,
|
|
12
|
+
artifact_id: int
|
|
13
|
+
):
|
|
14
|
+
return self._http_request(
|
|
15
|
+
"GET",
|
|
16
|
+
f"{self.base_endpoint}/{record_id}/artifacts/{artifact_id}"
|
|
17
|
+
)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from tapi.client import Client
|
|
2
|
+
from .types import RecordTypesAPI
|
|
3
|
+
from .artifacts import RecordArtifactsAPI
|
|
4
|
+
from tapi.utils.types import RecordFieldValue, RecordFilter
|
|
5
|
+
from typing import Optional, Dict, List, Union, Any, Literal
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class RecordsAPI(Client):
|
|
9
|
+
def __init__(self, domain: str, apiKey: str):
|
|
10
|
+
super().__init__(domain, apiKey)
|
|
11
|
+
self.base_endpoint = "records"
|
|
12
|
+
self.types = RecordTypesAPI(domain, apiKey)
|
|
13
|
+
self.artifacts = RecordArtifactsAPI(domain, apiKey)
|
|
14
|
+
|
|
15
|
+
def create(
|
|
16
|
+
self,
|
|
17
|
+
record_type_id: int,
|
|
18
|
+
field_values: List[Union[RecordFieldValue, Dict[str, Any]]],
|
|
19
|
+
case_ids: Optional[List[Union[str, int]]] = None,
|
|
20
|
+
test_mode: bool = False
|
|
21
|
+
):
|
|
22
|
+
return self._http_request(
|
|
23
|
+
"POST",
|
|
24
|
+
self.base_endpoint,
|
|
25
|
+
json = {key: value for key, value in locals().items() if value is not None and key != "self"}
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
def get(
|
|
29
|
+
self,
|
|
30
|
+
record_id: int
|
|
31
|
+
):
|
|
32
|
+
return self._http_request(
|
|
33
|
+
"GET",
|
|
34
|
+
f"{self.base_endpoint}/{record_id}"
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
def list(
|
|
38
|
+
self,
|
|
39
|
+
record_type_id: Optional[int] = None,
|
|
40
|
+
record_field_ids: Optional[int] = None,
|
|
41
|
+
range_start: Optional[Union[str, int]] = None,
|
|
42
|
+
range_end: Optional[Union[str, int]] = None,
|
|
43
|
+
story_ids: Optional[List[Union[str, int]]] = None,
|
|
44
|
+
order_direction: Literal["ASC", "DESC"] = "DESC",
|
|
45
|
+
order_field_id: Optional[int] = None,
|
|
46
|
+
filters: Optional[List[Union[RecordFilter, Union[Dict[str, str]]]]] = None,
|
|
47
|
+
test_mode: Optional[bool] = None,
|
|
48
|
+
per_page: int = 10,
|
|
49
|
+
page: int = 1
|
|
50
|
+
):
|
|
51
|
+
if not record_type_id and not record_field_ids:
|
|
52
|
+
raise ValueError("Please specify either 'record_type_id' or 'record_field_ids'.")
|
|
53
|
+
elif record_type_id and record_field_ids:
|
|
54
|
+
raise ValueError("Please specify only one of 'record_type_id' or 'record_field_ids', not both.")
|
|
55
|
+
|
|
56
|
+
return self._http_request(
|
|
57
|
+
"GET",
|
|
58
|
+
self.base_endpoint,
|
|
59
|
+
params = {key: value for key, value in locals().items() if value is not None and key != "self"}
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
def update(
|
|
63
|
+
self,
|
|
64
|
+
record_id: int,
|
|
65
|
+
add_child_records: Optional[List[Union[str, int]]] = None,
|
|
66
|
+
remove_child_records: Optional[List[Union[str, int]]] = None,
|
|
67
|
+
add_team_case_ids: Optional[List[Union[str, int]]] = None,
|
|
68
|
+
remove_team_case_ids: Optional[List[Union[str, int]]] = None,
|
|
69
|
+
field_values: List[Union[RecordFieldValue, Dict[str, Any]]] = None
|
|
70
|
+
):
|
|
71
|
+
return self._http_request(
|
|
72
|
+
"PUT",
|
|
73
|
+
f"{self.base_endpoint}/{record_id}",
|
|
74
|
+
json = {key: value for key, value in locals().items()
|
|
75
|
+
if value is not None and key not in ("self", "record_id")}
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
def delete(
|
|
79
|
+
self,
|
|
80
|
+
record_id: int
|
|
81
|
+
):
|
|
82
|
+
return self._http_request(
|
|
83
|
+
"DELETE",
|
|
84
|
+
f"{self.base_endpoint}/{record_id}"
|
|
85
|
+
)
|
tapi/api/record/types.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from tapi.client import Client
|
|
2
|
+
from typing import Dict, Optional, List, Union
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class RecordTypesAPI(Client):
|
|
6
|
+
def __init__(self, domain: str, apiKey: str):
|
|
7
|
+
super().__init__(domain, apiKey)
|
|
8
|
+
self.base_endpoint = "record_types"
|
|
9
|
+
|
|
10
|
+
def create(
|
|
11
|
+
self,
|
|
12
|
+
name: str,
|
|
13
|
+
team_id: int,
|
|
14
|
+
fields: List[Dict[str, Union[str, int, bool]]],
|
|
15
|
+
editable: Optional[bool] = None,
|
|
16
|
+
ttl_days: Optional[int] = None
|
|
17
|
+
):
|
|
18
|
+
return self._http_request(
|
|
19
|
+
"POST",
|
|
20
|
+
self.base_endpoint,
|
|
21
|
+
json = {key: value for key, value in locals().items() if value is not None and key != "self"}
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
def get(
|
|
25
|
+
self,
|
|
26
|
+
record_type_id: int
|
|
27
|
+
):
|
|
28
|
+
return self._http_request(
|
|
29
|
+
"GET",
|
|
30
|
+
f"{self.base_endpoint}/{record_type_id}"
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
def list(
|
|
34
|
+
self,
|
|
35
|
+
team_id: int,
|
|
36
|
+
per_page: int = 10,
|
|
37
|
+
page: int = 1
|
|
38
|
+
):
|
|
39
|
+
return self._http_request(
|
|
40
|
+
"GET",
|
|
41
|
+
self.base_endpoint,
|
|
42
|
+
params = {key: value for key, value in locals().items() if value is not None and key != "self"}
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
def delete(
|
|
46
|
+
self,
|
|
47
|
+
record_type_id: int
|
|
48
|
+
):
|
|
49
|
+
return self._http_request(
|
|
50
|
+
"DELETE",
|
|
51
|
+
f"{self.base_endpoint}/{record_type_id}"
|
|
52
|
+
)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from tapi.client import Client
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import Optional, Union, Literal
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ReportingAPI(Client):
|
|
7
|
+
def __init__(self, domain: str, apiKey: str):
|
|
8
|
+
super().__init__(domain, apiKey)
|
|
9
|
+
self.base_endpoint = "reporting"
|
|
10
|
+
|
|
11
|
+
def action_performance(
|
|
12
|
+
self,
|
|
13
|
+
team_id: Optional[int] = None,
|
|
14
|
+
story_id: Optional[int] = None,
|
|
15
|
+
action_id: Optional[int] = None,
|
|
16
|
+
filter_option: Optional[Literal["most_active_actions", "action_with_least_activity", "slowest_actions", "fastest_actions"]] = None,
|
|
17
|
+
per_page: int = 10,
|
|
18
|
+
page: int = 1,
|
|
19
|
+
):
|
|
20
|
+
return self._http_request(
|
|
21
|
+
"GET",
|
|
22
|
+
f"{self.base_endpoint}/action_performance",
|
|
23
|
+
params = {key: value for key, value in locals().items() if value is not None and key != "self"}
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
def time_saved(
|
|
27
|
+
self,
|
|
28
|
+
start_date: Optional[Union[datetime, str]] = None,
|
|
29
|
+
end_date: Optional[Union[datetime, str]] = None,
|
|
30
|
+
date_unit: Literal["hour", "day", "week", "month"] = "day",
|
|
31
|
+
fill_gaps: bool = True,
|
|
32
|
+
team_id: Optional[int] = None,
|
|
33
|
+
story_id: Optional[int] = None,
|
|
34
|
+
per_page: int = 10,
|
|
35
|
+
page: int = 1,
|
|
36
|
+
):
|
|
37
|
+
return self._http_request(
|
|
38
|
+
"GET",
|
|
39
|
+
f"{self.base_endpoint}/time_saved",
|
|
40
|
+
params = {key: value for key, value in locals().items() if value is not None and key != "self"}
|
|
41
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .resources import ResourcesAPI
|