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.
Files changed (69) hide show
  1. tapi/__init__.py +2 -0
  2. tapi/api/__init__.py +46 -0
  3. tapi/api/action/__init__.py +7 -0
  4. tapi/api/action/actions.py +106 -0
  5. tapi/api/action/events.py +33 -0
  6. tapi/api/action/logs.py +34 -0
  7. tapi/api/admin/__init__.py +12 -0
  8. tapi/api/admin/action_egress_control_rules.py +87 -0
  9. tapi/api/admin/admin.py +43 -0
  10. tapi/api/admin/ip_access_control.py +76 -0
  11. tapi/api/admin/job.py +42 -0
  12. tapi/api/admin/scim.py +27 -0
  13. tapi/api/admin/template.py +86 -0
  14. tapi/api/admin/user.py +104 -0
  15. tapi/api/audit_log/__init__.py +5 -0
  16. tapi/api/audit_log/audit_logs.py +24 -0
  17. tapi/api/case/__init__.py +20 -0
  18. tapi/api/case/actions.py +90 -0
  19. tapi/api/case/activities.py +35 -0
  20. tapi/api/case/assignees.py +21 -0
  21. tapi/api/case/blocks.py +112 -0
  22. tapi/api/case/cases.py +132 -0
  23. tapi/api/case/comments.py +102 -0
  24. tapi/api/case/fields.py +69 -0
  25. tapi/api/case/files.py +77 -0
  26. tapi/api/case/inputs.py +64 -0
  27. tapi/api/case/linked_cases.py +57 -0
  28. tapi/api/case/metadata.py +65 -0
  29. tapi/api/case/notes.py +78 -0
  30. tapi/api/case/records.py +54 -0
  31. tapi/api/case/subscribers.py +56 -0
  32. tapi/api/credential/__init__.py +1 -0
  33. tapi/api/credential/credentials.py +240 -0
  34. tapi/api/event/__init__.py +1 -0
  35. tapi/api/event/events.py +44 -0
  36. tapi/api/folder/__init__.py +1 -0
  37. tapi/api/folder/folders.py +71 -0
  38. tapi/api/note/__init__.py +5 -0
  39. tapi/api/note/notes.py +76 -0
  40. tapi/api/record/__init__.py +7 -0
  41. tapi/api/record/artifacts.py +17 -0
  42. tapi/api/record/records.py +85 -0
  43. tapi/api/record/types.py +52 -0
  44. tapi/api/report/__init__.py +5 -0
  45. tapi/api/report/reporting.py +41 -0
  46. tapi/api/resource/__init__.py +1 -0
  47. tapi/api/resource/resources.py +152 -0
  48. tapi/api/story/__init__.py +10 -0
  49. tapi/api/story/change_requests.py +64 -0
  50. tapi/api/story/drafts.py +45 -0
  51. tapi/api/story/groups.py +38 -0
  52. tapi/api/story/runs.py +43 -0
  53. tapi/api/story/stories.py +162 -0
  54. tapi/api/story/versions.py +65 -0
  55. tapi/api/team/__init__.py +4 -0
  56. tapi/api/team/members.py +62 -0
  57. tapi/api/team/teams.py +60 -0
  58. tapi/api/tenant.py +68 -0
  59. tapi/client/__init__.py +1 -0
  60. tapi/client/client.py +55 -0
  61. tapi/utils/helpers.py +9 -0
  62. tapi/utils/http.py +8 -0
  63. tapi/utils/testing_decorators.py +5 -0
  64. tapi/utils/types.py +300 -0
  65. tapi-0.1.2.dist-info/METADATA +2487 -0
  66. tapi-0.1.2.dist-info/RECORD +69 -0
  67. tapi-0.1.2.dist-info/WHEEL +5 -0
  68. tapi-0.1.2.dist-info/licenses/LICENSE +674 -0
  69. 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
@@ -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
+ )
@@ -0,0 +1,5 @@
1
+ from .notes import NotesAPI
2
+
3
+ __all__ = [
4
+ "NotesAPI"
5
+ ]
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,7 @@
1
+ from .records import RecordsAPI
2
+ from .types import RecordTypesAPI
3
+ from .artifacts import RecordArtifactsAPI
4
+
5
+ __all__ = [
6
+ "RecordsAPI", "RecordTypesAPI", "RecordArtifactsAPI"
7
+ ]
@@ -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
+ )
@@ -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,5 @@
1
+ from .reporting import ReportingAPI
2
+
3
+ __all__ = [
4
+ "ReportingAPI"
5
+ ]
@@ -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