Coverage for mindsdb / integrations / handlers / lightdash_handler / api.py: 0%
95 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-21 00:36 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-21 00:36 +0000
1import requests
2from urllib.parse import urljoin
5class Lightdash:
7 def __init__(self, url: str, api_key: str) -> None:
8 self.base_url = urljoin(url, "/api/v1/")
9 self.api_key = api_key
11 def _request(self, method: str, relative_endpoint: str, data=None):
12 kwargs = {
13 "method": method,
14 "url": urljoin(self.base_url, relative_endpoint),
15 "headers": {
16 "Authorization": "ApiKey " + self.api_key,
17 }
18 }
19 if data is not None:
20 kwargs["data"] = data
21 return requests.request(**kwargs)
23 def is_connected(self) -> bool:
24 if self.get_user() is not None:
25 return True
26 return False
28 def get_user(self):
29 """
30 Get user's details
31 Return format:
32 {'userUuid': '831b6c26-bdc2-4a56-9818-fd8ebaa406ac',
33 'email': 'test@test.com',
34 'firstName': 'Test',
35 'lastName': 'User',
36 'organizationUuid': 'd00805a0-b0b4-400d-a136-66f620493f11',
37 'organizationName': 'testing-comp',
38 'organizationCreatedAt': '2023-10-20T17:46:10.005Z',
39 'isTrackingAnonymized': False,
40 'isMarketingOptedIn': True,
41 'isSetupComplete': True,
42 'role': 'admin',
43 'isActive': True,
44 'abilityRules': [{'action': 'view',
45 'subject': 'OrganizationMemberProfile',
46 'conditions': {'organizationUuid': 'd00805a0-b0b4-400d-a136-66f620493f11'}},
47 {'action': ...
48 """
49 resp = self._request("get", "user")
50 if resp.ok:
51 return resp.json()["results"]
52 return {}
54 def get_org(self):
55 """
56 Get user's organization details
57 Return format:
58 {'organizationUuid': 'd00805a0-b0b4-400d-a136-66f620493f11',
59 'name': 'testing-comp',
60 'defaultProjectUuid': 'string',
61 'chartColors': ['string'],
62 'needsProject': False}
63 """
64 resp = self._request("get", "org")
65 if resp.ok:
66 return resp.json()["results"]
67 return {}
69 def get_projects(self):
70 """
71 Get user organization's pojects' details
72 Return format:
73 [{'name': 'Jaffle shop',
74 'projectUuid': '95dfda3b-02e2-4708-a014-5967966020f3',
75 'type': 'DEFAULT'}]
76 """
77 resp = self._request("get", "org/projects")
78 if resp.ok:
79 return resp.json()["results"]
80 return []
82 def get_org_members(self):
83 """
84 Get all the members in user's organization
85 Return format:
86 [{'userUuid': '831b6c26-bdc2-4a56-9818-fd8ebaa406ac',
87 'firstName': 'TestName',
88 'lastName': 'TestLastName',
89 'email': 'test@test.com',
90 'organizationUuid': 'd00805a0-b0b4-400d-a136-66f620493f11',
91 'role': 'admin',
92 'isActive': True,
93 'isInviteExpired': False}]
94 """
95 resp = self._request("get", "org/users")
96 if resp.ok:
97 return resp.json()["results"]
98 return []
100 def get_project(self, project_uuid: str):
101 """
102 Get details of a project in user's organization
103 Return format:
104 { "dbtVersion": "v1.4",
105 "copiedFromProjectUuid": "string",
106 "pinnedListUuid": "string",
107 "warehouseConnection": {
108 "role": "string",
109 "type": "snowflake",
110 "account": "string",
111 "database": "string",
112 "warehouse": "string",
113 "schema": "string",
114 "threads": 0,
115 "clientSessionKeepAlive": true,
116 "queryTag": "string",
117 "accessUrl": "string",
118 "startOfWeek": 0 },
119 "dbtConnection": {
120 "type": "dbt",
121 "target": "string",
122 "environment": [ {
123 "value": "string",
124 "key": "string" } ],
125 "profiles_dir": "string",
126 "project_dir": "string" },
127 "type": "DEFAULT",
128 "name": "string",
129 "projectUuid": "string",
130 "organizationUuid": "string" }
131 """
132 resp = self._request("get", f"projects/{project_uuid}")
133 if resp.ok:
134 return resp.json()["results"]
135 return {}
137 def get_charts_in_project(self, project_uuid: str):
138 """
139 List all charts in a project
140 Return format:
141 [{"name": "string",
142 "organizationUuid": "string",
143 "uuid": "string",
144 "description": "string",
145 "projectUuid": "string",
146 "spaceUuid": "string",
147 "pinnedListUuid": "string",
148 "spaceName": "string",
149 "dashboardUuid": "string",
150 "dashboardName": "string",
151 "chartType": "string"}]
152 """
153 resp = self._request("get", f"projects/{project_uuid}/charts")
154 if resp.ok:
155 return resp.json()["results"]
156 return []
158 def get_spaces_in_project(self, project_uuid: str):
159 """
160 List all spaces in a project
161 Return format:
162 [{"name": "string",
163 "organizationUuid": "string",
164 "uuid": "string",
165 "projectUuid": "string",
166 "pinnedListUuid": "string",
167 "pinnedListOrder": 0,
168 "isPrivate": true,
169 "dashboardCount": 0,
170 "chartCount": 0,
171 "access": [
172 "string" ]}]
173 """
174 resp = self._request("get", f"projects/{project_uuid}/spaces")
175 if resp.ok:
176 return resp.json()["results"]
177 return []
179 def get_project_access_list(self, project_uuid: str):
180 """
181 Get access list for a project. This is a list of users that have been explictly granted access to the project. There may be other users that have access to the project via their organization membership
182 Return format:
183 [{"lastName": "string",
184 "firstName": "string",
185 "email": "string",
186 "role": "viewer",
187 "projectUuid": "string",
188 "userUuid": "string" }]
189 """
190 resp = self._request("get", f"projects/{project_uuid}/access")
191 if resp.ok:
192 return resp.json()["results"]
193 return []
195 def get_validation_results(self, project_uuid: str):
196 """
197 Get validation results for a project. This will return the results of the latest validation job
198 Return format:
199 [{"source": "chart",
200 "spaceUuid": "string",
201 "projectUuid": "string",
202 "errorType": "chart",
203 "error": "string",
204 "name": "string",
205 "createdAt": "2019-08-24T14:15:22Z",
206 "validationId": 0,
207 "chartName": "string",
208 "chartViews": 0,
209 "lastUpdatedAt": "2019-08-24T14:15:22Z",
210 "lastUpdatedBy": "string",
211 "fieldName": "string",
212 "chartType": "line",
213 "chartUuid": "string"}]
214 """
215 resp = self._request("get", f"projects/{project_uuid}/validate")
216 if resp.ok:
217 return resp.json()["results"]
218 return []
220 def get_space(self, project_uuid: str, space_uuid: str):
221 """
222 Get details for a space in a project
223 Return format:
224 { "pinnedListOrder": 0,
225 "pinnedListUuid": "string",
226 "access": [ {
227 "role": "viewer",
228 "lastName": "string",
229 "firstName": "string",
230 "userUuid": "string" } ],
231 "dashboards": [ {
232 "name": "string",
233 "organizationUuid": "string",
234 "uuid": "string",
235 "description": "string",
236 "updatedAt": "2019-08-24T14:15:22Z",
237 "projectUuid": "string",
238 "updatedByUser": {
239 "userUuid": "string",
240 "firstName": "string",
241 "lastName": "string" },
242 "spaceUuid": "string",
243 "views": 0,
244 "firstViewedAt": "2019-08-24T14:15:22Z",
245 "pinnedListUuid": "string",
246 "pinnedListOrder": 0,
247 "validationErrors": [ {
248 "validationId": 0,
249 "createdAt": "2019-08-24T14:15:22Z",
250 "error": "string" } ] } ],
251 "projectUuid": "string",
252 "queries": [ {
253 "name": "string",
254 "uuid": "string",
255 "description": "string",
256 "updatedAt": "2019-08-24T14:15:22Z",
257 "updatedByUser": {
258 "userUuid": "string",
259 "firstName": "string",
260 "lastName": "string" },
261 "spaceUuid": "string",
262 "pinnedListUuid": "string",
263 "pinnedListOrder": 0,
264 "firstViewedAt": "2019-08-24T14:15:22Z",
265 "views": 0,
266 "validationErrors": [ {
267 "validationId": 0,
268 "createdAt": "2019-08-24T14:15:22Z",
269 "error": "string" } ],
270 "chartType": "line" } ],
271 "isPrivate": true,
272 "name": "string",
273 "uuid": "string",
274 "organizationUuid": "string" }
275 """
276 resp = self._request("get", f"projects/{project_uuid}/spaces/{space_uuid}")
277 if resp.ok:
278 return resp.json()["results"]
279 return {}
281 def get_chart_version_history(self, chart_uuid: str):
282 """
283 Get chart version history from last 30 days
284 Return format:
285 [{"createdAt": "2019-08-24T14:15:22Z",
286 "chartUuid": "string",
287 "versionUuid": "string",
288 "createdBy": {
289 "userUuid": "string",
290 "firstName": "string",
291 "lastName": "string" }}]
292 """
293 resp = self._request("get", f"saved/{chart_uuid}/history")
294 if resp.ok:
295 return resp.json()["results"]["history"]
296 return []
298 def get_chart(self, chart_uuid: str, version_uuid: str):
299 """
300 Get chart details
301 Return format:
302 { "chart": {
303 "dashboardName": "string",
304 "dashboardUuid": "string",
305 "pinnedListOrder": 0,
306 "pinnedListUuid": "string",
307 "spaceName": "string",
308 "spaceUuid": "string",
309 "organizationUuid": "string",
310 "updatedByUser": {
311 "userUuid": "string",
312 "firstName": "string",
313 "lastName": "string" },
314 "updatedAt": "2019-08-24T14:15:22Z",
315 "tableConfig": {
316 "columnOrder": [
317 "string" ] },
318 "chartConfig": {
319 "config": {
320 "legendPosition": "horizontal",
321 "showLegend": true,
322 "groupSortOverrides": [
323 "string" ],
324 "groupValueOptionOverrides": {},
325 "groupColorOverrides": {},
326 "groupLabelOverrides": {},
327 "showPercentage": true,
328 "showValue": true,
329 "valueLabel": "hidden",
330 "isDonut": true,
331 "metricId": "string",
332 "groupFieldIds": [
333 "string" ] },
334 "type": "pie" },
335 "pivotConfig": {
336 "columns": [
337 "string" ] },
338 "metricQuery": {
339 "additionalMetrics": [ {
340 "label": "string",
341 "type": "percentile",
342 "description": "string",
343 "sql": "string",
344 "hidden": true,
345 "round": 0,
346 "compact": "thousands",
347 "format": "km",
348 "table": "string",
349 "name": "string",
350 "index": 0,
351 "filters": [ {
352 "values": [
353 null ],
354 "operator": "isNull",
355 "id": "string",
356 "target": {
357 "fieldRef": "string" },
358 "settings": null,
359 "disabled": true } ],
360 "baseDimensionName": "string",
361 "uuid": "string",
362 "percentile": 0 } ],
363 "tableCalculations": [ {
364 "format": {
365 "suffix": "string",
366 "prefix": "string",
367 "compact": "thousands",
368 "currency": "string",
369 "separator": "default",
370 "round": 0,
371 "type": "default" },
372 "sql": "string",
373 "displayName": "string",
374 "name": "string",
375 "index": 0 } ],
376 "limit": 0,
377 "sorts": [ {
378 "descending": true,
379 "fieldId": "string" } ],
380 "filters": {
381 "metrics": {
382 "or": [
383 null ],
384 "id": "string" },
385 "dimensions": {
386 "or": [
387 null ],
388 "id": "string" } },
389 "metrics": [
390 "string" ],
391 "dimensions": [
392 "string" ] },
393 "tableName": "string",
394 "description": "string",
395 "name": "string",
396 "projectUuid": "string",
397 "uuid": "string" },
398 "createdBy": {
399 "userUuid": "string",
400 "firstName": "string",
401 "lastName": "string" },
402 "createdAt": "2019-08-24T14:15:22Z",
403 "versionUuid": "string",
404 "chartUuid": "string" }
405 """
406 resp = self._request("get", f"saved/{chart_uuid}/version/{version_uuid}")
407 if resp.ok:
408 return resp.json()["results"]
409 return {}
411 def get_scheduler_logs(self, project_uuid: str):
412 """
413 Get scheduled logs
414 Return format:
415 { "logs": [ {
416 "details": {},
417 "targetType": "email",
418 "target": "string",
419 "status": "scheduled",
420 "createdAt": "2019-08-24T14:15:22Z",
421 "scheduledTime": "2019-08-24T14:15:22Z",
422 "jobGroup": "string",
423 "jobId": "string",
424 "schedulerUuid": "string",
425 "task": "handleScheduledDelivery"
426 } ],
427 "dashboards": [ {
428 "dashboardUuid": "string",
429 "name": "string" } ],
430 "charts": [ {
431 "savedChartUuid": "string",
432 "name": "string" } ],
433 "users": [ {
434 "userUuid": "string",
435 "lastName": "string",
436 "firstName": "string" } ],
437 "schedulers": [ {
438 "options": {
439 "limit": 0,
440 "formatted": true },
441 "dashboardUuid": null,
442 "savedChartUuid": "string",
443 "cron": "string",
444 "format": "csv",
445 "createdBy": "string",
446 "updatedAt": "2019-08-24T14:15:22Z",
447 "createdAt": "2019-08-24T14:15:22Z",
448 "message": "string",
449 "name": "string",
450 "schedulerUuid": "string",
451 "targets": [ {
452 "channel": "string",
453 "schedulerUuid": "string",
454 "updatedAt": "2019-08-24T14:15:22Z",
455 "createdAt": "2019-08-24T14:15:22Z",
456 "schedulerSlackTargetUuid": "string" } ] } ] }
457 """
458 resp = self._request("get", f"schedulers/{project_uuid}/logs")
459 if resp.ok:
460 return resp.json()["results"]
461 return {}
463 def get_scheduler(self, scheduler_uuid: str):
464 """
465 Get details of a scheduler
466 Return format:
467 { "options": {
468 "limit": 0,
469 "formatted": true },
470 "dashboardUuid": null,
471 "savedChartUuid": "string",
472 "cron": "string",
473 "format": "csv",
474 "createdBy": "string",
475 "updatedAt": "2019-08-24T14:15:22Z",
476 "createdAt": "2019-08-24T14:15:22Z",
477 "message": "string",
478 "name": "string",
479 "schedulerUuid": "string",
480 "targets": [ {
481 "channel": "string",
482 "schedulerUuid": "string",
483 "updatedAt": "2019-08-24T14:15:22Z",
484 "createdAt": "2019-08-24T14:15:22Z",
485 "schedulerSlackTargetUuid": "string" } ] }
486 """
487 resp = self._request("get", f"schedulers/{scheduler_uuid}")
488 if resp.ok:
489 return resp.json()["results"]
490 return {}
492 def get_scheduler_jobs(self, scheduler_uuid: str):
493 """
494 Get jobs scheduled by a scheduler
495 Return format:
496 [ { "id": "string",
497 "date": "2019-08-24T14:15:22Z" } ]
498 """
499 resp = self._request("get", f"schedulers/{scheduler_uuid}/jobs")
500 if resp.ok:
501 return resp.json()["results"]
502 return []
504 def get_scheduler_job_status(self, job_id: str):
505 """
506 Get a generic job status
507 Return format:
508 { "status": "string" }
509 """
510 resp = self._request("get", f"schedulers/job/{job_id}/status")
511 if resp.ok:
512 return resp.json()["results"]
513 return {}