pyxecm 1.5__py3-none-any.whl → 1.6__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 pyxecm might be problematic. Click here for more details.

pyxecm/otawp.py ADDED
@@ -0,0 +1,1810 @@
1
+ """
2
+ Otawp module for synchorinizing the pojects , publsh and create run time instances for that.
3
+ loanmanagement is such application.
4
+ """
5
+
6
+ import logging
7
+ import xml.etree.ElementTree as ET
8
+ import uuid
9
+ import json
10
+ import re
11
+ import time
12
+ import requests
13
+ from .otds import OTDS
14
+
15
+ logger = logging.getLogger("pyxecm.otawp")
16
+
17
+ REQUEST_HEADERS = {
18
+ "Content-Type": "text/xml; charset=utf-8",
19
+ "accept": "application/xml"
20
+ }
21
+
22
+ REQUEST_FORM_HEADERS = {
23
+ "accept": "application/xml;charset=utf-8",
24
+ "Content-Type": "application/x-www-form-urlencoded",
25
+ }
26
+
27
+ REQUEST_HEADERS_JSON = {
28
+ "Content-Type": "application/json; charset=utf-8",
29
+ "accept": "application/json"
30
+ }
31
+ REQUEST_TIMEOUT = 60
32
+
33
+ class OTAWP:
34
+ """Used to automate settings in OpenText AppWorks Platform (OTAWP)."""
35
+ _config: dict
36
+ _config = None
37
+ _cookie = None
38
+ _otawp_ticket = None
39
+
40
+ def __init__(
41
+ self,
42
+ protocol: str,
43
+ hostname: str,
44
+ port: int,
45
+ username: str | None = None,
46
+ password: str | None = None,
47
+ otawp_ticket: str | None = None,
48
+ ):
49
+ otawp_config = {}
50
+
51
+ otawp_config["hostname"] = hostname if hostname else "appworks"
52
+ otawp_config["protocol"] = protocol if protocol else "http"
53
+ otawp_config["port"] = port if port else 8080
54
+ otawp_config["username"] = username if username else "sysadmin"
55
+ otawp_config["password"] = password if password else ""
56
+
57
+ if otawp_ticket:
58
+ self._cookie = {"defaultinst_SAMLart": otawp_ticket}
59
+
60
+ otds_base_url = "{}://{}".format(protocol, otawp_config["hostname"])
61
+ if str(port) not in ["80", "443"]:
62
+ otds_base_url += f":{port}"
63
+ otds_base_url += "/home/system"
64
+
65
+ otawp_config["gatewayAuthenticationUrl"] = (
66
+ otds_base_url
67
+ + "/com.eibus.web.soap.Gateway.wcp?organization=o=system,cn=cordys,cn=defaultInst,o=opentext.net"
68
+ )
69
+
70
+ otawp_config["soapGatewayUrl"] = (
71
+ otds_base_url
72
+ + "/com.eibus.web.soap.Gateway.wcp?organization=o=system,cn=cordys,cn=defaultInst,o=opentext.net&defaultinst_ct=abcd"
73
+ )
74
+
75
+ otawp_config["createPriority"] = (
76
+ otds_base_url
77
+ + "/app/entityRestService/api/OpentextCaseManagement/entities/Priority?defaultinst_ct=abcd"
78
+ )
79
+ otawp_config["getAllPriorities"] = (
80
+ otds_base_url
81
+ + "/app/entityRestService/api/OpentextCaseManagement/entities/Priority/lists/PriorityList"
82
+ )
83
+
84
+ otawp_config["createCustomer"] = (
85
+ otds_base_url
86
+ + "/app/entityRestService/api/OpentextCaseManagement/entities/Customer?defaultinst_ct=abcd"
87
+ )
88
+ otawp_config["getAllCustomeres"] = (
89
+ otds_base_url
90
+ + "/app/entityRestService/api/OpentextCaseManagement/entities/Customer/lists/CustomerList"
91
+ )
92
+
93
+ otawp_config["createCaseType"] = (
94
+ otds_base_url
95
+ + "/app/entityRestService/api/OpentextCaseManagement/entities/CaseType?defaultinst_ct=abcd"
96
+ )
97
+ otawp_config["getAllCaseTypes"] = (
98
+ otds_base_url
99
+ + "/app/entityRestService/api/OpentextCaseManagement/entities/CaseType/lists/AllCaseTypes"
100
+ )
101
+
102
+ otawp_config["createCategory"] = (
103
+ otds_base_url
104
+ + "/app/entityRestService/api/OpentextCaseManagement/entities/Category?defaultinst_ct=abcd"
105
+ )
106
+ otawp_config["getAllCategories"] = (
107
+ otds_base_url
108
+ + "/app/entityRestService/api/OpentextCaseManagement/entities/Category/lists/CategoryList"
109
+ )
110
+
111
+ otawp_config["createSource"] = (
112
+ otds_base_url
113
+ + "/app/entityRestService/api/OpentextCaseManagement/entities/Source"
114
+ )
115
+
116
+ otawp_config["getAllSources"] = (
117
+ otds_base_url
118
+ + "/app/entityRestService/api/OpentextCaseManagement/entities/Source/lists/AllSources"
119
+ )
120
+
121
+ otawp_config["getAllSubCategories"] = (
122
+ otds_base_url
123
+ + "/app/entityRestService/api/OpentextCaseManagement/entities/Category/childEntities/SubCategory/lists/AllSubcategories"
124
+ )
125
+
126
+ otawp_config["baseurl"] = (
127
+ otds_base_url
128
+ + ""
129
+ )
130
+ otawp_config["createLoan"] = (
131
+ otds_base_url
132
+ + "/app/entityRestService/api/OpentextCaseManagement/entities/Case?defaultinst_ct=abcd"
133
+ )
134
+ otawp_config["getAllLoans"] = (
135
+ otds_base_url
136
+ + "/app/entityRestService/api/OpentextCaseManagement/entities/Case/lists/AllCasesList"
137
+ )
138
+ self._config = otawp_config
139
+
140
+ # end method definition
141
+
142
+ def baseurl(self) -> dict:
143
+ """Returns the configuration dictionary
144
+ Returns:
145
+ dict: Configuration dictionary
146
+ """
147
+ return self.config()["baseurl"]
148
+
149
+ # end method definition
150
+
151
+ def config(self) -> dict:
152
+ """Returns the configuration dictionary
153
+ Returns:
154
+ dict: Configuration dictionary
155
+ """
156
+ return self._config
157
+
158
+ # end method definition
159
+
160
+ def cookie(self) -> dict:
161
+ """Returns the login cookie of OTAWP.
162
+ This is set by the authenticate() method
163
+ Returns:
164
+ dict: OTAWP cookie
165
+ """
166
+ return self._cookie
167
+
168
+ # end method definition
169
+
170
+ def credentials(self) -> str:
171
+ """Returns the SOAP payload with credentials (username and password)
172
+ Returns:
173
+ str: SOAP payload with username and password
174
+ """
175
+ username = self.config()["username"]
176
+ password = self.config()["password"]
177
+
178
+ soap_payload = f"""
179
+ <SOAP:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/">
180
+ <SOAP:Header>
181
+ <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
182
+ <wsse:UsernameToken xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
183
+ <wsse:Username>{username}</wsse:Username>
184
+ <wsse:Password>{password}</wsse:Password>
185
+ </wsse:UsernameToken>
186
+ <i18n:international xmlns:i18n="http://www.w3.org/2005/09/ws-i18n">
187
+ <locale xmlns="http://www.w3.org/2005/09/ws-i18n">en-US</locale>
188
+ </i18n:international>
189
+ </wsse:Security>
190
+ </SOAP:Header>
191
+ <SOAP:Body>
192
+ <samlp:Request xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" MajorVersion="1" MinorVersion="1">
193
+ <samlp:AuthenticationQuery>
194
+ <saml:Subject xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion">
195
+ <saml:NameIdentifier Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">{username}</saml:NameIdentifier>
196
+ </saml:Subject>
197
+ </samlp:AuthenticationQuery>
198
+ </samlp:Request>
199
+ </SOAP:Body>
200
+ </SOAP:Envelope>
201
+ """
202
+ return soap_payload
203
+
204
+ # end method definition
205
+
206
+ def credential_url(self) -> str:
207
+ """Returns the Credentials URL of OTAWP
208
+
209
+ Returns:
210
+ str: Credentials URL
211
+ """
212
+ return self.config()["gatewayAuthenticationUrl"]
213
+
214
+ # end method definition
215
+
216
+ def gateway_url(self) -> str:
217
+ """Returns soapGatewayUrl URL of OTAWP
218
+
219
+ Returns:
220
+ str: soapGatewayUrl URL
221
+ """
222
+ return self.config()["soapGatewayUrl"]
223
+
224
+ # end method definition
225
+
226
+ def create_priority_url(self) -> str:
227
+ """Returns createPriority URL of OTAWP
228
+
229
+ Returns:
230
+ str: createPriority URL
231
+ """
232
+ return self.config()["createPriority"]
233
+
234
+ # end method definition
235
+
236
+ def get_all_priorities_url(self) -> str:
237
+ """Returns getAllPriorities URL of OTAWP
238
+
239
+ Returns:
240
+ str: getAllPriorities URL
241
+ """
242
+ return self.config()["getAllPriorities"]
243
+
244
+ # end method definition
245
+
246
+ def create_customer_url(self) -> str:
247
+ """Returns createCustomer URL of OTAWP
248
+
249
+ Returns:
250
+ str: createCustomer url
251
+ """
252
+ return self.config()["createCustomer"]
253
+
254
+ # end method definition
255
+
256
+ def get_all_customeres_url(self) -> str:
257
+ """Returns getAllCustomeres url of OTAWP
258
+
259
+ Returns:
260
+ str: getAllCustomeres url
261
+ """
262
+ return self.config()["getAllCustomeres"]
263
+
264
+ # end method definition
265
+
266
+ def create_casetype_url(self) -> str:
267
+ """Returns createCaseType url of OTAWP
268
+
269
+ Returns:
270
+ str: createCaseType url
271
+ """
272
+ return self.config()["createCaseType"]
273
+
274
+ # end method definition
275
+
276
+ def get_all_case_types_url(self) -> str:
277
+ """Returns getAllCaseTypes URL of OTAWP
278
+
279
+ Returns:
280
+ str: getAllCaseTypes URL
281
+ """
282
+ return self.config()["getAllCaseTypes"]
283
+
284
+ # end method definition
285
+
286
+ def create_category_url(self) -> str:
287
+ """Returns createCategory URL of OTAWP
288
+
289
+ Returns:
290
+ str: createCategory URL
291
+ """
292
+ return self.config()["createCategory"]
293
+
294
+ # end method definition
295
+
296
+ def get_all_categories_url(self) -> str:
297
+ """Returns the getAllCategories URL of OTAWP
298
+
299
+ Returns:
300
+ str: getAllCategories URL
301
+ """
302
+ return self.config()["getAllCategories"]
303
+
304
+ # end method definition
305
+
306
+ def get_all_loans_url(self) -> str:
307
+ """Returns getAllLoans URL of OTAWP
308
+
309
+ Returns:
310
+ str: getAllLoans URL
311
+ """
312
+ return self.config()["getAllLoans"]
313
+
314
+ # end method definition
315
+
316
+ def remove_namespace(self, tag):
317
+ """Remove namespace from XML tag."""
318
+ return tag.split('}', 1)[-1]
319
+
320
+ # end method definition
321
+
322
+ def parse_xml(self, xml_string):
323
+ """Parse XML string and return a dictionary without namespaces."""
324
+ def element_to_dict(element):
325
+ """Convert XML element to dictionary."""
326
+ tag = self.remove_namespace(element.tag)
327
+ children = list(element)
328
+ if children:
329
+ return {tag: {self.remove_namespace(child.tag): element_to_dict(child) for child in children}}
330
+ return {tag: element.text.strip() if element.text else None}
331
+ root = ET.fromstring(xml_string)
332
+ return element_to_dict(root)
333
+
334
+ # end method definition
335
+
336
+ def find_key(self, data, target_key):
337
+ """Recursively search for a key in a nested dictionary and return its value."""
338
+ if isinstance(data, dict):
339
+ if target_key in data:
340
+ return data[target_key]
341
+ for _, value in data.items():
342
+ result = self.find_key(value, target_key)
343
+ if result is not None:
344
+ return result
345
+ elif isinstance(data, list):
346
+ for item in data:
347
+ result = self.find_key(item, target_key)
348
+ if result is not None:
349
+ return result
350
+ return None
351
+
352
+ # end method definition
353
+
354
+ def parse_request_response(
355
+ self,
356
+ response_object: object,
357
+ additional_error_message: str = "",
358
+ show_error: bool = True,
359
+ ) -> dict | None:
360
+ """Converts the text property of a request response object to a Python dict in a safe way
361
+ that also handles exceptions.
362
+
363
+ Content Server may produce corrupt response when it gets restarted
364
+ or hitting resource limits. So we try to avoid a fatal error and bail
365
+ out more gracefully.
366
+
367
+ Args:
368
+ response_object (object): this is reponse object delivered by the request call
369
+ additional_error_message (str): print a custom error message
370
+ show_error (bool): if True log an error, if False log a warning
371
+
372
+ Returns:
373
+ dict: response or None in case of an error
374
+ """
375
+
376
+ if not response_object:
377
+ return None
378
+
379
+ try:
380
+ dict_object = json.loads(response_object.text)
381
+ except json.JSONDecodeError as exception:
382
+ if additional_error_message:
383
+ message = "Cannot decode response as JSon. {}; error -> {}".format(
384
+ additional_error_message, exception
385
+ )
386
+ else:
387
+ message = "Cannot decode response as JSon; error -> {}".format(
388
+ exception
389
+ )
390
+ if show_error:
391
+ logger.error(message)
392
+ else:
393
+ logger.warning(message)
394
+ return None
395
+ return dict_object
396
+
397
+ # end method definition
398
+
399
+ def authenticate(self, revalidate: bool = False) -> dict | None:
400
+ """Authenticate at appworks.
401
+
402
+ Args:
403
+ revalidate (bool, optional): determine if a re-authentication is enforced
404
+ (e.g. if session has timed out with 401 error)
405
+ Returns:
406
+ dict: Cookie information. Also stores cookie information in self._cookie
407
+ """
408
+
409
+ logger.info("SAMLart generation started")
410
+ if self._cookie and not revalidate:
411
+ logger.info(
412
+ "Session still valid - return existing cookie -> %s",
413
+ str(self._cookie),
414
+ )
415
+ return self._cookie
416
+
417
+ otawp_ticket = "NotSet"
418
+
419
+ response = None
420
+ try:
421
+ self.credentials()
422
+ response = requests.post(
423
+ url=self.credential_url(),
424
+ data=self.credentials(),
425
+ headers=REQUEST_HEADERS,
426
+ timeout=REQUEST_TIMEOUT
427
+ )
428
+ except requests.exceptions.RequestException as exception:
429
+ logger.warning(
430
+ "Unable to connect to -> %s; error -> %s",
431
+ self.credential_url(),
432
+ exception.strerror,
433
+ )
434
+ logger.warning("OTAWP service may not be ready yet.")
435
+ return None
436
+
437
+ if response.ok:
438
+ logger.info("SAMLart generated successfully")
439
+ authenticate_dict = self.parse_xml(response.text)
440
+ if not authenticate_dict:
441
+ return None
442
+ assertion_artifact_dict = self.find_key(
443
+ authenticate_dict, "AssertionArtifact"
444
+ )
445
+ if isinstance(assertion_artifact_dict, dict):
446
+ otawp_ticket = assertion_artifact_dict.get("AssertionArtifact")
447
+ logger.info("SAML token -> %s", otawp_ticket)
448
+ else:
449
+ logger.error("Failed to request an OTAWP ticket; error -> %s", response.text)
450
+ return None
451
+
452
+ self._cookie = {"defaultinst_SAMLart": otawp_ticket, "defaultinst_ct": "abcd"}
453
+ self._otawp_ticket = otawp_ticket
454
+
455
+ return self._cookie
456
+
457
+ # end method definition
458
+
459
+ def create_workspace(
460
+ self,
461
+ workspace_name: str,
462
+ workspace_id: str
463
+ ) -> dict | None:
464
+ """Creates a workspace in cws
465
+ Args:
466
+ workspace_name (str): workspace_name
467
+ workspace_id (str): workspace_id
468
+ Returns:
469
+ response test or error text
470
+ """
471
+
472
+ logger.info(
473
+ "Create workspace with name -> '%s' and ID -> %s...",
474
+ workspace_name,
475
+ workspace_id,
476
+ )
477
+ unique_id = uuid.uuid4()
478
+
479
+ license_post_body_json = f"""<SOAP:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/">
480
+ <SOAP:Body>
481
+ <createWorkspace xmlns="http://schemas.cordys.com/cws/runtime/types/workspace/creation/DevelopmentWorkspaceCreator/1.0" async="false" workspaceID="__CWS System__" xmlns:c="http://schemas.cordys.com/cws/1.0">
482
+ <instance>
483
+ <c:Document s="T" path="D43B04C1-CD0B-A1EB-A898-53C71DB5D652">
484
+ <c:Header>
485
+ <c:System>
486
+ <c:TypeID>001A6B1E-0C0C-11DF-F5E9-866B84E5D671</c:TypeID>
487
+ <c:ID>D43B04C1-CD0B-A1EB-A898-53C71DB5D652</c:ID>
488
+ <c:Name>D43B04C1-CD0B-A1EB-A898-53C71DB5D652</c:Name>
489
+ <c:Description>D43B04C1-CD0B-A1EB-A898-53C71DB5D652</c:Description>
490
+ </c:System>
491
+ </c:Header>
492
+ <c:Content>
493
+ <DevelopmentWorkspaceCreator type="com.cordys.cws.runtime.types.workspace.creation.DevelopmentWorkspaceCreator" runtimeDocumentID="D43B04C1-CD0B-A1EB-A898-53C71DB61652">
494
+ <Workspace>
495
+ <uri id="{workspace_id}"/>
496
+ </Workspace>
497
+ </DevelopmentWorkspaceCreator>
498
+ </c:Content>
499
+ </c:Document>
500
+ </instance>
501
+ <__prefetch>
502
+ <Document xmlns="http://schemas.cordys.com/cws/1.0" path="{workspace_name}" s="N" isLocal="IN_LOCAL">
503
+ <Header>
504
+ <System>
505
+ <ID>{workspace_id}</ID>
506
+ <Name>{workspace_name}</Name>
507
+ <TypeID>{{4CE11E00-2D97-45C0-BC6C-FAEC1D871026}}</TypeID>
508
+ <ParentID/>
509
+ <Description>{workspace_name}</Description>
510
+ <CreatedBy>sysadmin</CreatedBy>
511
+ <CreationDate/>
512
+ <LastModifiedBy>sysadmin</LastModifiedBy>
513
+ <LastModifiedDate>2021-04-21T06:52:34.254</LastModifiedDate>
514
+ <FQN/>
515
+ <Annotation/>
516
+ <ParentID/>
517
+ <OptimisticLock/>
518
+ </System>
519
+ </Header>
520
+ <Content>
521
+ <DevelopmentWorkspace xmlns="http://schemas.cordys.com/cws/runtime/types/workspace/DevelopmentWorkspace/1.0" runtimeDocumentID="D43B04C1-CD0B-A1EB-A898-53C71DB59652" type="com.cordys.cws.runtime.types.workspace.DevelopmentWorkspace">
522
+ <ExternalID/>
523
+ <OrganizationName/>
524
+ <SCMAdapter>
525
+ <uri id="{unique_id}"/>
526
+ </SCMAdapter>
527
+ <UpgradedTo/>
528
+ <LastWorkspaceUpgradeStep/>
529
+ <Metaspace/>
530
+ </DevelopmentWorkspace>
531
+ </Content>
532
+ </Document>
533
+ <Document xmlns="http://schemas.cordys.com/cws/1.0" path="{workspace_name}/Untitled No SCM adapter" s="N" isLocal="IN_LOCAL">
534
+ <Header>
535
+ <System>
536
+ <ID>{unique_id}</ID>
537
+ <Name>Untitled No SCM adapter</Name>
538
+ <TypeID>{{E89F3F62-8CA3-4F93-95A8-F76642FD5124}}</TypeID>
539
+ <ParentID>{workspace_id}</ParentID>
540
+ <Description>Untitled No SCM adapter</Description>
541
+ <CreatedBy>sysadmin</CreatedBy>
542
+ <CreationDate/>
543
+ <LastModifiedBy>sysadmin</LastModifiedBy>
544
+ <LastModifiedDate>2021-04-21T06:52:34.254</LastModifiedDate>
545
+ <FQN/>
546
+ <Annotation/>
547
+ <OptimisticLock/>
548
+ </System>
549
+ </Header>
550
+ <Content>
551
+ <NullAdapter xmlns="http://schemas.cordys.com/cws/runtime/types/teamdevelopment/NullAdapter/1.0" runtimeDocumentID="D43B04C1-CD0B-A1EB-A898-53C71DB51652" type="com.cordys.cws.runtime.types.teamdevelopment.NullAdapter">
552
+ <Workspace>
553
+ <uri id="{workspace_id}"/>
554
+ </Workspace>
555
+ </NullAdapter>
556
+ </Content>
557
+ </Document>
558
+ </__prefetch>
559
+ </createWorkspace>
560
+ </SOAP:Body>
561
+ </SOAP:Envelope>"""
562
+
563
+ retries = 0
564
+ while True:
565
+ response = requests.post(
566
+ url=self.gateway_url(),
567
+ data=license_post_body_json,
568
+ headers=REQUEST_HEADERS,
569
+ cookies=self.cookie(),
570
+ timeout=None,
571
+ )
572
+ if response.ok:
573
+ logger.info(
574
+ "Successfully created workspace -> '%s' with ID -> %s",
575
+ workspace_name,
576
+ workspace_id,
577
+ )
578
+ return response.text
579
+ # Check if Session has expired - then re-authenticate and try once more
580
+ if response.status_code == 401 and retries == 0:
581
+ logger.warning("Session has expired - try to re-authenticate...")
582
+ self.authenticate(revalidate=True)
583
+ retries += 1
584
+ logger.error(response.text)
585
+ return response.text
586
+
587
+ # end method definition
588
+
589
+ def sync_workspace(
590
+ self,
591
+ workspace_name: str,
592
+ workspace_id: str
593
+ ) -> dict | None:
594
+ """ sync workspaces
595
+ Args:
596
+ workspace_name (str): workspace_name
597
+ workspace_id (str): workspace_id
598
+ Returns:
599
+ Request response (dictionary) or None if the REST call fails
600
+ """
601
+
602
+ logger.info("Start synchronization of workspace -> '%s'...", workspace_name)
603
+
604
+ license_post_body_json = f"""<SOAP:Envelope xmlns:SOAP=\"http://schemas.xmlsoap.org/soap/envelope/\">\r\n" +
605
+ " <SOAP:Body>\r\n" +
606
+ " <Synchronize workspaceID=\"{workspace_id}\" xmlns=\"http://schemas.cordys.com/cws/synchronize/1.0\" >\r\n" +
607
+ " <DocumentID/>\r\n" +
608
+ " <Asynchronous>false</Asynchronous>\r\n" +
609
+ " </Synchronize>\r\n" +
610
+ " </SOAP:Body>\r\n" +
611
+ "</SOAP:Envelope>"""
612
+ # self.authenticate(revalidate=True)
613
+
614
+ retries = 0
615
+ while True:
616
+ response = requests.post(
617
+ url=self.gateway_url(),
618
+ data=license_post_body_json,
619
+ headers=REQUEST_HEADERS,
620
+ cookies=self.cookie(),
621
+ timeout=None,
622
+ )
623
+ if response.ok:
624
+ logger.info("Workspace -> '%s' synced successfully", workspace_name)
625
+ return self.parse_xml(response.text)
626
+ if response.status_code == 401 and retries == 0:
627
+ logger.warning("Session has expired - try to re-authenticate...")
628
+ self.authenticate(revalidate=True)
629
+ retries += 1
630
+ logger.error(response.text)
631
+ return None
632
+
633
+ # end method definition
634
+
635
+ def publish_project(
636
+ self,
637
+ workspace_name: str,
638
+ project_name: str,
639
+ workspace_id: str,
640
+ project_id: str
641
+ ) -> dict | bool:
642
+ """
643
+ Publish the workspace project.
644
+
645
+ Args:
646
+ workspace_name (str): The name of the workspace.
647
+ project_name (str): The name of the project.
648
+ workspace_id (str): The workspace ID.
649
+ project_id (str): The project ID.
650
+
651
+ Returns:
652
+ dict | bool: Request response (dictionary) if successful, False if it fails after retries.
653
+ """
654
+
655
+ logger.info(
656
+ "Publish project -> '%s' in workspace -> '%s'...",
657
+ project_name,
658
+ workspace_name,
659
+ )
660
+
661
+ project_publish = f"""<SOAP:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/">
662
+ <SOAP:Body>
663
+ <deployObject xmlns="http://schemas.cordys.com/cws/internal/buildhelper/BuildHelper/1.0" async="false" workspaceID="{workspace_id}" xmlns:c="http://schemas.cordys.com/cws/1.0">
664
+ <object>
665
+ <c:uri id="{project_id}"/>
666
+ </object>
667
+ </deployObject>
668
+ </SOAP:Body>
669
+ </SOAP:Envelope>"""
670
+
671
+ # Initialize retry parameters
672
+ max_retries = 10
673
+ retries = 0
674
+ success_indicator = "deployObjectResponse"
675
+
676
+ while retries < max_retries:
677
+ response = requests.post(
678
+ url=self.gateway_url(),
679
+ data=project_publish,
680
+ headers=REQUEST_HEADERS,
681
+ cookies=self.cookie(),
682
+ timeout=None,
683
+ )
684
+
685
+ # Check if the response is successful
686
+ if response.ok:
687
+ # Check if the response contains the success indicator
688
+ if success_indicator in response.text:
689
+ logger.info(
690
+ "Successfully published project -> '%s' in workspace -> '%s'",
691
+ project_name,
692
+ workspace_name,
693
+ )
694
+ return True
695
+
696
+ # If success indicator is not found, retry
697
+ logger.warning(
698
+ "Expected success indicator -> '%s' but it was not found in response. Retrying in 30 seconds... (Attempt %d of %d)",
699
+ success_indicator,
700
+ retries + 1,
701
+ max_retries,
702
+ )
703
+ time.sleep(30)
704
+ retries += 1
705
+ continue
706
+
707
+ # Check for session expiry and retry authentication (only once)
708
+ if response.status_code == 401 and retries == 0:
709
+ logger.warning("Session has expired - re-authenticating...")
710
+ self.authenticate(revalidate=True)
711
+ retries += 1
712
+ continue
713
+
714
+ # Log any other error and break the loop
715
+ logger.error(
716
+ "Error publishing project -> '%s' in workspace -> '%s'; response -> %s",
717
+ project_name,
718
+ workspace_name,
719
+ response.text,
720
+ )
721
+ break
722
+
723
+ # After reaching the maximum number of retries, log failure and return False
724
+ logger.error(
725
+ "Max retries reached. Failed to publish project -> '%s' in workspace -> '%s'.",
726
+ project_name,
727
+ workspace_name,
728
+ )
729
+ return False
730
+
731
+ # end method definition
732
+
733
+ def create_priority(
734
+ self,
735
+ name: str,
736
+ description: str,
737
+ status: int
738
+ ) -> dict | None:
739
+ """ Create Priority entity instances.
740
+
741
+ Args:
742
+ name (str): name
743
+ description (str): description
744
+ status (int): status
745
+ Returns:
746
+ dict: Request response (dictionary) or None if the REST call fails
747
+ """
748
+ create_priority = {
749
+ "Properties": {
750
+ "Name": name,
751
+ "Description": description,
752
+ "Status": status
753
+ }
754
+ }
755
+ retries = 0
756
+ while True:
757
+ response = requests.post(
758
+ url=self.create_priority_url(),
759
+ json=create_priority,
760
+ headers=REQUEST_HEADERS_JSON,
761
+ cookies=self.cookie(),
762
+ timeout=None,
763
+ )
764
+ if response.ok:
765
+ logger.info("Priority created successfully")
766
+ return self.parse_request_response(
767
+ response, "This can be normal during restart", False
768
+ )
769
+ if response.status_code == 401 and retries == 0:
770
+ logger.warning("Session has expired - try to re-authenticate...")
771
+ self.authenticate(revalidate=True)
772
+ retries += 1
773
+ logger.error(response.text)
774
+ return None
775
+
776
+ # end method definition
777
+
778
+ def get_all_priorities(
779
+ self
780
+ ) -> dict | None:
781
+ """ Get all priorities from entity
782
+ Args:
783
+ None
784
+ Returns:
785
+ dict: Request response (dictionary) or None if the REST call fails
786
+ """
787
+ retries = 0
788
+ while True:
789
+ response = requests.get(
790
+ url=self.get_all_priorities_url(),
791
+ headers=REQUEST_HEADERS_JSON,
792
+ cookies=self.cookie(),
793
+ timeout=None,
794
+ )
795
+ if response.ok:
796
+ authenticate_dict = self.parse_request_response(
797
+ response, "This can be normal during restart", False
798
+ )
799
+ if not authenticate_dict:
800
+ return None
801
+ return authenticate_dict
802
+ if response.status_code == 401 and retries == 0:
803
+ logger.warning("Session has expired - try to re-authenticate...")
804
+ self.authenticate(revalidate=True)
805
+ retries += 1
806
+ logger.error(response.text)
807
+ return None
808
+
809
+ # end method definition
810
+
811
+ def create_customer(
812
+ self,
813
+ customer_name: str,
814
+ legal_business_name: str,
815
+ trading_name: str
816
+ ) -> dict | None:
817
+ """ Create customer entity instance
818
+
819
+ Args:
820
+ customer_name (str): customer_name
821
+ legal_business_name (str): legal_business_name
822
+ trading_name (str): trading_name
823
+ Returns:
824
+ dict: Request response (dictionary) or None if the REST call fails
825
+ """
826
+ create_customer = {
827
+ "Properties": {
828
+ "CustomerName": customer_name,
829
+ "LegalBusinessName": legal_business_name,
830
+ "TradingName": trading_name
831
+ }
832
+ }
833
+ retries = 0
834
+ while True:
835
+ response = requests.post(
836
+ url=self.create_customer_url(),
837
+ json=create_customer,
838
+ headers=REQUEST_HEADERS_JSON,
839
+ cookies=self.cookie(),
840
+ timeout=None,
841
+ )
842
+ if response.ok:
843
+ logger.info("Customer record created successfully")
844
+ return self.parse_request_response(response, "This can be normal during restart", False)
845
+ if response.status_code == 401 and retries == 0:
846
+ logger.warning("Session has expired - try to re-authenticate...")
847
+ self.authenticate(revalidate=True)
848
+ retries += 1
849
+ logger.error(response.text)
850
+ return None
851
+
852
+ # end method definition
853
+
854
+ def get_all_customers(
855
+ self
856
+ ) -> dict | None:
857
+ """get all customer entity imstances
858
+
859
+ Args:
860
+ None
861
+ Returns:
862
+ dict: Request response (dictionary) or None if the REST call fails
863
+ """
864
+
865
+ retries = 0
866
+ while True:
867
+ response = requests.get(
868
+ url=self.get_all_customeres_url(),
869
+ headers=REQUEST_HEADERS_JSON,
870
+ cookies=self.cookie(),
871
+ timeout=None,
872
+ )
873
+ if response.ok:
874
+ authenticate_dict = self.parse_request_response(
875
+ response, "This can be normal during restart", False
876
+ )
877
+ if not authenticate_dict:
878
+ return None
879
+ return authenticate_dict
880
+ if response.status_code == 401 and retries == 0:
881
+ logger.warning("Session has expired - try to re-authenticate...")
882
+ self.authenticate(revalidate=True)
883
+ retries += 1
884
+ logger.error(response.text)
885
+ return None
886
+
887
+ # end method definition
888
+
889
+ def create_case_type(
890
+ self,
891
+ name: str,
892
+ description: str,
893
+ status: int
894
+ ) -> dict | None:
895
+ """create case_type entity instances
896
+
897
+ Args:
898
+ name (str): name
899
+ description (str): description
900
+ status (str): status
901
+ Returns:
902
+ dict: Request response (dictionary) or None if the REST call fails
903
+ """
904
+ create_case_type = {
905
+ "Properties": {
906
+ "Name": name,
907
+ "Description": description,
908
+ "Status": status
909
+ }
910
+ }
911
+ retries = 0
912
+ while True:
913
+ response = requests.post(
914
+ url=self.create_casetype_url(),
915
+ json=create_case_type,
916
+ headers=REQUEST_HEADERS_JSON,
917
+ cookies=self.cookie(),
918
+ timeout=None,
919
+ )
920
+ if response.ok:
921
+ logger.info("Case type created successfully")
922
+ return self.parse_request_response(
923
+ response, "This can be normal during restart", False
924
+ )
925
+ if response.status_code == 401 and retries == 0:
926
+ logger.warning("Session has expired - try to re-authenticate...")
927
+ self.authenticate(revalidate=True)
928
+ retries += 1
929
+ logger.error(response.text)
930
+ return None
931
+
932
+ # end method definition
933
+
934
+ def get_all_case_type(
935
+ self
936
+ ) -> dict | None:
937
+ """get all case type entty instances
938
+
939
+ Args:
940
+ None
941
+ Returns:
942
+ dict: Request response (dictionary) or None if the REST call fails
943
+ """
944
+ retries = 0
945
+ while True:
946
+ response = requests.get(
947
+ url=self.get_all_case_types_url(),
948
+ headers=REQUEST_HEADERS_JSON,
949
+ cookies=self.cookie(),
950
+ timeout=None,
951
+ )
952
+ if response.ok:
953
+ authenticate_dict = self.parse_request_response(
954
+ response, "This can be normal during restart", False
955
+ )
956
+ if not authenticate_dict:
957
+ return None
958
+ return authenticate_dict
959
+ if response.status_code == 401 and retries == 0:
960
+ logger.warning("Session has expired - try to re-authenticate...")
961
+ self.authenticate(revalidate=True)
962
+ retries += 1
963
+ logger.error(response.text)
964
+ return None
965
+
966
+ # end method definition
967
+
968
+ def create_category(
969
+ self,
970
+ case_prefix: str,
971
+ description: str,
972
+ name: str,
973
+ status: int
974
+ ) -> dict | None:
975
+ """create category entity instance
976
+
977
+ Args:
978
+ case_prefix (str): workspace_name
979
+ description (str): description
980
+ name (str): name
981
+ status (str): status
982
+ Returns:
983
+ dict: Request response (dictionary) or None if the REST call fails
984
+ """
985
+ create_categoty = {
986
+ "Properties": {
987
+ "CasePrefix": case_prefix,
988
+ "Description": description,
989
+ "Name": name,
990
+ "Status": status
991
+ }
992
+ }
993
+ retries = 0
994
+ while True:
995
+ response = requests.post(
996
+ url=self.create_category_url(),
997
+ json=create_categoty,
998
+ headers=REQUEST_HEADERS_JSON,
999
+ cookies=self.cookie(),
1000
+ timeout=None,
1001
+ )
1002
+ if response.ok:
1003
+ logger.info("Category created successfully")
1004
+ return self.parse_request_response(response, "This can be normal during restart", False)
1005
+ if response.status_code == 401 and retries == 0:
1006
+ logger.warning("Session has expired - try to re-authenticate...")
1007
+ self.authenticate(revalidate=True)
1008
+ retries += 1
1009
+ logger.error(response.text)
1010
+ return None
1011
+
1012
+ # end method definition
1013
+
1014
+ def get_all_categories(
1015
+ self
1016
+ ) -> dict | None:
1017
+ """Get all categories entity intances
1018
+
1019
+ Args:
1020
+ None
1021
+ Returns:
1022
+ dict: Request response (dictionary) or None if the REST call fails
1023
+ """
1024
+
1025
+ retries = 0
1026
+ while True:
1027
+ response = requests.get(
1028
+ url=self.get_all_categories_url(),
1029
+ headers=REQUEST_HEADERS_JSON,
1030
+ cookies=self.cookie(),
1031
+ timeout=None,
1032
+ )
1033
+ if response.ok:
1034
+ authenticate_dict = self.parse_request_response(
1035
+ response, "This can be normal during restart", False
1036
+ )
1037
+ if not authenticate_dict:
1038
+ return None
1039
+ return authenticate_dict
1040
+ if response.status_code == 401 and retries == 0:
1041
+ logger.warning("Session has expired - try to re-authenticate...")
1042
+ self.authenticate(revalidate=True)
1043
+ retries += 1
1044
+ logger.error(response.text)
1045
+ return None
1046
+
1047
+ # end method definition
1048
+
1049
+ def create_sub_categoy(
1050
+ self,
1051
+ name: str,
1052
+ description: str,
1053
+ status: int,
1054
+ parentid: int
1055
+ ) -> dict | None:
1056
+ """ create sub_categoy entity istances
1057
+
1058
+ Args:
1059
+ name (str): name
1060
+ description (str): description
1061
+ status (int): status
1062
+ parentid (int): parentid
1063
+ Returns:
1064
+ dict: Request response (dictionary) or None if the REST call fails
1065
+ """
1066
+ create_sub_categoty = {
1067
+ "Properties": {
1068
+ "Name": name,
1069
+ "Description": description,
1070
+ "Status": status
1071
+ }
1072
+ }
1073
+ retries = 0
1074
+ while True:
1075
+ base_url = self.baseurl()
1076
+ endpoint = "/app/entityRestService/api/OpentextCaseManagement/entities/Category/items/"
1077
+ child_path = "/childEntities/SubCategory?defaultinst_ct=abcd"
1078
+ response = requests.post(
1079
+ url=base_url + endpoint + str(parentid) + child_path,
1080
+ json=create_sub_categoty,
1081
+ headers=REQUEST_HEADERS_JSON,
1082
+ cookies=self.cookie(),
1083
+ timeout=None,
1084
+ )
1085
+ if response.ok:
1086
+ logger.info("Sub category created successfully")
1087
+ return self.parse_request_response(
1088
+ response, "This can be normal during restart", False
1089
+ )
1090
+ if response.status_code == 401 and retries == 0:
1091
+ logger.warning("Session has expired - try to re-authenticate...")
1092
+ self.authenticate(revalidate=True)
1093
+ retries += 1
1094
+ logger.error(response.text)
1095
+ return None
1096
+
1097
+ # end method definition
1098
+
1099
+ def get_all_sub_categeries(
1100
+ self,
1101
+ parentid: int
1102
+ ) -> dict | None:
1103
+ """Get all sub categeries entity instances
1104
+
1105
+ Args:
1106
+ parentid (int): parentid
1107
+ Returns:
1108
+ dict: Request response (dictionary) or None if the REST call fails
1109
+ """
1110
+ retries = 0
1111
+ while True:
1112
+ base_url = self.baseurl()
1113
+ endpoint = "/app/entityRestService/api/OpentextCaseManagement/entities/Category/items/"
1114
+ child_path = "/childEntities/SubCategory"
1115
+ response = requests.get(
1116
+ url=base_url + endpoint + str(parentid) + child_path,
1117
+ headers=REQUEST_HEADERS_JSON,
1118
+ cookies=self.cookie(),
1119
+ timeout=None,
1120
+ )
1121
+ if response.ok:
1122
+ authenticate_dict = self.parse_request_response(
1123
+ response, "This can be normal during restart", False
1124
+ )
1125
+ if not authenticate_dict:
1126
+ return None
1127
+ return authenticate_dict
1128
+ if response.status_code == 401 and retries == 0:
1129
+ logger.warning("Session has expired - try to re-authenticate...")
1130
+ self.authenticate(revalidate=True)
1131
+ retries += 1
1132
+ logger.error(response.text)
1133
+ return None
1134
+
1135
+ # end method definition
1136
+
1137
+ def create_loan(
1138
+ self,
1139
+ subject: str,
1140
+ description: str,
1141
+ loan_amount: str,
1142
+ loan_duration_in_months: str,
1143
+ category: str,
1144
+ subcategory: str,
1145
+ piority: str,
1146
+ service: str,
1147
+ customer: str
1148
+
1149
+ ) -> dict | None:
1150
+ """create loan entity instance
1151
+
1152
+ Args:
1153
+ subject (str): subject
1154
+ description (str): description
1155
+ loan_amount (str): loan_amount
1156
+ loan_duration_in_months (str): loan_duration_in_months
1157
+ category (str): category
1158
+ subcategory (str): subcategory
1159
+ piority (str): piority
1160
+ service (str): service
1161
+ customer (str): customer
1162
+ Returns:
1163
+ dict: Request response (dictionary) or None if the REST call fails
1164
+ """
1165
+ create_loan = f"""<SOAP:Envelope xmlns:SOAP=\"http://schemas.xmlsoap.org/soap/envelope/\">\r\n
1166
+ <SOAP:Body>\r\n
1167
+ <CreateCase xmlns=\"http://schemas/OpentextCaseManagement/Case/operations\">\r\n
1168
+ <ns0:Case-create xmlns:ns0=\"http://schemas/OpentextCaseManagement/Case\">\r\n
1169
+ <ns0:Subject>{subject}</ns0:Subject>\r\n
1170
+ <ns0:Description>{description}</ns0:Description>\r\n
1171
+ <ns0:LoanAmount>{loan_amount}</ns0:LoanAmount>\r\n
1172
+ <ns0:LoanDurationInMonths>{loan_duration_in_months}</ns0:LoanDurationInMonths>\r\n
1173
+ \r\n
1174
+ <ns0:CaseType>\r\n
1175
+ <ns1:CaseType-id xmlns:ns1=\"http://schemas/OpentextCaseManagement/CaseType\">\r\n
1176
+ <ns1:Id>{service}</ns1:Id>\r\n
1177
+ </ns1:CaseType-id>\r\n
1178
+ </ns0:CaseType>\r\n
1179
+ \r\n
1180
+ <ns0:Category>\r\n
1181
+ <ns2:Category-id xmlns:ns2=\"http://schemas/OpentextCaseManagement/Category\">\r\n
1182
+ <ns2:Id>{category}</ns2:Id>\r\n
1183
+ </ns2:Category-id>\r\n
1184
+ </ns0:Category>\r\n
1185
+ \r\n
1186
+ <ns0:SubCategory>\r\n
1187
+ <ns5:SubCategory-id xmlns:ns5=\"http://schemas/OpentextCaseManagement/Category.SubCategory\">\r\n
1188
+ <ns5:Id>{category}</ns5:Id>\r\n
1189
+ <ns5:Id1>{subcategory}</ns5:Id1>\r\n
1190
+ </ns5:SubCategory-id>\r\n
1191
+ </ns0:SubCategory>\r\n
1192
+ \r\n
1193
+ <ns0:Priority>\r\n
1194
+ <ns3:Priority-id xmlns:ns3=\"http://schemas/OpentextCaseManagement/Priority\">\r\n
1195
+ <ns3:Id>{piority}</ns3:Id>\r\n
1196
+ </ns3:Priority-id>\r\n
1197
+ </ns0:Priority>\r\n
1198
+ \r\n
1199
+ <ns0:ToCustomer>\r\n
1200
+ <ns9:Customer-id xmlns:ns9=\"http://schemas/OpentextCaseManagement/Customer\">\r\n
1201
+ <ns9:Id>{customer}</ns9:Id>\r\n
1202
+ </ns9:Customer-id>\r\n
1203
+ </ns0:ToCustomer>\r\n
1204
+ \r\n
1205
+ </ns0:Case-create>\r\n
1206
+ </CreateCase>\r\n
1207
+ </SOAP:Body>\r\n
1208
+ </SOAP:Envelope>"""
1209
+
1210
+ retries = 0
1211
+ while True:
1212
+ response = requests.post(
1213
+ url=self.gateway_url(),
1214
+ data=create_loan,
1215
+ headers=REQUEST_HEADERS,
1216
+ cookies=self.cookie(),
1217
+ timeout=None,
1218
+ )
1219
+ if response.ok:
1220
+ logger.info("Loan created successfully")
1221
+ return self.parse_xml(response.text)
1222
+ if response.status_code == 401 and retries == 0:
1223
+ logger.warning("Session has expired - try to re-authenticate...")
1224
+ self.authenticate(revalidate=True)
1225
+ retries += 1
1226
+ logger.error(response.text)
1227
+ return None
1228
+
1229
+ # end method definition
1230
+
1231
+ def get_all_loan(
1232
+ self
1233
+ ) -> dict | None:
1234
+ """get all loan entity instances
1235
+
1236
+ Args:
1237
+ None
1238
+ Returns:
1239
+ dict: Request response (dictionary) or None if the REST call fails
1240
+ """
1241
+
1242
+ retries = 0
1243
+ while True:
1244
+ response = requests.get(
1245
+ url=self.get_all_loans_url(),
1246
+ headers=REQUEST_HEADERS_JSON,
1247
+ cookies=self.cookie(),
1248
+ timeout=None,
1249
+ )
1250
+ if response.ok:
1251
+ authenticate_dict = self.parse_request_response(
1252
+ response, "This can be normal during restart", False
1253
+ )
1254
+ if not authenticate_dict:
1255
+ return None
1256
+ return authenticate_dict
1257
+ if response.status_code == 401 and retries == 0:
1258
+ logger.warning("Session has expired - try to re-authenticate...")
1259
+ self.authenticate(revalidate=True)
1260
+ retries += 1
1261
+ else:
1262
+ logger.error(response.text)
1263
+ return None
1264
+
1265
+ # end method definition
1266
+
1267
+ def validate_workspace_response(
1268
+ self,
1269
+ response: str,
1270
+ workspace_name: str
1271
+ ) -> bool:
1272
+ """
1273
+ Verify if the workspace exists or was created successfully.
1274
+
1275
+ Args:
1276
+ response (str): response to validate
1277
+ workspace_name (str): The name of the workspace.
1278
+
1279
+ Returns:
1280
+ bool: True if the workspace exists or was created successfully, else False.
1281
+ """
1282
+
1283
+ if "Object already exists" in response or "createWorkspaceResponse" in response:
1284
+ logger.info(
1285
+ "The workspace already exists or was created with the name -> '%s'",
1286
+ workspace_name,
1287
+ )
1288
+ return True
1289
+
1290
+ logger.info(
1291
+ "The workspace -> '%s' does not exist or was not created. Please verify configurtion!",
1292
+ workspace_name,
1293
+ )
1294
+ return False
1295
+
1296
+ # end method definition
1297
+
1298
+ def is_workspace_already_exists(
1299
+ self,
1300
+ response: str,
1301
+ workspace_name: str
1302
+ ) -> bool:
1303
+ """verify is workspace exists
1304
+ Args:
1305
+ workspace_name (str): workspace_name
1306
+ Returns:
1307
+ bool: return true if workspace exist else return false
1308
+ """
1309
+
1310
+ if "Object already exists" in response:
1311
+ logger.info(
1312
+ "The workspace already exists with the name -> '%s'", workspace_name
1313
+ )
1314
+ return True
1315
+ logger.info(
1316
+ "The Workspace has been created with the name -> '%s'", workspace_name
1317
+ )
1318
+ return False
1319
+
1320
+ # end method definition
1321
+
1322
+ def create_workspace_with_retry(self, workspace_name: str, workspace_gui_id: str) -> dict | None:
1323
+ """
1324
+ Calls create_workspace and retries if the response contains specific error messages.
1325
+ Retries until the response does not contain the errors or a max retry limit is reached.
1326
+ """
1327
+
1328
+ max_retries = 20 # Define the maximum number of retries
1329
+ retries = 0
1330
+ error_messages = [
1331
+ "Collaborative Workspace Service Container is not able to handle the SOAP request",
1332
+ "Service Group Lookup failure"
1333
+ ]
1334
+
1335
+ while retries < max_retries:
1336
+ response = self.create_workspace(workspace_name, workspace_gui_id)
1337
+
1338
+ # Check if any error message is in the response
1339
+ if any(error_message in response for error_message in error_messages):
1340
+ logger.info("Workspace service error, waiting 60 seconds to retry... (Retry %d of %d)", retries + 1, max_retries)
1341
+ time.sleep(60)
1342
+ retries += 1
1343
+ else:
1344
+ logger.info("Collaborative Workspace Service Container is ready")
1345
+ return response
1346
+
1347
+ # After max retries, log and return the response or handle as needed
1348
+ logger.error(
1349
+ "Max retries reached for workspace -> '%s', unable to create successfully.",
1350
+ workspace_name,
1351
+ )
1352
+ return response
1353
+
1354
+ # end method definition
1355
+
1356
+ def loan_management_runtime(self) -> dict | None:
1357
+ """it will create all runtime objects for loan management application
1358
+ Args:
1359
+ None
1360
+ Returns:
1361
+ None
1362
+ """
1363
+
1364
+ logger.debug(" RUNTIME -->> Category instance creation started ........ ")
1365
+ category_resp_dict = []
1366
+ if not self.verify_category_exists("Short Term Loan"):
1367
+ self.create_category("LOAN","Short Term Loan","Short Term Loan",1)
1368
+ if not self.verify_category_exists("Long Term Loan"):
1369
+ self.create_category("LOAN","Long Term Loan","Long Term Loan",1)
1370
+ if not self.verify_category_exists("Flexi Loan"):
1371
+ self.create_category("LOAN","Flexi Loan","Flexi Loan",1)
1372
+ category_resp_dict = self.get_category_lists()
1373
+ logger.debug(" RUNTIME -->> Category instance creation ended")
1374
+
1375
+ ############################# Sub category
1376
+ logger.debug(" RUNTIME -->> Sub Category instance creation started ........")
1377
+ stl = 0
1378
+ ltl = 0
1379
+ fl = 0
1380
+ if not self.verify_sub_category_exists("Business",0,category_resp_dict):
1381
+ response_dict = self.create_sub_categoy("Business","Business",1,category_resp_dict[0])
1382
+ stl = response_dict["Identity"]["Id"]
1383
+ logger.info("Sub category id stl: %s ", stl)
1384
+ else:
1385
+ stl = self.return_sub_category_exists_id("Business",0,category_resp_dict)
1386
+ logger.info("Sub category id stl -> %s ", stl)
1387
+
1388
+ if not self.verify_sub_category_exists("Business",1,category_resp_dict):
1389
+ response_dict=self.create_sub_categoy("Business","Business",1,category_resp_dict[1])
1390
+ ltl = response_dict["Identity"]["Id"]
1391
+ logger.info("Sub category id ltl -> %s ", ltl)
1392
+ else:
1393
+ ltl = self.return_sub_category_exists_id("Business",1,category_resp_dict)
1394
+ logger.info("Sub category id ltl -> %s ", ltl)
1395
+ if not self.verify_sub_category_exists("Business",2,category_resp_dict):
1396
+ response_dict= self.create_sub_categoy("Business","Business",1,category_resp_dict[2])
1397
+ fl = response_dict["Identity"]["Id"]
1398
+ logger.info("Sub category id fl -> %s ", fl)
1399
+ else:
1400
+ fl = self.return_sub_category_exists_id("Business",2,category_resp_dict)
1401
+ logger.info("Sub category id fl -> %s ", fl)
1402
+ logger.debug(" RUNTIME -->> Sub Category instance creation ended")
1403
+
1404
+ ############################# Case Types
1405
+ logger.debug(" RUNTIME -->> Case Types instance creation started ........")
1406
+ case_type_list = []
1407
+
1408
+ if not self.vverify_case_type_exists("Query"):
1409
+ self.create_case_type("Query","Query",1)
1410
+ if not self.vverify_case_type_exists("Help"):
1411
+ self.create_case_type("Help","Help",1)
1412
+ if not self.vverify_case_type_exists("Update Contact Details"):
1413
+ self.create_case_type("Update Contact Details","Update Contact Details",1)
1414
+ if not self.vverify_case_type_exists("New Loan Request"):
1415
+ self.create_case_type("New Loan Request","New Loan Request",1)
1416
+ if not self.vverify_case_type_exists("Loan Closure"):
1417
+ self.create_case_type("Loan Closure","Loan Closure",1)
1418
+ case_type_list = self.get_case_type_lists()
1419
+ logger.debug(" RUNTIME -->> Case Types instance creation ended")
1420
+
1421
+ ############################# CUSTMOR
1422
+ logger.debug(" RUNTIME -->> Customer instance creation stated ........")
1423
+ customer_list = []
1424
+ if not self.verify_customer_exists("InaPlex Limited"):
1425
+ self.create_customer("InaPlex Limited","InaPlex Limited","InaPlex Limited")
1426
+
1427
+ if not self.verify_customer_exists("Interwoven, Inc"):
1428
+ self.create_customer("Interwoven, Inc","Interwoven, Inc","Interwoven, Inc")
1429
+
1430
+ if not self.verify_customer_exists("Jones Lang LaSalle"):
1431
+ self.create_customer("Jones Lang LaSalle","Jones Lang LaSalle","Jones Lang LaSalle")
1432
+
1433
+ if not self.verify_customer_exists("Key Point Consulting"):
1434
+ self.create_customer("Key Point Consulting","Key Point Consulting","Key Point Consulting")
1435
+
1436
+ customer_list = self.get_customer_lists()
1437
+ logger.debug(" RUNTIME -->> Customer instance creation ended")
1438
+
1439
+ ######################################## PRIORITY
1440
+ logger.debug(" RUNTIME -->> priority instance creation started ........")
1441
+ prioity_list = []
1442
+ if not self.verify_priority_exists("High"):
1443
+ self.create_priority("High","High",1)
1444
+ if not self.verify_priority_exists("Medium"):
1445
+ self.create_priority("Medium","Medium",1)
1446
+ if not self.verify_priority_exists("Low"):
1447
+ self.create_priority("Low","Low",1)
1448
+ prioity_list = self.get_priority_lists()
1449
+ logger.debug(" RUNTIME -->> priority instance creation ended")
1450
+
1451
+ ############################# LOAN
1452
+ loan_for_business = "Loan for Business1"
1453
+ loan_for_corporate_business = "Loan for Corporate Business1"
1454
+ loan_for_business_loan_request = "Loan for Business Loan Request1"
1455
+
1456
+ logger.debug(" RUNTIME -->> loan instance creation started ........")
1457
+ loan_resp_dict = self.get_all_loan()
1458
+ names = [item["Properties"]["Subject"] for item in loan_resp_dict["_embedded"]["AllCasesList"]]
1459
+ if loan_for_business in names:
1460
+ logger.info("Customer record Loan_for_business exists")
1461
+ else:
1462
+ logger.info("Creating customer Record with Loan_for_business ")
1463
+ response_dict = self.create_loan(
1464
+ loan_for_business,
1465
+ loan_for_business,
1466
+ 1,
1467
+ 2,
1468
+ category_resp_dict[0],
1469
+ stl,
1470
+ prioity_list[0],
1471
+ case_type_list[0],
1472
+ customer_list[0],
1473
+ )
1474
+
1475
+ if loan_for_corporate_business in names:
1476
+ logger.info("Customer record Loan_for_Corporate_Business exists")
1477
+ else:
1478
+ logger.info("Creating customer Record with Loan_for_Corporate_Business ")
1479
+ response_dict = self.create_loan(
1480
+ loan_for_corporate_business,
1481
+ loan_for_corporate_business,
1482
+ 1,
1483
+ 2,
1484
+ category_resp_dict[1],
1485
+ ltl,
1486
+ prioity_list[1],
1487
+ case_type_list[1],
1488
+ customer_list[1],
1489
+ )
1490
+
1491
+ if loan_for_business_loan_request in names:
1492
+ logger.info("Customer record Loan_for_business_Loan_Request exists")
1493
+ else:
1494
+ logger.info("Creating customer Record with loan_for_business_loan_request")
1495
+ response_dict = self.create_loan(
1496
+ loan_for_business_loan_request,
1497
+ loan_for_business_loan_request,
1498
+ 1,
1499
+ 2,
1500
+ category_resp_dict[2],
1501
+ fl,
1502
+ prioity_list[2],
1503
+ case_type_list[2],
1504
+ customer_list[2],
1505
+ )
1506
+ logger.debug(" RUNTIME -->> loan instance creation ended")
1507
+
1508
+ # end method definition
1509
+
1510
+ def get_category_lists(self) -> list:
1511
+ """get All category entty instances id's
1512
+ Args:
1513
+ None
1514
+ Returns:
1515
+ list: list of category IDs
1516
+ """
1517
+
1518
+ category_resp_dict = []
1519
+ categoy_resp_dict = self.get_all_categories()
1520
+ for item in categoy_resp_dict["_embedded"]["CategoryList"]:
1521
+ first_item_href = item["_links"]["item"]["href"]
1522
+ integer_value = int(re.search(r'\d+', first_item_href).group())
1523
+ logger.info("Category created with ID -> %d", integer_value)
1524
+ category_resp_dict.append(integer_value)
1525
+ logger.info("All extracted category IDs -> %s", category_resp_dict)
1526
+
1527
+ return category_resp_dict
1528
+
1529
+ # end method definition
1530
+
1531
+ def get_case_type_lists(self) -> list:
1532
+ """Get All CaseType entity instances IDs
1533
+ Args:
1534
+ None
1535
+ Returns:
1536
+ list: list contains CaseType IDs
1537
+ """
1538
+
1539
+ case_type_list = []
1540
+ casetype_resp_dict = self.get_all_case_type()
1541
+ for item in casetype_resp_dict["_embedded"]["AllCaseTypes"]:
1542
+ first_item_href = item["_links"]["item"]["href"]
1543
+ integer_value = int(re.search(r'\d+', first_item_href).group())
1544
+ logger.info("Case type created with ID -> %d", integer_value)
1545
+ case_type_list.append(integer_value)
1546
+ logger.info("All extracted case type IDs -> %s", case_type_list)
1547
+
1548
+ return case_type_list
1549
+
1550
+ # end method definition
1551
+
1552
+ def get_customer_lists(self) -> list:
1553
+ """Get all customer entity instances id's
1554
+ Args:
1555
+ None
1556
+ Returns:
1557
+ list: list of customer IDs
1558
+ """
1559
+
1560
+ customer_list = []
1561
+ customer_resp_dict = self.get_all_customers()
1562
+ for item in customer_resp_dict["_embedded"]["CustomerList"]:
1563
+ first_item_href = item["_links"]["item"]["href"]
1564
+ integer_value = int(re.search(r'\d+', first_item_href).group())
1565
+ logger.info("Customer created with ID -> %d", integer_value)
1566
+ customer_list.append(integer_value)
1567
+ logger.info("All extracted Customer IDs -> %s ", customer_list)
1568
+ return customer_list
1569
+
1570
+ # end method definition
1571
+
1572
+ def get_priority_lists(self) -> list:
1573
+ """get all priority entity instances IDs
1574
+ Args:
1575
+ None
1576
+ Returns:
1577
+ list: list contains priority IDs
1578
+ """
1579
+
1580
+ prioity_list = []
1581
+ authenticate_dict = self.get_all_priorities()
1582
+ for item in authenticate_dict["_embedded"]["PriorityList"]:
1583
+ first_item_href = item["_links"]["item"]["href"]
1584
+ integer_value = int(re.search(r'\d+', first_item_href).group())
1585
+ logger.info("Priority created with ID -> %d", integer_value)
1586
+ prioity_list.append(integer_value)
1587
+ logger.info("All extracted priority IDs -> %s ", prioity_list)
1588
+
1589
+ return prioity_list
1590
+
1591
+ # end method definition
1592
+
1593
+ def verify_category_exists(self, name: str) -> bool:
1594
+ """verify category entity instance already exists
1595
+ Args:
1596
+ name (str): name of the category
1597
+ Returns:
1598
+ bool: returns True if already record exists with same name, else returns False
1599
+ """
1600
+
1601
+ categoy_resp_dict = self.get_all_categories()
1602
+ names = [item["Properties"]["Name"] for item in categoy_resp_dict["_embedded"]["CategoryList"]]
1603
+ if name in names:
1604
+ logger.info("Category record -> '%s' already exists", name)
1605
+ return True
1606
+ logger.info("Creating category record -> '%s'", name)
1607
+
1608
+ return False
1609
+
1610
+ # end method definition
1611
+
1612
+ def vverify_case_type_exists(self, name: str) -> bool:
1613
+ """verify case type entity instance already exists
1614
+ Args:
1615
+ name (str): name of the case type
1616
+ Returns:
1617
+ bool: returns True if already record exists with same name, else returns False
1618
+ """
1619
+
1620
+ casetype_resp_dict = self.get_all_case_type()
1621
+ names = [item["Properties"]["Name"] for item in casetype_resp_dict["_embedded"]["AllCaseTypes"]]
1622
+ if name in names:
1623
+ logger.info("Case type record -> '%s' already exists", name)
1624
+ return True
1625
+ logger.info("Creating case type record -> '%s'", name)
1626
+
1627
+ return False
1628
+
1629
+ # end method definition
1630
+
1631
+ def verify_customer_exists(self, name: str) -> bool:
1632
+ """verify cusomer entty instance already exists
1633
+ Args:
1634
+ name (str): name of the customer
1635
+ Returns:
1636
+ bool: returns True if already record exists with same name, else returns False
1637
+ """
1638
+ customer_resp_dict = self.get_all_customers()
1639
+ names = [item["Properties"]["CustomerName"] for item in customer_resp_dict["_embedded"]["CustomerList"]]
1640
+ if name in names:
1641
+ logger.info("Customer -> '%s' already exists", name)
1642
+ return True
1643
+ logger.info("Creating customer -> '%s'", name)
1644
+ return False
1645
+
1646
+ # end method definition
1647
+
1648
+ def verify_priority_exists(self, name: str) -> bool:
1649
+ """verify piority entity instance already exists
1650
+ Args:
1651
+ name (str): name of the priority
1652
+ Returns:
1653
+ bool: returns True if already record exists with same name, else returns False
1654
+ """
1655
+
1656
+ authenticate_dict = self.get_all_priorities()
1657
+ names = [item["Properties"]["Name"] for item in authenticate_dict["_embedded"]["PriorityList"]]
1658
+ if name in names:
1659
+ logger.info("Priority -> '%s' already exists", name)
1660
+ return True
1661
+ logger.info("Creating priority -> '%s'", name)
1662
+
1663
+ return False
1664
+
1665
+ # end method definition
1666
+
1667
+ def verify_sub_category_exists(self, name: str, index: int, category_resp_dict: list) -> bool:
1668
+ """verify sub category entity instance already exists
1669
+ Args:
1670
+ name (str): name of the sub category
1671
+ Returns:
1672
+ bool: returns true if record already exists with same name, else returns false
1673
+ """
1674
+
1675
+ subcategoy_resp_dict = self.get_all_sub_categeries(category_resp_dict[index])
1676
+ names = [item["Properties"]["Name"] for item in subcategoy_resp_dict["_embedded"]["SubCategory"]]
1677
+ stl=0
1678
+ if name in names:
1679
+ logger.info("Sub category -> '%s' already exists", name)
1680
+ for item in subcategoy_resp_dict["_embedded"]["SubCategory"]:
1681
+ stl = item["Identity"]["Id"]
1682
+ logger.info("Sub category created with ID -> %s", stl)
1683
+ return True
1684
+ logger.info("Creating sub category -> '%s'", name)
1685
+
1686
+ return False
1687
+
1688
+ # end method definition
1689
+
1690
+ def return_sub_category_exists_id(self, name: str, index: int, category_resp_dict: list) -> int:
1691
+ """verify sub category entity instance id already exists
1692
+ Args:
1693
+ name (str): name of the sub-category
1694
+ Returns:
1695
+ bool: returns true if record already exists with same name, else returns false
1696
+ """
1697
+
1698
+ subcategoy_resp_dict = self.get_all_sub_categeries(category_resp_dict[index])
1699
+ names = [item["Properties"]["Name"] for item in subcategoy_resp_dict["_embedded"]["SubCategory"]]
1700
+ stl=0
1701
+ if name in names:
1702
+ logger.info("Sub category record -> '%s' already exists", name)
1703
+ for item in subcategoy_resp_dict["_embedded"]["SubCategory"]:
1704
+ stl = item["Identity"]["Id"]
1705
+ logger.info("Sub category created with ID -> %s", stl)
1706
+ return stl
1707
+
1708
+ return None
1709
+
1710
+ # end method definition
1711
+
1712
+ def create_users_from_config_file(self, otawpsection: str, _otds: OTDS):
1713
+ """read user information from customizer file and call create user method
1714
+ Args:
1715
+ otawpsection (str): yaml bock related to appworks
1716
+ Returns:
1717
+ None
1718
+ """
1719
+
1720
+ otds = otawpsection.get("otds", {})
1721
+ if otds is not None:
1722
+ users = otds.get("users", [])
1723
+ if users is not None:
1724
+ for user in users:
1725
+ _otds.add_user(
1726
+ user.get("partition"),
1727
+ user.get("name"),
1728
+ user.get("description"),
1729
+ user.get("first_name"),
1730
+ user.get("last_name"),
1731
+ user.get("email"),
1732
+ )
1733
+ roles = otds.get("roles", [])
1734
+ if roles is not None:
1735
+ for role in roles:
1736
+ _otds.add_user_to_group(
1737
+ user.get("name") + "@" + user.get("partition"),
1738
+ # user.get('name'),
1739
+ role.get("name"),
1740
+ )
1741
+ else:
1742
+ logger.error(
1743
+ "Verifying Users section: roles section not presented in yaml for otds users"
1744
+ )
1745
+ else:
1746
+ logger.error(
1747
+ "Verifying Users section: user section not presented in yaml"
1748
+ )
1749
+ else:
1750
+ logger.error("Verifying Users section: otds section not presented in yaml")
1751
+
1752
+ # end method definition
1753
+
1754
+ def create_roles_from_config_file(self, otawpsection: str, _otds: OTDS):
1755
+ """read grop information from customizer file and call create grop method
1756
+ Args:
1757
+ otawpsection (str): yaml bock related to appworks
1758
+ _otds (object): the OTDS object used to access the OTDS REST API
1759
+ Returns:
1760
+ None
1761
+ """
1762
+
1763
+ otds = otawpsection.get("otds", {})
1764
+ if otds is not None:
1765
+ roles = otds.get("roles", [])
1766
+ if roles is not None:
1767
+ for role in roles:
1768
+ # Add new group if it does not yet exist:
1769
+ if not _otds.get_group(group=role.get("name"), show_error=False):
1770
+ _otds.add_group(
1771
+ role.get("partition"),
1772
+ role.get("name"),
1773
+ role.get("description"),
1774
+ )
1775
+ else:
1776
+ logger.error(
1777
+ "Verifying roles section: roles section not presented in yaml"
1778
+ )
1779
+ else:
1780
+ logger.error("Verifying roles section: otds section not presented in yaml")
1781
+
1782
+ # end method definition
1783
+
1784
+ def create_loanruntime_from_config_file(self, platform: str):
1785
+ """verify flag and call loan_management_runtime()
1786
+ Args:
1787
+ platform (str): yaml bock related to platform
1788
+ Returns:
1789
+ None
1790
+ """
1791
+
1792
+ runtime = platform.get("runtime", {})
1793
+ if runtime is not None:
1794
+ app_names = runtime.get("appNames", [])
1795
+ if app_names is not None:
1796
+ for app_name in app_names:
1797
+ if app_name == "loanManagement":
1798
+ self.loan_management_runtime()
1799
+ else:
1800
+ logger.error(
1801
+ "Verifying runtime section: loanManagement not exits in yaml entry"
1802
+ )
1803
+ else:
1804
+ logger.error(
1805
+ "Verifying runtime section: App name section is empty in yaml"
1806
+ )
1807
+ else:
1808
+ logger.error("Verifying runtime section: Runtime section is empty in yaml")
1809
+
1810
+ # end method definition