swipeflow-api 1.1.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.
- swipeflow_api/__init__.py +63 -0
- swipeflow_api/client.py +161 -0
- swipeflow_api/exceptions.py +110 -0
- swipeflow_api/models.py +211 -0
- swipeflow_api/py.typed +0 -0
- swipeflow_api/resources.py +412 -0
- swipeflow_api-1.1.0.dist-info/METADATA +568 -0
- swipeflow_api-1.1.0.dist-info/RECORD +11 -0
- swipeflow_api-1.1.0.dist-info/WHEEL +5 -0
- swipeflow_api-1.1.0.dist-info/licenses/LICENSE +15 -0
- swipeflow_api-1.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
"""Resource classes for SwipeFlow API endpoints."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, List, Optional
|
|
4
|
+
|
|
5
|
+
from .models import Project, Item, Webhook, ApiKey, User, ItemStatus
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class BaseResource:
|
|
9
|
+
"""Base class for API resources."""
|
|
10
|
+
|
|
11
|
+
def __init__(self, client):
|
|
12
|
+
"""Initialize resource with client reference.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
client: SwipeFlowClient instance
|
|
16
|
+
"""
|
|
17
|
+
self.client = client
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ProjectsResource(BaseResource):
|
|
21
|
+
"""Resource for project operations."""
|
|
22
|
+
|
|
23
|
+
def list(self, skip: int = 0, limit: int = 20) -> List[Dict[str, Any]]:
|
|
24
|
+
"""List all projects.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
skip: Number of projects to skip
|
|
28
|
+
limit: Maximum number of projects to return
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
List of project dictionaries
|
|
32
|
+
"""
|
|
33
|
+
response = self.client.request("GET", "/v1/projects", params={"skip": skip, "limit": limit})
|
|
34
|
+
return response.get("items", [])
|
|
35
|
+
|
|
36
|
+
def get(self, project_id: str) -> Dict[str, Any]:
|
|
37
|
+
"""Get a specific project.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
project_id: Project ID
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Project data
|
|
44
|
+
"""
|
|
45
|
+
return self.client.request("GET", f"/v1/projects/{project_id}")
|
|
46
|
+
|
|
47
|
+
def create(self, name: str, description: Optional[str] = None) -> Dict[str, Any]:
|
|
48
|
+
"""Create a new project.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
name: Project name
|
|
52
|
+
description: Optional project description
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
Created project data
|
|
56
|
+
"""
|
|
57
|
+
data = {"name": name}
|
|
58
|
+
if description:
|
|
59
|
+
data["description"] = description
|
|
60
|
+
return self.client.request("POST", "/v1/projects", json_data=data)
|
|
61
|
+
|
|
62
|
+
def update(self, project_id: str, name: Optional[str] = None, description: Optional[str] = None) -> Dict[str, Any]:
|
|
63
|
+
"""Update a project.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
project_id: Project ID
|
|
67
|
+
name: New project name
|
|
68
|
+
description: New project description
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
Updated project data
|
|
72
|
+
"""
|
|
73
|
+
data = {}
|
|
74
|
+
if name:
|
|
75
|
+
data["name"] = name
|
|
76
|
+
if description is not None:
|
|
77
|
+
data["description"] = description
|
|
78
|
+
return self.client.request("PUT", f"/v1/projects/{project_id}", json_data=data)
|
|
79
|
+
|
|
80
|
+
def delete(self, project_id: str) -> None:
|
|
81
|
+
"""Delete a project.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
project_id: Project ID
|
|
85
|
+
"""
|
|
86
|
+
self.client.request("DELETE", f"/v1/projects/{project_id}")
|
|
87
|
+
|
|
88
|
+
def add_member(self, project_id: str, user_id: str, role: str) -> Dict[str, Any]:
|
|
89
|
+
"""Add a member to a project.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
project_id: Project ID
|
|
93
|
+
user_id: User ID to add
|
|
94
|
+
role: Role (OWNER, ADMIN, EDITOR, VIEWER)
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
Updated project data
|
|
98
|
+
"""
|
|
99
|
+
data = {"user_id": user_id, "role": role}
|
|
100
|
+
return self.client.request("POST", f"/v1/projects/{project_id}/members", json_data=data)
|
|
101
|
+
|
|
102
|
+
def remove_member(self, project_id: str, user_id: str) -> Dict[str, Any]:
|
|
103
|
+
"""Remove a member from a project.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
project_id: Project ID
|
|
107
|
+
user_id: User ID to remove
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
Updated project data
|
|
111
|
+
"""
|
|
112
|
+
return self.client.request("DELETE", f"/v1/projects/{project_id}/members/{user_id}")
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class ItemsResource(BaseResource):
|
|
116
|
+
"""Resource for item operations."""
|
|
117
|
+
|
|
118
|
+
def list(self, project_id: str, status: Optional[str] = None, skip: int = 0, limit: int = 20) -> List[Dict[str, Any]]:
|
|
119
|
+
"""List items in a project.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
project_id: Project ID
|
|
123
|
+
status: Optional status filter (PENDING, APPROVED, REJECTED, CHANGE_REQUESTED, PROCESSED)
|
|
124
|
+
skip: Number of items to skip
|
|
125
|
+
limit: Maximum number of items to return
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
List of item dictionaries
|
|
129
|
+
"""
|
|
130
|
+
params = {"skip": skip, "limit": limit}
|
|
131
|
+
if status:
|
|
132
|
+
params["status"] = status
|
|
133
|
+
response = self.client.request("GET", f"/v1/projects/{project_id}/items", params=params)
|
|
134
|
+
return response.get("items", [])
|
|
135
|
+
|
|
136
|
+
def get(self, project_id: str, item_id: str) -> Dict[str, Any]:
|
|
137
|
+
"""Get a specific item.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
project_id: Project ID
|
|
141
|
+
item_id: Item ID
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
Item data
|
|
145
|
+
"""
|
|
146
|
+
return self.client.request("GET", f"/v1/projects/{project_id}/items/{item_id}")
|
|
147
|
+
|
|
148
|
+
def create(self, project_id: str, title: str, content: Dict[str, Any]) -> Dict[str, Any]:
|
|
149
|
+
"""Create a new item.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
project_id: Project ID
|
|
153
|
+
title: Item title
|
|
154
|
+
content: Item content (type, data)
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
Created item data
|
|
158
|
+
"""
|
|
159
|
+
data = {"title": title, "content": content}
|
|
160
|
+
return self.client.request("POST", f"/v1/projects/{project_id}/items", json_data=data)
|
|
161
|
+
|
|
162
|
+
def update(
|
|
163
|
+
self, project_id: str, item_id: str, title: Optional[str] = None, content: Optional[Dict[str, Any]] = None
|
|
164
|
+
) -> Dict[str, Any]:
|
|
165
|
+
"""Update an item.
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
project_id: Project ID
|
|
169
|
+
item_id: Item ID
|
|
170
|
+
title: New title
|
|
171
|
+
content: New content
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
Updated item data
|
|
175
|
+
"""
|
|
176
|
+
data = {}
|
|
177
|
+
if title:
|
|
178
|
+
data["title"] = title
|
|
179
|
+
if content:
|
|
180
|
+
data["content"] = content
|
|
181
|
+
return self.client.request("PUT", f"/v1/projects/{project_id}/items/{item_id}", json_data=data)
|
|
182
|
+
|
|
183
|
+
def delete(self, project_id: str, item_id: str) -> None:
|
|
184
|
+
"""Delete an item.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
project_id: Project ID
|
|
188
|
+
item_id: Item ID
|
|
189
|
+
"""
|
|
190
|
+
self.client.request("DELETE", f"/v1/projects/{project_id}/items/{item_id}")
|
|
191
|
+
|
|
192
|
+
def approve(self, project_id: str, item_id: str, comment: Optional[str] = None) -> Dict[str, Any]:
|
|
193
|
+
"""Approve an item.
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
project_id: Project ID
|
|
197
|
+
item_id: Item ID
|
|
198
|
+
comment: Optional approval comment
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
Updated item data
|
|
202
|
+
"""
|
|
203
|
+
data = {"type": "APPROVED"}
|
|
204
|
+
if comment:
|
|
205
|
+
data["comment"] = comment
|
|
206
|
+
return self.client.request("POST", f"/v1/projects/{project_id}/items/{item_id}/approve", json_data=data)
|
|
207
|
+
|
|
208
|
+
def reject(self, project_id: str, item_id: str, comment: Optional[str] = None) -> Dict[str, Any]:
|
|
209
|
+
"""Reject an item.
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
project_id: Project ID
|
|
213
|
+
item_id: Item ID
|
|
214
|
+
comment: Optional rejection comment
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
Updated item data
|
|
218
|
+
"""
|
|
219
|
+
data = {"type": "REJECTED"}
|
|
220
|
+
if comment:
|
|
221
|
+
data["comment"] = comment
|
|
222
|
+
return self.client.request("POST", f"/v1/projects/{project_id}/items/{item_id}/reject", json_data=data)
|
|
223
|
+
|
|
224
|
+
def request_changes(self, project_id: str, item_id: str, comment: Optional[str] = None) -> Dict[str, Any]:
|
|
225
|
+
"""Request changes on an item.
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
project_id: Project ID
|
|
229
|
+
item_id: Item ID
|
|
230
|
+
comment: Optional request comment
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
Updated item data
|
|
234
|
+
"""
|
|
235
|
+
data = {"type": "CHANGE_REQUESTED"}
|
|
236
|
+
if comment:
|
|
237
|
+
data["comment"] = comment
|
|
238
|
+
return self.client.request("POST", f"/v1/projects/{project_id}/items/{item_id}/request-changes", json_data=data)
|
|
239
|
+
|
|
240
|
+
def get_versions(self, project_id: str, item_id: str) -> List[Dict[str, Any]]:
|
|
241
|
+
"""Get version history of an item.
|
|
242
|
+
|
|
243
|
+
Args:
|
|
244
|
+
project_id: Project ID
|
|
245
|
+
item_id: Item ID
|
|
246
|
+
|
|
247
|
+
Returns:
|
|
248
|
+
List of version data
|
|
249
|
+
"""
|
|
250
|
+
response = self.client.request("GET", f"/v1/projects/{project_id}/items/{item_id}/versions")
|
|
251
|
+
return response.get("items", [])
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
class WebhooksResource(BaseResource):
|
|
255
|
+
"""Resource for webhook operations."""
|
|
256
|
+
|
|
257
|
+
def list(self, project_id: str, skip: int = 0, limit: int = 20) -> List[Dict[str, Any]]:
|
|
258
|
+
"""List webhooks for a project.
|
|
259
|
+
|
|
260
|
+
Args:
|
|
261
|
+
project_id: Project ID
|
|
262
|
+
skip: Number of webhooks to skip
|
|
263
|
+
limit: Maximum number of webhooks to return
|
|
264
|
+
|
|
265
|
+
Returns:
|
|
266
|
+
List of webhook dictionaries
|
|
267
|
+
"""
|
|
268
|
+
params = {"skip": skip, "limit": limit}
|
|
269
|
+
response = self.client.request("GET", f"/v1/projects/{project_id}/webhooks", params=params)
|
|
270
|
+
return response.get("items", [])
|
|
271
|
+
|
|
272
|
+
def get(self, project_id: str, webhook_id: str) -> Dict[str, Any]:
|
|
273
|
+
"""Get a specific webhook.
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
project_id: Project ID
|
|
277
|
+
webhook_id: Webhook ID
|
|
278
|
+
|
|
279
|
+
Returns:
|
|
280
|
+
Webhook data
|
|
281
|
+
"""
|
|
282
|
+
return self.client.request("GET", f"/v1/projects/{project_id}/webhooks/{webhook_id}")
|
|
283
|
+
|
|
284
|
+
def create(self, project_id: str, name: str, url: str, events: List[str]) -> Dict[str, Any]:
|
|
285
|
+
"""Create a new webhook.
|
|
286
|
+
|
|
287
|
+
Args:
|
|
288
|
+
project_id: Project ID
|
|
289
|
+
name: Webhook name
|
|
290
|
+
url: Webhook URL
|
|
291
|
+
events: List of events to subscribe to
|
|
292
|
+
|
|
293
|
+
Returns:
|
|
294
|
+
Created webhook data
|
|
295
|
+
"""
|
|
296
|
+
data = {"name": name, "url": url, "events": events}
|
|
297
|
+
return self.client.request("POST", f"/v1/projects/{project_id}/webhooks", json_data=data)
|
|
298
|
+
|
|
299
|
+
def update(
|
|
300
|
+
self, project_id: str, webhook_id: str, name: Optional[str] = None, url: Optional[str] = None,
|
|
301
|
+
events: Optional[List[str]] = None, active: Optional[bool] = None
|
|
302
|
+
) -> Dict[str, Any]:
|
|
303
|
+
"""Update a webhook.
|
|
304
|
+
|
|
305
|
+
Args:
|
|
306
|
+
project_id: Project ID
|
|
307
|
+
webhook_id: Webhook ID
|
|
308
|
+
name: New webhook name
|
|
309
|
+
url: New webhook URL
|
|
310
|
+
events: New events list
|
|
311
|
+
active: Whether webhook is active
|
|
312
|
+
|
|
313
|
+
Returns:
|
|
314
|
+
Updated webhook data
|
|
315
|
+
"""
|
|
316
|
+
data = {}
|
|
317
|
+
if name:
|
|
318
|
+
data["name"] = name
|
|
319
|
+
if url:
|
|
320
|
+
data["url"] = url
|
|
321
|
+
if events:
|
|
322
|
+
data["events"] = events
|
|
323
|
+
if active is not None:
|
|
324
|
+
data["active"] = active
|
|
325
|
+
return self.client.request("PUT", f"/v1/projects/{project_id}/webhooks/{webhook_id}", json_data=data)
|
|
326
|
+
|
|
327
|
+
def delete(self, project_id: str, webhook_id: str) -> None:
|
|
328
|
+
"""Delete a webhook.
|
|
329
|
+
|
|
330
|
+
Args:
|
|
331
|
+
project_id: Project ID
|
|
332
|
+
webhook_id: Webhook ID
|
|
333
|
+
"""
|
|
334
|
+
self.client.request("DELETE", f"/v1/projects/{project_id}/webhooks/{webhook_id}")
|
|
335
|
+
|
|
336
|
+
def test(self, project_id: str, webhook_id: str) -> Dict[str, Any]:
|
|
337
|
+
"""Test a webhook by sending a test payload.
|
|
338
|
+
|
|
339
|
+
Args:
|
|
340
|
+
project_id: Project ID
|
|
341
|
+
webhook_id: Webhook ID
|
|
342
|
+
|
|
343
|
+
Returns:
|
|
344
|
+
Test result data
|
|
345
|
+
"""
|
|
346
|
+
return self.client.request("POST", f"/v1/projects/{project_id}/webhooks/{webhook_id}/test")
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
class ApiKeysResource(BaseResource):
|
|
350
|
+
"""Resource for API key operations."""
|
|
351
|
+
|
|
352
|
+
def list(self, skip: int = 0, limit: int = 20) -> List[Dict[str, Any]]:
|
|
353
|
+
"""List API keys.
|
|
354
|
+
|
|
355
|
+
Args:
|
|
356
|
+
skip: Number of keys to skip
|
|
357
|
+
limit: Maximum number of keys to return
|
|
358
|
+
|
|
359
|
+
Returns:
|
|
360
|
+
List of API key dictionaries
|
|
361
|
+
"""
|
|
362
|
+
response = self.client.request("GET", "/v1/api-keys", params={"skip": skip, "limit": limit})
|
|
363
|
+
return response.get("items", [])
|
|
364
|
+
|
|
365
|
+
def create(self, name: str) -> Dict[str, Any]:
|
|
366
|
+
"""Create a new API key.
|
|
367
|
+
|
|
368
|
+
Args:
|
|
369
|
+
name: Key name
|
|
370
|
+
|
|
371
|
+
Returns:
|
|
372
|
+
Created API key data (includes the actual key)
|
|
373
|
+
"""
|
|
374
|
+
data = {"name": name}
|
|
375
|
+
return self.client.request("POST", "/v1/api-keys", json_data=data)
|
|
376
|
+
|
|
377
|
+
def delete(self, key_id: str) -> None:
|
|
378
|
+
"""Delete an API key.
|
|
379
|
+
|
|
380
|
+
Args:
|
|
381
|
+
key_id: API key ID
|
|
382
|
+
"""
|
|
383
|
+
self.client.request("DELETE", f"/v1/api-keys/{key_id}")
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
class AuthResource(BaseResource):
|
|
387
|
+
"""Resource for authentication operations."""
|
|
388
|
+
|
|
389
|
+
def get_profile(self) -> Dict[str, Any]:
|
|
390
|
+
"""Get current user profile.
|
|
391
|
+
|
|
392
|
+
Returns:
|
|
393
|
+
User profile data
|
|
394
|
+
"""
|
|
395
|
+
return self.client.request("GET", "/v1/auth/profile")
|
|
396
|
+
|
|
397
|
+
def update_profile(self, name: Optional[str] = None, avatar_url: Optional[str] = None) -> Dict[str, Any]:
|
|
398
|
+
"""Update user profile.
|
|
399
|
+
|
|
400
|
+
Args:
|
|
401
|
+
name: New user name
|
|
402
|
+
avatar_url: New avatar URL
|
|
403
|
+
|
|
404
|
+
Returns:
|
|
405
|
+
Updated user data
|
|
406
|
+
"""
|
|
407
|
+
data = {}
|
|
408
|
+
if name:
|
|
409
|
+
data["name"] = name
|
|
410
|
+
if avatar_url:
|
|
411
|
+
data["avatar_url"] = avatar_url
|
|
412
|
+
return self.client.request("PUT", "/v1/auth/profile", json_data=data)
|