MindsDB 25.3.4.0__py3-none-any.whl → 25.3.4.1__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.

Potentially problematic release.


This version of MindsDB might be problematic. Click here for more details.

@@ -0,0 +1,753 @@
1
+ from typing import List
2
+
3
+ import pandas as pd
4
+
5
+ from mindsdb.integrations.handlers.confluence_handler.confluence_api_client import ConfluenceAPIClient
6
+ from mindsdb.integrations.libs.api_handler import APIResource
7
+ from mindsdb.integrations.utilities.sql_utils import (
8
+ FilterCondition,
9
+ FilterOperator,
10
+ SortColumn
11
+ )
12
+ from mindsdb.utilities import log
13
+
14
+
15
+ logger = log.getLogger(__name__)
16
+
17
+
18
+ class ConfluenceSpacesTable(APIResource):
19
+ """
20
+ The table abstraction for the 'spaces' resource of the Confluence API.
21
+ """
22
+ def list(
23
+ self,
24
+ conditions: List[FilterCondition] = None,
25
+ limit: int = None,
26
+ sort: List[SortColumn] = None,
27
+ targets: List[str] = None,
28
+ **kwargs
29
+ ):
30
+ """
31
+ Executes a parsed SELECT SQL query on the 'spaces' resource of the Confluence API.
32
+
33
+ Args:
34
+ conditions (List[FilterCondition]): The list of parsed filter conditions.
35
+ limit (int): The maximum number of records to return.
36
+ sort (List[SortColumn]): The list of parsed sort columns.
37
+ targets (List[str]): The list of target columns to return.
38
+ """
39
+ spaces = []
40
+ client: ConfluenceAPIClient = self.handler.connect()
41
+
42
+ ids, keys, space_type, status = None, None, None, None
43
+ for condition in conditions:
44
+ if condition.column == "id":
45
+ if condition.op == FilterOperator.EQUAL:
46
+ ids = [condition.value]
47
+
48
+ elif condition.op == FilterOperator.IN:
49
+ ids = condition.value
50
+
51
+ else:
52
+ raise ValueError(
53
+ f"Unsupported operator '{condition.op}' for column 'id'."
54
+ )
55
+
56
+ condition.applied = True
57
+
58
+ if condition.column == "key":
59
+ if condition.op == FilterOperator.EQUAL:
60
+ keys = [condition.value]
61
+
62
+ elif condition.op == FilterOperator.IN:
63
+ keys = condition.value
64
+
65
+ else:
66
+ raise ValueError(
67
+ f"Unsupported operator '{condition.op}' for column 'key'."
68
+ )
69
+
70
+ condition.applied = True
71
+
72
+ if condition.column == "type":
73
+ if condition.op == FilterOperator.EQUAL:
74
+ space_type = condition.value
75
+
76
+ else:
77
+ raise ValueError(
78
+ f"Unsupported operator '{condition.op}' for column 'type'."
79
+ )
80
+
81
+ condition.applied = True
82
+
83
+ if condition.column == "status":
84
+ if condition.op == FilterOperator.EQUAL:
85
+ status = condition.value
86
+
87
+ else:
88
+ raise ValueError(
89
+ f"Unsupported operator '{condition.op}' for column 'status'."
90
+ )
91
+
92
+ condition.applied = True
93
+
94
+ sort_condition = None
95
+ if sort:
96
+ for sort_column in sort:
97
+ if sort_column.column in ["id", "key", "name"]:
98
+ if sort_column.ascending:
99
+ sort_condition = sort_column.column
100
+
101
+ else:
102
+ sort_condition = f"-{sort_column.column}"
103
+
104
+ sort_column.applied = True
105
+ break
106
+
107
+ spaces = client.get_spaces(
108
+ ids=ids,
109
+ keys=keys,
110
+ space_type=space_type,
111
+ status=status,
112
+ sort_condition=sort_condition,
113
+ limit=limit
114
+ )
115
+
116
+ spaces_df = pd.json_normalize(spaces, sep="_")
117
+ spaces_df = spaces_df[self.get_columns()]
118
+
119
+ return spaces_df
120
+
121
+ def get_columns(self) -> List[str]:
122
+ """
123
+ Retrieves the attributes (columns) of the 'spaces' resource.
124
+
125
+ Returns:
126
+ List[Text]: A list of attributes (columns) of the 'spaces' resource.
127
+ """
128
+ return [
129
+ "id",
130
+ "key",
131
+ "name",
132
+ "type",
133
+ "description_view_representation",
134
+ "description_view_value",
135
+ "status",
136
+ "authorId",
137
+ "createdAt",
138
+ "homepageId",
139
+ "_links_webui",
140
+ "currentActiveAlias",
141
+ ]
142
+
143
+
144
+ class ConfluencePagesTable(APIResource):
145
+ """
146
+ The table abstraction for the 'pages' resource of the Confluence API.
147
+ """
148
+ def list(
149
+ self,
150
+ conditions: List[FilterCondition] = None,
151
+ limit: int = None,
152
+ sort: List[SortColumn] = None,
153
+ targets: List[str] = None,
154
+ **kwargs
155
+ ):
156
+ """
157
+ Executes a parsed SELECT SQL query on the 'pages' resource of the Confluence API.
158
+
159
+ Args:
160
+ conditions (List[FilterCondition]): The list of parsed filter conditions.
161
+ limit (int): The maximum number of records to return.
162
+ sort (List[SortColumn]): The list of parsed sort columns.
163
+ targets (List[str]): The list of target columns to return.
164
+ """
165
+ pages = []
166
+ client: ConfluenceAPIClient = self.handler.connect()
167
+
168
+ page_ids, space_ids, statuses, title = None, None, None, None
169
+ for condition in conditions:
170
+ if condition.column == "id":
171
+ if condition.op == FilterOperator.EQUAL:
172
+ page_ids = [condition.value]
173
+
174
+ elif condition.op == FilterOperator.IN:
175
+ page_ids = condition.value
176
+
177
+ else:
178
+ raise ValueError(
179
+ f"Unsupported operator '{condition.op}' for column 'page_id'."
180
+ )
181
+
182
+ condition.applied = True
183
+
184
+ if condition.column == "spaceId":
185
+ if condition.op == FilterOperator.EQUAL:
186
+ space_ids = [condition.value]
187
+
188
+ elif condition.op == FilterOperator.IN:
189
+ space_ids = condition.value
190
+
191
+ else:
192
+ raise ValueError(
193
+ f"Unsupported operator '{condition.op}' for column 'spaceId'."
194
+ )
195
+
196
+ condition.applied = True
197
+
198
+ if condition.column == "status":
199
+ if condition.op == FilterOperator.EQUAL:
200
+ statuses = [condition.value]
201
+
202
+ elif condition.op == FilterOperator.IN:
203
+ statuses = condition.value
204
+
205
+ else:
206
+ raise ValueError(
207
+ f"Unsupported operator '{condition.op}' for column 'status'."
208
+ )
209
+
210
+ condition.applied = True
211
+
212
+ if condition.column == "title":
213
+ if condition.op == FilterOperator.EQUAL:
214
+ title = condition.value
215
+
216
+ else:
217
+ raise ValueError(
218
+ f"Unsupported operator '{condition.op}' for column 'title'."
219
+ )
220
+
221
+ condition.applied = True
222
+
223
+ sort_condition = None
224
+ if sort:
225
+ for sort_column in sort:
226
+ if sort_column.column in ["id", "title", "createdAt"]:
227
+ sort_condition = sort_column.column if sort_column != "createdAt" else "created-date"
228
+ if not sort_column.ascending:
229
+ sort_condition = f"-{sort_condition}"
230
+
231
+ sort_column.applied = True
232
+ break
233
+
234
+ pages = client.get_pages(
235
+ page_ids=page_ids,
236
+ space_ids=space_ids,
237
+ statuses=statuses,
238
+ title=title,
239
+ sort_condition=sort_condition,
240
+ limit=limit
241
+ )
242
+
243
+ pages_df = pd.json_normalize(pages, sep="_")
244
+ pages_df = pages_df[self.get_columns()]
245
+
246
+ return pages_df
247
+
248
+ def get_columns(self) -> List[str]:
249
+ """
250
+ Retrieves the attributes (columns) of the 'pages' resource.
251
+
252
+ Returns:
253
+ List[Text]: A list of attributes (columns) of the 'pages' resource.
254
+ """
255
+ return [
256
+ "id",
257
+ "status",
258
+ "title",
259
+ "spaceId",
260
+ "parentId",
261
+ "parentType",
262
+ "position",
263
+ "authorId",
264
+ "ownerId",
265
+ "lastOwnerId",
266
+ "createdAt",
267
+ "version_createdAt",
268
+ "version_message",
269
+ "version_number",
270
+ "version_minorEdit",
271
+ "version_authorId",
272
+ "body_storage_representation",
273
+ "body_storage_value",
274
+ "_links_webui",
275
+ "_links_editui",
276
+ "_links_tinyui",
277
+ ]
278
+
279
+
280
+ class ConfluenceBlogPostsTable(APIResource):
281
+ """
282
+ The table abstraction for the 'blogposts' resource of the Confluence API.
283
+ """
284
+ def list(
285
+ self,
286
+ conditions: List[FilterCondition] = None,
287
+ limit: int = None,
288
+ sort: List[SortColumn] = None,
289
+ targets: List[str] = None,
290
+ **kwargs
291
+ ):
292
+ """
293
+ Executes a parsed SELECT SQL query on the 'blogposts' resource of the Confluence API.
294
+
295
+ Args:
296
+ conditions (List[FilterCondition]): The list of parsed filter conditions.
297
+ limit (int): The maximum number of records to return.
298
+ sort (List[SortColumn]): The list of parsed sort columns.
299
+ targets (List[str]): The list of target columns to return.
300
+ """
301
+ blogposts = []
302
+ client: ConfluenceAPIClient = self.handler.connect()
303
+
304
+ post_ids, space_ids, statuses, title = None, None, None, None
305
+ for condition in conditions:
306
+ if condition.column == "id":
307
+ if condition.op == FilterOperator.EQUAL:
308
+ post_ids = [condition.value]
309
+
310
+ elif condition.op == FilterOperator.IN:
311
+ post_ids = condition.value
312
+
313
+ else:
314
+ raise ValueError(
315
+ f"Unsupported operator '{condition.op}' for column 'id'."
316
+ )
317
+
318
+ condition.applied = True
319
+
320
+ if condition.column == "spaceId":
321
+ if condition.op == FilterOperator.EQUAL:
322
+ space_ids = [condition.value]
323
+
324
+ elif condition.op == FilterOperator.IN:
325
+ space_ids = condition.value
326
+
327
+ else:
328
+ raise ValueError(
329
+ f"Unsupported operator '{condition.op}' for column 'spaceKey'."
330
+ )
331
+
332
+ condition.applied = True
333
+
334
+ if condition.column == "status":
335
+ if condition.op == FilterOperator.EQUAL:
336
+ statuses = [condition.value]
337
+
338
+ elif condition.op == FilterOperator.IN:
339
+ statuses = condition.value
340
+
341
+ else:
342
+ raise ValueError(
343
+ f"Unsupported operator '{condition.op}' for column 'status'."
344
+ )
345
+
346
+ condition.applied = True
347
+
348
+ if condition.column == "title":
349
+ if condition.op == FilterOperator.EQUAL:
350
+ title = condition.value
351
+
352
+ else:
353
+ raise ValueError(
354
+ f"Unsupported operator '{condition.op}' for column 'title'."
355
+ )
356
+
357
+ condition.applied = True
358
+
359
+ sort_condition = None
360
+ if sort:
361
+ for sort_column in sort:
362
+ if sort_column.column in ["id", "title", "createdAt"]:
363
+ sort_condition = sort_column.column if sort_column != "createdAt" else "created-date"
364
+ if not sort_column.ascending:
365
+ sort_condition = f"-{sort_condition}"
366
+
367
+ sort_column.applied = True
368
+ break
369
+
370
+ blogposts = client.get_blogposts(
371
+ post_ids=post_ids,
372
+ space_ids=space_ids,
373
+ statuses=statuses,
374
+ title=title,
375
+ sort_condition=sort_condition,
376
+ limit=limit
377
+ )
378
+
379
+ blogposts_df = pd.json_normalize(blogposts, sep="_")
380
+ blogposts_df = blogposts_df[self.get_columns()]
381
+
382
+ return blogposts_df
383
+
384
+ def get_columns(self) -> List[str]:
385
+ """
386
+ Retrieves the attributes (columns) of the 'blogposts' resource.
387
+
388
+ Returns:
389
+ List[Text]: A list of attributes (columns) of the 'blogposts' resource.
390
+ """
391
+ return [
392
+ "id",
393
+ "status",
394
+ "title",
395
+ "spaceId",
396
+ "authorId",
397
+ "createdAt",
398
+ "version_createdAt",
399
+ "version_message",
400
+ "version_number",
401
+ "version_minorEdit",
402
+ "version_authorId",
403
+ "body_storage_representation",
404
+ "body_storage_value",
405
+ "_links_webui",
406
+ "_links_editui",
407
+ "_links_tinyui",
408
+ ]
409
+
410
+
411
+ class ConfluenceWhiteboardsTable(APIResource):
412
+ """
413
+ The table abstraction for the 'whiteboards' resource of the Confluence API.
414
+ """
415
+ def list(
416
+ self,
417
+ conditions: List[FilterCondition] = None,
418
+ limit: int = None,
419
+ sort: List[SortColumn] = None,
420
+ targets: List[str] = None,
421
+ **kwargs
422
+ ):
423
+ """
424
+ Executes a parsed SELECT SQL query on the 'whiteboards' resource of the Confluence API.
425
+
426
+ Args:
427
+ conditions (List[FilterCondition]): The list of parsed filter conditions.
428
+ limit (int): The maximum number of records to return.
429
+ sort (List[SortColumn]): The list of parsed sort columns.
430
+ targets (List[str]): The list of target columns to return.
431
+ """
432
+ whiteboards = []
433
+ client: ConfluenceAPIClient = self.handler.connect()
434
+
435
+ whiteboard_ids = None
436
+ for condition in conditions:
437
+ if condition.column == "id":
438
+ if condition.op == FilterOperator.EQUAL:
439
+ whiteboard_ids = [condition.value]
440
+
441
+ elif condition.op == FilterOperator.IN:
442
+ whiteboard_ids = condition.value
443
+
444
+ else:
445
+ raise ValueError(
446
+ f"Unsupported operator '{condition.op}' for column 'id'."
447
+ )
448
+
449
+ condition.applied = True
450
+
451
+ if not whiteboard_ids:
452
+ raise ValueError("The 'id' column must be provided in the WHERE clause.")
453
+
454
+ whiteboards = [client.get_whiteboard_by_id(whiteboard_id) for whiteboard_id in whiteboard_ids]
455
+
456
+ whiteboards_df = pd.json_normalize(whiteboards, sep="_")
457
+ whiteboards_df = whiteboards_df[self.get_columns()]
458
+
459
+ return whiteboards_df
460
+
461
+ def get_columns(self) -> List[str]:
462
+ """
463
+ Retrieves the attributes (columns) of the 'whiteboards' resource.
464
+
465
+ Returns:
466
+ List[Text]: A list of attributes (columns) of the 'whiteboards' resource.
467
+ """
468
+ return [
469
+ "id",
470
+ "type",
471
+ "status",
472
+ "title",
473
+ "parentId",
474
+ "parentType",
475
+ "position",
476
+ "authorId",
477
+ "ownerId",
478
+ "createdAt",
479
+ "version_createdAt",
480
+ "version_message",
481
+ "version_number",
482
+ "version_minorEdit",
483
+ "version_authorId",
484
+ ]
485
+
486
+
487
+ class ConfluenceDatabasesTable(APIResource):
488
+ """
489
+ The table abstraction for the 'databases' resource of the Confluence API.
490
+ """
491
+ def list(
492
+ self,
493
+ conditions: List[FilterCondition] = None,
494
+ limit: int = None,
495
+ sort: List[SortColumn] = None,
496
+ targets: List[str] = None,
497
+ **kwargs
498
+ ):
499
+ """
500
+ Executes a parsed SELECT SQL query on the 'databases' resource of the Confluence API.
501
+
502
+ Args:
503
+ conditions (List[FilterCondition]): The list of parsed filter conditions.
504
+ limit (int): The maximum number of records to return.
505
+ sort (List[SortColumn]): The list of parsed sort columns.
506
+ targets (List[str]): The list of target columns to return.
507
+ """
508
+ databases = []
509
+ client: ConfluenceAPIClient = self.handler.connect()
510
+
511
+ database_ids = None
512
+ for condition in conditions:
513
+ if condition.column == "id":
514
+ if condition.op == FilterOperator.EQUAL:
515
+ database_ids = [condition.value]
516
+
517
+ elif condition.op == FilterOperator.IN:
518
+ database_ids = condition.value
519
+
520
+ else:
521
+ raise ValueError(
522
+ f"Unsupported operator '{condition.op}' for column 'id'."
523
+ )
524
+
525
+ condition.applied = True
526
+
527
+ if not database_ids:
528
+ raise ValueError("The 'id' column must be provided in the WHERE clause.")
529
+
530
+ databases = [client.get_database_by_id(database_id) for database_id in database_ids]
531
+
532
+ databases_df = pd.json_normalize(databases, sep="_")
533
+ databases_df = databases_df[self.get_columns()]
534
+
535
+ return databases_df
536
+
537
+ def get_columns(self) -> List[str]:
538
+ """
539
+ Retrieves the attributes (columns) of the 'databases' resource.
540
+
541
+ Returns:
542
+ List[Text]: A list of attributes (columns) of the 'databases' resource.
543
+ """
544
+ return [
545
+ "id",
546
+ "type",
547
+ "status",
548
+ "title",
549
+ "parentId",
550
+ "parentType",
551
+ "position",
552
+ "authorId",
553
+ "ownerId",
554
+ "createdAt",
555
+ "version_createdAt",
556
+ "version_message",
557
+ "version_number",
558
+ "version_minorEdit",
559
+ "version_authorId",
560
+ ]
561
+
562
+
563
+ class ConfluenceTasksTable(APIResource):
564
+ """
565
+ The table abstraction for the 'tasks' resource of the Confluence API.
566
+ """
567
+ def list(
568
+ self,
569
+ conditions: List[FilterCondition] = None,
570
+ limit: int = None,
571
+ sort: List[SortColumn] = None,
572
+ targets: List[str] = None,
573
+ **kwargs
574
+ ):
575
+ """
576
+ Executes a parsed SELECT SQL query on the 'tasks' resource of the Confluence API.
577
+
578
+ Args:
579
+ conditions (List[FilterCondition]): The list of parsed filter conditions.
580
+ limit (int): The maximum number of records to return.
581
+ sort (List[SortColumn]): The list of parsed sort columns.
582
+ targets (List[str]): The list of target columns to return.
583
+ """
584
+ tasks = []
585
+ client: ConfluenceAPIClient = self.handler.connect()
586
+
587
+ task_ids = None
588
+ space_ids = None
589
+ page_ids = None
590
+ blogpost_ids = None
591
+ created_by_ids = None
592
+ assigned_to_ids = None
593
+ completed_by_ids = None
594
+ status = None
595
+
596
+ for condition in conditions:
597
+ if condition.column == "id":
598
+ if condition.op == FilterOperator.EQUAL:
599
+ task_ids = [condition.value]
600
+
601
+ elif condition.op == FilterOperator.IN:
602
+ task_ids = condition.value
603
+
604
+ else:
605
+ raise ValueError(
606
+ f"Unsupported operator '{condition.op}' for column 'id'."
607
+ )
608
+
609
+ condition.applied = True
610
+
611
+ if condition.column == "spaceId":
612
+ if condition.op == FilterOperator.EQUAL:
613
+ space_ids = [condition.value]
614
+
615
+ elif condition.op == FilterOperator.IN:
616
+ space_ids = condition.value
617
+
618
+ else:
619
+ raise ValueError(
620
+ f"Unsupported operator '{condition.op}' for column 'spaceId'."
621
+ )
622
+
623
+ condition.applied = True
624
+
625
+ if condition.column == "pageId":
626
+ if condition.op == FilterOperator.EQUAL:
627
+ page_ids = [condition.value]
628
+
629
+ elif condition.op == FilterOperator.IN:
630
+ page_ids = condition.value
631
+
632
+ else:
633
+ raise ValueError(
634
+ f"Unsupported operator '{condition.op}' for column 'pageId'."
635
+ )
636
+
637
+ condition.applied = True
638
+
639
+ if condition.column == "blogPostId":
640
+ if condition.op == FilterOperator.EQUAL:
641
+ blogpost_ids = [condition.value]
642
+
643
+ elif condition.op == FilterOperator.IN:
644
+ blogpost_ids = condition.value
645
+
646
+ else:
647
+ raise ValueError(
648
+ f"Unsupported operator '{condition.op}' for column 'blogPostId'."
649
+ )
650
+
651
+ condition.applied = True
652
+
653
+ if condition.column == "createdBy":
654
+ if condition.op == FilterOperator.EQUAL:
655
+ created_by_ids = [condition.value]
656
+
657
+ elif condition.op == FilterOperator.IN:
658
+ created_by_ids = condition.value
659
+
660
+ else:
661
+ raise ValueError(
662
+ f"Unsupported operator '{condition.op}' for column 'createdBy'."
663
+ )
664
+
665
+ condition.applied = True
666
+
667
+ if condition.column == "assignedTo":
668
+ if condition.op == FilterOperator.EQUAL:
669
+ assigned_to_ids = [condition.value]
670
+
671
+ elif condition.op == FilterOperator.IN:
672
+ assigned_to_ids = condition.value
673
+
674
+ else:
675
+ raise ValueError(
676
+ f"Unsupported operator '{condition.op}' for column 'assignedTo'."
677
+ )
678
+
679
+ condition.applied = True
680
+
681
+ if condition.column == "completedBy":
682
+ if condition.op == FilterOperator.EQUAL:
683
+ completed_by_ids = [condition.value]
684
+
685
+ elif condition.op == FilterOperator.IN:
686
+ completed_by_ids = condition.value
687
+
688
+ else:
689
+ raise ValueError(
690
+ f"Unsupported operator '{condition.op}' for column 'completedBy'."
691
+ )
692
+
693
+ condition.applied = True
694
+
695
+ if condition.column == "status":
696
+ if condition.op == FilterOperator.EQUAL:
697
+ status = condition.value
698
+
699
+ else:
700
+ raise ValueError(
701
+ f"Unsupported operator '{condition.op}' for column 'status'."
702
+ )
703
+
704
+ condition.applied = True
705
+
706
+ tasks = client.get_tasks(
707
+ task_ids=task_ids,
708
+ space_ids=space_ids,
709
+ page_ids=page_ids,
710
+ blogpost_ids=blogpost_ids,
711
+ created_by_ids=created_by_ids,
712
+ assigned_to_ids=assigned_to_ids,
713
+ completed_by_ids=completed_by_ids,
714
+ status=status,
715
+ limit=limit
716
+ )
717
+ tasks_df = pd.json_normalize(tasks, sep="_")
718
+
719
+ # Each task will have either a 'pageId' or 'blogPostId' but not both.
720
+ # In situations where they are all from the same resource, the other column will be empty.
721
+ # We will fill the empty column with None to ensure consistency.
722
+ for column in ["pageId", "blogPostId"]:
723
+ if column not in tasks_df.columns:
724
+ tasks_df[column] = None
725
+
726
+ tasks_df = tasks_df[self.get_columns()]
727
+
728
+ return tasks_df
729
+
730
+ def get_columns(self) -> List[str]:
731
+ """
732
+ Retrieves the attributes (columns) of the 'tasks' resource.
733
+
734
+ Returns:
735
+ List[Text]: A list of attributes (columns) of the 'tasks' resource.
736
+ """
737
+ return [
738
+ "id",
739
+ "localId",
740
+ "spaceId",
741
+ "pageId",
742
+ "blogPostId",
743
+ "status",
744
+ "body_storage_representation",
745
+ "body_storage_value",
746
+ "createdBy",
747
+ "assignedTo",
748
+ "completedBy",
749
+ "createdAt",
750
+ "updatedAt",
751
+ "dueAt",
752
+ "completedAt",
753
+ ]