itk-dev-shared-components 2.8.0__tar.gz → 2.9.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 (47) hide show
  1. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/PKG-INFO +2 -2
  2. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/eflyt/eflyt_case.py +14 -10
  3. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/graph/mail.py +21 -2
  4. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/kmd_nova/nova_cases.py +21 -55
  5. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/kmd_nova/nova_documents.py +16 -18
  6. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/kmd_nova/nova_notes.py +1 -0
  7. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/kmd_nova/nova_objects.py +1 -0
  8. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/kmd_nova/nova_tasks.py +20 -3
  9. itk_dev_shared_components-2.9.0/itk_dev_shared_components/kmd_nova/util.py +72 -0
  10. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components.egg-info/PKG-INFO +2 -2
  11. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/pyproject.toml +1 -1
  12. itk_dev_shared_components-2.8.0/itk_dev_shared_components/kmd_nova/util.py +0 -36
  13. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/LICENSE +0 -0
  14. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/README.md +0 -0
  15. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/__init__.py +0 -0
  16. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/eflyt/__init__.py +0 -0
  17. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/eflyt/eflyt_login.py +0 -0
  18. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/eflyt/eflyt_search.py +0 -0
  19. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/eflyt/eflyt_util.py +0 -0
  20. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/graph/__init__.py +0 -0
  21. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/graph/authentication.py +0 -0
  22. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/graph/common.py +0 -0
  23. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/graph/file.py +0 -0
  24. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/graph/site.py +0 -0
  25. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/kmd_nova/__init__.py +0 -0
  26. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/kmd_nova/authentication.py +0 -0
  27. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/kmd_nova/cpr.py +0 -0
  28. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/misc/__init__.py +0 -0
  29. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/misc/address_lookup.py +0 -0
  30. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/misc/cpr_util.py +0 -0
  31. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/misc/cvr_lookup.py +0 -0
  32. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/misc/file_util.py +0 -0
  33. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/sap/__init__.py +0 -0
  34. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/sap/fmcacov.py +0 -0
  35. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/sap/gridview_util.py +0 -0
  36. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/sap/multi_session.py +0 -0
  37. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/sap/opret_kundekontakt.py +0 -0
  38. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/sap/sap_login.py +0 -0
  39. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/sap/sap_util.py +0 -0
  40. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/sap/tree_util.py +0 -0
  41. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/smtp/__init__.py +0 -0
  42. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/smtp/smtp_util.py +0 -0
  43. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components.egg-info/SOURCES.txt +0 -0
  44. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components.egg-info/dependency_links.txt +0 -0
  45. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components.egg-info/requires.txt +0 -0
  46. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components.egg-info/top_level.txt +0 -0
  47. {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: itk_dev_shared_components
3
- Version: 2.8.0
3
+ Version: 2.9.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
@@ -130,7 +130,9 @@ def change_tab(browser: webdriver.Chrome, tab_index: int):
130
130
 
131
131
 
132
132
  def approve_case(browser: webdriver.Chrome):
133
- """Approve a case, even if blocked by a note."""
133
+ """Approve a case.
134
+ If any person on the case is blocking approval, approve each person individually.
135
+ """
134
136
  change_tab(browser, 0)
135
137
 
136
138
  deadline_field = browser.find_element(By.ID, "ctl00_ContentPlaceHolder2_ptFanePerson_ncPersonTab_txtDeadline")
@@ -142,20 +144,22 @@ def approve_case(browser: webdriver.Chrome):
142
144
  browser.find_element(By.ID, "ctl00_ContentPlaceHolder2_ptFanePerson_stcPersonTab1_btnApproveYes").click()
143
145
 
144
146
  approve_persons_button = browser.find_element(By.ID, "ctl00_ContentPlaceHolder2_ptFanePerson_stcPersonTab1_btnGodkendAlle")
145
- if not approve_persons_button.is_enabled():
147
+ if approve_persons_button.is_enabled():
148
+ approve_persons_button.click()
149
+ else:
150
+ # Approve each person individually
151
+ person_count = len(browser.find_elements(By.XPATH, '//table[@id="ctl00_ContentPlaceHolder2_GridViewMovingPersons"]//tr')) - 1
146
152
 
147
- person_table = browser.find_element(By.ID, "ctl00_ContentPlaceHolder2_GridViewMovingPersons")
148
- rows = person_table.find_elements(By.TAG_NAME, "tr")
149
- rows.pop(0)
153
+ for i in range(person_count):
154
+ browser.find_element(By.XPATH, f'//table[@id="ctl00_ContentPlaceHolder2_GridViewMovingPersons"]//tr[{i+2}]//td[2]').click()
150
155
 
151
- for row in rows:
152
- row.find_element(By.XPATH, "td[2]").click()
153
156
  browser.find_element(By.ID, "ctl00_ContentPlaceHolder2_ptFanePerson_stcPersonTab1_btnGodkend").click()
154
157
  approve_button = browser.find_element(By.ID, "ctl00_ContentPlaceHolder2_ptFanePerson_stcPersonTab1_btnApproveYes")
155
158
  if approve_button.is_displayed():
156
159
  approve_button.click()
157
- else:
158
- approve_persons_button.click()
160
+
161
+ # Go back to the case
162
+ browser.find_element(By.XPATH, '//table[@id="ctl00_ContentPlaceHolder2_GridViewMovingPersons"]//tr[1]//td[2]').click()
159
163
 
160
164
 
161
165
  def check_all_approved(browser: webdriver.Chrome) -> bool:
@@ -167,7 +171,7 @@ def check_all_approved(browser: webdriver.Chrome) -> bool:
167
171
 
168
172
  for row in rows:
169
173
  row_status = row.find_element(By.XPATH, "td[6]").text
170
- if row_status != "Godkendt":
174
+ if row_status not in ("Godkendt", "Afsluttet"):
171
175
  return False
172
176
  return True
173
177
 
@@ -122,14 +122,33 @@ def get_folder_id_from_path(user: str, folder_path: str, graph_access: GraphAcce
122
122
  # Get child folders
123
123
  for child_folder in child_folders:
124
124
  endpoint = f"https://graph.microsoft.com/v1.0/users/{user}/mailFolders/{folder_id}/childFolders"
125
- response = get_request(endpoint, graph_access).json()
126
- folder_id = _find_folder(response, child_folder)
125
+ folder_id = recursive_find_folder(endpoint, graph_access, child_folder)
127
126
  if folder_id is None:
128
127
  raise ValueError(f"Child folder '{child_folder}' not found under '{main_folder}' for user '{user}'.")
129
128
 
130
129
  return folder_id
131
130
 
132
131
 
132
+ def recursive_find_folder(endpoint: str, graph_access: GraphAccess, target_folder: str) -> str:
133
+ """Look for target folder at endpoint, recursively going through pagination if available and necessary.
134
+
135
+ Args:
136
+ endpoint: Graph endpoint to lookup folder.
137
+ graph_access: Access token for Graph API.
138
+ target_folder: ID of target folder.
139
+
140
+ Returns:
141
+ Return folder ID.
142
+ """
143
+ response = get_request(endpoint, graph_access).json()
144
+ folder_id = _find_folder(response, target_folder)
145
+
146
+ if folder_id is None and '@odata.nextLink' in response:
147
+ return recursive_find_folder(response['@odata.nextLink'], graph_access, target_folder)
148
+
149
+ return folder_id
150
+
151
+
133
152
  def list_email_attachments(email: Email, graph_access: GraphAccess) -> tuple[Attachment]:
134
153
  """List all attachments of the given email. This function only gets the id, name and size
135
154
  of the attachment. Use get_attachment_data to get the actual data of an attachment.
@@ -2,14 +2,13 @@
2
2
  to the KMD Nova api."""
3
3
 
4
4
  import uuid
5
- import base64
6
5
  import urllib.parse
7
6
 
8
7
  import requests
9
8
 
10
9
  from itk_dev_shared_components.kmd_nova.authentication import NovaAccess
11
- from itk_dev_shared_components.kmd_nova.nova_objects import NovaCase, CaseParty, JournalNote, Caseworker, Department
12
- from itk_dev_shared_components.kmd_nova.util import datetime_from_iso_string
10
+ from itk_dev_shared_components.kmd_nova.nova_objects import NovaCase, CaseParty, Department
11
+ from itk_dev_shared_components.kmd_nova.util import datetime_from_iso_string, extract_caseworker
13
12
 
14
13
 
15
14
  def get_case(case_uuid: str, nova_access: NovaAccess) -> NovaCase:
@@ -125,7 +124,7 @@ def _get_nova_cases(nova_access: NovaAccess, payload: dict) -> list[NovaCase]:
125
124
  kle_number = case_dict['caseClassification']['kleNumber']['code'],
126
125
  proceeding_facet = case_dict['caseClassification']['proceedingFacet']['code'],
127
126
  sensitivity = case_dict["sensitivity"]["sensitivity"],
128
- caseworker = _extract_case_worker(case_dict),
127
+ caseworker = extract_caseworker(case_dict),
129
128
  security_unit=security_unit,
130
129
  responsible_department=responsible_department
131
130
  )
@@ -189,6 +188,11 @@ def _create_payload(*, case_uuid: str = None, identification: str = None, identi
189
188
  "novaUserId": True,
190
189
  "fullName": True,
191
190
  "racfId": True
191
+ },
192
+ "losIdentity": {
193
+ "novaUnitId": True,
194
+ "fullName": True,
195
+ "administrativeUnitId": True
192
196
  }
193
197
  },
194
198
  "responsibleDepartment": {
@@ -235,29 +239,6 @@ def _extract_departments(case_dict: dict) -> tuple[Department, Department]:
235
239
  return security_unit, responsible_department
236
240
 
237
241
 
238
- def _extract_case_worker(case_dict: dict) -> Caseworker | None:
239
- """Extract the case worker from a HTTP request response.
240
- If the case worker is in a unexpected format, None is returned.
241
-
242
- Args:
243
- case_dict: The dictionary describing the case.
244
-
245
- Returns:
246
- A case worker object describing the case worker if any.
247
- """
248
- if 'caseworker' in case_dict:
249
- try:
250
- return Caseworker(
251
- uuid = case_dict['caseworker']['kspIdentity']['novaUserId'],
252
- name = case_dict['caseworker']['kspIdentity']['fullName'],
253
- ident = case_dict['caseworker']['kspIdentity']['racfId']
254
- )
255
- except KeyError:
256
- return None
257
-
258
- return None
259
-
260
-
261
242
  def _extract_case_parties(case_dict: dict) -> list[CaseParty]:
262
243
  """Extract the case parties from a HTTP request response.
263
244
 
@@ -281,29 +262,6 @@ def _extract_case_parties(case_dict: dict) -> list[CaseParty]:
281
262
  return parties
282
263
 
283
264
 
284
- def _extract_journal_notes(case_dict: dict) -> list:
285
- """Extract the journal notes from a HTTP request response.
286
-
287
- Args:
288
- case_dict: The dictionary describing the journal note.
289
-
290
- Returns:
291
- A journal note object describing the journal note.
292
- """
293
- notes = []
294
- for note_dict in case_dict['journalNotes']['journalNotes']:
295
- note = JournalNote(
296
- uuid = note_dict['uuid'],
297
- title = note_dict['journalNoteAttributes']['title'],
298
- journal_date = note_dict['journalNoteAttributes']['journalNoteDate'],
299
- note_format = note_dict['journalNoteAttributes']['format'],
300
- note = base64.b64decode(note_dict['journalNoteAttributes']['note']),
301
- approved = note_dict['journalNoteAttributes'].get('approved', False)
302
- )
303
- notes.append(note)
304
- return notes
305
-
306
-
307
265
  def add_case(case: NovaCase, nova_access: NovaAccess):
308
266
  """Add a case to KMD Nova. The case will be created as 'Active'.
309
267
 
@@ -371,12 +329,20 @@ def add_case(case: NovaCase, nova_access: NovaAccess):
371
329
  }
372
330
 
373
331
  if case.caseworker:
374
- payload['caseworker'] = {
375
- "kspIdentity": {
376
- "racfId": case.caseworker.ident,
377
- "fullName": case.caseworker.name
332
+ if case.caseworker.type == 'user':
333
+ payload['caseworker'] = {
334
+ "kspIdentity": {
335
+ "racfId": case.caseworker.ident,
336
+ "fullName": case.caseworker.name
337
+ }
338
+ }
339
+ elif case.caseworker.type == 'group':
340
+ payload['caseworker'] = {
341
+ "losIdentity": {
342
+ "administrativeUnitId": case.caseworker.ident,
343
+ "fullName": case.caseworker.name
344
+ }
378
345
  }
379
- }
380
346
 
381
347
  headers = {'Content-Type': 'application/json', 'Authorization': f"Bearer {nova_access.get_bearer_token()}"}
382
348
 
@@ -10,8 +10,8 @@ import urllib.parse
10
10
  import requests
11
11
 
12
12
  from itk_dev_shared_components.kmd_nova.authentication import NovaAccess
13
- from itk_dev_shared_components.kmd_nova.nova_objects import Document, Caseworker
14
- from itk_dev_shared_components.kmd_nova. util import datetime_from_iso_string
13
+ from itk_dev_shared_components.kmd_nova.nova_objects import Document
14
+ from itk_dev_shared_components.kmd_nova.util import datetime_from_iso_string, extract_caseworker
15
15
 
16
16
 
17
17
  def get_documents(case_uuid: str, nova_access: NovaAccess) -> list[Document]:
@@ -56,16 +56,6 @@ def get_documents(case_uuid: str, nova_access: NovaAccess) -> list[Document]:
56
56
 
57
57
  documents = []
58
58
  for document_dict in response.json()['documents']:
59
-
60
- if 'caseworker' in document_dict:
61
- caseworker = Caseworker(
62
- uuid = document_dict['caseworker']['kspIdentity']['novaUserId'],
63
- name = document_dict['caseworker']['kspIdentity']['fullName'],
64
- ident = document_dict['caseworker']['kspIdentity']['racfId']
65
- )
66
- else:
67
- caseworker = None
68
-
69
59
  doc = Document(
70
60
  uuid = document_dict['documentUuid'],
71
61
  document_number = document_dict['documentNumber'],
@@ -78,7 +68,7 @@ def get_documents(case_uuid: str, nova_access: NovaAccess) -> list[Document]:
78
68
  file_extension = document_dict['fileExtension'],
79
69
  category_name = document_dict.get('documentCategoryName'),
80
70
  category_uuid = document_dict.get('documentCategoryUuid'),
81
- caseworker=caseworker
71
+ caseworker=extract_caseworker(document_dict)
82
72
  )
83
73
  documents.append(doc)
84
74
 
@@ -197,12 +187,20 @@ def attach_document_to_case(case_uuid: str, document: Document, nova_access: Nov
197
187
  }
198
188
 
199
189
  if document.caseworker:
200
- payload['caseworker'] = {
201
- "kspIdentity": {
202
- "racfId": document.caseworker.ident,
203
- "fullName": document.caseworker.name
190
+ if document.caseworker.type == 'user':
191
+ payload['caseworker'] = {
192
+ "kspIdentity": {
193
+ "racfId": document.caseworker.ident,
194
+ "fullName": document.caseworker.name
195
+ }
196
+ }
197
+ elif document.caseworker.type == 'group':
198
+ payload['caseworker'] = {
199
+ "losIdentity": {
200
+ "administrativeUnitId": document.caseworker.ident,
201
+ "fullName": document.caseworker.name
202
+ }
204
203
  }
205
- }
206
204
 
207
205
  headers = {'Content-Type': 'application/json', 'Authorization': f"Bearer {nova_access.get_bearer_token()}"}
208
206
  response = requests.post(url, params=params, headers=headers, json=payload, timeout=60)
@@ -18,6 +18,7 @@ def add_text_note(case_uuid: str, note_title: str, note_text: str, caseworker: C
18
18
  case_uuid: The uuid of the case to add the journal note to.
19
19
  note_title: The title of the note.
20
20
  note_text: The text content of the note.
21
+ caseworker: The author of the note.
21
22
  approved: Whether the journal note should be marked as approved in Nova.
22
23
  nova_access: The NovaAccess object used to authenticate.
23
24
 
@@ -22,6 +22,7 @@ class Caseworker:
22
22
  uuid: str
23
23
  name: str
24
24
  ident: str
25
+ type: Literal['user', 'group'] = 'user'
25
26
 
26
27
 
27
28
  @dataclass(slots=True, kw_only=True)
@@ -35,7 +35,6 @@ def attach_task_to_case(case_uuid: str, task: Task, nova_access: NovaAccess) ->
35
35
  "caseUuid": case_uuid,
36
36
  "title": task.title,
37
37
  "description": task.description, # Optional
38
- "caseworkerPersonId": task.caseworker.uuid, # Optional
39
38
  "statusCode": task.status_code,
40
39
  "deadline": datetime_to_iso_string(task.deadline),
41
40
  "startDate": datetime_to_iso_string(task.started_date), # Optional
@@ -43,6 +42,11 @@ def attach_task_to_case(case_uuid: str, task: Task, nova_access: NovaAccess) ->
43
42
  "taskTypeName": "Aktivitet"
44
43
  }
45
44
 
45
+ if task.caseworker.type == 'user':
46
+ payload["caseworkerPersonId"] = task.caseworker.uuid
47
+ elif task.caseworker.type == 'group':
48
+ payload["caseworkerGroupId"] = task.caseworker.uuid
49
+
46
50
  headers = {'Content-Type': 'application/json', 'Authorization': f"Bearer {nova_access.get_bearer_token()}"}
47
51
  response = requests.post(url, params=params, headers=headers, json=payload, timeout=60)
48
52
  response.raise_for_status()
@@ -114,7 +118,16 @@ def _extract_caseworker(task_dict: dict) -> Caseworker | None:
114
118
  return Caseworker(
115
119
  uuid = task_dict['caseWorker']['id'],
116
120
  ident = task_dict['caseWorker']['ident'],
117
- name = task_dict['caseWorker']['name']
121
+ name = task_dict['caseWorker']['name'],
122
+ type='user'
123
+ )
124
+
125
+ if 'caseWorkerGroup' in task_dict:
126
+ return Caseworker(
127
+ uuid = task_dict['caseWorkerGroup']['id'],
128
+ ident = None,
129
+ name = task_dict['caseWorkerGroup']['name'],
130
+ type='group'
118
131
  )
119
132
 
120
133
  return None
@@ -143,7 +156,6 @@ def update_task(task: Task, case_uuid: str, nova_access: NovaAccess):
143
156
  "caseUuid": case_uuid,
144
157
  "title": task.title,
145
158
  "description": task.description,
146
- "caseworkerPersonId": task.caseworker.uuid,
147
159
  "statusCode": task.status_code,
148
160
  "deadline": datetime_to_iso_string(task.deadline),
149
161
  "startDate": datetime_to_iso_string(task.started_date),
@@ -151,6 +163,11 @@ def update_task(task: Task, case_uuid: str, nova_access: NovaAccess):
151
163
  "taskType": "Aktivitet"
152
164
  }
153
165
 
166
+ if task.caseworker.type == 'user':
167
+ payload["caseworkerPersonId"] = task.caseworker.uuid
168
+ elif task.caseworker.type == 'group':
169
+ payload["caseworkerGroupId"] = task.caseworker.uuid
170
+
154
171
  headers = {'Content-Type': 'application/json', 'Authorization': f"Bearer {nova_access.get_bearer_token()}"}
155
172
  response = requests.put(url, params=params, headers=headers, json=payload, timeout=60)
156
173
  response.raise_for_status()
@@ -0,0 +1,72 @@
1
+ """This module contains helper functions regarding the KMD Nova API."""
2
+
3
+ from datetime import datetime
4
+ from typing import Optional
5
+
6
+ from itk_dev_shared_components.kmd_nova.nova_objects import Caseworker
7
+
8
+
9
+ def datetime_from_iso_string(date_string: Optional[str]) -> Optional[datetime]:
10
+ """A helper function to convert an ISO date string to a datetime.
11
+ If the date string is None, None is returned.
12
+
13
+ Args:
14
+ date_string: A date string in ISO format.
15
+
16
+ Returns:
17
+ A datetime object representing the date string.
18
+ """
19
+ if not date_string:
20
+ return None
21
+
22
+ return datetime.fromisoformat(date_string)
23
+
24
+
25
+ def datetime_to_iso_string(datetime_: Optional[datetime]) -> Optional[str]:
26
+ """A helper function to convert a datetime to an ISO formatted string.
27
+ If the the datetime is None, None is returned.
28
+
29
+ Args:
30
+ datetime_: The datetime object to convert.
31
+
32
+ Returns:
33
+ A datetime string in ISO format.
34
+ """
35
+ if datetime_:
36
+ return datetime_.isoformat()
37
+
38
+ return None
39
+
40
+
41
+ def extract_caseworker(response_dict: dict) -> Caseworker | None:
42
+ """Extract the case worker from a HTTP request response.
43
+ If the case worker is in a unexpected format, None is returned.
44
+
45
+ Args:
46
+ response_dict: The dictionary describing the response object.
47
+
48
+ Returns:
49
+ A case worker object describing the case worker if any.
50
+ """
51
+ try:
52
+ if 'caseworker' in response_dict:
53
+ if 'kspIdentity' in response_dict['caseworker']:
54
+ return Caseworker(
55
+ uuid = response_dict['caseworker']['kspIdentity']['novaUserId'],
56
+ name = response_dict['caseworker']['kspIdentity']['fullName'],
57
+ ident = response_dict['caseworker']['kspIdentity']['racfId'],
58
+ type='user'
59
+ )
60
+
61
+ if 'losIdentity' in response_dict['caseworker']:
62
+ return Caseworker(
63
+ uuid = response_dict['caseworker']['losIdentity']['novaUnitId'],
64
+ name = response_dict['caseworker']['losIdentity']['fullName'],
65
+ ident = str(response_dict['caseworker']['losIdentity']['administrativeUnitId']),
66
+ type='group'
67
+ )
68
+
69
+ except KeyError:
70
+ pass
71
+
72
+ return None
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: itk_dev_shared_components
3
- Version: 2.8.0
3
+ Version: 2.9.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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "itk_dev_shared_components"
7
- version = "2.8.0"
7
+ version = "2.9.0"
8
8
  authors = [
9
9
  { name="ITK Development", email="itk-rpa@mkb.aarhus.dk" },
10
10
  ]
@@ -1,36 +0,0 @@
1
- """This module contains helper functions regarding the KMD Nova API."""
2
-
3
- from datetime import datetime
4
- from typing import Optional
5
-
6
-
7
- def datetime_from_iso_string(date_string: Optional[str]) -> Optional[datetime]:
8
- """A helper function to convert an ISO date string to a datetime.
9
- If the date string is None, None is returned.
10
-
11
- Args:
12
- date_string: A date string in ISO format.
13
-
14
- Returns:
15
- A datetime object representing the date string.
16
- """
17
- if not date_string:
18
- return None
19
-
20
- return datetime.fromisoformat(date_string)
21
-
22
-
23
- def datetime_to_iso_string(datetime_: Optional[datetime]) -> Optional[str]:
24
- """A helper function to convert a datetime to an ISO formatted string.
25
- If the the datetime is None, None is returned.
26
-
27
- Args:
28
- datetime_: The datetime object to convert.
29
-
30
- Returns:
31
- A datetime string in ISO format.
32
- """
33
- if datetime_:
34
- return datetime_.isoformat()
35
-
36
- return None