pyxecm 1.6__py3-none-any.whl → 2.0.1__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/__init__.py +7 -4
- pyxecm/avts.py +727 -254
- pyxecm/coreshare.py +686 -467
- pyxecm/customizer/__init__.py +16 -4
- pyxecm/customizer/__main__.py +58 -0
- pyxecm/customizer/api/__init__.py +5 -0
- pyxecm/customizer/api/__main__.py +6 -0
- pyxecm/customizer/api/app.py +163 -0
- pyxecm/customizer/api/auth/__init__.py +1 -0
- pyxecm/customizer/api/auth/functions.py +92 -0
- pyxecm/customizer/api/auth/models.py +13 -0
- pyxecm/customizer/api/auth/router.py +78 -0
- pyxecm/customizer/api/common/__init__.py +1 -0
- pyxecm/customizer/api/common/functions.py +47 -0
- pyxecm/customizer/api/common/metrics.py +92 -0
- pyxecm/customizer/api/common/models.py +21 -0
- pyxecm/customizer/api/common/payload_list.py +870 -0
- pyxecm/customizer/api/common/router.py +72 -0
- pyxecm/customizer/api/settings.py +128 -0
- pyxecm/customizer/api/terminal/__init__.py +1 -0
- pyxecm/customizer/api/terminal/router.py +87 -0
- pyxecm/customizer/api/v1_csai/__init__.py +1 -0
- pyxecm/customizer/api/v1_csai/router.py +87 -0
- pyxecm/customizer/api/v1_maintenance/__init__.py +1 -0
- pyxecm/customizer/api/v1_maintenance/functions.py +100 -0
- pyxecm/customizer/api/v1_maintenance/models.py +12 -0
- pyxecm/customizer/api/v1_maintenance/router.py +76 -0
- pyxecm/customizer/api/v1_otcs/__init__.py +1 -0
- pyxecm/customizer/api/v1_otcs/functions.py +61 -0
- pyxecm/customizer/api/v1_otcs/router.py +179 -0
- pyxecm/customizer/api/v1_payload/__init__.py +1 -0
- pyxecm/customizer/api/v1_payload/functions.py +179 -0
- pyxecm/customizer/api/v1_payload/models.py +51 -0
- pyxecm/customizer/api/v1_payload/router.py +499 -0
- pyxecm/customizer/browser_automation.py +721 -286
- pyxecm/customizer/customizer.py +1076 -1425
- pyxecm/customizer/exceptions.py +35 -0
- pyxecm/customizer/guidewire.py +1186 -0
- pyxecm/customizer/k8s.py +901 -379
- pyxecm/customizer/log.py +107 -0
- pyxecm/customizer/m365.py +2967 -920
- pyxecm/customizer/nhc.py +1169 -0
- pyxecm/customizer/openapi.py +258 -0
- pyxecm/customizer/payload.py +18228 -7820
- pyxecm/customizer/pht.py +717 -286
- pyxecm/customizer/salesforce.py +516 -342
- pyxecm/customizer/sap.py +58 -41
- pyxecm/customizer/servicenow.py +611 -372
- pyxecm/customizer/settings.py +445 -0
- pyxecm/customizer/successfactors.py +408 -346
- pyxecm/customizer/translate.py +83 -48
- pyxecm/helper/__init__.py +5 -2
- pyxecm/helper/assoc.py +83 -43
- pyxecm/helper/data.py +2406 -870
- pyxecm/helper/logadapter.py +27 -0
- pyxecm/helper/web.py +229 -101
- pyxecm/helper/xml.py +596 -171
- pyxecm/maintenance_page/__init__.py +5 -0
- pyxecm/maintenance_page/__main__.py +6 -0
- pyxecm/maintenance_page/app.py +51 -0
- pyxecm/maintenance_page/settings.py +28 -0
- pyxecm/maintenance_page/static/favicon.avif +0 -0
- pyxecm/maintenance_page/templates/maintenance.html +165 -0
- pyxecm/otac.py +235 -141
- pyxecm/otawp.py +2668 -1220
- pyxecm/otca.py +569 -0
- pyxecm/otcs.py +7956 -3237
- pyxecm/otds.py +2178 -925
- pyxecm/otiv.py +36 -21
- pyxecm/otmm.py +1272 -325
- pyxecm/otpd.py +231 -127
- pyxecm-2.0.1.dist-info/METADATA +122 -0
- pyxecm-2.0.1.dist-info/RECORD +76 -0
- {pyxecm-1.6.dist-info → pyxecm-2.0.1.dist-info}/WHEEL +1 -1
- pyxecm-1.6.dist-info/METADATA +0 -53
- pyxecm-1.6.dist-info/RECORD +0 -32
- {pyxecm-1.6.dist-info → pyxecm-2.0.1.dist-info/licenses}/LICENSE +0 -0
- {pyxecm-1.6.dist-info → pyxecm-2.0.1.dist-info}/top_level.txt +0 -0
pyxecm/avts.py
CHANGED
|
@@ -1,83 +1,101 @@
|
|
|
1
|
-
"""
|
|
2
|
-
AVTS stands for Aviator Search and is an OpenText offering for LLMM-based search across multiple repositories
|
|
3
|
-
|
|
4
|
-
Class: AVTS
|
|
5
|
-
Methods:
|
|
6
|
-
__init__: class initializer
|
|
7
|
-
request_header: Returns the request header used for Application calls.
|
|
8
|
-
do_request: Call an Aviator Search REST API in a safe way
|
|
9
|
-
parse_request_response: Converts the request response (JSon) to a Python list in a safe way
|
|
10
|
-
authenticate: Authenticate at Search Aviator via oAuth authentication
|
|
11
|
-
repo_create_extended_ecm: Create a new repository to crawl in Aviator Search
|
|
12
|
-
start_crawling: Start crawling of a repository
|
|
13
|
-
stop_crawling: Stop the crawling of a repository
|
|
14
|
-
get_repo_list: Get a list of all repositories
|
|
15
|
-
get_repo_by_name: Get a repository by name
|
|
16
|
-
"""
|
|
1
|
+
"""AVTS stands for Aviator Search and is an OpenText offering for LLMM-based search across multiple repositories."""
|
|
17
2
|
|
|
18
3
|
__author__ = "Dr. Marc Diefenbruch"
|
|
19
|
-
__copyright__ = "Copyright 2024, OpenText"
|
|
4
|
+
__copyright__ = "Copyright (C) 2024-2025, OpenText"
|
|
20
5
|
__credits__ = ["Kai-Philip Gatzweiler"]
|
|
21
6
|
__maintainer__ = "Dr. Marc Diefenbruch"
|
|
22
7
|
__email__ = "mdiefenb@opentext.com"
|
|
23
8
|
|
|
9
|
+
import base64
|
|
24
10
|
import json
|
|
25
11
|
import logging
|
|
26
|
-
import time
|
|
27
12
|
import os
|
|
28
|
-
import
|
|
13
|
+
import platform
|
|
14
|
+
import sys
|
|
15
|
+
import time
|
|
16
|
+
from importlib.metadata import version
|
|
29
17
|
|
|
30
18
|
import requests
|
|
31
19
|
|
|
32
|
-
|
|
20
|
+
APP_NAME = "pyxecm"
|
|
21
|
+
APP_VERSION = version("pyxecm")
|
|
22
|
+
MODULE_NAME = APP_NAME + ".avts"
|
|
23
|
+
|
|
24
|
+
PYTHON_VERSION = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
|
|
25
|
+
OS_INFO = f"{platform.system()} {platform.release()}"
|
|
26
|
+
ARCH_INFO = platform.machine()
|
|
27
|
+
REQUESTS_VERSION = requests.__version__
|
|
33
28
|
|
|
34
|
-
|
|
29
|
+
USER_AGENT = (
|
|
30
|
+
f"{APP_NAME}/{APP_VERSION} ({MODULE_NAME}/{APP_VERSION}; "
|
|
31
|
+
f"Python/{PYTHON_VERSION}; {OS_INFO}; {ARCH_INFO}; Requests/{REQUESTS_VERSION})"
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
REQUEST_HEADERS = {"User-Agent": USER_AGENT, "accept": "application/json", "Content-Type": "application/json"}
|
|
35
35
|
|
|
36
36
|
REQUEST_TIMEOUT = 60
|
|
37
37
|
REQUEST_RETRY_DELAY = 20
|
|
38
38
|
REQUEST_MAX_RETRIES = 2
|
|
39
39
|
|
|
40
|
+
default_logger = logging.getLogger(MODULE_NAME)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class AVTS:
|
|
44
|
+
"""Configure and interact with Aviator Search REST API."""
|
|
40
45
|
|
|
41
|
-
|
|
42
|
-
"""Used to configure and interact with Aviator Search"""
|
|
46
|
+
logger: logging.Logger = default_logger
|
|
43
47
|
|
|
44
48
|
_config: dict
|
|
45
49
|
_session = None
|
|
46
50
|
|
|
47
51
|
def __init__(
|
|
48
52
|
self,
|
|
49
|
-
otds_url: str,
|
|
50
53
|
client_id: str,
|
|
51
54
|
client_secret: str,
|
|
52
55
|
base_url: str,
|
|
53
56
|
username: str,
|
|
54
57
|
password: str,
|
|
55
|
-
|
|
56
|
-
|
|
58
|
+
otds_url: str,
|
|
59
|
+
logger: logging.Logger = default_logger,
|
|
60
|
+
) -> None:
|
|
61
|
+
"""Initialize the Aviator Search (AVTS) object.
|
|
57
62
|
|
|
58
63
|
Args:
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
client_secret (str):
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
client_id (str):
|
|
65
|
+
The client ID for the Aviator Search oAuth client.
|
|
66
|
+
client_secret (str):
|
|
67
|
+
The client secret for the Aviator Search oAuth client.
|
|
68
|
+
base_url (str):
|
|
69
|
+
The Aviator Search base URL.
|
|
70
|
+
username (str):
|
|
71
|
+
User with administrative permissions in Aviator Search.
|
|
72
|
+
password (str):
|
|
73
|
+
Password of the user with administrative permissions in Aviator Search.
|
|
74
|
+
otds_url (str):
|
|
75
|
+
The URL of the OTDS Server used by Aviator Search.
|
|
76
|
+
logger (logging.Logger, optional):
|
|
77
|
+
The logging object to use for all log messages. Defaults to default_logger.
|
|
78
|
+
|
|
65
79
|
"""
|
|
66
80
|
|
|
81
|
+
if logger != default_logger:
|
|
82
|
+
self.logger = logger.getChild("avts")
|
|
83
|
+
for logfilter in logger.filters:
|
|
84
|
+
self.logger.addFilter(logfilter)
|
|
85
|
+
|
|
67
86
|
avts_config = {}
|
|
68
87
|
|
|
69
88
|
# Store the credentials and parameters in a config dictionary:
|
|
70
|
-
avts_config["otdsUrl"] = otds_url
|
|
71
89
|
avts_config["clientId"] = client_id
|
|
72
90
|
avts_config["clientSecret"] = client_secret
|
|
73
91
|
avts_config["baseUrl"] = base_url
|
|
74
92
|
avts_config["username"] = username
|
|
75
93
|
avts_config["password"] = password
|
|
94
|
+
avts_config["otdsUrl"] = otds_url
|
|
76
95
|
|
|
77
96
|
avts_config["tokenUrl"] = avts_config["otdsUrl"] + "/otdsws/oauth2/token"
|
|
78
|
-
avts_config["repoUrl"] =
|
|
79
|
-
|
|
80
|
-
)
|
|
97
|
+
avts_config["repoUrl"] = avts_config["baseUrl"] + "/aviator-gateway/avts-api/admin/v1/repo"
|
|
98
|
+
avts_config["questionsUrl"] = avts_config["baseUrl"] + "/aviator-gateway/avts-api/search/v1/questions"
|
|
81
99
|
|
|
82
100
|
self._config = avts_config
|
|
83
101
|
self._accesstoken = None
|
|
@@ -87,23 +105,34 @@ class AVTS(object):
|
|
|
87
105
|
# end method definition
|
|
88
106
|
|
|
89
107
|
def config(self) -> dict:
|
|
90
|
-
"""
|
|
108
|
+
"""Return the configuration dictionary.
|
|
91
109
|
|
|
92
110
|
Returns:
|
|
93
111
|
dict: Configuration dictionary
|
|
112
|
+
|
|
94
113
|
"""
|
|
114
|
+
|
|
95
115
|
return self._config
|
|
96
116
|
|
|
97
117
|
# end method definition
|
|
98
118
|
|
|
99
119
|
def request_header(self, content_type: str = "") -> dict:
|
|
100
|
-
"""
|
|
101
|
-
|
|
120
|
+
"""Return the request header used for Application calls.
|
|
121
|
+
|
|
122
|
+
Consists of Bearer access token and Content Type
|
|
102
123
|
|
|
103
124
|
Args:
|
|
104
|
-
content_type (str, optional):
|
|
105
|
-
|
|
106
|
-
|
|
125
|
+
content_type (str, optional):
|
|
126
|
+
Custom content type for the request.
|
|
127
|
+
Typical values:
|
|
128
|
+
* application/json - Used for sending JSON-encoded data
|
|
129
|
+
* application/x-www-form-urlencoded - The default for HTML forms.
|
|
130
|
+
Data is sent as key-value pairs in the body of the request, similar to query parameters.
|
|
131
|
+
* multipart/form-data - Used for file uploads or when a form includes non-ASCII characters
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
dict: The request header values.
|
|
135
|
+
|
|
107
136
|
"""
|
|
108
137
|
|
|
109
138
|
request_header = {}
|
|
@@ -125,7 +154,7 @@ class AVTS(object):
|
|
|
125
154
|
url: str,
|
|
126
155
|
method: str = "GET",
|
|
127
156
|
headers: dict | None = None,
|
|
128
|
-
data: dict | None = None,
|
|
157
|
+
data: dict | list | None = None,
|
|
129
158
|
json_data: dict | None = None,
|
|
130
159
|
files: dict | None = None,
|
|
131
160
|
timeout: int | None = REQUEST_TIMEOUT,
|
|
@@ -135,24 +164,40 @@ class AVTS(object):
|
|
|
135
164
|
max_retries: int = REQUEST_MAX_RETRIES,
|
|
136
165
|
retry_forever: bool = False,
|
|
137
166
|
) -> dict | None:
|
|
138
|
-
"""Call an Aviator Search REST API in a safe way
|
|
167
|
+
"""Call an Aviator Search REST API in a safe way.
|
|
139
168
|
|
|
140
169
|
Args:
|
|
141
|
-
url (str):
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
170
|
+
url (str):
|
|
171
|
+
URL to send the request to.
|
|
172
|
+
method (str, optional):
|
|
173
|
+
HTTP method (GET, POST, etc.). Defaults to "GET".
|
|
174
|
+
headers (dict | None, optional):
|
|
175
|
+
Request headers. Defaults to None.
|
|
176
|
+
data (dict | None, optional):
|
|
177
|
+
Request payload. Defaults to None.
|
|
178
|
+
json_data (dict | None, optional):
|
|
179
|
+
Request payload for the JSON parameter. Defaults to None.
|
|
180
|
+
files (dict | None, optional):
|
|
181
|
+
Dictionary of {"name": file-tuple} for multipart encoding upload.
|
|
182
|
+
The file-tuple can be a 2-tuple ("filename", fileobj) or a 3-tuple
|
|
183
|
+
("filename", fileobj, "content_type").
|
|
184
|
+
timeout (int | None, optional):
|
|
185
|
+
Timeout for the request in seconds. Defaults to REQUEST_TIMEOUT.
|
|
186
|
+
show_error (bool, optional):
|
|
187
|
+
Whether or not an error should be logged in case of a failed REST call.
|
|
188
|
+
If False, then only a warning is logged. Defaults to True.
|
|
189
|
+
failure_message (str, optional):
|
|
190
|
+
Specific error message. Defaults to "".
|
|
191
|
+
success_message (str, optional):
|
|
192
|
+
Specific success message. Defaults to "".
|
|
193
|
+
max_retries (int, optional):
|
|
194
|
+
Number of retries on connection errors. Defaults to REQUEST_MAX_RETRIES.
|
|
195
|
+
retry_forever (bool, optional):
|
|
196
|
+
Whether to wait forever without timeout. Defaults to False.
|
|
153
197
|
|
|
154
198
|
Returns:
|
|
155
199
|
dict | None: Response of Aviator Search REST API or None in case of an error.
|
|
200
|
+
|
|
156
201
|
"""
|
|
157
202
|
|
|
158
203
|
retries = 0
|
|
@@ -170,30 +215,35 @@ class AVTS(object):
|
|
|
170
215
|
|
|
171
216
|
if response.ok:
|
|
172
217
|
if success_message:
|
|
173
|
-
logger.debug(success_message)
|
|
218
|
+
self.logger.debug(success_message)
|
|
174
219
|
return self.parse_request_response(response)
|
|
220
|
+
elif (
|
|
221
|
+
response.status_code == 500
|
|
222
|
+
and "Cannot modify configuration" in response.text
|
|
223
|
+
and "while the Processor is running" in response.text
|
|
224
|
+
):
|
|
225
|
+
self.logger.warning("Another operation is already running. Waiting 5 seconds to retry...")
|
|
226
|
+
time.sleep(5)
|
|
227
|
+
retries += 1
|
|
175
228
|
# Check if Session has expired - then re-authenticate and try once more
|
|
176
229
|
elif response.status_code == 401 and retries == 0:
|
|
177
|
-
logger.
|
|
230
|
+
self.logger.info("Session has expired - try to re-authenticate...")
|
|
178
231
|
self.authenticate()
|
|
179
232
|
retries += 1
|
|
180
233
|
else:
|
|
181
234
|
# Handle plain HTML responses to not pollute the logs
|
|
182
235
|
content_type = response.headers.get("content-type", None)
|
|
183
|
-
if content_type == "text/html"
|
|
184
|
-
response_text = "HTML content (see debug log)"
|
|
185
|
-
else:
|
|
186
|
-
response_text = response.text
|
|
236
|
+
response_text = "HTML content (see debug log)" if content_type == "text/html" else response.text
|
|
187
237
|
|
|
188
238
|
if show_error:
|
|
189
|
-
logger.error(
|
|
239
|
+
self.logger.error(
|
|
190
240
|
"%s; status -> %s; error -> %s",
|
|
191
241
|
failure_message,
|
|
192
242
|
response.status_code,
|
|
193
243
|
response_text,
|
|
194
244
|
)
|
|
195
245
|
else:
|
|
196
|
-
logger.warning(
|
|
246
|
+
self.logger.warning(
|
|
197
247
|
"%s; status -> %s; warning -> %s",
|
|
198
248
|
failure_message,
|
|
199
249
|
response.status_code,
|
|
@@ -201,7 +251,7 @@ class AVTS(object):
|
|
|
201
251
|
)
|
|
202
252
|
|
|
203
253
|
if content_type == "text/html":
|
|
204
|
-
logger.debug(
|
|
254
|
+
self.logger.debug(
|
|
205
255
|
"%s; status -> %s; warning -> %s",
|
|
206
256
|
failure_message,
|
|
207
257
|
response.status_code,
|
|
@@ -211,39 +261,39 @@ class AVTS(object):
|
|
|
211
261
|
return None
|
|
212
262
|
except requests.exceptions.Timeout:
|
|
213
263
|
if retries <= max_retries:
|
|
214
|
-
logger.warning(
|
|
264
|
+
self.logger.warning(
|
|
215
265
|
"Request timed out. Retrying in %s seconds...",
|
|
216
266
|
str(REQUEST_RETRY_DELAY),
|
|
217
267
|
)
|
|
218
268
|
retries += 1
|
|
219
269
|
time.sleep(REQUEST_RETRY_DELAY) # Add a delay before retrying
|
|
220
270
|
else:
|
|
221
|
-
logger.error(
|
|
222
|
-
"%s; timeout error",
|
|
271
|
+
self.logger.error(
|
|
272
|
+
"%s; timeout error.",
|
|
223
273
|
failure_message,
|
|
224
274
|
)
|
|
225
275
|
if retry_forever:
|
|
226
276
|
# If it fails after REQUEST_MAX_RETRIES retries we let it wait forever
|
|
227
|
-
logger.warning("Turn timeouts off and wait forever...")
|
|
277
|
+
self.logger.warning("Turn timeouts off and wait forever...")
|
|
228
278
|
timeout = None
|
|
229
279
|
else:
|
|
230
280
|
return None
|
|
231
281
|
except requests.exceptions.ConnectionError:
|
|
232
282
|
if retries <= max_retries:
|
|
233
|
-
logger.warning(
|
|
283
|
+
self.logger.warning(
|
|
234
284
|
"Connection error. Retrying in %s seconds...",
|
|
235
285
|
str(REQUEST_RETRY_DELAY),
|
|
236
286
|
)
|
|
237
287
|
retries += 1
|
|
238
288
|
time.sleep(REQUEST_RETRY_DELAY) # Add a delay before retrying
|
|
239
289
|
else:
|
|
240
|
-
logger.error(
|
|
241
|
-
"%s; connection error",
|
|
290
|
+
self.logger.error(
|
|
291
|
+
"%s; connection error.",
|
|
242
292
|
failure_message,
|
|
243
293
|
)
|
|
244
294
|
if retry_forever:
|
|
245
295
|
# If it fails after REQUEST_MAX_RETRIES retries we let it wait forever
|
|
246
|
-
logger.warning("Turn timeouts off and wait forever...")
|
|
296
|
+
self.logger.warning("Turn timeouts off and wait forever...")
|
|
247
297
|
timeout = None
|
|
248
298
|
time.sleep(REQUEST_RETRY_DELAY) # Add a delay before retrying
|
|
249
299
|
else:
|
|
@@ -257,43 +307,47 @@ class AVTS(object):
|
|
|
257
307
|
additional_error_message: str = "",
|
|
258
308
|
show_error: bool = True,
|
|
259
309
|
) -> list | None:
|
|
260
|
-
"""
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
310
|
+
"""Convert the request response (JSon) to a Python list in a safe way that also handles exceptions.
|
|
311
|
+
|
|
312
|
+
It first tries to load the response.text
|
|
313
|
+
via json.loads() that produces a dict output. Only if response.text is
|
|
314
|
+
not set or is empty it just converts the response_object to a dict using
|
|
315
|
+
the vars() built-in method.
|
|
265
316
|
|
|
266
317
|
Args:
|
|
267
|
-
response_object (
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
318
|
+
response_object (requests.Response):
|
|
319
|
+
This is reponse object delivered by the request call.
|
|
320
|
+
additional_error_message (str, optional):
|
|
321
|
+
Use a more specific error message in case of an error.
|
|
322
|
+
show_error (bool, optional):
|
|
323
|
+
If True, write an error to the log file.
|
|
324
|
+
If False, write a warning to the log file.
|
|
325
|
+
|
|
272
326
|
Returns:
|
|
273
|
-
list
|
|
327
|
+
list | None:
|
|
328
|
+
The response information or None in case of an error.
|
|
329
|
+
|
|
274
330
|
"""
|
|
275
331
|
|
|
276
332
|
if not response_object:
|
|
277
333
|
return None
|
|
278
334
|
|
|
279
335
|
try:
|
|
280
|
-
if response_object.text
|
|
281
|
-
list_object = json.loads(response_object.text)
|
|
282
|
-
else:
|
|
283
|
-
list_object = vars(response_object)
|
|
336
|
+
list_object = json.loads(response_object.text) if response_object.text else vars(response_object)
|
|
284
337
|
except json.JSONDecodeError as exception:
|
|
285
338
|
if additional_error_message:
|
|
286
339
|
message = "Cannot decode response as JSON. {}; error -> {}".format(
|
|
287
|
-
additional_error_message,
|
|
340
|
+
additional_error_message,
|
|
341
|
+
exception,
|
|
288
342
|
)
|
|
289
343
|
else:
|
|
290
344
|
message = "Cannot decode response as JSON; error -> {}".format(
|
|
291
|
-
exception
|
|
345
|
+
exception,
|
|
292
346
|
)
|
|
293
347
|
if show_error:
|
|
294
|
-
logger.error(message)
|
|
348
|
+
self.logger.error(message)
|
|
295
349
|
else:
|
|
296
|
-
logger.warning(message)
|
|
350
|
+
self.logger.warning(message)
|
|
297
351
|
return None
|
|
298
352
|
else:
|
|
299
353
|
return list_object
|
|
@@ -301,7 +355,13 @@ class AVTS(object):
|
|
|
301
355
|
# end method definition
|
|
302
356
|
|
|
303
357
|
def authenticate(self) -> str | None:
|
|
304
|
-
"""Authenticate at Search
|
|
358
|
+
"""Authenticate at Aviator Search via OAuth.
|
|
359
|
+
|
|
360
|
+
Returns:
|
|
361
|
+
str | None:
|
|
362
|
+
The access token or None in case of an error.
|
|
363
|
+
|
|
364
|
+
"""
|
|
305
365
|
|
|
306
366
|
if not self._session:
|
|
307
367
|
self._session = requests.Session()
|
|
@@ -315,10 +375,11 @@ class AVTS(object):
|
|
|
315
375
|
}
|
|
316
376
|
request_payload = {
|
|
317
377
|
"client_id": self.config()["clientId"],
|
|
318
|
-
"grant_type": "password",
|
|
319
378
|
"client_secret": self.config()["clientSecret"],
|
|
379
|
+
"grant_type": "password",
|
|
320
380
|
"username": self.config()["username"],
|
|
321
381
|
"password": self.config()["password"],
|
|
382
|
+
"scope": "otds:roles",
|
|
322
383
|
}
|
|
323
384
|
|
|
324
385
|
response = self.do_request(
|
|
@@ -327,7 +388,10 @@ class AVTS(object):
|
|
|
327
388
|
headers=request_header,
|
|
328
389
|
data=request_payload,
|
|
329
390
|
timeout=None,
|
|
330
|
-
failure_message=
|
|
391
|
+
failure_message="Failed to authenticate to OTDS with username -> '{}' and client_id -> {}".format(
|
|
392
|
+
self.config()["username"],
|
|
393
|
+
self.config()["clientId"],
|
|
394
|
+
),
|
|
331
395
|
)
|
|
332
396
|
|
|
333
397
|
if response is not None:
|
|
@@ -337,7 +401,7 @@ class AVTS(object):
|
|
|
337
401
|
|
|
338
402
|
# end method definition
|
|
339
403
|
|
|
340
|
-
def
|
|
404
|
+
def create_extended_ecm_repo(
|
|
341
405
|
self,
|
|
342
406
|
name: str,
|
|
343
407
|
username: str,
|
|
@@ -345,128 +409,221 @@ class AVTS(object):
|
|
|
345
409
|
otcs_url: str,
|
|
346
410
|
otcs_api_url: str,
|
|
347
411
|
node_id: int,
|
|
348
|
-
version: str = "24.3.0",
|
|
349
412
|
) -> dict | None:
|
|
350
|
-
"""Create a new repository to crawl
|
|
413
|
+
"""Create a new Extended ECM repository to crawl with Aviator Search.
|
|
351
414
|
|
|
352
415
|
Args:
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
username (str):
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
416
|
+
name (str):
|
|
417
|
+
The name of the repository.
|
|
418
|
+
username (str):
|
|
419
|
+
Username to use for crawling.
|
|
420
|
+
password (str):
|
|
421
|
+
Password of the user used for crawling.
|
|
422
|
+
otcs_url (str):
|
|
423
|
+
Base URL of Content Server e.g. https://otcs.base-url.tld/cs/cs
|
|
424
|
+
otcs_api_url (str):
|
|
425
|
+
The REST API URL of Content Server.
|
|
426
|
+
node_id (int):
|
|
427
|
+
Root Node ID for crawling
|
|
359
428
|
|
|
360
429
|
Returns:
|
|
361
|
-
dict | None:
|
|
430
|
+
dict | None:
|
|
431
|
+
Parsed response object from the API or None in case of an error
|
|
432
|
+
|
|
362
433
|
"""
|
|
363
434
|
|
|
364
435
|
payload = {
|
|
365
|
-
"
|
|
366
|
-
"name": name,
|
|
367
|
-
"metadataFields": ["NODE"],
|
|
368
|
-
"socName": "xECM",
|
|
436
|
+
"authType": "Basic",
|
|
369
437
|
"params": [
|
|
370
438
|
{
|
|
371
439
|
"id": "OpenTextApiUrl",
|
|
372
|
-
"label": "
|
|
440
|
+
"label": "Service URL",
|
|
373
441
|
"ctlType": "text",
|
|
442
|
+
"description": "OpenText Content Management API URL",
|
|
374
443
|
"required": True,
|
|
444
|
+
"defaultValue": "localhost",
|
|
445
|
+
"visible": True,
|
|
446
|
+
"editable": False,
|
|
375
447
|
"value": otcs_api_url,
|
|
376
448
|
},
|
|
377
449
|
{
|
|
378
450
|
"id": "Username",
|
|
379
|
-
"label": "
|
|
451
|
+
"label": "Username",
|
|
380
452
|
"ctlType": "text",
|
|
453
|
+
"description": "OpenText Content Management Username",
|
|
381
454
|
"required": True,
|
|
455
|
+
"defaultValue": "",
|
|
456
|
+
"visible": True,
|
|
457
|
+
"editable": True,
|
|
382
458
|
"value": username,
|
|
383
459
|
},
|
|
384
460
|
{
|
|
385
461
|
"id": "Password",
|
|
386
|
-
"label": "
|
|
462
|
+
"label": "Password",
|
|
387
463
|
"ctlType": "password",
|
|
464
|
+
"description": "OpenText Content Management password",
|
|
388
465
|
"required": True,
|
|
466
|
+
"defaultValue": "",
|
|
467
|
+
"visible": True,
|
|
468
|
+
"editable": True,
|
|
389
469
|
"value": password,
|
|
390
470
|
},
|
|
391
471
|
{
|
|
392
|
-
"id": "
|
|
393
|
-
"label": "
|
|
472
|
+
"id": "sourceLink",
|
|
473
|
+
"label": "Source Link",
|
|
394
474
|
"ctlType": "text",
|
|
475
|
+
"description": "Example: <OpenText Content Management API URL>/app/nodes/${NODE}/metadata",
|
|
476
|
+
"required": False,
|
|
477
|
+
"defaultValue": otcs_url + "/app/nodes/${NODE}/metadata",
|
|
478
|
+
"visible": True,
|
|
479
|
+
"editable": True,
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
"id": "RootNodeIds",
|
|
483
|
+
"label": "Root Node ID's",
|
|
484
|
+
"ctlType": "text",
|
|
485
|
+
"description": "List of nodes to be crawled(comma seperated)",
|
|
395
486
|
"required": True,
|
|
396
|
-
"
|
|
487
|
+
"defaultValue": "",
|
|
488
|
+
"visible": True,
|
|
489
|
+
"editable": False,
|
|
490
|
+
"value": "2000",
|
|
397
491
|
},
|
|
398
492
|
{
|
|
399
|
-
"id": "
|
|
400
|
-
"label": "
|
|
493
|
+
"id": "proxy",
|
|
494
|
+
"label": "Proxy Service",
|
|
495
|
+
"ctlType": "boolean",
|
|
496
|
+
"description": "",
|
|
497
|
+
"required": False,
|
|
498
|
+
"defaultValue": "false",
|
|
499
|
+
"value": "false",
|
|
500
|
+
"visible": True,
|
|
501
|
+
"editable": True,
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
"id": "proxyScheme",
|
|
505
|
+
"label": "Proxy Scheme",
|
|
506
|
+
"ctlType": "select",
|
|
507
|
+
"description": "",
|
|
508
|
+
"required": False,
|
|
509
|
+
"defaultValue": "HTTP",
|
|
510
|
+
"value": "HTTP",
|
|
511
|
+
"visible": True,
|
|
512
|
+
"acceptedValues": ["HTTP", "HTTPS", "SOCKS5"],
|
|
513
|
+
"editable": True,
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
"id": "proxyHost",
|
|
517
|
+
"label": "Proxy Host",
|
|
401
518
|
"ctlType": "text",
|
|
519
|
+
"description": "",
|
|
402
520
|
"required": False,
|
|
403
|
-
"defaultValue":
|
|
521
|
+
"defaultValue": "",
|
|
522
|
+
"value": "",
|
|
523
|
+
"visible": True,
|
|
524
|
+
"editable": True,
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
"id": "proxyPort",
|
|
528
|
+
"label": "Proxy Port",
|
|
529
|
+
"ctlType": "text",
|
|
530
|
+
"description": "",
|
|
531
|
+
"required": False,
|
|
532
|
+
"defaultValue": "",
|
|
533
|
+
"value": "",
|
|
404
534
|
"visible": True,
|
|
535
|
+
"editable": True,
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
"id": "ProxyConfigService",
|
|
539
|
+
"label": "Proxy Config Service",
|
|
540
|
+
"ctlType": "text",
|
|
541
|
+
"description": "",
|
|
542
|
+
"required": False,
|
|
543
|
+
"defaultValue": "",
|
|
544
|
+
"value": "",
|
|
545
|
+
"visible": False,
|
|
546
|
+
"editable": True,
|
|
405
547
|
},
|
|
406
548
|
],
|
|
407
|
-
"
|
|
408
|
-
"
|
|
409
|
-
|
|
410
|
-
|
|
549
|
+
"config": {
|
|
550
|
+
"type": "nifi",
|
|
551
|
+
"id": "xECM",
|
|
552
|
+
"crawlConfig": {
|
|
553
|
+
"name": "GetOpenText",
|
|
554
|
+
"type": "idol.nifi.connector.GetOpenText",
|
|
411
555
|
"group": "idol.nifi.connector",
|
|
412
556
|
"artifact": "idol-nifi-connector-opentext",
|
|
413
|
-
"version":
|
|
557
|
+
"version": "25.1.0-nifi1",
|
|
414
558
|
},
|
|
415
|
-
"
|
|
416
|
-
"name": "
|
|
417
|
-
"type": "idol.nifi.connector.
|
|
559
|
+
"viewConfig": {
|
|
560
|
+
"name": "ViewOpenText",
|
|
561
|
+
"type": "idol.nifi.connector.ViewOpenText",
|
|
418
562
|
"group": "idol.nifi.connector",
|
|
419
563
|
"artifact": "idol-nifi-connector-opentext",
|
|
420
|
-
"version":
|
|
564
|
+
"version": "25.1.0-nifi1",
|
|
421
565
|
},
|
|
422
|
-
"
|
|
566
|
+
"omniConfig": {
|
|
423
567
|
"name": "GetOpenTextGroups",
|
|
424
568
|
"type": "idol.nifi.connector.GetOpenTextGroups",
|
|
425
569
|
"group": "idol.nifi.connector",
|
|
426
570
|
"artifact": "idol-nifi-connector-opentext",
|
|
427
|
-
"version":
|
|
571
|
+
"version": "25.1.0-nifi1",
|
|
572
|
+
"repoName": "ECM",
|
|
428
573
|
},
|
|
429
|
-
|
|
430
|
-
"idolProperties": {
|
|
431
|
-
"view": {
|
|
574
|
+
"crawlProps": {
|
|
432
575
|
"Password": "${Password}",
|
|
433
576
|
"Username": "${UserName}",
|
|
577
|
+
"META:SOURCE": "OPENTEXT",
|
|
578
|
+
"RootNodeIds": "${RootNodeIds}",
|
|
579
|
+
"MappedSecurity": "true",
|
|
434
580
|
"OpenTextApiUrl": "${OpenTextApiUrl}",
|
|
581
|
+
"ProxyConfigService": "${ProxyConfigService}",
|
|
435
582
|
},
|
|
436
|
-
"
|
|
583
|
+
"viewProps": {
|
|
437
584
|
"Password": "${Password}",
|
|
438
585
|
"Username": "${UserName}",
|
|
439
|
-
"RootNodeId": "${RootNodeId}",
|
|
440
|
-
"META:SOURCE": "OPENTEXT",
|
|
441
|
-
"MappedSecurity": "true",
|
|
442
586
|
"OpenTextApiUrl": "${OpenTextApiUrl}",
|
|
587
|
+
"ProxyConfigService": "${ProxyConfigService}",
|
|
443
588
|
},
|
|
444
|
-
"
|
|
589
|
+
"omniProps": {
|
|
445
590
|
"Password": "${Password}",
|
|
446
591
|
"Username": "${UserName}",
|
|
447
592
|
"OpenTextApiUrl": "${OpenTextApiUrl}",
|
|
593
|
+
"ProxyConfigService": "${ProxyConfigService}",
|
|
448
594
|
"OpenTextApiPageSize": "10",
|
|
449
595
|
},
|
|
596
|
+
"metadataFields": ["NODE"],
|
|
450
597
|
},
|
|
598
|
+
"name": name,
|
|
599
|
+
"id": "xECM",
|
|
600
|
+
"sourceId": "xECM",
|
|
451
601
|
}
|
|
452
602
|
|
|
453
603
|
request_header = self.request_header()
|
|
454
604
|
request_url = self.config()["repoUrl"]
|
|
455
605
|
|
|
456
|
-
|
|
606
|
+
response = self.do_request(
|
|
457
607
|
url=request_url,
|
|
458
608
|
method="POST",
|
|
459
609
|
json_data=payload,
|
|
460
610
|
headers=request_header,
|
|
461
611
|
timeout=None,
|
|
462
612
|
failure_message="Failed to create repository -> '{}' ({})".format(
|
|
463
|
-
name,
|
|
613
|
+
name,
|
|
614
|
+
node_id,
|
|
464
615
|
),
|
|
616
|
+
show_error=False,
|
|
465
617
|
)
|
|
466
618
|
|
|
619
|
+
if response is None:
|
|
620
|
+
self.logger.error("Failed to create repository -> %s (%s)!", name, node_id)
|
|
621
|
+
|
|
622
|
+
return response
|
|
623
|
+
|
|
467
624
|
# end method definition
|
|
468
625
|
|
|
469
|
-
def
|
|
626
|
+
def create_msteams_repo(
|
|
470
627
|
self,
|
|
471
628
|
name: str,
|
|
472
629
|
client_id: str,
|
|
@@ -477,36 +634,41 @@ class AVTS(object):
|
|
|
477
634
|
index_call_recordings: bool = True,
|
|
478
635
|
index_message_replies: bool = True,
|
|
479
636
|
index_user_chats: bool = True,
|
|
480
|
-
oauth2_site_name: str = "AVTS",
|
|
481
|
-
oauth2_sites_file: str = "",
|
|
482
|
-
version: str = "24.3.0",
|
|
483
637
|
) -> dict | None:
|
|
484
|
-
"""Create a new repository to crawl
|
|
638
|
+
"""Create a new Microsoft Teams repository to crawl with Aviator Search.
|
|
485
639
|
|
|
486
640
|
Args:
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
641
|
+
name (str):
|
|
642
|
+
The name of the repository.
|
|
643
|
+
client_id (str):
|
|
644
|
+
The M365 client ID.
|
|
645
|
+
tenant_id (str):
|
|
646
|
+
The M365 tenant ID.
|
|
647
|
+
certificate_file (str):
|
|
648
|
+
The path to the certificate file.
|
|
649
|
+
certificate_password (str):
|
|
650
|
+
The password for the certificate.
|
|
651
|
+
index_attachments (bool, optional):
|
|
652
|
+
Whether or not to index / crawl attachments.
|
|
653
|
+
index_call_recordings (bool, optional):
|
|
654
|
+
Whether or not to index / crawl meeting recordings.
|
|
655
|
+
index_message_replies (bool, optional):
|
|
656
|
+
Whether or not to index / crawl message replies.
|
|
657
|
+
index_user_chats (bool, optional):
|
|
658
|
+
Whether or not to index / crawl user chats.
|
|
490
659
|
|
|
491
660
|
Returns:
|
|
492
|
-
dict | None:
|
|
661
|
+
dict | None:
|
|
662
|
+
Parsed response object from the API or None in case of an error
|
|
663
|
+
|
|
493
664
|
"""
|
|
494
665
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
# Read the content of the file
|
|
499
|
-
certificate_file_content = file.read()
|
|
500
|
-
# Convert the bytes to a base64 string
|
|
501
|
-
certificate_file_content_base64 = base64.b64encode(
|
|
502
|
-
certificate_file_content
|
|
503
|
-
).decode("utf-8")
|
|
666
|
+
certificate_file_content_base64 = self.get_certificate_file_content_base64(
|
|
667
|
+
certificate_file,
|
|
668
|
+
)
|
|
504
669
|
|
|
505
670
|
payload = {
|
|
506
|
-
"id": "MSTeams",
|
|
507
|
-
"socName": "Microsoft Teams",
|
|
508
671
|
"authType": "OAUTH",
|
|
509
|
-
"name": name,
|
|
510
672
|
"params": [
|
|
511
673
|
{
|
|
512
674
|
"id": "OAuth2SiteName",
|
|
@@ -516,6 +678,7 @@ class AVTS(object):
|
|
|
516
678
|
"defaultValue": "AVTS",
|
|
517
679
|
"value": "AVTS",
|
|
518
680
|
"visible": False,
|
|
681
|
+
"editable": True,
|
|
519
682
|
},
|
|
520
683
|
{
|
|
521
684
|
"id": "OAuth2SitesFile",
|
|
@@ -525,6 +688,7 @@ class AVTS(object):
|
|
|
525
688
|
"defaultValue": "",
|
|
526
689
|
"value": "",
|
|
527
690
|
"visible": False,
|
|
691
|
+
"editable": True,
|
|
528
692
|
},
|
|
529
693
|
{
|
|
530
694
|
"id": "sourceLink",
|
|
@@ -533,6 +697,7 @@ class AVTS(object):
|
|
|
533
697
|
"required": False,
|
|
534
698
|
"defaultValue": "",
|
|
535
699
|
"visible": True,
|
|
700
|
+
"editable": True,
|
|
536
701
|
},
|
|
537
702
|
{
|
|
538
703
|
"id": "clientID",
|
|
@@ -543,6 +708,7 @@ class AVTS(object):
|
|
|
543
708
|
"defaultValue": "",
|
|
544
709
|
"value": client_id,
|
|
545
710
|
"visible": True,
|
|
711
|
+
"editable": True,
|
|
546
712
|
},
|
|
547
713
|
{
|
|
548
714
|
"id": "tenant",
|
|
@@ -553,6 +719,7 @@ class AVTS(object):
|
|
|
553
719
|
"defaultValue": "",
|
|
554
720
|
"value": tenant_id,
|
|
555
721
|
"visible": True,
|
|
722
|
+
"editable": False,
|
|
556
723
|
},
|
|
557
724
|
{
|
|
558
725
|
"id": "IndexAttachments",
|
|
@@ -561,8 +728,9 @@ class AVTS(object):
|
|
|
561
728
|
"description": "Specifies whether to index attachments",
|
|
562
729
|
"required": False,
|
|
563
730
|
"defaultValue": "true",
|
|
564
|
-
"value":
|
|
565
|
-
"visible":
|
|
731
|
+
"value": "true",
|
|
732
|
+
"visible": str(index_attachments).lower(),
|
|
733
|
+
"editable": True,
|
|
566
734
|
},
|
|
567
735
|
{
|
|
568
736
|
"id": "IndexCallRecordings",
|
|
@@ -573,6 +741,7 @@ class AVTS(object):
|
|
|
573
741
|
"defaultValue": "true",
|
|
574
742
|
"value": str(index_call_recordings).lower(),
|
|
575
743
|
"visible": True,
|
|
744
|
+
"editable": True,
|
|
576
745
|
},
|
|
577
746
|
{
|
|
578
747
|
"id": "IndexMessageReplies",
|
|
@@ -583,6 +752,7 @@ class AVTS(object):
|
|
|
583
752
|
"defaultValue": "true",
|
|
584
753
|
"value": str(index_message_replies).lower(),
|
|
585
754
|
"visible": True,
|
|
755
|
+
"editable": True,
|
|
586
756
|
},
|
|
587
757
|
{
|
|
588
758
|
"id": "IndexUserChats",
|
|
@@ -593,6 +763,7 @@ class AVTS(object):
|
|
|
593
763
|
"defaultValue": "true",
|
|
594
764
|
"value": str(index_user_chats).lower(),
|
|
595
765
|
"visible": True,
|
|
766
|
+
"editable": True,
|
|
596
767
|
},
|
|
597
768
|
{
|
|
598
769
|
"id": "certificateFile",
|
|
@@ -601,8 +772,9 @@ class AVTS(object):
|
|
|
601
772
|
"description": 'Please upload a valid "*.pfx" certificate file',
|
|
602
773
|
"required": True,
|
|
603
774
|
"defaultValue": "",
|
|
604
|
-
"value": "C:\\fakepath\\certificate.pfx",
|
|
775
|
+
"value": "C:\\fakepath\\certificate 1 3 (1).pfx",
|
|
605
776
|
"visible": True,
|
|
777
|
+
"editable": True,
|
|
606
778
|
"fileDatabase64": f"data:application/x-pkcs12;base64,{certificate_file_content_base64}",
|
|
607
779
|
},
|
|
608
780
|
{
|
|
@@ -613,42 +785,126 @@ class AVTS(object):
|
|
|
613
785
|
"defaultValue": "",
|
|
614
786
|
"value": certificate_password,
|
|
615
787
|
"visible": True,
|
|
788
|
+
"editable": True,
|
|
789
|
+
},
|
|
790
|
+
{
|
|
791
|
+
"id": "proxy",
|
|
792
|
+
"label": "Proxy Service",
|
|
793
|
+
"ctlType": "boolean",
|
|
794
|
+
"description": "",
|
|
795
|
+
"required": False,
|
|
796
|
+
"defaultValue": "false",
|
|
797
|
+
"value": "false",
|
|
798
|
+
"visible": True,
|
|
799
|
+
"editable": True,
|
|
800
|
+
},
|
|
801
|
+
{
|
|
802
|
+
"id": "proxyScheme",
|
|
803
|
+
"label": "Proxy Scheme",
|
|
804
|
+
"ctlType": "select",
|
|
805
|
+
"description": "",
|
|
806
|
+
"required": False,
|
|
807
|
+
"defaultValue": "HTTP",
|
|
808
|
+
"value": "HTTP",
|
|
809
|
+
"visible": True,
|
|
810
|
+
"acceptedValues": [
|
|
811
|
+
"HTTP",
|
|
812
|
+
"HTTPS",
|
|
813
|
+
"SOCKS5",
|
|
814
|
+
],
|
|
815
|
+
"editable": True,
|
|
816
|
+
},
|
|
817
|
+
{
|
|
818
|
+
"id": "proxyHost",
|
|
819
|
+
"label": "Proxy Host",
|
|
820
|
+
"ctlType": "text",
|
|
821
|
+
"description": "",
|
|
822
|
+
"required": False,
|
|
823
|
+
"defaultValue": "",
|
|
824
|
+
"value": "",
|
|
825
|
+
"visible": True,
|
|
826
|
+
"editable": True,
|
|
827
|
+
},
|
|
828
|
+
{
|
|
829
|
+
"id": "proxyPort",
|
|
830
|
+
"label": "Proxy Port",
|
|
831
|
+
"ctlType": "text",
|
|
832
|
+
"description": "",
|
|
833
|
+
"required": False,
|
|
834
|
+
"defaultValue": "",
|
|
835
|
+
"value": "",
|
|
836
|
+
"visible": True,
|
|
837
|
+
"editable": True,
|
|
838
|
+
},
|
|
839
|
+
{
|
|
840
|
+
"id": "ProxyConfigService",
|
|
841
|
+
"label": "Proxy Config Service",
|
|
842
|
+
"ctlType": "text",
|
|
843
|
+
"description": "",
|
|
844
|
+
"required": False,
|
|
845
|
+
"defaultValue": "",
|
|
846
|
+
"value": "",
|
|
847
|
+
"visible": False,
|
|
848
|
+
"editable": True,
|
|
616
849
|
},
|
|
617
850
|
],
|
|
618
|
-
"
|
|
619
|
-
"
|
|
851
|
+
"config": {
|
|
852
|
+
"type": "nifi",
|
|
853
|
+
"id": "MSTeams",
|
|
854
|
+
"crawlConfig": {
|
|
855
|
+
"name": "GetMicrosoftTeams",
|
|
856
|
+
"type": "idol.nifi.connector.GetMicrosoftTeams",
|
|
857
|
+
"group": "idol.nifi.connector",
|
|
858
|
+
"artifact": "idol-nifi-connector-officeteams",
|
|
859
|
+
"version": "25.1.0-nifi1",
|
|
860
|
+
},
|
|
861
|
+
"viewConfig": {
|
|
620
862
|
"name": "ViewMicrosoftTeams",
|
|
621
863
|
"type": "idol.nifi.connector.ViewMicrosoftTeams",
|
|
622
864
|
"group": "idol.nifi.connector",
|
|
623
865
|
"artifact": "idol-nifi-connector-officeteams",
|
|
624
|
-
"version":
|
|
866
|
+
"version": "25.1.0-nifi1",
|
|
625
867
|
},
|
|
626
|
-
"
|
|
627
|
-
"name": "
|
|
628
|
-
"type": "idol.nifi.connector.
|
|
868
|
+
"omniConfig": {
|
|
869
|
+
"name": "GetMicrosoftTeamsGroups",
|
|
870
|
+
"type": "idol.nifi.connector.GetMicrosoftTeamsGroups",
|
|
629
871
|
"group": "idol.nifi.connector",
|
|
630
872
|
"artifact": "idol-nifi-connector-officeteams",
|
|
631
|
-
"version":
|
|
873
|
+
"version": "25.1.0-nifi1",
|
|
874
|
+
"repoName": "OneDrive",
|
|
632
875
|
},
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
"view": {
|
|
636
|
-
"Oauth2SiteName": "${OAuth2SiteName}",
|
|
637
|
-
"Oauth2SitesFile": "${OAuth2SitesFile}",
|
|
638
|
-
"IndexCallRecordings": "true",
|
|
639
|
-
},
|
|
640
|
-
"crawler": {
|
|
641
|
-
"META:SOURCE": "MSTeams",
|
|
876
|
+
"crawlProps": {
|
|
877
|
+
"META:SOURCE": "Microsoft Teams",
|
|
642
878
|
"IndexUserChats": "${IndexUserChats}",
|
|
879
|
+
"MappedSecurity": "true",
|
|
643
880
|
"Oauth2SiteName": "${OAuth2SiteName}",
|
|
644
881
|
"Oauth2SitesFile": "${OAuth2SitesFile}",
|
|
645
882
|
"IndexAttachments": "${IndexAttachments}",
|
|
883
|
+
"ProxyConfigService": "${ProxyConfigService}",
|
|
646
884
|
"IndexCallRecordings": "${IndexCallRecordings}",
|
|
647
885
|
"IndexMessageReplies": "${IndexMessageReplies}",
|
|
886
|
+
"ChatMessageGroupingSection": "chat",
|
|
887
|
+
"ChannelMessageGroupingSection": "channel",
|
|
888
|
+
"[chat]MessageGroupingInterval": "24 hour",
|
|
889
|
+
"[chat]MessageGroupingStrategy": "Interval",
|
|
890
|
+
"[channel]MessageGroupingInterval": "24 hour",
|
|
891
|
+
"[channel]MessageGroupingStrategy": "Interval",
|
|
648
892
|
},
|
|
893
|
+
"viewProps": {
|
|
894
|
+
"Oauth2SiteName": "${OAuth2SiteName}",
|
|
895
|
+
"Oauth2SitesFile": "${OAuth2SitesFile}",
|
|
896
|
+
"ProxyConfigService": "${ProxyConfigService}",
|
|
897
|
+
},
|
|
898
|
+
"omniProps": {
|
|
899
|
+
"Oauth2SiteName": "${OAuth2SiteName}",
|
|
900
|
+
"Oauth2SitesFile": "${OAuth2SitesFile}",
|
|
901
|
+
"ProxyConfigService": "${ProxyConfigService}",
|
|
902
|
+
},
|
|
903
|
+
"metadataFields": [],
|
|
649
904
|
},
|
|
650
|
-
"
|
|
651
|
-
"
|
|
905
|
+
"name": name,
|
|
906
|
+
"id": "MSTeams",
|
|
907
|
+
"sourceId": "MSTeams",
|
|
652
908
|
}
|
|
653
909
|
|
|
654
910
|
request_header = self.request_header()
|
|
@@ -661,9 +917,11 @@ class AVTS(object):
|
|
|
661
917
|
headers=request_header,
|
|
662
918
|
timeout=None,
|
|
663
919
|
failure_message="Failed to create repository -> '{}'".format(name),
|
|
920
|
+
show_error=False,
|
|
664
921
|
)
|
|
665
922
|
|
|
666
923
|
if response is None:
|
|
924
|
+
self.logger.error("Failed to create repository -> '%s'", name)
|
|
667
925
|
return None
|
|
668
926
|
|
|
669
927
|
self.repo_admin_consent(response["id"])
|
|
@@ -672,7 +930,7 @@ class AVTS(object):
|
|
|
672
930
|
|
|
673
931
|
# end method definition
|
|
674
932
|
|
|
675
|
-
def
|
|
933
|
+
def create_sharepoint_repo(
|
|
676
934
|
self,
|
|
677
935
|
name: str,
|
|
678
936
|
client_id: str,
|
|
@@ -686,34 +944,47 @@ class AVTS(object):
|
|
|
686
944
|
index_user_profiles: bool = True,
|
|
687
945
|
oauth2_site_name: str = "AVTS",
|
|
688
946
|
oauth2_sites_file: str = "",
|
|
689
|
-
version: str = "24.3.0",
|
|
690
947
|
) -> dict | None:
|
|
691
|
-
"""Create a new repository to crawl
|
|
948
|
+
"""Create a new Microsoft SharePoint repository to crawl with Aviator Search.
|
|
692
949
|
|
|
693
950
|
Args:
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
951
|
+
name (str):
|
|
952
|
+
The name of the repository.
|
|
953
|
+
client_id (str):
|
|
954
|
+
The M365 client ID.
|
|
955
|
+
tenant_id (str):
|
|
956
|
+
The M365 tenant ID.
|
|
957
|
+
certificate_file (str):
|
|
958
|
+
TODO: _description_
|
|
959
|
+
certificate_password (int):
|
|
960
|
+
TODO: _description_
|
|
961
|
+
sharepoint_url (str):
|
|
962
|
+
The SharePoint URL.
|
|
963
|
+
sharepoint_url_type (str):
|
|
964
|
+
The SharePoint URL type.
|
|
965
|
+
sharepoint_mysite_url (str):
|
|
966
|
+
The SharePoint MySite URL.
|
|
967
|
+
sharepoint_admin_url (str):
|
|
968
|
+
The SharePoint administration URL.
|
|
969
|
+
index_user_profiles (bool, optional):
|
|
970
|
+
TODO: _description_. Defaults to True.
|
|
971
|
+
oauth2_site_name (str, optional):
|
|
972
|
+
TODO: _description_. Defaults to "AVTS".
|
|
973
|
+
oauth2_sites_file (str, optional):
|
|
974
|
+
TODO: _description_. Defaults to "".
|
|
697
975
|
|
|
698
976
|
Returns:
|
|
699
|
-
dict | None:
|
|
977
|
+
dict | None:
|
|
978
|
+
Parsed response object from the API or None in case of an error
|
|
979
|
+
|
|
700
980
|
"""
|
|
701
981
|
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
# Read the content of the file
|
|
706
|
-
certificate_file_content = file.read()
|
|
707
|
-
# Convert the bytes to a base64 string
|
|
708
|
-
certificate_file_content_base64 = base64.b64encode(
|
|
709
|
-
certificate_file_content
|
|
710
|
-
).decode("utf-8")
|
|
982
|
+
certificate_file_content_base64 = self.get_certificate_file_content_base64(
|
|
983
|
+
certificate_file,
|
|
984
|
+
)
|
|
711
985
|
|
|
712
986
|
payload = {
|
|
713
|
-
"id": "SharePoint",
|
|
714
|
-
"socName": "SharePoint Online",
|
|
715
987
|
"authType": "OAUTH",
|
|
716
|
-
"name": name,
|
|
717
988
|
"params": [
|
|
718
989
|
{
|
|
719
990
|
"id": "OAuth2SiteName",
|
|
@@ -723,6 +994,7 @@ class AVTS(object):
|
|
|
723
994
|
"defaultValue": "AVTS",
|
|
724
995
|
"value": oauth2_site_name,
|
|
725
996
|
"visible": False,
|
|
997
|
+
"editable": True,
|
|
726
998
|
},
|
|
727
999
|
{
|
|
728
1000
|
"id": "OAuth2SitesFile",
|
|
@@ -732,6 +1004,7 @@ class AVTS(object):
|
|
|
732
1004
|
"defaultValue": "",
|
|
733
1005
|
"value": oauth2_sites_file,
|
|
734
1006
|
"visible": False,
|
|
1007
|
+
"editable": True,
|
|
735
1008
|
},
|
|
736
1009
|
{
|
|
737
1010
|
"id": "sourceLink",
|
|
@@ -741,8 +1014,8 @@ class AVTS(object):
|
|
|
741
1014
|
"required": False,
|
|
742
1015
|
"defaultValue": "",
|
|
743
1016
|
"visible": True,
|
|
744
|
-
"
|
|
745
|
-
+ "${FILEDIRREF}/Forms/AllItems.aspx?id=${FILEREF}&parent=${FILEDIRREF}",
|
|
1017
|
+
"editable": True,
|
|
1018
|
+
"value": sharepoint_url + "${FILEDIRREF}/Forms/AllItems.aspx?id=${FILEREF}&parent=${FILEDIRREF}",
|
|
746
1019
|
},
|
|
747
1020
|
{
|
|
748
1021
|
"id": "clientID",
|
|
@@ -753,6 +1026,7 @@ class AVTS(object):
|
|
|
753
1026
|
"defaultValue": "",
|
|
754
1027
|
"value": client_id,
|
|
755
1028
|
"visible": True,
|
|
1029
|
+
"editable": True,
|
|
756
1030
|
},
|
|
757
1031
|
{
|
|
758
1032
|
"id": "tenant",
|
|
@@ -763,6 +1037,7 @@ class AVTS(object):
|
|
|
763
1037
|
"defaultValue": "",
|
|
764
1038
|
"value": tenant_id,
|
|
765
1039
|
"visible": True,
|
|
1040
|
+
"editable": True,
|
|
766
1041
|
},
|
|
767
1042
|
{
|
|
768
1043
|
"id": "sharePointUrl",
|
|
@@ -771,8 +1046,19 @@ class AVTS(object):
|
|
|
771
1046
|
"description": 'The URL to start synchronizing from. Specify a URL that matches "SharePoint URL type"',
|
|
772
1047
|
"required": True,
|
|
773
1048
|
"defaultValue": "",
|
|
774
|
-
"value":
|
|
1049
|
+
"value": sharepoint_mysite_url,
|
|
775
1050
|
"visible": True,
|
|
1051
|
+
"editable": False,
|
|
1052
|
+
},
|
|
1053
|
+
{
|
|
1054
|
+
"id": "MappedWebApplicationPolicies",
|
|
1055
|
+
"label": "Mapped Web Application Policies",
|
|
1056
|
+
"ctlType": "boolean",
|
|
1057
|
+
"required": False,
|
|
1058
|
+
"defaultValue": "false",
|
|
1059
|
+
"value": "false",
|
|
1060
|
+
"visible": True,
|
|
1061
|
+
"editable": False,
|
|
776
1062
|
},
|
|
777
1063
|
{
|
|
778
1064
|
"id": "sharePointAdminUrl",
|
|
@@ -783,6 +1069,7 @@ class AVTS(object):
|
|
|
783
1069
|
"defaultValue": "",
|
|
784
1070
|
"value": sharepoint_admin_url,
|
|
785
1071
|
"visible": True,
|
|
1072
|
+
"editable": False,
|
|
786
1073
|
},
|
|
787
1074
|
{
|
|
788
1075
|
"id": "sharePointMySiteUrl",
|
|
@@ -793,6 +1080,7 @@ class AVTS(object):
|
|
|
793
1080
|
"defaultValue": "",
|
|
794
1081
|
"value": sharepoint_mysite_url,
|
|
795
1082
|
"visible": True,
|
|
1083
|
+
"editable": False,
|
|
796
1084
|
},
|
|
797
1085
|
{
|
|
798
1086
|
"id": "sharePointOnline",
|
|
@@ -803,15 +1091,7 @@ class AVTS(object):
|
|
|
803
1091
|
"defaultValue": "true",
|
|
804
1092
|
"value": "true",
|
|
805
1093
|
"visible": False,
|
|
806
|
-
|
|
807
|
-
{
|
|
808
|
-
"id": "MappedWebApplicationPolicies",
|
|
809
|
-
"label": "Mapped Web Application Policies",
|
|
810
|
-
"ctlType": "text",
|
|
811
|
-
"required": False,
|
|
812
|
-
"defaultValue": "false",
|
|
813
|
-
"value": "false",
|
|
814
|
-
"visible": False,
|
|
1094
|
+
"editable": False,
|
|
815
1095
|
},
|
|
816
1096
|
{
|
|
817
1097
|
"id": "TenantAdminSitesIncludeTypes",
|
|
@@ -822,6 +1102,7 @@ class AVTS(object):
|
|
|
822
1102
|
"defaultValue": "all",
|
|
823
1103
|
"value": "all",
|
|
824
1104
|
"visible": False,
|
|
1105
|
+
"editable": False,
|
|
825
1106
|
},
|
|
826
1107
|
{
|
|
827
1108
|
"id": "URLType",
|
|
@@ -830,7 +1111,7 @@ class AVTS(object):
|
|
|
830
1111
|
"description": 'The type of URL specified by "Sharepoint URL"',
|
|
831
1112
|
"required": True,
|
|
832
1113
|
"defaultValue": "",
|
|
833
|
-
"value":
|
|
1114
|
+
"value": sharepoint_url_type,
|
|
834
1115
|
"visible": True,
|
|
835
1116
|
"acceptedValues": [
|
|
836
1117
|
"WebApplication",
|
|
@@ -838,6 +1119,7 @@ class AVTS(object):
|
|
|
838
1119
|
"PersonalSiteCollection",
|
|
839
1120
|
"TenantAdmin",
|
|
840
1121
|
],
|
|
1122
|
+
"editable": False,
|
|
841
1123
|
},
|
|
842
1124
|
{
|
|
843
1125
|
"id": "IndexUserProfiles",
|
|
@@ -848,6 +1130,7 @@ class AVTS(object):
|
|
|
848
1130
|
"defaultValue": "false",
|
|
849
1131
|
"value": str(index_user_profiles).lower(),
|
|
850
1132
|
"visible": True,
|
|
1133
|
+
"editable": True,
|
|
851
1134
|
},
|
|
852
1135
|
{
|
|
853
1136
|
"id": "certificateFile",
|
|
@@ -856,8 +1139,9 @@ class AVTS(object):
|
|
|
856
1139
|
"description": 'Please upload a valid "*.pfx" certificate file',
|
|
857
1140
|
"required": True,
|
|
858
1141
|
"defaultValue": "",
|
|
859
|
-
"value": "C:\\fakepath\\certificate.pfx",
|
|
1142
|
+
"value": "C:\\fakepath\\certificate 1 3 (1).pfx",
|
|
860
1143
|
"visible": True,
|
|
1144
|
+
"editable": True,
|
|
861
1145
|
"fileDatabase64": f"data:application/x-pkcs12;base64,{certificate_file_content_base64}",
|
|
862
1146
|
},
|
|
863
1147
|
{
|
|
@@ -868,51 +1152,141 @@ class AVTS(object):
|
|
|
868
1152
|
"defaultValue": "",
|
|
869
1153
|
"value": certificate_password,
|
|
870
1154
|
"visible": True,
|
|
1155
|
+
"editable": True,
|
|
1156
|
+
},
|
|
1157
|
+
{
|
|
1158
|
+
"id": "proxy",
|
|
1159
|
+
"label": "Proxy Service",
|
|
1160
|
+
"ctlType": "boolean",
|
|
1161
|
+
"description": "",
|
|
1162
|
+
"required": False,
|
|
1163
|
+
"defaultValue": "false",
|
|
1164
|
+
"value": "false",
|
|
1165
|
+
"visible": True,
|
|
1166
|
+
"editable": True,
|
|
1167
|
+
},
|
|
1168
|
+
{
|
|
1169
|
+
"id": "proxyScheme",
|
|
1170
|
+
"label": "Proxy Scheme",
|
|
1171
|
+
"ctlType": "select",
|
|
1172
|
+
"description": "",
|
|
1173
|
+
"required": False,
|
|
1174
|
+
"defaultValue": "HTTP",
|
|
1175
|
+
"value": "HTTP",
|
|
1176
|
+
"visible": True,
|
|
1177
|
+
"acceptedValues": [
|
|
1178
|
+
"HTTP",
|
|
1179
|
+
"HTTPS",
|
|
1180
|
+
"SOCKS5",
|
|
1181
|
+
],
|
|
1182
|
+
"editable": True,
|
|
1183
|
+
},
|
|
1184
|
+
{
|
|
1185
|
+
"id": "proxyHost",
|
|
1186
|
+
"label": "Proxy Host",
|
|
1187
|
+
"ctlType": "text",
|
|
1188
|
+
"description": "",
|
|
1189
|
+
"required": False,
|
|
1190
|
+
"defaultValue": "",
|
|
1191
|
+
"value": "",
|
|
1192
|
+
"visible": True,
|
|
1193
|
+
"editable": True,
|
|
1194
|
+
},
|
|
1195
|
+
{
|
|
1196
|
+
"id": "proxyPort",
|
|
1197
|
+
"label": "Proxy Port",
|
|
1198
|
+
"ctlType": "text",
|
|
1199
|
+
"description": "",
|
|
1200
|
+
"required": False,
|
|
1201
|
+
"defaultValue": "",
|
|
1202
|
+
"value": "",
|
|
1203
|
+
"visible": True,
|
|
1204
|
+
"editable": True,
|
|
1205
|
+
},
|
|
1206
|
+
{
|
|
1207
|
+
"id": "ProxyConfigService",
|
|
1208
|
+
"label": "Proxy Config Service",
|
|
1209
|
+
"ctlType": "text",
|
|
1210
|
+
"description": "",
|
|
1211
|
+
"required": False,
|
|
1212
|
+
"defaultValue": "",
|
|
1213
|
+
"value": "",
|
|
1214
|
+
"visible": False,
|
|
1215
|
+
"editable": True,
|
|
871
1216
|
},
|
|
872
1217
|
],
|
|
873
|
-
"
|
|
874
|
-
"
|
|
1218
|
+
"config": {
|
|
1219
|
+
"type": "nifi",
|
|
1220
|
+
"id": "SharePoint",
|
|
1221
|
+
"crawlConfig": {
|
|
1222
|
+
"name": "GetSharePointOData",
|
|
1223
|
+
"type": "idol.nifi.connector.GetSharePointOData",
|
|
1224
|
+
"group": "idol.nifi.connector",
|
|
1225
|
+
"artifact": "idol-nifi-connector-sharepointodata",
|
|
1226
|
+
"version": "25.1.0-nifi1",
|
|
1227
|
+
},
|
|
1228
|
+
"viewConfig": {
|
|
875
1229
|
"name": "ViewSharePointOData",
|
|
876
1230
|
"type": "idol.nifi.connector.ViewSharePointOData",
|
|
877
1231
|
"group": "idol.nifi.connector",
|
|
878
1232
|
"artifact": "idol-nifi-connector-sharepointodata",
|
|
879
|
-
"version":
|
|
1233
|
+
"version": "25.1.0-nifi1",
|
|
880
1234
|
},
|
|
881
|
-
"
|
|
882
|
-
"name": "
|
|
883
|
-
"type": "idol.nifi.connector.
|
|
1235
|
+
"omniConfig": {
|
|
1236
|
+
"name": "GetSharePointGroupsOData",
|
|
1237
|
+
"type": "idol.nifi.connector.GetSharePointGroupsOData",
|
|
884
1238
|
"group": "idol.nifi.connector",
|
|
885
1239
|
"artifact": "idol-nifi-connector-sharepointodata",
|
|
886
|
-
"version":
|
|
1240
|
+
"version": "25.1.0-nifi1",
|
|
1241
|
+
"repoName": "SharePoint",
|
|
887
1242
|
},
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
"view": {
|
|
1243
|
+
"crawlProps": {
|
|
1244
|
+
"META:SOURCE": "SharePoint Online",
|
|
891
1245
|
"SharepointUrl": "${sharePointUrl}",
|
|
1246
|
+
"MappedSecurity": "true",
|
|
892
1247
|
"Oauth2SiteName": "${OAuth2SiteName}",
|
|
893
1248
|
"Oauth2SitesFile": "${OAuth2SitesFile}",
|
|
894
1249
|
"SharepointOnline": "${sharePointOnline}",
|
|
1250
|
+
"IndexUserProfiles": "${IndexUserProfiles}",
|
|
895
1251
|
"SharepointUrlType": "${URLType}",
|
|
1252
|
+
"ProxyConfigService": "${ProxyConfigService}",
|
|
896
1253
|
"SharepointAdminUrl": "${sharePointAdminUrl}",
|
|
897
1254
|
"SharepointMySiteUrl": "${sharePointMySiteUrl}",
|
|
1255
|
+
"RetrieveUserDetailsAs": "Title",
|
|
898
1256
|
"MappedWebApplicationPolicies": "${MappedWebApplicationPolicies}",
|
|
1257
|
+
"TenantAdminSitesIncludeTypes": "${TenantAdminSitesIncludeTypes}",
|
|
899
1258
|
},
|
|
900
|
-
"
|
|
901
|
-
"META:SOURCE": "SharePoint",
|
|
1259
|
+
"viewProps": {
|
|
902
1260
|
"SharepointUrl": "${sharePointUrl}",
|
|
903
1261
|
"Oauth2SiteName": "${OAuth2SiteName}",
|
|
904
1262
|
"Oauth2SitesFile": "${OAuth2SitesFile}",
|
|
905
1263
|
"SharepointOnline": "${sharePointOnline}",
|
|
906
|
-
"IndexUserProfiles": "${IndexUserProfiles}",
|
|
907
1264
|
"SharepointUrlType": "${URLType}",
|
|
1265
|
+
"ProxyConfigService": "${ProxyConfigService}",
|
|
908
1266
|
"SharepointAdminUrl": "${sharePointAdminUrl}",
|
|
909
1267
|
"SharepointMySiteUrl": "${sharePointMySiteUrl}",
|
|
910
1268
|
"MappedWebApplicationPolicies": "${MappedWebApplicationPolicies}",
|
|
1269
|
+
},
|
|
1270
|
+
"omniProps": {
|
|
1271
|
+
"SharepointUrl": "${sharePointUrl}",
|
|
1272
|
+
"Oauth2SiteName": "${OAuth2SiteName}",
|
|
1273
|
+
"Oauth2SitesFile": "${OAuth2SitesFile}",
|
|
1274
|
+
"SharepointOnline": "true",
|
|
1275
|
+
"SharepointUrlType": "${URLType}",
|
|
1276
|
+
"ProxyConfigService": "${ProxyConfigService}",
|
|
1277
|
+
"SharepointAdminUrl": "${sharePointAdminUrl}",
|
|
1278
|
+
"SharepointMySiteUrl": "${sharePointMySiteUrl}",
|
|
1279
|
+
"MappedWebApplicationPolicies": "false",
|
|
911
1280
|
"TenantAdminSitesIncludeTypes": "${TenantAdminSitesIncludeTypes}",
|
|
912
1281
|
},
|
|
1282
|
+
"metadataFields": [
|
|
1283
|
+
"FILEREF",
|
|
1284
|
+
"FILEDIRREF",
|
|
1285
|
+
],
|
|
913
1286
|
},
|
|
914
|
-
"
|
|
915
|
-
"
|
|
1287
|
+
"name": name,
|
|
1288
|
+
"id": "SharePoint",
|
|
1289
|
+
"sourceId": "SharePoint",
|
|
916
1290
|
}
|
|
917
1291
|
|
|
918
1292
|
request_header = self.request_header()
|
|
@@ -925,9 +1299,11 @@ class AVTS(object):
|
|
|
925
1299
|
headers=request_header,
|
|
926
1300
|
timeout=None,
|
|
927
1301
|
failure_message="Failed to create repository -> '{}'".format(name),
|
|
1302
|
+
show_error=False,
|
|
928
1303
|
)
|
|
929
1304
|
|
|
930
1305
|
if response is None:
|
|
1306
|
+
self.logger.error("Failed to create repository -> '%s'!", name)
|
|
931
1307
|
return None
|
|
932
1308
|
|
|
933
1309
|
self.repo_admin_consent(response["id"])
|
|
@@ -937,21 +1313,22 @@ class AVTS(object):
|
|
|
937
1313
|
# end method definition
|
|
938
1314
|
|
|
939
1315
|
def repo_admin_consent(self, repo_id: str) -> dict | None:
|
|
940
|
-
"""Send admin consent information for a repository
|
|
1316
|
+
"""Send admin consent information for a repository.
|
|
941
1317
|
|
|
942
1318
|
Args:
|
|
943
|
-
repo_id (str):
|
|
1319
|
+
repo_id (str):
|
|
1320
|
+
The ID of the repository.
|
|
944
1321
|
|
|
945
1322
|
Returns:
|
|
946
|
-
dict | None:
|
|
1323
|
+
dict | None:
|
|
1324
|
+
Parsed response object from the API or None in case of an error
|
|
1325
|
+
|
|
947
1326
|
"""
|
|
948
1327
|
|
|
949
1328
|
request_header = self.request_header()
|
|
950
1329
|
request_url = self.config()["repoUrl"]
|
|
951
1330
|
|
|
952
|
-
request_url = (
|
|
953
|
-
self.config()["repoUrl"] + "/" + repo_id + "/authorize?admin_consent=true"
|
|
954
|
-
)
|
|
1331
|
+
request_url = self.config()["repoUrl"] + "/" + repo_id + "/authorize?admin_consent=true"
|
|
955
1332
|
|
|
956
1333
|
return self.do_request(
|
|
957
1334
|
url=request_url,
|
|
@@ -959,22 +1336,26 @@ class AVTS(object):
|
|
|
959
1336
|
headers=request_header,
|
|
960
1337
|
timeout=None,
|
|
961
1338
|
failure_message="Failed to set admin_consent for repository -> '{}'".format(
|
|
962
|
-
repo_id
|
|
1339
|
+
repo_id,
|
|
963
1340
|
),
|
|
964
1341
|
)
|
|
965
1342
|
|
|
966
1343
|
# end method definition
|
|
967
1344
|
|
|
968
1345
|
def start_crawling(self, repo_name: str) -> list | None:
|
|
969
|
-
"""Start crawling of a repository
|
|
1346
|
+
"""Start crawling of a repository.
|
|
970
1347
|
|
|
971
1348
|
Args:
|
|
972
|
-
repo_name (str):
|
|
1349
|
+
repo_name (str):
|
|
1350
|
+
The name of the repository.
|
|
1351
|
+
|
|
973
1352
|
Returns:
|
|
974
|
-
list | None:
|
|
1353
|
+
list | None:
|
|
1354
|
+
Parsed response object from the API or None in case of an error
|
|
1355
|
+
|
|
975
1356
|
"""
|
|
976
1357
|
|
|
977
|
-
logger.info("Start crawling repository -> %s", repo_name)
|
|
1358
|
+
self.logger.info("Start crawling repository -> '%s'...", repo_name)
|
|
978
1359
|
|
|
979
1360
|
repo = self.get_repo_by_name(name=repo_name)
|
|
980
1361
|
if repo is None:
|
|
@@ -988,20 +1369,24 @@ class AVTS(object):
|
|
|
988
1369
|
method="POST",
|
|
989
1370
|
headers=request_header,
|
|
990
1371
|
timeout=None,
|
|
991
|
-
failure_message="Failed to start crawling repository -> '{}'".format(
|
|
992
|
-
repo_name
|
|
1372
|
+
failure_message="Failed to start crawling repository -> '{}'!".format(
|
|
1373
|
+
repo_name,
|
|
993
1374
|
),
|
|
994
1375
|
)
|
|
995
1376
|
|
|
996
1377
|
# end method definition
|
|
997
1378
|
|
|
998
|
-
def stop_crawling(self, repo_name: str) ->
|
|
999
|
-
"""Stop the crawling of a repository
|
|
1379
|
+
def stop_crawling(self, repo_name: str) -> dict | None:
|
|
1380
|
+
"""Stop the crawling of a repository.
|
|
1000
1381
|
|
|
1001
1382
|
Args:
|
|
1002
|
-
repo_name (str):
|
|
1383
|
+
repo_name (str):
|
|
1384
|
+
The name of the repository.
|
|
1385
|
+
|
|
1003
1386
|
Returns:
|
|
1004
|
-
|
|
1387
|
+
dict | None:
|
|
1388
|
+
Parsed response object from the API or None in case of an error
|
|
1389
|
+
|
|
1005
1390
|
"""
|
|
1006
1391
|
|
|
1007
1392
|
repo = self.get_repo_by_name(name=repo_name)
|
|
@@ -1016,18 +1401,20 @@ class AVTS(object):
|
|
|
1016
1401
|
method="POST",
|
|
1017
1402
|
headers=request_header,
|
|
1018
1403
|
timeout=None,
|
|
1019
|
-
failure_message="Failed to stop crawling repository -> '{}'".format(
|
|
1020
|
-
repo_name
|
|
1404
|
+
failure_message="Failed to stop crawling repository -> '{}'!".format(
|
|
1405
|
+
repo_name,
|
|
1021
1406
|
),
|
|
1022
1407
|
)
|
|
1023
1408
|
|
|
1024
1409
|
# end method definition
|
|
1025
1410
|
|
|
1026
1411
|
def get_repo_list(self) -> list | None:
|
|
1027
|
-
"""Get a list of all repositories
|
|
1412
|
+
"""Get a list of all repositories.
|
|
1028
1413
|
|
|
1029
1414
|
Returns:
|
|
1030
|
-
list | None:
|
|
1415
|
+
list | None:
|
|
1416
|
+
Parsed response object from the API listing all repositories or None in case of an error.
|
|
1417
|
+
|
|
1031
1418
|
"""
|
|
1032
1419
|
|
|
1033
1420
|
request_header = self.request_header()
|
|
@@ -1038,18 +1425,22 @@ class AVTS(object):
|
|
|
1038
1425
|
method="GET",
|
|
1039
1426
|
headers=request_header,
|
|
1040
1427
|
timeout=None,
|
|
1041
|
-
failure_message="Failed to get list of repositories to crawl
|
|
1428
|
+
failure_message="Failed to get list of repositories to crawl",
|
|
1042
1429
|
)
|
|
1043
1430
|
|
|
1044
1431
|
# end method definition
|
|
1045
1432
|
|
|
1046
1433
|
def get_repo_by_name(self, name: str) -> dict | None:
|
|
1047
|
-
"""Get a repository by name
|
|
1434
|
+
"""Get a repository by name.
|
|
1048
1435
|
|
|
1049
1436
|
Args:
|
|
1050
|
-
name (str):
|
|
1437
|
+
name (str):
|
|
1438
|
+
The name of the repository.
|
|
1439
|
+
|
|
1051
1440
|
Returns:
|
|
1052
|
-
dict | None:
|
|
1441
|
+
dict | None:
|
|
1442
|
+
ID of a repostiory by name or None in case of an error
|
|
1443
|
+
|
|
1053
1444
|
"""
|
|
1054
1445
|
|
|
1055
1446
|
repo_list = self.get_repo_list()
|
|
@@ -1063,3 +1454,85 @@ class AVTS(object):
|
|
|
1063
1454
|
)
|
|
1064
1455
|
|
|
1065
1456
|
# end method definition
|
|
1457
|
+
|
|
1458
|
+
def get_certificate_file_content_base64(self, filepath: str) -> str | None:
|
|
1459
|
+
"""Return the certificate as a base64 string.
|
|
1460
|
+
|
|
1461
|
+
In Kubernetes deploymnets the certificate is already mounted base64 encoded.
|
|
1462
|
+
|
|
1463
|
+
Args:
|
|
1464
|
+
filepath (str):
|
|
1465
|
+
The path to the certificate file.
|
|
1466
|
+
|
|
1467
|
+
Returns:
|
|
1468
|
+
str | None:
|
|
1469
|
+
Base64 encoded certificate file content.
|
|
1470
|
+
|
|
1471
|
+
"""
|
|
1472
|
+
|
|
1473
|
+
if not os.path.isfile(filepath):
|
|
1474
|
+
return None
|
|
1475
|
+
|
|
1476
|
+
file_ext = os.path.splitext(filepath)[1].lower()
|
|
1477
|
+
|
|
1478
|
+
if self.running_in_kubernetes_pod() and file_ext == ".pfx":
|
|
1479
|
+
# Return file directly as already base64 encoded
|
|
1480
|
+
self.logger.warning(
|
|
1481
|
+
"Detected a binary pfx file in Kubernetes environment, expecting it to be already base64 encoded",
|
|
1482
|
+
)
|
|
1483
|
+
with open(filepath, encoding="UTF-8") as file:
|
|
1484
|
+
return file.read().strip()
|
|
1485
|
+
|
|
1486
|
+
else:
|
|
1487
|
+
# Return file as base64 encoded
|
|
1488
|
+
with open(filepath, "rb") as file:
|
|
1489
|
+
# Read the content of the file
|
|
1490
|
+
file_content = file.read()
|
|
1491
|
+
# Convert the bytes to a base64 string
|
|
1492
|
+
return base64.b64encode(file_content).decode("utf-8")
|
|
1493
|
+
|
|
1494
|
+
# end method definition
|
|
1495
|
+
|
|
1496
|
+
def running_in_kubernetes_pod(self) -> bool:
|
|
1497
|
+
"""Check if the application is running inside a Kubernetes pod.
|
|
1498
|
+
|
|
1499
|
+
This function determines whether the process is running in a Kubernetes
|
|
1500
|
+
environment by checking for the presence of the `KUBERNETES_SERVICE_HOST`
|
|
1501
|
+
and `KUBERNETES_SERVICE_PORT` environment variables.
|
|
1502
|
+
|
|
1503
|
+
Returns:
|
|
1504
|
+
bool:
|
|
1505
|
+
True if running inside a Kubernetes pod, False otherwise.
|
|
1506
|
+
|
|
1507
|
+
"""
|
|
1508
|
+
|
|
1509
|
+
return bool(os.getenv("KUBERNETES_SERVICE_HOST") and os.getenv("KUBERNETES_SERVICE_PORT"))
|
|
1510
|
+
|
|
1511
|
+
# end method definition
|
|
1512
|
+
|
|
1513
|
+
def set_questions(self, questions: list) -> list | None:
|
|
1514
|
+
"""Get a list of all repositories.
|
|
1515
|
+
|
|
1516
|
+
Args:
|
|
1517
|
+
questions (list):
|
|
1518
|
+
List of proposed questions.
|
|
1519
|
+
|
|
1520
|
+
Returns:
|
|
1521
|
+
list | None:
|
|
1522
|
+
Parsed response object from the API listing all repositories or None in case of an error.
|
|
1523
|
+
|
|
1524
|
+
"""
|
|
1525
|
+
|
|
1526
|
+
request_header = self.request_header()
|
|
1527
|
+
request_url = self.config()["questionsUrl"]
|
|
1528
|
+
|
|
1529
|
+
return self.do_request(
|
|
1530
|
+
url=request_url,
|
|
1531
|
+
method="PUT",
|
|
1532
|
+
headers=request_header,
|
|
1533
|
+
data=json.dumps(questions),
|
|
1534
|
+
timeout=None,
|
|
1535
|
+
failure_message="Failed to set list of questions to ask",
|
|
1536
|
+
)
|
|
1537
|
+
|
|
1538
|
+
# end method definition
|