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.
Files changed (38) hide show
  1. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/PKG-INFO +1 -1
  2. itk_dev_shared_components-2.3.0/itk_dev_shared_components/graph/common.py +54 -0
  3. itk_dev_shared_components-2.3.0/itk_dev_shared_components/graph/file.py +54 -0
  4. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/graph/mail.py +7 -34
  5. itk_dev_shared_components-2.3.0/itk_dev_shared_components/graph/site.py +104 -0
  6. {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
  7. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components.egg-info/PKG-INFO +1 -1
  8. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components.egg-info/SOURCES.txt +3 -0
  9. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/pyproject.toml +1 -1
  10. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/LICENSE +0 -0
  11. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/README.md +0 -0
  12. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/__init__.py +0 -0
  13. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/graph/__init__.py +0 -0
  14. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/graph/authentication.py +0 -0
  15. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/kmd_nova/__init__.py +0 -0
  16. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/kmd_nova/authentication.py +0 -0
  17. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/kmd_nova/cpr.py +0 -0
  18. {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
  19. {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
  20. {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
  21. {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
  22. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/kmd_nova/util.py +0 -0
  23. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/misc/__init__.py +0 -0
  24. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/misc/cpr_util.py +0 -0
  25. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/sap/__init__.py +0 -0
  26. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/sap/fmcacov.py +0 -0
  27. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/sap/gridview_util.py +0 -0
  28. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/sap/multi_session.py +0 -0
  29. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/sap/opret_kundekontakt.py +0 -0
  30. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/sap/sap_login.py +0 -0
  31. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/sap/sap_util.py +0 -0
  32. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/sap/tree_util.py +0 -0
  33. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/smtp/__init__.py +0 -0
  34. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components/smtp/smtp_util.py +0 -0
  35. {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
  36. {itk_dev_shared_components-2.2.0 → itk_dev_shared_components-2.3.0}/itk_dev_shared_components.egg-info/requires.txt +0 -0
  37. {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
  38. {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.2.0
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 = _get_request(endpoint, graph_access)
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 = _get_request(endpoint, graph_access)
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 = _get_request(endpoint, graph_access).json()
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 = _get_request(endpoint, graph_access).json()
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 = _get_request(endpoint, graph_access).json()
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 = _get_request(endpoint, graph_access)
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
- payload = {
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": "CprNummer",
54
- "identification": cpr
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
- return Caseworker(
183
- uuid = case_dict['caseworker']['kspIdentity']['novaUserId'],
184
- name = case_dict['caseworker']['kspIdentity']['fullName'],
185
- ident = case_dict['caseworker']['kspIdentity']['racfId']
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.2.0
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "itk_dev_shared_components"
7
- version = "2.2.0"
7
+ version = "2.3.0"
8
8
  authors = [
9
9
  { name="ITK Development", email="itk-rpa@mkb.aarhus.dk" },
10
10
  ]