itk-dev-shared-components 2.2.0__tar.gz → 2.3.0__tar.gz
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.
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/PKG-INFO +1 -1
- itk_dev_shared_components-2.3.0/itk_dev_shared_components/graph/common.py +54 -0
- itk_dev_shared_components-2.3.0/itk_dev_shared_components/graph/file.py +54 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/graph/mail.py +7 -34
- itk_dev_shared_components-2.3.0/itk_dev_shared_components/graph/site.py +104 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/kmd_nova/nova_cases.py +90 -43
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components.egg-info/PKG-INFO +1 -1
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components.egg-info/SOURCES.txt +3 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/pyproject.toml +1 -1
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/LICENSE +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/README.md +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/__init__.py +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/graph/__init__.py +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/graph/authentication.py +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/kmd_nova/__init__.py +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/kmd_nova/authentication.py +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/kmd_nova/cpr.py +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/kmd_nova/nova_documents.py +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/kmd_nova/nova_notes.py +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/kmd_nova/nova_objects.py +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/kmd_nova/nova_tasks.py +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/kmd_nova/util.py +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/misc/__init__.py +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/misc/cpr_util.py +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/sap/__init__.py +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/sap/fmcacov.py +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/sap/gridview_util.py +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/sap/multi_session.py +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/sap/opret_kundekontakt.py +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/sap/sap_login.py +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/sap/sap_util.py +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/sap/tree_util.py +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/smtp/__init__.py +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/smtp/smtp_util.py +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components.egg-info/dependency_links.txt +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components.egg-info/requires.txt +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components.egg-info/top_level.txt +0 -0
- {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: itk_dev_shared_components
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: Shared components to use in RPA projects
|
|
5
5
|
Author-email: ITK Development <itk-rpa@mkb.aarhus.dk>
|
|
6
6
|
Project-URL: Homepage, https://github.com/itk-dev-rpa/itk-dev-shared-components
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""This module contains common functions like HTTP request wrappers which are used across other modules."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
import requests
|
|
6
|
+
|
|
7
|
+
from itk_dev_shared_components.graph.authentication import GraphAccess
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_request(endpoint: str, graph_access: GraphAccess) -> requests.models.Response:
|
|
11
|
+
"""Sends a get request to the given Graph endpoint using the GraphAccess
|
|
12
|
+
and returns the json object of the response.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
endpoint: The URL of the Graph endpoint.
|
|
16
|
+
graph_access: The GraphAccess object used to authenticate.
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
Response: The response object of the GET request.
|
|
20
|
+
|
|
21
|
+
Raises:
|
|
22
|
+
HTTPError: Any errors raised while performing GET request.
|
|
23
|
+
"""
|
|
24
|
+
token = graph_access.get_access_token()
|
|
25
|
+
headers = {"Authorization": f"Bearer {token}"}
|
|
26
|
+
|
|
27
|
+
response = requests.get(endpoint, headers=headers, timeout=30)
|
|
28
|
+
response.raise_for_status()
|
|
29
|
+
|
|
30
|
+
return response
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def put_request(endpoint: str, graph_access: GraphAccess, data: Any) -> requests.models.Response:
|
|
34
|
+
"""Sends a put request to the given Graph endpoint using the GraphAccess
|
|
35
|
+
and returns the json object of the response.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
endpoint: The URL of the Graph endpoint.
|
|
39
|
+
data: The data to send in the request.
|
|
40
|
+
graph_access: The GraphAccess object used to authenticate.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Response: The response object of the PUT request.
|
|
44
|
+
|
|
45
|
+
Raises:
|
|
46
|
+
HTTPError: Any errors raised while performing PUT request.
|
|
47
|
+
"""
|
|
48
|
+
token = graph_access.get_access_token()
|
|
49
|
+
headers = {"Authorization": f"Bearer {token}"}
|
|
50
|
+
|
|
51
|
+
response = requests.put(endpoint, headers=headers, data=data, timeout=30)
|
|
52
|
+
response.raise_for_status()
|
|
53
|
+
|
|
54
|
+
return response
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""This module is responsible for accessing files using the Microsoft Graph API."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
|
|
5
|
+
from itk_dev_shared_components.graph.authentication import GraphAccess
|
|
6
|
+
from itk_dev_shared_components.graph.common import get_request
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class DriveItem:
|
|
11
|
+
"""A class representing a DriveItem."""
|
|
12
|
+
|
|
13
|
+
id: str = field(repr=False)
|
|
14
|
+
name: str
|
|
15
|
+
web_url: str
|
|
16
|
+
last_modified: str
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_drive_item(graph_access: GraphAccess, site_id: str, drive_item_path: str) -> str:
|
|
20
|
+
"""Given a site id and a drive_item_path, gets the corresponding DriveItem
|
|
21
|
+
|
|
22
|
+
You need to authorize against Graph to get the GraphAccess before using this function
|
|
23
|
+
see the graph.authentication module.
|
|
24
|
+
|
|
25
|
+
See https://learn.microsoft.com/en-us/graph/api/driveitem-get for further documentation
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
graph_access: The GraphAccess object used to authenticate.
|
|
29
|
+
site_id: The id of the site in SharePoint.
|
|
30
|
+
drive_item_path: The path to the DriveItem in SharePoint.
|
|
31
|
+
"""
|
|
32
|
+
endpoint = f"https://graph.microsoft.com/v1.0/sites/{site_id}/drive/root:/{drive_item_path}"
|
|
33
|
+
response = get_request(endpoint, graph_access)
|
|
34
|
+
raw_response = response.json()
|
|
35
|
+
|
|
36
|
+
return _unpack_drive_item_response(raw_response)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _unpack_drive_item_response(drive_item_raw: dict[str, str]) -> DriveItem:
|
|
40
|
+
"""Unpack a json HTTP response and create a DriveItem object.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
drive_item_raw: The json dictionary created by response.json().
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
DriveItem: A DriveItem object.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
return DriveItem(
|
|
50
|
+
id=drive_item_raw["id"],
|
|
51
|
+
name=drive_item_raw["name"],
|
|
52
|
+
web_url=drive_item_raw["webUrl"],
|
|
53
|
+
last_modified=drive_item_raw["lastModifiedDateTime"],
|
|
54
|
+
)
|
|
@@ -7,6 +7,7 @@ import requests
|
|
|
7
7
|
from bs4 import BeautifulSoup
|
|
8
8
|
|
|
9
9
|
from itk_dev_shared_components.graph.authentication import GraphAccess
|
|
10
|
+
from itk_dev_shared_components.graph.common import get_request
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
@dataclass
|
|
@@ -67,7 +68,7 @@ def get_emails_from_folder(user: str, folder_path: str, graph_access: GraphAcces
|
|
|
67
68
|
|
|
68
69
|
endpoint = f"https://graph.microsoft.com/v1.0/users/{user}/mailFolders/{folder_id}/messages?$top=1000"
|
|
69
70
|
|
|
70
|
-
response =
|
|
71
|
+
response = get_request(endpoint, graph_access)
|
|
71
72
|
emails_raw = response.json()['value']
|
|
72
73
|
|
|
73
74
|
return _unpack_email_response(user, emails_raw)
|
|
@@ -84,7 +85,7 @@ def get_email_as_mime(email: Email, graph_access: GraphAccess) -> io.BytesIO:
|
|
|
84
85
|
io.BytesIO: A file-like object of the MIME file.
|
|
85
86
|
"""
|
|
86
87
|
endpoint = f"https://graph.microsoft.com/v1.0/users/{email.user}/messages/{email.id}/$value"
|
|
87
|
-
response =
|
|
88
|
+
response = get_request(endpoint, graph_access)
|
|
88
89
|
data = response.content
|
|
89
90
|
return io.BytesIO(data)
|
|
90
91
|
|
|
@@ -113,7 +114,7 @@ def get_folder_id_from_path(user: str, folder_path: str, graph_access: GraphAcce
|
|
|
113
114
|
|
|
114
115
|
# Get main folder
|
|
115
116
|
endpoint = f"https://graph.microsoft.com/v1.0/users/{user}/mailFolders"
|
|
116
|
-
response =
|
|
117
|
+
response = get_request(endpoint, graph_access).json()
|
|
117
118
|
folder_id = _find_folder(response, main_folder)
|
|
118
119
|
if folder_id is None:
|
|
119
120
|
raise ValueError(f"Top level folder '{main_folder}' was not found for user '{user}'.")
|
|
@@ -121,7 +122,7 @@ def get_folder_id_from_path(user: str, folder_path: str, graph_access: GraphAcce
|
|
|
121
122
|
# Get child folders
|
|
122
123
|
for child_folder in child_folders:
|
|
123
124
|
endpoint = f"https://graph.microsoft.com/v1.0/users/{user}/mailFolders/{folder_id}/childFolders"
|
|
124
|
-
response =
|
|
125
|
+
response = get_request(endpoint, graph_access).json()
|
|
125
126
|
folder_id = _find_folder(response, child_folder)
|
|
126
127
|
if folder_id is None:
|
|
127
128
|
raise ValueError(f"Child folder '{child_folder}' not found under '{main_folder}' for user '{user}'.")
|
|
@@ -141,7 +142,7 @@ def list_email_attachments(email: Email, graph_access: GraphAccess) -> tuple[Att
|
|
|
141
142
|
tuple[Attachment]: A tuple of Attachment objects describing the attachments.
|
|
142
143
|
"""
|
|
143
144
|
endpoint = f"https://graph.microsoft.com/v1.0/users/{email.user}/messages/{email.id}/attachments?$select=name,size,id"
|
|
144
|
-
response =
|
|
145
|
+
response = get_request(endpoint, graph_access).json()
|
|
145
146
|
|
|
146
147
|
attachments = []
|
|
147
148
|
for att in response['value']:
|
|
@@ -162,7 +163,7 @@ def get_attachment_data(attachment: Attachment, graph_access: GraphAccess) -> io
|
|
|
162
163
|
"""
|
|
163
164
|
email = attachment.email
|
|
164
165
|
endpoint = f"https://graph.microsoft.com/v1.0/users/{email.user}/messages/{email.id}/attachments/{attachment.id}/$value"
|
|
165
|
-
response =
|
|
166
|
+
response = get_request(endpoint, graph_access)
|
|
166
167
|
data_bytes = response.content
|
|
167
168
|
return io.BytesIO(data_bytes)
|
|
168
169
|
|
|
@@ -287,31 +288,3 @@ def _unpack_email_response(user: str, emails_raw: list[dict[str, str]]) -> tuple
|
|
|
287
288
|
)
|
|
288
289
|
|
|
289
290
|
return tuple(emails)
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
def _get_request(endpoint: str, graph_access: GraphAccess) -> requests.models.Response:
|
|
293
|
-
"""Sends a get request to the given Graph endpoint using the GraphAccess
|
|
294
|
-
and returns the json object of the response.
|
|
295
|
-
|
|
296
|
-
Args:
|
|
297
|
-
endpoint: The URL of the Graph endpoint.
|
|
298
|
-
graph_access: The GraphAccess object used to authenticate.
|
|
299
|
-
timeout: Timeout in seconds of the HTTP request. Defaults to 10.
|
|
300
|
-
|
|
301
|
-
Returns:
|
|
302
|
-
Response: The response object of the GET request.
|
|
303
|
-
|
|
304
|
-
Raises:
|
|
305
|
-
HTTPError: Any errors raised while performing GET request.
|
|
306
|
-
"""
|
|
307
|
-
token = graph_access.get_access_token()
|
|
308
|
-
headers = {'Authorization': f"Bearer {token}"}
|
|
309
|
-
|
|
310
|
-
response = requests.get(
|
|
311
|
-
endpoint,
|
|
312
|
-
headers=headers,
|
|
313
|
-
timeout=30
|
|
314
|
-
)
|
|
315
|
-
response.raise_for_status()
|
|
316
|
-
|
|
317
|
-
return response
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""This module is responsible for accessing sites using the Microsoft Graph API."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
|
|
5
|
+
from itk_dev_shared_components.graph.authentication import GraphAccess
|
|
6
|
+
from itk_dev_shared_components.graph.common import get_request, put_request
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class Site:
|
|
11
|
+
"""A class representing a Site."""
|
|
12
|
+
|
|
13
|
+
id: str = field(repr=False)
|
|
14
|
+
name: str
|
|
15
|
+
display_name: str
|
|
16
|
+
description: str
|
|
17
|
+
web_url: str
|
|
18
|
+
created: str
|
|
19
|
+
last_modified: str
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def get_site(graph_access: GraphAccess, site_path: str) -> Site:
|
|
23
|
+
"""Retrieve properties and relationships for a site resource.
|
|
24
|
+
A site resource represents a team site in SharePoint.
|
|
25
|
+
|
|
26
|
+
You need to authorize against Graph to get the GraphAccess before using this function
|
|
27
|
+
see the graph.authentication module.
|
|
28
|
+
|
|
29
|
+
See https://learn.microsoft.com/en-us/graph/api/site-get?view=graph-rest-1.0
|
|
30
|
+
for a list of possible site_paths to pass as argument.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
graph_access: The GraphAccess object used to authenticate.
|
|
34
|
+
site_path: The path to the team site in SharePoint.
|
|
35
|
+
|
|
36
|
+
returns:
|
|
37
|
+
A Site object
|
|
38
|
+
"""
|
|
39
|
+
endpoint = f"https://graph.microsoft.com/v1.0/sites/{site_path}"
|
|
40
|
+
response = get_request(endpoint, graph_access)
|
|
41
|
+
|
|
42
|
+
return _unpack_site_response(response.json())
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def download_file_contents(graph_access: GraphAccess, site_id: str, drive_item_id: str) -> bytes:
|
|
46
|
+
"""Given a site_id, a drive_item_id, and a download destination, downloads a single file from a site resource
|
|
47
|
+
|
|
48
|
+
You need to authorize against Graph to get the GraphAccess before using this function
|
|
49
|
+
see the graph.authentication module.
|
|
50
|
+
|
|
51
|
+
See https://learn.microsoft.com/en-us/graph/api/driveitem-get-content for further documentation
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
graph_access: The GraphAccess object used to authenticate.
|
|
55
|
+
site_id: The id of the site in SharePoint.
|
|
56
|
+
drive_item_id: The id of the DriveItem in SharePoint.
|
|
57
|
+
|
|
58
|
+
returns:
|
|
59
|
+
bytes containing the contents of the file
|
|
60
|
+
"""
|
|
61
|
+
endpoint = f"https://graph.microsoft.com/v1.0/sites/{site_id}/drive/items/{drive_item_id}/content"
|
|
62
|
+
response = get_request(endpoint, graph_access)
|
|
63
|
+
return response.content
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def upload_file_contents(graph_access: GraphAccess, site_id: str, drive_item_path: str, file_contents: bytes):
|
|
67
|
+
"""Given a site_id, a drive_item_path, and file_contents as bytes, uploads a single file to a site
|
|
68
|
+
|
|
69
|
+
You need to authorize against Graph to get the GraphAccess before using this function
|
|
70
|
+
see the graph.authentication module.
|
|
71
|
+
|
|
72
|
+
See https://learn.microsoft.com/en-us/graph/api/driveitem-put-content for further documentation
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
graph_access: The GraphAccess object used to authenticate.
|
|
76
|
+
site_id: The id of the site in SharePoint.
|
|
77
|
+
drive_item_path: The path to upload the file contents to.
|
|
78
|
+
file_contents: A bytes object containing the file's contents.
|
|
79
|
+
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
endpoint = f"https://graph.microsoft.com/v1.0/sites/{site_id}/drive/root:/{drive_item_path}:/content"
|
|
83
|
+
put_request(endpoint, graph_access, file_contents)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _unpack_site_response(site_raw: dict[str, str]) -> Site:
|
|
87
|
+
"""Unpack a json HTTP response and create a Site object.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
site_raw: The json dictionary created by response.json().
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
Site: A Site object.
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
return Site(
|
|
97
|
+
id=site_raw["id"],
|
|
98
|
+
name=site_raw["name"],
|
|
99
|
+
display_name=site_raw["displayName"],
|
|
100
|
+
description=site_raw["description"],
|
|
101
|
+
web_url=site_raw["webUrl"],
|
|
102
|
+
created=site_raw["createdDateTime"],
|
|
103
|
+
last_modified=site_raw["lastModifiedDateTime"],
|
|
104
|
+
)
|
|
@@ -28,16 +28,93 @@ def get_cases(nova_access: NovaAccess, cpr: str = None, case_number: str = None,
|
|
|
28
28
|
|
|
29
29
|
Raises:
|
|
30
30
|
ValueError: If no search terms are given.
|
|
31
|
-
requests.exceptions.HTTPError: If the request failed.
|
|
32
31
|
"""
|
|
33
32
|
|
|
34
33
|
if not any((cpr, case_number, case_title)):
|
|
35
34
|
raise ValueError("No search terms given.")
|
|
36
35
|
|
|
36
|
+
payload = _create_payload(cpr, "CprNummer", case_number, case_title, limit)
|
|
37
|
+
return _get_nova_cases(nova_access, payload)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_cvr_cases(nova_access: NovaAccess, cvr: str = None, case_number: str = None, case_title: str = None, limit: int = 100) -> list[NovaCase]:
|
|
41
|
+
"""Search for cases on different search terms.
|
|
42
|
+
Currently supports search on cvr number, case number and case title. At least one search term must be given.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
nova_access: The NovaAccess object used to authenticate.
|
|
46
|
+
cvr: The cvr number to search on. E.g. "01234567"
|
|
47
|
+
case_number: The case number to search on. E.g. "S2022-12345"
|
|
48
|
+
case_title: The case title to search on.
|
|
49
|
+
limit: The maximum number of cases to find (1-500).
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
A list of NovaCase objects.
|
|
53
|
+
|
|
54
|
+
Raises:
|
|
55
|
+
ValueError: If no search terms are given.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
if not any((cvr, case_number, case_title)):
|
|
59
|
+
raise ValueError("No search terms given.")
|
|
60
|
+
|
|
61
|
+
payload = _create_payload(cvr, "CvrNummer", case_number, case_title, limit)
|
|
62
|
+
return _get_nova_cases(nova_access, payload)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _get_nova_cases(nova_access: NovaAccess, payload: dict) -> list[NovaCase]:
|
|
66
|
+
"""Search for cases with a payload of search terms.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
nova_access: The NovaAccess object used to authenticate.
|
|
70
|
+
payload: A dictionary containing case identifier, identifier type, case number case title and limit
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
A list of NovaCase objects.
|
|
74
|
+
|
|
75
|
+
Raises:
|
|
76
|
+
requests.exceptions.HTTPError: If the request failed.
|
|
77
|
+
"""
|
|
37
78
|
url = urllib.parse.urljoin(nova_access.domain, "api/Case/GetList")
|
|
38
79
|
params = {"api-version": "1.0-Case"}
|
|
39
80
|
|
|
40
|
-
|
|
81
|
+
headers = {'Content-Type': 'application/json', 'Authorization': f"Bearer {nova_access.get_bearer_token()}"}
|
|
82
|
+
|
|
83
|
+
response = requests.put(url, params=params, headers=headers, json=payload, timeout=60)
|
|
84
|
+
response.raise_for_status()
|
|
85
|
+
|
|
86
|
+
if response.json()['pagingInformation']['numberOfRows'] == 0:
|
|
87
|
+
return []
|
|
88
|
+
|
|
89
|
+
# Convert json to NovaCase objects
|
|
90
|
+
cases = []
|
|
91
|
+
for case_dict in response.json()['cases']:
|
|
92
|
+
security_unit, responsible_department = _extract_departments(case_dict)
|
|
93
|
+
case = NovaCase(
|
|
94
|
+
uuid = case_dict['common']['uuid'],
|
|
95
|
+
title = case_dict['caseAttributes']['title'],
|
|
96
|
+
case_date = datetime_from_iso_string(case_dict['caseAttributes']['caseDate']),
|
|
97
|
+
case_number = case_dict['caseAttributes']['userFriendlyCaseNumber'],
|
|
98
|
+
active_code = case_dict['state']['activeCode'],
|
|
99
|
+
progress_state = case_dict['state']['progressState'],
|
|
100
|
+
case_parties = _extract_case_parties(case_dict),
|
|
101
|
+
document_count = case_dict['numberOfDocuments'],
|
|
102
|
+
note_count = case_dict['numberOfJournalNotes'],
|
|
103
|
+
kle_number = case_dict['caseClassification']['kleNumber']['code'],
|
|
104
|
+
proceeding_facet = case_dict['caseClassification']['proceedingFacet']['code'],
|
|
105
|
+
sensitivity = case_dict["sensitivity"]["sensitivity"],
|
|
106
|
+
caseworker = _extract_case_worker(case_dict),
|
|
107
|
+
security_unit=security_unit,
|
|
108
|
+
responsible_department=responsible_department
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
cases.append(case)
|
|
112
|
+
|
|
113
|
+
return cases
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _create_payload(identification: str = None, identification_type: str = "CprNummer", case_number: str = None, case_title: str = None, limit: int = 100) -> dict:
|
|
117
|
+
return {
|
|
41
118
|
"common": {
|
|
42
119
|
"transactionId": str(uuid.uuid4())
|
|
43
120
|
},
|
|
@@ -50,8 +127,8 @@ def get_cases(nova_access: NovaAccess, cpr: str = None, case_number: str = None,
|
|
|
50
127
|
"title": case_title
|
|
51
128
|
},
|
|
52
129
|
"caseParty": {
|
|
53
|
-
"identificationType":
|
|
54
|
-
"identification":
|
|
130
|
+
"identificationType": identification_type,
|
|
131
|
+
"identification": identification
|
|
55
132
|
},
|
|
56
133
|
"caseGetOutput": {
|
|
57
134
|
"numberOfSecondaryParties": True,
|
|
@@ -110,40 +187,6 @@ def get_cases(nova_access: NovaAccess, cpr: str = None, case_number: str = None,
|
|
|
110
187
|
}
|
|
111
188
|
}
|
|
112
189
|
|
|
113
|
-
headers = {'Content-Type': 'application/json', 'Authorization': f"Bearer {nova_access.get_bearer_token()}"}
|
|
114
|
-
|
|
115
|
-
response = requests.put(url, params=params, headers=headers, json=payload, timeout=60)
|
|
116
|
-
response.raise_for_status()
|
|
117
|
-
|
|
118
|
-
if response.json()['pagingInformation']['numberOfRows'] == 0:
|
|
119
|
-
return []
|
|
120
|
-
|
|
121
|
-
# Convert json to NovaCase objects
|
|
122
|
-
cases = []
|
|
123
|
-
for case_dict in response.json()['cases']:
|
|
124
|
-
security_unit, responsible_department = _extract_departments(case_dict)
|
|
125
|
-
case = NovaCase(
|
|
126
|
-
uuid = case_dict['common']['uuid'],
|
|
127
|
-
title = case_dict['caseAttributes']['title'],
|
|
128
|
-
case_date = datetime_from_iso_string(case_dict['caseAttributes']['caseDate']),
|
|
129
|
-
case_number = case_dict['caseAttributes']['userFriendlyCaseNumber'],
|
|
130
|
-
active_code = case_dict['state']['activeCode'],
|
|
131
|
-
progress_state = case_dict['state']['progressState'],
|
|
132
|
-
case_parties = _extract_case_parties(case_dict),
|
|
133
|
-
document_count = case_dict['numberOfDocuments'],
|
|
134
|
-
note_count = case_dict['numberOfJournalNotes'],
|
|
135
|
-
kle_number = case_dict['caseClassification']['kleNumber']['code'],
|
|
136
|
-
proceeding_facet = case_dict['caseClassification']['proceedingFacet']['code'],
|
|
137
|
-
sensitivity = case_dict["sensitivity"]["sensitivity"],
|
|
138
|
-
caseworker = _extract_case_worker(case_dict),
|
|
139
|
-
security_unit=security_unit,
|
|
140
|
-
responsible_department=responsible_department
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
cases.append(case)
|
|
144
|
-
|
|
145
|
-
return cases
|
|
146
|
-
|
|
147
190
|
|
|
148
191
|
def _extract_departments(case_dict: dict) -> tuple[Department, Department]:
|
|
149
192
|
"""Extract the departments from a HTTP request response.
|
|
@@ -171,6 +214,7 @@ def _extract_departments(case_dict: dict) -> tuple[Department, Department]:
|
|
|
171
214
|
|
|
172
215
|
def _extract_case_worker(case_dict: dict) -> Caseworker | None:
|
|
173
216
|
"""Extract the case worker from a HTTP request response.
|
|
217
|
+
If the case worker is in a unexpected format, None is returned.
|
|
174
218
|
|
|
175
219
|
Args:
|
|
176
220
|
case_dict: The dictionary describing the case.
|
|
@@ -179,11 +223,14 @@ def _extract_case_worker(case_dict: dict) -> Caseworker | None:
|
|
|
179
223
|
A case worker object describing the case worker if any.
|
|
180
224
|
"""
|
|
181
225
|
if 'caseworker' in case_dict:
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
226
|
+
try:
|
|
227
|
+
return Caseworker(
|
|
228
|
+
uuid = case_dict['caseworker']['kspIdentity']['novaUserId'],
|
|
229
|
+
name = case_dict['caseworker']['kspIdentity']['fullName'],
|
|
230
|
+
ident = case_dict['caseworker']['kspIdentity']['racfId']
|
|
231
|
+
)
|
|
232
|
+
except KeyError:
|
|
233
|
+
return None
|
|
187
234
|
|
|
188
235
|
return None
|
|
189
236
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: itk_dev_shared_components
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: Shared components to use in RPA projects
|
|
5
5
|
Author-email: ITK Development <itk-rpa@mkb.aarhus.dk>
|
|
6
6
|
Project-URL: Homepage, https://github.com/itk-dev-rpa/itk-dev-shared-components
|
|
@@ -9,7 +9,10 @@ itk_dev_shared_components.egg-info/requires.txt
|
|
|
9
9
|
itk_dev_shared_components.egg-info/top_level.txt
|
|
10
10
|
itk_dev_shared_components/graph/__init__.py
|
|
11
11
|
itk_dev_shared_components/graph/authentication.py
|
|
12
|
+
itk_dev_shared_components/graph/common.py
|
|
13
|
+
itk_dev_shared_components/graph/file.py
|
|
12
14
|
itk_dev_shared_components/graph/mail.py
|
|
15
|
+
itk_dev_shared_components/graph/site.py
|
|
13
16
|
itk_dev_shared_components/kmd_nova/__init__.py
|
|
14
17
|
itk_dev_shared_components/kmd_nova/authentication.py
|
|
15
18
|
itk_dev_shared_components/kmd_nova/cpr.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|