semantic-link-labs 0.12.1__py3-none-any.whl → 0.12.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.
Potentially problematic release.
This version of semantic-link-labs might be problematic. Click here for more details.
- {semantic_link_labs-0.12.1.dist-info → semantic_link_labs-0.12.2.dist-info}/METADATA +3 -2
- {semantic_link_labs-0.12.1.dist-info → semantic_link_labs-0.12.2.dist-info}/RECORD +27 -23
- sempy_labs/__init__.py +6 -0
- sempy_labs/_a_lib_info.py +1 -1
- sempy_labs/_data_access_security.py +98 -0
- sempy_labs/_data_pipelines.py +23 -9
- sempy_labs/_dataflows.py +0 -1
- sempy_labs/_deployment_pipelines.py +49 -27
- sempy_labs/_eventstreams.py +9 -1
- sempy_labs/_helper_functions.py +16 -1
- sempy_labs/_job_scheduler.py +63 -33
- sempy_labs/_labels.py +4 -6
- sempy_labs/_model_dependencies.py +5 -2
- sempy_labs/_warehouses.py +55 -0
- sempy_labs/admin/__init__.py +6 -0
- sempy_labs/admin/_sharing_links.py +110 -0
- sempy_labs/graph/__init__.py +12 -0
- sempy_labs/graph/_groups.py +157 -2
- sempy_labs/graph/_users.py +162 -0
- sempy_labs/lakehouse/_shortcuts.py +16 -11
- sempy_labs/report/_bpareporttemplate/.pbi/localSettings.json +9 -0
- sempy_labs/report/_bpareporttemplate/.platform +11 -0
- sempy_labs/report/_reportwrapper.py +53 -6
- sempy_labs/tom/_model.py +22 -9
- {semantic_link_labs-0.12.1.dist-info → semantic_link_labs-0.12.2.dist-info}/WHEEL +0 -0
- {semantic_link_labs-0.12.1.dist-info → semantic_link_labs-0.12.2.dist-info}/licenses/LICENSE +0 -0
- {semantic_link_labs-0.12.1.dist-info → semantic_link_labs-0.12.2.dist-info}/top_level.txt +0 -0
sempy_labs/_job_scheduler.py
CHANGED
|
@@ -8,6 +8,7 @@ from sempy_labs._helper_functions import (
|
|
|
8
8
|
_base_api,
|
|
9
9
|
_create_dataframe,
|
|
10
10
|
resolve_workspace_id,
|
|
11
|
+
resolve_item_id,
|
|
11
12
|
)
|
|
12
13
|
from uuid import UUID
|
|
13
14
|
import sempy_labs._icons as icons
|
|
@@ -113,7 +114,7 @@ def _get_item_job_instance(url: str) -> pd.DataFrame:
|
|
|
113
114
|
}
|
|
114
115
|
df = _create_dataframe(columns=columns)
|
|
115
116
|
|
|
116
|
-
response = _base_api(request=url)
|
|
117
|
+
response = _base_api(request=url, client="fabric_sp")
|
|
117
118
|
|
|
118
119
|
rows = []
|
|
119
120
|
for v in response.json().get("value", []):
|
|
@@ -171,11 +172,9 @@ def list_item_schedules(
|
|
|
171
172
|
"""
|
|
172
173
|
|
|
173
174
|
workspace_id = resolve_workspace_id(workspace)
|
|
174
|
-
(
|
|
175
|
-
item=item, type=type, workspace=workspace_id
|
|
176
|
-
)
|
|
175
|
+
item_id = resolve_item_id(item=item, type=type, workspace=workspace_id)
|
|
177
176
|
|
|
178
|
-
|
|
177
|
+
base_columns = {
|
|
179
178
|
"Job Schedule Id": "string",
|
|
180
179
|
"Enabled": "bool",
|
|
181
180
|
"Created Date Time": "datetime",
|
|
@@ -183,48 +182,75 @@ def list_item_schedules(
|
|
|
183
182
|
"End Date Time": "string",
|
|
184
183
|
"Local Time Zone Id": "string",
|
|
185
184
|
"Type": "string",
|
|
186
|
-
"Interval": "string",
|
|
187
|
-
"Weekdays": "string",
|
|
188
|
-
"Times": "string",
|
|
189
185
|
"Owner Id": "string",
|
|
190
186
|
"Owner Type": "string",
|
|
191
|
-
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
optional_columns = {
|
|
190
|
+
"Occurrence Day of Month": "int_fillna",
|
|
191
|
+
"Occurrence Week Index": "string",
|
|
192
|
+
"Occurrence Weekday": "string",
|
|
192
193
|
"Occurrence Type": "string",
|
|
193
|
-
"
|
|
194
|
+
"Interval": "int_fillna",
|
|
195
|
+
"Times": "string",
|
|
196
|
+
"Recurrence": "int_fillna",
|
|
197
|
+
"Weekdays": "string",
|
|
194
198
|
}
|
|
195
|
-
df = _create_dataframe(columns=columns)
|
|
196
199
|
|
|
197
200
|
response = _base_api(
|
|
198
|
-
request=f"v1/workspaces/{workspace_id}/items/{item_id}/jobs/{job_type}/schedules"
|
|
201
|
+
request=f"v1/workspaces/{workspace_id}/items/{item_id}/jobs/{job_type}/schedules",
|
|
202
|
+
client="fabric_sp",
|
|
199
203
|
)
|
|
200
204
|
|
|
201
205
|
rows = []
|
|
202
206
|
for v in response.json().get("value", []):
|
|
203
207
|
config = v.get("configuration", {})
|
|
204
208
|
own = v.get("owner", {})
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
209
|
+
occurrence = config.get("occurrence", {})
|
|
210
|
+
type = config.get("type")
|
|
211
|
+
|
|
212
|
+
row = {
|
|
213
|
+
"Job Schedule Id": v.get("id"),
|
|
214
|
+
"Enabled": v.get("enabled"),
|
|
215
|
+
"Created Date Time": v.get("createdDateTime"),
|
|
216
|
+
"Start Date Time": config.get("startDateTime"),
|
|
217
|
+
"End Date Time": config.get("endDateTime"),
|
|
218
|
+
"Local Time Zone Id": config.get("localTimeZoneId"),
|
|
219
|
+
"Type": type,
|
|
220
|
+
"Owner Id": own.get("id"),
|
|
221
|
+
"Owner Type": own.get("type"),
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if type == "Cron":
|
|
225
|
+
row["Interval"] = config.get("interval")
|
|
226
|
+
elif type == "Daily":
|
|
227
|
+
row["Times"] = config.get("times")
|
|
228
|
+
elif type == "Weekly":
|
|
229
|
+
row["Times"] = config.get("times")
|
|
230
|
+
row["Weekdays"] = config.get("weekdays")
|
|
231
|
+
elif type == "Monthly":
|
|
232
|
+
occurrence_type = occurrence.get("occurrenceType")
|
|
233
|
+
row["Times"] = config.get("times")
|
|
234
|
+
row["Recurrence"] = config.get("recurrence")
|
|
235
|
+
row["Occurrence Type"] = occurrence_type
|
|
236
|
+
|
|
237
|
+
if occurrence_type == "OrdinalWeekday":
|
|
238
|
+
row["Occurrence Week Index"] = occurrence.get("weekIndex")
|
|
239
|
+
row["Occurrence Weekday"] = occurrence.get("weekday")
|
|
240
|
+
elif occurrence_type == "DayOfMonth":
|
|
241
|
+
row["Occurrence Day of Month"] = occurrence.get("dayOfMonth")
|
|
242
|
+
|
|
243
|
+
rows.append(row)
|
|
244
|
+
|
|
245
|
+
# Build final column map based on what was actually present
|
|
246
|
+
columns = base_columns.copy()
|
|
226
247
|
|
|
227
248
|
if rows:
|
|
249
|
+
# Find which optional columns were actually included in rows
|
|
250
|
+
all_used_columns = set().union(*(r.keys() for r in rows))
|
|
251
|
+
for col in all_used_columns:
|
|
252
|
+
if col in optional_columns:
|
|
253
|
+
columns[col] = optional_columns[col]
|
|
228
254
|
df = pd.DataFrame(rows, columns=list(columns.keys()))
|
|
229
255
|
_update_dataframe_datatypes(dataframe=df, column_map=columns)
|
|
230
256
|
|
|
@@ -267,6 +293,7 @@ def run_on_demand_item_job(
|
|
|
267
293
|
method="post",
|
|
268
294
|
lro_return_status_code=True,
|
|
269
295
|
status_codes=202,
|
|
296
|
+
client="fabric_sp",
|
|
270
297
|
)
|
|
271
298
|
|
|
272
299
|
print(f"{icons.green_dot} The '{item_name}' {type.lower()} has been executed.")
|
|
@@ -334,6 +361,7 @@ def create_item_schedule_cron(
|
|
|
334
361
|
method="post",
|
|
335
362
|
payload=payload,
|
|
336
363
|
status_codes=201,
|
|
364
|
+
client="fabric_sp",
|
|
337
365
|
)
|
|
338
366
|
|
|
339
367
|
print(
|
|
@@ -403,6 +431,7 @@ def create_item_schedule_daily(
|
|
|
403
431
|
method="post",
|
|
404
432
|
payload=payload,
|
|
405
433
|
status_codes=201,
|
|
434
|
+
client="fabric_sp",
|
|
406
435
|
)
|
|
407
436
|
|
|
408
437
|
print(
|
|
@@ -492,6 +521,7 @@ def create_item_schedule_weekly(
|
|
|
492
521
|
method="post",
|
|
493
522
|
payload=payload,
|
|
494
523
|
status_codes=201,
|
|
524
|
+
client="fabric_sp",
|
|
495
525
|
)
|
|
496
526
|
|
|
497
527
|
print(
|
sempy_labs/_labels.py
CHANGED
|
@@ -5,6 +5,9 @@ from typing import Optional, Union
|
|
|
5
5
|
from uuid import UUID
|
|
6
6
|
from sempy.fabric.exceptions import FabricHTTPException
|
|
7
7
|
from sempy._utils._log import log
|
|
8
|
+
from sempy_labs._helper_functions import (
|
|
9
|
+
_get_url_prefix,
|
|
10
|
+
)
|
|
8
11
|
|
|
9
12
|
|
|
10
13
|
@log
|
|
@@ -87,12 +90,7 @@ def list_item_labels(workspace: Optional[Union[str, UUID]] = None) -> pd.DataFra
|
|
|
87
90
|
if artifact_ids:
|
|
88
91
|
payload["artifacts"] = [{"artifactId": i} for i in artifact_ids]
|
|
89
92
|
|
|
90
|
-
|
|
91
|
-
response = client.get("/v1.0/myorg/capacities")
|
|
92
|
-
if response.status_code != 200:
|
|
93
|
-
raise FabricHTTPException("Failed to retrieve URL prefix.")
|
|
94
|
-
context = response.json().get("@odata.context")
|
|
95
|
-
prefix = context.split("/v1.0")[0]
|
|
93
|
+
prefix = _get_url_prefix()
|
|
96
94
|
|
|
97
95
|
response = requests.post(
|
|
98
96
|
f"{prefix}/metadata/informationProtection/artifacts",
|
|
@@ -334,7 +334,10 @@ def measure_dependency_tree(
|
|
|
334
334
|
|
|
335
335
|
# Visualize the tree structure using RenderTree
|
|
336
336
|
for pre, _, node in RenderTree(node_dict[measure_name]):
|
|
337
|
-
if
|
|
337
|
+
if (
|
|
338
|
+
hasattr(node, "custom_property")
|
|
339
|
+
and icons.table_icon in node.custom_property
|
|
340
|
+
):
|
|
338
341
|
print(f"{pre}{node.custom_property}'{node.name}'")
|
|
339
342
|
else:
|
|
340
|
-
print(f"{pre}{node.
|
|
343
|
+
print(f"{pre}'{node.name}'")
|
sempy_labs/_warehouses.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from ._helper_functions import (
|
|
2
|
+
resolve_item_id,
|
|
2
3
|
resolve_workspace_name_and_id,
|
|
3
4
|
_base_api,
|
|
4
5
|
_create_dataframe,
|
|
@@ -232,3 +233,57 @@ def get_warehouse_columns(
|
|
|
232
233
|
)
|
|
233
234
|
|
|
234
235
|
return df
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
@log
|
|
239
|
+
def get_warehouse_connection_string(
|
|
240
|
+
warehouse: str | UUID,
|
|
241
|
+
workspace: Optional[str | UUID] = None,
|
|
242
|
+
guest_tenant_id: Optional[UUID] = None,
|
|
243
|
+
private_link_type: Optional[str] = None,
|
|
244
|
+
) -> str:
|
|
245
|
+
"""
|
|
246
|
+
Returns the SQL connection string of the specified warehouse.
|
|
247
|
+
|
|
248
|
+
Parameters
|
|
249
|
+
----------
|
|
250
|
+
warehouse : str | uuid.UUID
|
|
251
|
+
Name or ID of the Fabric warehouse.
|
|
252
|
+
workspace : str | uuid.UUID, default=None
|
|
253
|
+
The Fabric workspace name or ID.
|
|
254
|
+
Defaults to None which resolves to the workspace of the attached lakehouse
|
|
255
|
+
or if no lakehouse attached, resolves to the workspace of the notebook.
|
|
256
|
+
guest_tenant_id : uuid.UUID, default=None
|
|
257
|
+
The guest tenant ID if the end user's tenant is different from the warehouse tenant.
|
|
258
|
+
private_link_type : str, default=None
|
|
259
|
+
Indicates the type of private link this connection string uses. Must be either 'Workspace' or 'None' or left as None.
|
|
260
|
+
|
|
261
|
+
Returns
|
|
262
|
+
-------
|
|
263
|
+
str
|
|
264
|
+
Returns the SQL connection string of the specified warehouse.
|
|
265
|
+
"""
|
|
266
|
+
workspace_id = resolve_workspace_id(workspace)
|
|
267
|
+
warehouse_id = resolve_item_id(
|
|
268
|
+
item=warehouse, type="Warehouse", workspace=workspace
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
url = f"/v1/workspaces/{workspace_id}/warehouses/{warehouse_id}/connectionString"
|
|
272
|
+
|
|
273
|
+
if private_link_type is not None and private_link_type not in ["Workspace", "None"]:
|
|
274
|
+
raise ValueError(
|
|
275
|
+
f"{icons.red_dot} private_link_type must be 'Workspace' or 'None' or left as None."
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
if guest_tenant_id or private_link_type:
|
|
279
|
+
params = []
|
|
280
|
+
if guest_tenant_id:
|
|
281
|
+
params.append(f"guestTenantId={guest_tenant_id}")
|
|
282
|
+
if private_link_type:
|
|
283
|
+
params.append(f"privateLinkType={private_link_type}")
|
|
284
|
+
param_str = "?" + "&".join(params)
|
|
285
|
+
url += param_str
|
|
286
|
+
|
|
287
|
+
response = _base_api(request=url, client="fabric_sp")
|
|
288
|
+
|
|
289
|
+
return response.json().get("connectionString")
|
sempy_labs/admin/__init__.py
CHANGED
|
@@ -94,6 +94,10 @@ from ._tenant_keys import (
|
|
|
94
94
|
list_tenant_keys,
|
|
95
95
|
rotate_tenant_key,
|
|
96
96
|
)
|
|
97
|
+
from ._sharing_links import (
|
|
98
|
+
remove_all_sharing_links,
|
|
99
|
+
remove_sharing_links,
|
|
100
|
+
)
|
|
97
101
|
|
|
98
102
|
__all__ = [
|
|
99
103
|
"list_items",
|
|
@@ -155,4 +159,6 @@ __all__ = [
|
|
|
155
159
|
"delete_tag",
|
|
156
160
|
"list_tenant_keys",
|
|
157
161
|
"rotate_tenant_key",
|
|
162
|
+
"remove_all_sharing_links",
|
|
163
|
+
"remove_sharing_links",
|
|
158
164
|
]
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
from sempy._utils._log import log
|
|
2
|
+
from sempy_labs._helper_functions import (
|
|
3
|
+
_base_api,
|
|
4
|
+
_is_valid_uuid,
|
|
5
|
+
)
|
|
6
|
+
import sempy_labs._icons as icons
|
|
7
|
+
from typing import List
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@log
|
|
11
|
+
def remove_all_sharing_links(sharing_link_type: str = "OrgLink"):
|
|
12
|
+
"""
|
|
13
|
+
Deletes all organization sharing links for all Fabric items in the tenant. This action cannot be undone.
|
|
14
|
+
|
|
15
|
+
This is a wrapper function for the following API: `Sharing Links - Remove All Sharing Links <https://learn.microsoft.com/rest/api/fabric/admin/sharing-links/remove-all-sharing-links>`_.
|
|
16
|
+
|
|
17
|
+
Service Principal Authentication is supported (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
sharing_link_type : str, default='OrgLink'
|
|
22
|
+
Specifies the type of sharing link that is required to be deleted. Additional sharing link types may be added over time.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
payload = {"sharingLinkType": sharing_link_type}
|
|
26
|
+
|
|
27
|
+
_base_api(
|
|
28
|
+
request="/v1/admin/items/removeAllSharingLinks",
|
|
29
|
+
client="fabric_sp",
|
|
30
|
+
lro_return_status_code=True,
|
|
31
|
+
status_codes=[200, 202],
|
|
32
|
+
method="post",
|
|
33
|
+
payload=payload,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
print(
|
|
37
|
+
f"{icons.green_dot} All organization sharing links for all Fbric items in the tenant have been deleted."
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@log
|
|
42
|
+
def remove_sharing_links(items: List[dict], sharing_link_type: str = "OrgLink"):
|
|
43
|
+
"""
|
|
44
|
+
Deletes all organization sharing links for the specified Fabric items. This action cannot be undone.
|
|
45
|
+
|
|
46
|
+
This is a wrapper function for the following API: `Sharing Links - Bulk Remove Sharing Links <https://learn.microsoft.com/rest/api/fabric/admin/sharing-links/bulk-remove-sharing-links>`_.
|
|
47
|
+
|
|
48
|
+
Service Principal Authentication is supported (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
49
|
+
|
|
50
|
+
Parameters
|
|
51
|
+
----------
|
|
52
|
+
items : List[dict]
|
|
53
|
+
A list of dictionaries, each representing an item. The 'item' and 'workspace' accepts either name or ID. Examples:
|
|
54
|
+
|
|
55
|
+
[
|
|
56
|
+
{
|
|
57
|
+
"item": "MyReport",
|
|
58
|
+
"type": "Report",
|
|
59
|
+
"workspace": "Workpsace 1",
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"item": "MyReport2",
|
|
63
|
+
"type": "Report",
|
|
64
|
+
"workspace": "Workspace 2",
|
|
65
|
+
},
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
[
|
|
69
|
+
{
|
|
70
|
+
"item": "fe472f5e-636e-4c10-a1c6-7e9edc0b542a",
|
|
71
|
+
"type": "Report",
|
|
72
|
+
"workspace": "Workspace 1",
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"item": "fe472f5e-636e-4c10-a1c6-7e9edc0b542c",
|
|
76
|
+
"type": "Notebook",
|
|
77
|
+
"workspace": "476fcafe-b514-495d-b13f-ca9a4f0b1d8f",
|
|
78
|
+
},
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
sharing_link_type : str, default='OrgLink'
|
|
82
|
+
Specifies the type of sharing link that is required to be deleted. Additional sharing link types may be added over time.
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
from sempy_labs.admin._items import _resolve_item_id
|
|
86
|
+
|
|
87
|
+
payload = {"items": [], "sharingLinkType": sharing_link_type}
|
|
88
|
+
|
|
89
|
+
for i in items:
|
|
90
|
+
item = i.get("item")
|
|
91
|
+
type = i.get("type")
|
|
92
|
+
workspace = i.get("workspace")
|
|
93
|
+
if _is_valid_uuid(item):
|
|
94
|
+
payload["items"].append({"id": item, "type": type})
|
|
95
|
+
else:
|
|
96
|
+
item_id = _resolve_item_id(item=item, type=type, workspace=workspace)
|
|
97
|
+
payload["items"].append({"id": item_id, "type": type})
|
|
98
|
+
|
|
99
|
+
_base_api(
|
|
100
|
+
request="/v1/admin/items/bulkRemoveSharingLinks",
|
|
101
|
+
client="fabric_sp",
|
|
102
|
+
method="post",
|
|
103
|
+
payload=payload,
|
|
104
|
+
lro_return_status_code=True,
|
|
105
|
+
status_codes=[200, 202],
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
print(
|
|
109
|
+
f"{icons.green_dot} Organizational sharing links for all specified items have been deleted."
|
|
110
|
+
)
|
sempy_labs/graph/__init__.py
CHANGED
|
@@ -6,12 +6,18 @@ from ._groups import (
|
|
|
6
6
|
add_group_owners,
|
|
7
7
|
resolve_group_id,
|
|
8
8
|
renew_group,
|
|
9
|
+
create_group,
|
|
10
|
+
delete_group,
|
|
11
|
+
update_group,
|
|
9
12
|
)
|
|
10
13
|
from ._users import (
|
|
11
14
|
resolve_user_id,
|
|
12
15
|
get_user,
|
|
13
16
|
list_users,
|
|
14
17
|
send_mail,
|
|
18
|
+
create_user,
|
|
19
|
+
delete_user,
|
|
20
|
+
update_user,
|
|
15
21
|
)
|
|
16
22
|
from ._teams import (
|
|
17
23
|
list_teams,
|
|
@@ -30,4 +36,10 @@ __all__ = [
|
|
|
30
36
|
"list_users",
|
|
31
37
|
"send_mail",
|
|
32
38
|
"list_teams",
|
|
39
|
+
"create_user",
|
|
40
|
+
"create_group",
|
|
41
|
+
"delete_user",
|
|
42
|
+
"delete_group",
|
|
43
|
+
"update_user",
|
|
44
|
+
"update_group",
|
|
33
45
|
]
|
sempy_labs/graph/_groups.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import pandas as pd
|
|
2
2
|
from uuid import UUID
|
|
3
|
-
from
|
|
3
|
+
from sempy_labs._helper_functions import (
|
|
4
4
|
_is_valid_uuid,
|
|
5
5
|
_base_api,
|
|
6
6
|
_create_dataframe,
|
|
@@ -8,7 +8,7 @@ from .._helper_functions import (
|
|
|
8
8
|
)
|
|
9
9
|
from sempy._utils._log import log
|
|
10
10
|
import sempy_labs._icons as icons
|
|
11
|
-
from typing import List, Literal
|
|
11
|
+
from typing import List, Literal, Optional
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
@log
|
|
@@ -424,3 +424,158 @@ def renew_group(group: str | UUID):
|
|
|
424
424
|
)
|
|
425
425
|
|
|
426
426
|
print(f"{icons.green_dot} The '{group}' group has been renewed.")
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
@log
|
|
430
|
+
def create_group(
|
|
431
|
+
display_name: str,
|
|
432
|
+
description: Optional[str] = None,
|
|
433
|
+
mail_enabled: bool = False,
|
|
434
|
+
security_enabled: bool = True,
|
|
435
|
+
mail_nickname: str = None,
|
|
436
|
+
owners: Optional[str | UUID | List[str | UUID]] = None,
|
|
437
|
+
members: Optional[str | UUID | List[str | UUID]] = None,
|
|
438
|
+
):
|
|
439
|
+
"""
|
|
440
|
+
Creates a new group.
|
|
441
|
+
|
|
442
|
+
This is a wrapper function for the following API: `Create group <https://learn.microsoft.com/graph/api/group-post-groups>`_.
|
|
443
|
+
|
|
444
|
+
Service Principal Authentication is required (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
445
|
+
|
|
446
|
+
Parameters
|
|
447
|
+
----------
|
|
448
|
+
display_name : str
|
|
449
|
+
The name of the group.
|
|
450
|
+
description : str, optional
|
|
451
|
+
The description of the group.
|
|
452
|
+
mail_enabled : bool, default=False
|
|
453
|
+
Whether the group is mail-enabled.
|
|
454
|
+
security_enabled : bool, default=True
|
|
455
|
+
Whether the group is security-enabled.
|
|
456
|
+
mail_nickname : str, default=None
|
|
457
|
+
The mail alias for the group.
|
|
458
|
+
owners : str | uuid.UUID | List[str | uuid.UUID], default=None
|
|
459
|
+
The owners of the group.
|
|
460
|
+
members : str | uuid.UUID | List[str | uuid.UUID], default=None
|
|
461
|
+
The members of the group.
|
|
462
|
+
"""
|
|
463
|
+
from sempy_labs.graph._users import resolve_user_id
|
|
464
|
+
|
|
465
|
+
payload = {
|
|
466
|
+
"displayName": display_name,
|
|
467
|
+
"description": description,
|
|
468
|
+
"mailEnabled": mail_enabled,
|
|
469
|
+
"securityEnabled": security_enabled,
|
|
470
|
+
"mailNickname": mail_nickname,
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
if owners:
|
|
474
|
+
if isinstance(owners, str):
|
|
475
|
+
owners = [owners]
|
|
476
|
+
user_list = []
|
|
477
|
+
for o in owners:
|
|
478
|
+
user_id = resolve_user_id(o)
|
|
479
|
+
user_list.append(f"https://graph.microsoft.com/v1.0/users/{user_id}")
|
|
480
|
+
payload["owners@odata.bind"] = user_list
|
|
481
|
+
if members:
|
|
482
|
+
if isinstance(members, str):
|
|
483
|
+
members = [members]
|
|
484
|
+
user_list = []
|
|
485
|
+
for m in members:
|
|
486
|
+
user_id = resolve_user_id(m)
|
|
487
|
+
user_list.append(f"https://graph.microsoft.com/v1.0/users/{user_id}")
|
|
488
|
+
payload["members@odata.bind"] = user_list
|
|
489
|
+
|
|
490
|
+
_base_api(
|
|
491
|
+
request="groups",
|
|
492
|
+
client="graph",
|
|
493
|
+
payload=payload,
|
|
494
|
+
method="post",
|
|
495
|
+
status_codes=201,
|
|
496
|
+
)
|
|
497
|
+
|
|
498
|
+
print(f"{icons.green_dot} The '{display_name}' group has been created.")
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
@log
|
|
502
|
+
def delete_group(group: str | UUID):
|
|
503
|
+
"""
|
|
504
|
+
Deletes a group.
|
|
505
|
+
|
|
506
|
+
This is a wrapper function for the following API: `Delete group <https://learn.microsoft.com/graph/api/group-delete>`_.
|
|
507
|
+
|
|
508
|
+
Service Principal Authentication is required (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
509
|
+
|
|
510
|
+
Parameters
|
|
511
|
+
----------
|
|
512
|
+
group : str | uuid.UUID
|
|
513
|
+
The group name or ID.
|
|
514
|
+
"""
|
|
515
|
+
|
|
516
|
+
group_id = resolve_group_id(group)
|
|
517
|
+
|
|
518
|
+
_base_api(
|
|
519
|
+
request=f"groups/{group_id}",
|
|
520
|
+
client="graph",
|
|
521
|
+
status_codes=204,
|
|
522
|
+
method="delete",
|
|
523
|
+
)
|
|
524
|
+
|
|
525
|
+
print(f"{icons.green_dot} The '{group}' group has been deleted successfully.")
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
@log
|
|
529
|
+
def update_group(
|
|
530
|
+
group: str | UUID,
|
|
531
|
+
display_name: Optional[str] = None,
|
|
532
|
+
mail_nickname: Optional[str] = None,
|
|
533
|
+
description: Optional[str] = None,
|
|
534
|
+
security_enabled: Optional[bool] = None,
|
|
535
|
+
):
|
|
536
|
+
"""
|
|
537
|
+
Updates a group's properties.
|
|
538
|
+
|
|
539
|
+
This is a wrapper function for the following API: `Update group <https://learn.microsoft.com/en-us/graph/api/group-update>`_.
|
|
540
|
+
|
|
541
|
+
Service Principal Authentication is required (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
542
|
+
|
|
543
|
+
Parameters
|
|
544
|
+
----------
|
|
545
|
+
group : str | uuid.UUID
|
|
546
|
+
The group name or ID.
|
|
547
|
+
display_name : str, default=None
|
|
548
|
+
The new display name for the group.
|
|
549
|
+
mail_nickname : str, default=None
|
|
550
|
+
The new mail nickname for the group.
|
|
551
|
+
description : str, default=None
|
|
552
|
+
The new description for the group.
|
|
553
|
+
security_enabled : bool, default=None
|
|
554
|
+
Whether the group is security-enabled.
|
|
555
|
+
"""
|
|
556
|
+
|
|
557
|
+
group_id = resolve_group_id(group)
|
|
558
|
+
|
|
559
|
+
payload = {}
|
|
560
|
+
if display_name:
|
|
561
|
+
payload["displayName"] = display_name
|
|
562
|
+
if mail_nickname:
|
|
563
|
+
payload["mailNickname"] = mail_nickname
|
|
564
|
+
if description:
|
|
565
|
+
payload["description"] = description
|
|
566
|
+
if security_enabled is not None and isinstance(security_enabled, bool):
|
|
567
|
+
payload["securityEnabled"] = security_enabled
|
|
568
|
+
|
|
569
|
+
if not payload:
|
|
570
|
+
print(f"{icons.info} No properties to update.")
|
|
571
|
+
return
|
|
572
|
+
|
|
573
|
+
_base_api(
|
|
574
|
+
request=f"groups/{group_id}",
|
|
575
|
+
client="graph",
|
|
576
|
+
status_codes=204,
|
|
577
|
+
payload=payload,
|
|
578
|
+
method="patch",
|
|
579
|
+
)
|
|
580
|
+
|
|
581
|
+
print(f"{icons.green_dot} The '{group}' group has been updated successfully.")
|