pyxecm 2.0.1__py3-none-any.whl → 2.0.3__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 +3 -2
- pyxecm/avts.py +3 -1
- pyxecm/customizer/api/app.py +2 -2
- pyxecm/customizer/api/auth/functions.py +37 -30
- pyxecm/customizer/api/common/functions.py +54 -0
- pyxecm/customizer/api/common/router.py +50 -3
- pyxecm/customizer/api/settings.py +5 -3
- pyxecm/customizer/api/terminal/router.py +43 -18
- pyxecm/customizer/api/v1_csai/models.py +18 -0
- pyxecm/customizer/api/v1_csai/router.py +26 -1
- pyxecm/customizer/api/v1_payload/functions.py +9 -3
- pyxecm/customizer/browser_automation.py +508 -200
- pyxecm/customizer/customizer.py +123 -22
- pyxecm/customizer/guidewire.py +170 -37
- pyxecm/customizer/payload.py +614 -257
- pyxecm/customizer/settings.py +21 -3
- pyxecm/helper/xml.py +1 -1
- pyxecm/otawp.py +10 -6
- pyxecm/otca.py +187 -21
- pyxecm/otcs.py +496 -206
- pyxecm/otds.py +1 -0
- pyxecm/otkd.py +1369 -0
- pyxecm/otmm.py +190 -66
- {pyxecm-2.0.1.dist-info → pyxecm-2.0.3.dist-info}/METADATA +3 -6
- {pyxecm-2.0.1.dist-info → pyxecm-2.0.3.dist-info}/RECORD +28 -26
- {pyxecm-2.0.1.dist-info → pyxecm-2.0.3.dist-info}/WHEEL +1 -1
- {pyxecm-2.0.1.dist-info → pyxecm-2.0.3.dist-info}/licenses/LICENSE +0 -0
- {pyxecm-2.0.1.dist-info → pyxecm-2.0.3.dist-info}/top_level.txt +0 -0
pyxecm/otcs.py
CHANGED
|
@@ -87,7 +87,7 @@ except ModuleNotFoundError:
|
|
|
87
87
|
|
|
88
88
|
|
|
89
89
|
class OTCS:
|
|
90
|
-
"""Used to automate stettings in OpenText
|
|
90
|
+
"""Used to automate stettings in OpenText Content Management."""
|
|
91
91
|
|
|
92
92
|
logger: logging.Logger = default_logger
|
|
93
93
|
|
|
@@ -148,6 +148,24 @@ class OTCS:
|
|
|
148
148
|
ITEM_TYPE_WORKFLOW_MAP = 128
|
|
149
149
|
ITEM_TYPE_WORKFLOW_STATUS = 190
|
|
150
150
|
|
|
151
|
+
PERMISSION_TYPES = [
|
|
152
|
+
"see",
|
|
153
|
+
"see_contents",
|
|
154
|
+
"modify",
|
|
155
|
+
"edit_attributes",
|
|
156
|
+
"add_items",
|
|
157
|
+
"reserve",
|
|
158
|
+
"add_major_version",
|
|
159
|
+
"delete_versions",
|
|
160
|
+
"delete",
|
|
161
|
+
"edit_permissions",
|
|
162
|
+
]
|
|
163
|
+
PERMISSION_ASSIGNEE_TYPES = [
|
|
164
|
+
"owner",
|
|
165
|
+
"group",
|
|
166
|
+
"public",
|
|
167
|
+
"custom",
|
|
168
|
+
]
|
|
151
169
|
_config: dict
|
|
152
170
|
_otcs_ticket = None
|
|
153
171
|
_otds_ticket = None
|
|
@@ -858,6 +876,9 @@ class OTCS:
|
|
|
858
876
|
# a cookie that is in process of being renewed
|
|
859
877
|
# by another thread:
|
|
860
878
|
with self._session_lock:
|
|
879
|
+
if not self.cookie():
|
|
880
|
+
self.logger.error("Cannot call -> %s - user is not authenticatd!", url)
|
|
881
|
+
return None
|
|
861
882
|
# IMPORTANT: this needs to be a copy - dicts are mutable and
|
|
862
883
|
# we need to preserve the old value to detect in reauthenticate()
|
|
863
884
|
# if the cookie has been renewed already or not:
|
|
@@ -1671,11 +1692,8 @@ class OTCS:
|
|
|
1671
1692
|
"Requesting OTCS ticket with existing OTDS ticket; calling -> %s",
|
|
1672
1693
|
request_url,
|
|
1673
1694
|
)
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
"Accept": "application/json",
|
|
1677
|
-
"OTDSTicket": self._otds_ticket,
|
|
1678
|
-
}
|
|
1695
|
+
# Add the OTDS ticket to the request headers:
|
|
1696
|
+
request_header = REQUEST_FORM_HEADERS | {"OTDSTicket": self._otds_ticket}
|
|
1679
1697
|
|
|
1680
1698
|
try:
|
|
1681
1699
|
response = requests.get(
|
|
@@ -1923,7 +1941,7 @@ class OTCS:
|
|
|
1923
1941
|
"""
|
|
1924
1942
|
|
|
1925
1943
|
request_url = self.config()["serverInfoUrl"]
|
|
1926
|
-
request_header = self.request_form_header()
|
|
1944
|
+
request_header = self.request_form_header()
|
|
1927
1945
|
|
|
1928
1946
|
self.logger.debug(
|
|
1929
1947
|
"Retrieve Content Server information; calling -> %s",
|
|
@@ -2019,12 +2037,18 @@ class OTCS:
|
|
|
2019
2037
|
# end method definition
|
|
2020
2038
|
|
|
2021
2039
|
@cache
|
|
2022
|
-
def get_user(self, name: str, show_error: bool = False) -> dict | None:
|
|
2040
|
+
def get_user(self, name: str, user_type: int = 0, show_error: bool = False) -> dict | None:
|
|
2023
2041
|
"""Look up an Content Server user based on the login name.
|
|
2024
2042
|
|
|
2025
2043
|
Args:
|
|
2026
2044
|
name (str):
|
|
2027
2045
|
Name of the user (login).
|
|
2046
|
+
user_type (int, optional):
|
|
2047
|
+
Type ID of user:
|
|
2048
|
+
0 - Regular User
|
|
2049
|
+
17 - Service User
|
|
2050
|
+
Defaults to 0 -> (Regular User)
|
|
2051
|
+
|
|
2028
2052
|
show_error (bool, optional):
|
|
2029
2053
|
If True, treat as an error if the user is not found. Defaults to False.
|
|
2030
2054
|
|
|
@@ -2082,8 +2106,8 @@ class OTCS:
|
|
|
2082
2106
|
"""
|
|
2083
2107
|
|
|
2084
2108
|
# Add query parameters (these are NOT passed via JSon body!)
|
|
2085
|
-
# type = 0 ==> User
|
|
2086
|
-
query = {"where_type":
|
|
2109
|
+
# type = 0 ==> regular User
|
|
2110
|
+
query = {"where_type": user_type, "where_name": name}
|
|
2087
2111
|
encoded_query = urllib.parse.urlencode(query=query, doseq=True)
|
|
2088
2112
|
request_url = self.config()["membersUrlv2"] + "?{}".format(encoded_query)
|
|
2089
2113
|
|
|
@@ -2122,18 +2146,26 @@ class OTCS:
|
|
|
2122
2146
|
"""Add Content Server user.
|
|
2123
2147
|
|
|
2124
2148
|
Args:
|
|
2125
|
-
name (str):
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2149
|
+
name (str):
|
|
2150
|
+
The login name of the user.
|
|
2151
|
+
password (str):
|
|
2152
|
+
The password of the user.
|
|
2153
|
+
first_name (str):
|
|
2154
|
+
The first name of the user.
|
|
2155
|
+
last_name (str):
|
|
2156
|
+
The last name of the user.
|
|
2157
|
+
email (str):
|
|
2158
|
+
The email address of the user.
|
|
2159
|
+
title (str):
|
|
2160
|
+
The title of the user.
|
|
2161
|
+
base_group (int):
|
|
2162
|
+
The base group id of the user (e.g. department)
|
|
2132
2163
|
privileges (list, optional):
|
|
2133
2164
|
Possible values are Login, Public Access, Content Manager,
|
|
2134
2165
|
Modify Users, Modify Groups, User Admin Rights,
|
|
2135
2166
|
Grant Discovery, System Admin Rights
|
|
2136
|
-
user_type (int, optional):
|
|
2167
|
+
user_type (int, optional):
|
|
2168
|
+
The ID of the user type. 0 = regular user, 17 = service user.
|
|
2137
2169
|
|
|
2138
2170
|
Returns:
|
|
2139
2171
|
dict | None:
|
|
@@ -2268,9 +2300,12 @@ class OTCS:
|
|
|
2268
2300
|
"""Update a defined field for a user.
|
|
2269
2301
|
|
|
2270
2302
|
Args:
|
|
2271
|
-
user_id (int):
|
|
2272
|
-
|
|
2273
|
-
field (str):
|
|
2303
|
+
user_id (int):
|
|
2304
|
+
The ID of the user to update.
|
|
2305
|
+
field (str):
|
|
2306
|
+
The user data field to update.
|
|
2307
|
+
value (str):
|
|
2308
|
+
The new value for user data field.
|
|
2274
2309
|
|
|
2275
2310
|
Returns:
|
|
2276
2311
|
dict | None:
|
|
@@ -3669,7 +3704,8 @@ class OTCS:
|
|
|
3669
3704
|
"""Get a node based on the workspace ID (= node ID) and path (list of folder names).
|
|
3670
3705
|
|
|
3671
3706
|
Args:
|
|
3672
|
-
workspace_id (int):
|
|
3707
|
+
workspace_id (int):
|
|
3708
|
+
The node ID of the workspace.
|
|
3673
3709
|
path (list):
|
|
3674
3710
|
A list of container items (top down).
|
|
3675
3711
|
The last item is name of to be retrieved item.
|
|
@@ -3871,8 +3907,10 @@ class OTCS:
|
|
|
3871
3907
|
"""Get a node based on the nickname.
|
|
3872
3908
|
|
|
3873
3909
|
Args:
|
|
3874
|
-
nickname (str):
|
|
3875
|
-
|
|
3910
|
+
nickname (str):
|
|
3911
|
+
The nickname of the node.
|
|
3912
|
+
show_error (bool):
|
|
3913
|
+
If True, treat as error if node is not found.
|
|
3876
3914
|
|
|
3877
3915
|
Returns:
|
|
3878
3916
|
dict | None:
|
|
@@ -4315,7 +4353,7 @@ class OTCS:
|
|
|
4315
4353
|
The name of the attribute that includes the value to match with
|
|
4316
4354
|
value (str):
|
|
4317
4355
|
The lookup value that is matched agains the node attribute value.
|
|
4318
|
-
attribute_set (str, optional):
|
|
4356
|
+
attribute_set (str | None, optional):
|
|
4319
4357
|
The name of the attribute set
|
|
4320
4358
|
|
|
4321
4359
|
Returns:
|
|
@@ -4343,7 +4381,7 @@ class OTCS:
|
|
|
4343
4381
|
)
|
|
4344
4382
|
if not category_schema:
|
|
4345
4383
|
self.logger.debug(
|
|
4346
|
-
"Node -> '%s' (%s) does not have category -> '%s'. Cannot lookup -> '%s'. Skipping...",
|
|
4384
|
+
"Node -> '%s' (%s) does not have category -> '%s'. Cannot lookup value -> '%s'. Skipping...",
|
|
4347
4385
|
node_name,
|
|
4348
4386
|
node_id,
|
|
4349
4387
|
category,
|
|
@@ -4365,6 +4403,8 @@ class OTCS:
|
|
|
4365
4403
|
)
|
|
4366
4404
|
continue
|
|
4367
4405
|
attribute_key = attribute_schema["key"]
|
|
4406
|
+
# Split the attribute key once (1) at the first underscore from the right.
|
|
4407
|
+
# rsplit delivers a list and [-1] delivers the last list item:
|
|
4368
4408
|
attribute_id = attribute_key.rsplit("_", 1)[-1]
|
|
4369
4409
|
|
|
4370
4410
|
if attribute_set:
|
|
@@ -4399,6 +4439,7 @@ class OTCS:
|
|
|
4399
4439
|
attribute_value = cat_data.get(key)
|
|
4400
4440
|
if not attribute_value:
|
|
4401
4441
|
break
|
|
4442
|
+
# Is it a multi-value attribute (i.e. a list of values)?
|
|
4402
4443
|
if isinstance(attribute_value, list):
|
|
4403
4444
|
if value in attribute_value:
|
|
4404
4445
|
# Create a "results" dict that is compatible with normal REST calls
|
|
@@ -4437,89 +4478,6 @@ class OTCS:
|
|
|
4437
4478
|
|
|
4438
4479
|
# end method definition
|
|
4439
4480
|
|
|
4440
|
-
def lookup_node_old(
|
|
4441
|
-
self,
|
|
4442
|
-
parent_node_id: int,
|
|
4443
|
-
category: str,
|
|
4444
|
-
attribute: str,
|
|
4445
|
-
value: str,
|
|
4446
|
-
) -> dict | None:
|
|
4447
|
-
"""Lookup the node under a parent node that has a specified value in a category attribute.
|
|
4448
|
-
|
|
4449
|
-
Args:
|
|
4450
|
-
parent_node_id (int):
|
|
4451
|
-
The node ID of the parent (typically folder or workspace).
|
|
4452
|
-
category (str):
|
|
4453
|
-
The name of the category.
|
|
4454
|
-
attribute (str):
|
|
4455
|
-
The name of the attribute that includes the value to match with
|
|
4456
|
-
value (str):
|
|
4457
|
-
The lookup value that is matched agains the node attribute value.
|
|
4458
|
-
|
|
4459
|
-
Returns:
|
|
4460
|
-
dict | None:
|
|
4461
|
-
Node wrapped in dictionary with "results" key or None if the REST API fails.
|
|
4462
|
-
|
|
4463
|
-
"""
|
|
4464
|
-
|
|
4465
|
-
# get_subnodes_iterator() returns a python generator that we use for iterating over all nodes
|
|
4466
|
-
# in an efficient way avoiding to retrieve all nodes at once (which could be a large number):
|
|
4467
|
-
for node in self.get_subnodes_iterator(
|
|
4468
|
-
parent_node_id=parent_node_id,
|
|
4469
|
-
fields=["properties", "categories"],
|
|
4470
|
-
metadata=True,
|
|
4471
|
-
):
|
|
4472
|
-
schema = node["metadata"]["categories"]
|
|
4473
|
-
data = node["data"]["categories"]
|
|
4474
|
-
for cat_data, cat_schema in zip(data, schema, strict=False):
|
|
4475
|
-
data_values = list(cat_data.values())
|
|
4476
|
-
schema_values = list(cat_schema.values())
|
|
4477
|
-
# Schema has one additional element (the first one) representing
|
|
4478
|
-
# the category object itself. This includes the name. We need
|
|
4479
|
-
# to remove (pop) it from the schema list to make sure the schema list
|
|
4480
|
-
# and the data list have the same number of items. Otherwise
|
|
4481
|
-
# the following for loop with zip() would not properly align the
|
|
4482
|
-
# two lists:
|
|
4483
|
-
category_name = schema_values.pop(0)["name"]
|
|
4484
|
-
# Set attributes (standing for the set itself, not it's contained attributes)
|
|
4485
|
-
# are only in the schema values, not in the data values. We need to remove
|
|
4486
|
-
# them as well to avoid mis-alignment:
|
|
4487
|
-
schema_values = [schema_value for schema_value in schema_values if schema_value.get("persona") != "set"]
|
|
4488
|
-
if category_name == category:
|
|
4489
|
-
for attr_data, attr_schema in zip(
|
|
4490
|
-
data_values,
|
|
4491
|
-
schema_values,
|
|
4492
|
-
strict=False,
|
|
4493
|
-
):
|
|
4494
|
-
attr_name = attr_schema["name"]
|
|
4495
|
-
if attr_name == attribute:
|
|
4496
|
-
if isinstance(attr_data, list):
|
|
4497
|
-
if value in attr_data:
|
|
4498
|
-
# Create a "results" dict that is compatible with normal REST calls
|
|
4499
|
-
# to not break get_result_value() method that may be called on the result:
|
|
4500
|
-
return {"results": node}
|
|
4501
|
-
elif value == attr_data:
|
|
4502
|
-
# Create a results dict that is compatible with normal REST calls
|
|
4503
|
-
# to not break get_result_value() method that may be called on the result:
|
|
4504
|
-
return {"results": node}
|
|
4505
|
-
# we can break here and continue with the next node
|
|
4506
|
-
# as we had the right category but did not find the matching value
|
|
4507
|
-
break
|
|
4508
|
-
# end for cat_data, cat_schema in zip(data, schema)
|
|
4509
|
-
# end for node in nodes
|
|
4510
|
-
|
|
4511
|
-
self.logger.debug(
|
|
4512
|
-
"Couldn't find a node with the value -> '%s' in the attribute -> '%s' of category -> '%s' in parent with node ID -> %s.",
|
|
4513
|
-
value,
|
|
4514
|
-
attribute,
|
|
4515
|
-
category,
|
|
4516
|
-
parent_node_id,
|
|
4517
|
-
)
|
|
4518
|
-
|
|
4519
|
-
return None
|
|
4520
|
-
|
|
4521
|
-
# end method definition
|
|
4522
|
-
|
|
4523
4481
|
def lookup_node_by_regex(
|
|
4524
4482
|
self,
|
|
4525
4483
|
parent_node_id: int,
|
|
@@ -4861,13 +4819,18 @@ class OTCS:
|
|
|
4861
4819
|
node_id (int):
|
|
4862
4820
|
ID of the node. You can use the get_volume() function below to
|
|
4863
4821
|
to the node id for a volume.
|
|
4864
|
-
name (str):
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4822
|
+
name (str):
|
|
4823
|
+
New name of the node.
|
|
4824
|
+
description (str):
|
|
4825
|
+
New description of the node.
|
|
4826
|
+
name_multilingual (dict | None, optional):
|
|
4827
|
+
The multi-lingual node names.
|
|
4828
|
+
description_multilingual (dict | None, optional):
|
|
4829
|
+
The multi-lingual descriptions.
|
|
4868
4830
|
|
|
4869
4831
|
Returns:
|
|
4870
|
-
dict | None:
|
|
4832
|
+
dict | None:
|
|
4833
|
+
Request response or None if the renaming fails.
|
|
4871
4834
|
|
|
4872
4835
|
"""
|
|
4873
4836
|
|
|
@@ -5044,6 +5007,285 @@ class OTCS:
|
|
|
5044
5007
|
|
|
5045
5008
|
# end method definition
|
|
5046
5009
|
|
|
5010
|
+
def get_node_audit(
|
|
5011
|
+
self,
|
|
5012
|
+
node_id: int,
|
|
5013
|
+
filter_event_type: int | None = None,
|
|
5014
|
+
filter_user_id: int | None = None,
|
|
5015
|
+
filter_date_start: str | None = None,
|
|
5016
|
+
filter_date_end: str | None = None,
|
|
5017
|
+
limit: int = 100,
|
|
5018
|
+
page: int = 1,
|
|
5019
|
+
sort: str = "desc_audit_date",
|
|
5020
|
+
) -> dict | None:
|
|
5021
|
+
"""Get the audit information for a given node ID.
|
|
5022
|
+
|
|
5023
|
+
Args:
|
|
5024
|
+
node_id (int):
|
|
5025
|
+
The ID of the node to get the audit for.
|
|
5026
|
+
filter_event_type (int | None, optional):
|
|
5027
|
+
Type of audit events to filter by. Possible values:
|
|
5028
|
+
- 9 : Permission Changed
|
|
5029
|
+
- 10 : Attribute Value Changed
|
|
5030
|
+
- 92 : Create from Copy
|
|
5031
|
+
- 264 : Classification Applied
|
|
5032
|
+
- 301 : Deployed from Warehouse
|
|
5033
|
+
- 416 : XML Import
|
|
5034
|
+
- 6000 : Content Sharing - Shared with external system
|
|
5035
|
+
- 6014 : Content Sharing - Share Coordinator changed
|
|
5036
|
+
- ...
|
|
5037
|
+
filter_user_id (int, optional):
|
|
5038
|
+
Filter audit events by user ID. Defaults to no filter.
|
|
5039
|
+
The date should be provided in YYYY-MM-DD notation. Time
|
|
5040
|
+
is not considered (only days)
|
|
5041
|
+
filter_date_start (str | None, optional):
|
|
5042
|
+
Filter audit events by start date. Defaults to no filter.
|
|
5043
|
+
The date should be provided in YYYY-MM-DD notation. Time
|
|
5044
|
+
is not considered (only days)
|
|
5045
|
+
filter_date_end (str | None, optional):
|
|
5046
|
+
Filter audit events by end date. Defaults to no filter.
|
|
5047
|
+
limit (int, optional):
|
|
5048
|
+
The maximum number of results to return. Defaults to 100.
|
|
5049
|
+
page (int, optional):
|
|
5050
|
+
The page of results to retrieve. Defaults to 1 (first page).
|
|
5051
|
+
sort (str, optional):
|
|
5052
|
+
Sort order of audit results. Format can be sort=desc_audit_date or sort=asc_audit_date.
|
|
5053
|
+
Results are sorted in descending order by default.
|
|
5054
|
+
|
|
5055
|
+
Returns:
|
|
5056
|
+
dict | None:
|
|
5057
|
+
Subnode information as a dictionary, or None if no nodes with
|
|
5058
|
+
the given parent ID are found.
|
|
5059
|
+
|
|
5060
|
+
Example:
|
|
5061
|
+
{
|
|
5062
|
+
'collection': {
|
|
5063
|
+
'paging': {
|
|
5064
|
+
'limit': 100,
|
|
5065
|
+
'page': 1,
|
|
5066
|
+
'page_total': 1,
|
|
5067
|
+
'range_max': 23,
|
|
5068
|
+
'range_min': 1,
|
|
5069
|
+
'total_count': 23
|
|
5070
|
+
},
|
|
5071
|
+
'sorting': {
|
|
5072
|
+
'sort': [
|
|
5073
|
+
{
|
|
5074
|
+
'key': 'sort',
|
|
5075
|
+
'value': 'desc_audit_date'
|
|
5076
|
+
}
|
|
5077
|
+
]
|
|
5078
|
+
}
|
|
5079
|
+
},
|
|
5080
|
+
'links': {
|
|
5081
|
+
'data': {
|
|
5082
|
+
'self': {
|
|
5083
|
+
'body': '',
|
|
5084
|
+
'content_type': '',
|
|
5085
|
+
'href': '/api/v2/nodes/29572/audit?fields=properties&limit=100&sort=desc_audit_date',
|
|
5086
|
+
'method': 'GET',
|
|
5087
|
+
'name': ''
|
|
5088
|
+
}
|
|
5089
|
+
}
|
|
5090
|
+
},
|
|
5091
|
+
'results': {
|
|
5092
|
+
'data': {
|
|
5093
|
+
'audit': [
|
|
5094
|
+
{
|
|
5095
|
+
'id': 29572,
|
|
5096
|
+
'event_type': 6000,
|
|
5097
|
+
'audit_date': '2025-05-23T10:20:56Z',
|
|
5098
|
+
'user_id': 8306,
|
|
5099
|
+
'agent_id': None,
|
|
5100
|
+
'audit_language_code': None,
|
|
5101
|
+
'target_user_id': None,
|
|
5102
|
+
'audit_name': 'Shared with Microsoft Teams Content Sharing Provider'
|
|
5103
|
+
},
|
|
5104
|
+
...
|
|
5105
|
+
],
|
|
5106
|
+
'audit_event_types': [
|
|
5107
|
+
{
|
|
5108
|
+
'id': 92,
|
|
5109
|
+
'name': 'Create from Copy'
|
|
5110
|
+
},
|
|
5111
|
+
{
|
|
5112
|
+
'id': 6014,
|
|
5113
|
+
'name': 'Content Sharing - Share Coordinators Changed'
|
|
5114
|
+
},
|
|
5115
|
+
{
|
|
5116
|
+
'id': 301,
|
|
5117
|
+
'name': 'Deployed from Warehouse'
|
|
5118
|
+
},
|
|
5119
|
+
...
|
|
5120
|
+
]
|
|
5121
|
+
}
|
|
5122
|
+
}
|
|
5123
|
+
}
|
|
5124
|
+
|
|
5125
|
+
"""
|
|
5126
|
+
|
|
5127
|
+
# Add query parameters (these are NOT passed via JSon body!)
|
|
5128
|
+
query = {"limit": limit, "sort": sort}
|
|
5129
|
+
if filter_event_type:
|
|
5130
|
+
query["where_type"] = filter_event_type
|
|
5131
|
+
if filter_user_id:
|
|
5132
|
+
query["where_user_id"] = filter_user_id
|
|
5133
|
+
if filter_date_start:
|
|
5134
|
+
query["where_audit_date_start"] = filter_date_start
|
|
5135
|
+
if filter_date_end:
|
|
5136
|
+
query["where_audit_date_end"] = filter_date_end
|
|
5137
|
+
if page > 1:
|
|
5138
|
+
query["page"] = page
|
|
5139
|
+
|
|
5140
|
+
encoded_query = urllib.parse.urlencode(query=query, doseq=True)
|
|
5141
|
+
|
|
5142
|
+
request_url = self.config()["nodesUrlv2"] + "/" + str(node_id) + "/audit" + "?{}".format(encoded_query)
|
|
5143
|
+
|
|
5144
|
+
request_header = self.request_form_header()
|
|
5145
|
+
|
|
5146
|
+
self.logger.debug(
|
|
5147
|
+
"Get audit of node with ID -> %s (page -> %d, item limit -> %d); calling -> %s",
|
|
5148
|
+
str(node_id),
|
|
5149
|
+
page,
|
|
5150
|
+
limit,
|
|
5151
|
+
request_url,
|
|
5152
|
+
)
|
|
5153
|
+
|
|
5154
|
+
return self.do_request(
|
|
5155
|
+
url=request_url,
|
|
5156
|
+
method="GET",
|
|
5157
|
+
headers=request_header,
|
|
5158
|
+
timeout=None,
|
|
5159
|
+
failure_message="Failed to get audit for node with ID -> {}".format(
|
|
5160
|
+
node_id,
|
|
5161
|
+
),
|
|
5162
|
+
)
|
|
5163
|
+
|
|
5164
|
+
# end method definition
|
|
5165
|
+
|
|
5166
|
+
def get_node_audit_iterator(
|
|
5167
|
+
self,
|
|
5168
|
+
node_id: int,
|
|
5169
|
+
filter_event_type: int | None = None,
|
|
5170
|
+
filter_user_id: int | None = None,
|
|
5171
|
+
filter_date_start: str | None = None,
|
|
5172
|
+
filter_date_end: str | None = None,
|
|
5173
|
+
page_size: int = 25,
|
|
5174
|
+
sort: str = "desc_audit_date",
|
|
5175
|
+
) -> iter:
|
|
5176
|
+
"""Get an iterator object that can be used to traverse subnodes.
|
|
5177
|
+
|
|
5178
|
+
Filters can be applied that are given by the "filter" parameters.
|
|
5179
|
+
|
|
5180
|
+
Using a generator avoids loading a large number of nodes into memory at once.
|
|
5181
|
+
Instead you can iterate over the potential large list of subnodes.
|
|
5182
|
+
|
|
5183
|
+
Example usage:
|
|
5184
|
+
```python
|
|
5185
|
+
audit_entries = otcs_object.get_node_audit_iterator(node_id=15838)
|
|
5186
|
+
for audit_entry in audit_entries:
|
|
5187
|
+
logger.info("Audit entry -> '%s'", ...)
|
|
5188
|
+
```
|
|
5189
|
+
|
|
5190
|
+
Args:
|
|
5191
|
+
node_id (int):
|
|
5192
|
+
The ID of the node to get the audit for.
|
|
5193
|
+
filter_event_type (int, optional):
|
|
5194
|
+
Type of audit events to filter by. Possible values:
|
|
5195
|
+
- 9 : Permission Changed
|
|
5196
|
+
- 10 : Attribute Value Changed
|
|
5197
|
+
- 92 : Create from Copy
|
|
5198
|
+
- 264 : Classification Applied
|
|
5199
|
+
- 301 : Deployed from Warehouse
|
|
5200
|
+
- 416 : XML Import
|
|
5201
|
+
- 6000 : Content Sharing - Shared with external system
|
|
5202
|
+
- 6014 : Content Sharing - Share Coordinator changed
|
|
5203
|
+
- ...
|
|
5204
|
+
filter_user_id (int, optional):
|
|
5205
|
+
Filter audit events by user ID. Defaults to no filter.
|
|
5206
|
+
The date should be provided in YYYY-MM-DD notation. Time
|
|
5207
|
+
is not considered (only days)
|
|
5208
|
+
filter_date_start (str, optional):
|
|
5209
|
+
Filter audit events by start date. Defaults to no filter.
|
|
5210
|
+
The date should be provided in YYYY-MM-DD notation. Time
|
|
5211
|
+
is not considered (only days)
|
|
5212
|
+
filter_date_end (str, optional):
|
|
5213
|
+
Filter audit events by end date. Defaults to no filter.
|
|
5214
|
+
limit (int, optional):
|
|
5215
|
+
The maximum number of results to return. Defaults to 100.
|
|
5216
|
+
page (int, optional):
|
|
5217
|
+
The page of results to retrieve. Defaults to 1 (first page).
|
|
5218
|
+
sort (str, optional):
|
|
5219
|
+
Sort order of audit results. Format can be sort=desc_audit_date or sort=asc_audit_date.
|
|
5220
|
+
Results are sorted in descending order by default.
|
|
5221
|
+
page_size (int, optional):
|
|
5222
|
+
The number of subnodes that are requested per page.
|
|
5223
|
+
For the iterator this is basically the chunk size.
|
|
5224
|
+
|
|
5225
|
+
Returns:
|
|
5226
|
+
iter:
|
|
5227
|
+
A generator yielding one node per iteration under the parent.
|
|
5228
|
+
If the REST API fails, returns no value.
|
|
5229
|
+
|
|
5230
|
+
"""
|
|
5231
|
+
|
|
5232
|
+
response = self.get_node_audit(
|
|
5233
|
+
node_id=node_id,
|
|
5234
|
+
filter_event_type=filter_event_type,
|
|
5235
|
+
filter_user_id=filter_user_id,
|
|
5236
|
+
filter_date_start=filter_date_start,
|
|
5237
|
+
filter_date_end=filter_date_end,
|
|
5238
|
+
)
|
|
5239
|
+
if (
|
|
5240
|
+
not response
|
|
5241
|
+
or "collection" not in response
|
|
5242
|
+
or "paging" not in response["collection"]
|
|
5243
|
+
or not response["collection"]["paging"].get("total_count")
|
|
5244
|
+
):
|
|
5245
|
+
self.logger.debug(
|
|
5246
|
+
"Item with node ID -> %s has no audit information! Cannot iterate audit.",
|
|
5247
|
+
str(node_id),
|
|
5248
|
+
)
|
|
5249
|
+
# Don't return None! Plain return is what we need for iterators.
|
|
5250
|
+
# Natural Termination: If the generator does not yield, it behaves
|
|
5251
|
+
# like an empty iterable when used in a loop or converted to a list:
|
|
5252
|
+
return
|
|
5253
|
+
|
|
5254
|
+
audit_size = response["collection"]["paging"]["total_count"]
|
|
5255
|
+
|
|
5256
|
+
# If the container has many items we need to go through all pages
|
|
5257
|
+
# Adding page_size - 1 ensures that any remainder from the division is
|
|
5258
|
+
# accounted for, effectively rounding up. Integer division (//) performs floor division,
|
|
5259
|
+
# giving the desired number of pages:
|
|
5260
|
+
total_pages = (audit_size + page_size - 1) // page_size
|
|
5261
|
+
|
|
5262
|
+
for page in range(1, total_pages + 1):
|
|
5263
|
+
# Get the next page of sub node items:
|
|
5264
|
+
response = self.get_node_audit(
|
|
5265
|
+
node_id=node_id,
|
|
5266
|
+
filter_event_type=filter_event_type,
|
|
5267
|
+
filter_user_id=filter_user_id,
|
|
5268
|
+
filter_date_start=filter_date_start,
|
|
5269
|
+
filter_date_end=filter_date_end,
|
|
5270
|
+
limit=page_size,
|
|
5271
|
+
page=page,
|
|
5272
|
+
sort=sort,
|
|
5273
|
+
)
|
|
5274
|
+
if not response or not response.get("results", None):
|
|
5275
|
+
self.logger.warning(
|
|
5276
|
+
"Failed to retrieve audit for node ID -> %d (page -> %d)",
|
|
5277
|
+
node_id,
|
|
5278
|
+
page,
|
|
5279
|
+
)
|
|
5280
|
+
return None
|
|
5281
|
+
|
|
5282
|
+
# Yield nodes one at a time
|
|
5283
|
+
yield from response["results"]["data"]["audit"]
|
|
5284
|
+
|
|
5285
|
+
# end for page in range(1, total_pages + 1)
|
|
5286
|
+
|
|
5287
|
+
# end method definition
|
|
5288
|
+
|
|
5047
5289
|
def get_volumes(self) -> dict | None:
|
|
5048
5290
|
"""Get all Volumes.
|
|
5049
5291
|
|
|
@@ -5123,11 +5365,14 @@ class OTCS:
|
|
|
5123
5365
|
"""Get Volume information based on the volume type ID.
|
|
5124
5366
|
|
|
5125
5367
|
Args:
|
|
5126
|
-
volume_type (int):
|
|
5127
|
-
|
|
5368
|
+
volume_type (int):
|
|
5369
|
+
The ID of the volume type.
|
|
5370
|
+
timeout (int, optional):
|
|
5371
|
+
The timeout for the request in seconds.
|
|
5128
5372
|
|
|
5129
5373
|
Returns:
|
|
5130
|
-
dict | None:
|
|
5374
|
+
dict | None:
|
|
5375
|
+
Volume details or None if volume is not found.
|
|
5131
5376
|
|
|
5132
5377
|
Example:
|
|
5133
5378
|
["results"]["data"]["properties"]["id"] is the node ID of the volume.
|
|
@@ -5411,7 +5656,7 @@ class OTCS:
|
|
|
5411
5656
|
"12508_9": "MS Word", # Text drop-down
|
|
5412
5657
|
}
|
|
5413
5658
|
}
|
|
5414
|
-
classifications (list):
|
|
5659
|
+
classifications (list | None, optional):
|
|
5415
5660
|
List of classification item IDs to apply to the new item.
|
|
5416
5661
|
description (str, optional):
|
|
5417
5662
|
A description of the document.
|
|
@@ -5972,13 +6217,16 @@ class OTCS:
|
|
|
5972
6217
|
"""Get document content from Extended ECM and read content as JSON.
|
|
5973
6218
|
|
|
5974
6219
|
Args:
|
|
5975
|
-
node_id (int):
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
6220
|
+
node_id (int):
|
|
6221
|
+
The node ID of the document to download
|
|
6222
|
+
version_number (str, optional):
|
|
6223
|
+
The version of the document to download.
|
|
6224
|
+
If version = "" then download the latest
|
|
6225
|
+
version.
|
|
5979
6226
|
|
|
5980
6227
|
Returns:
|
|
5981
|
-
list | dict | None:
|
|
6228
|
+
list | dict | None:
|
|
6229
|
+
Content of the file or None in case of an error.
|
|
5982
6230
|
|
|
5983
6231
|
"""
|
|
5984
6232
|
|
|
@@ -6528,11 +6776,14 @@ class OTCS:
|
|
|
6528
6776
|
"""Get Extended ECM external system connection (e.g. SAP, Salesforce, SuccessFactors).
|
|
6529
6777
|
|
|
6530
6778
|
Args:
|
|
6531
|
-
connection_name (str):
|
|
6532
|
-
|
|
6779
|
+
connection_name (str):
|
|
6780
|
+
The name of the connection to an external system.
|
|
6781
|
+
show_error (bool, optional):
|
|
6782
|
+
If True, treat as error if connection is not found.
|
|
6533
6783
|
|
|
6534
6784
|
Returns:
|
|
6535
|
-
dict | None:
|
|
6785
|
+
dict | None:
|
|
6786
|
+
External system Details or None if the REST call fails.
|
|
6536
6787
|
|
|
6537
6788
|
"""
|
|
6538
6789
|
# Encode special characters in connection_name
|
|
@@ -6570,7 +6821,7 @@ class OTCS:
|
|
|
6570
6821
|
base_url: str,
|
|
6571
6822
|
username: str,
|
|
6572
6823
|
password: str,
|
|
6573
|
-
authentication_method: str = "BASIC",
|
|
6824
|
+
authentication_method: str = "BASIC",
|
|
6574
6825
|
client_id: str | None = None,
|
|
6575
6826
|
client_secret: str | None = None,
|
|
6576
6827
|
) -> dict | None:
|
|
@@ -6591,9 +6842,9 @@ class OTCS:
|
|
|
6591
6842
|
The password (used for BASIC authentication)
|
|
6592
6843
|
authentication_method (str, optional):
|
|
6593
6844
|
Either BASIC (using username and password) or OAUTH.
|
|
6594
|
-
client_id (str, optional):
|
|
6845
|
+
client_id (str | None, optional):
|
|
6595
6846
|
The OAUTH Client ID (only required if authenticationMethod = OAUTH).
|
|
6596
|
-
client_secret (str, optional):
|
|
6847
|
+
client_secret (str | None, optional):
|
|
6597
6848
|
OAUTH Client Secret (only required if authenticationMethod = OAUTH).
|
|
6598
6849
|
|
|
6599
6850
|
Returns:
|
|
@@ -6799,12 +7050,12 @@ class OTCS:
|
|
|
6799
7050
|
Name of the transport package ZIP file.
|
|
6800
7051
|
package_description (str, optional):
|
|
6801
7052
|
Description of the transport package. Default is an empty string.
|
|
6802
|
-
replacements (list
|
|
7053
|
+
replacements (list[dict] | None, optional):
|
|
6803
7054
|
List of replacement values to be applied to all XML files in the transport.
|
|
6804
7055
|
Each dictionary must contain:
|
|
6805
7056
|
- 'placeholder': text to replace
|
|
6806
7057
|
- 'value': text to replace with
|
|
6807
|
-
extractions (list
|
|
7058
|
+
extractions (list[dict] | None, optional):
|
|
6808
7059
|
List of XML subtrees to extract from each XML file in the transport.
|
|
6809
7060
|
Each dictionary must contain:
|
|
6810
7061
|
- 'xpath': defining the subtree to extract
|
|
@@ -7029,14 +7280,16 @@ class OTCS:
|
|
|
7029
7280
|
"""Search and replace strings in the XML files of the transport package.
|
|
7030
7281
|
|
|
7031
7282
|
Args:
|
|
7032
|
-
zip_file_path (str):
|
|
7033
|
-
|
|
7283
|
+
zip_file_path (str):
|
|
7284
|
+
Path to transport zip file.
|
|
7285
|
+
replacements (list[dict]):
|
|
7034
7286
|
List of replacement values; dict needs to have two values:
|
|
7035
7287
|
- placeholder: The text to replace.
|
|
7036
7288
|
- value: The replacement text.
|
|
7037
7289
|
|
|
7038
7290
|
Returns:
|
|
7039
|
-
bool:
|
|
7291
|
+
bool:
|
|
7292
|
+
True = success, False = error.
|
|
7040
7293
|
|
|
7041
7294
|
"""
|
|
7042
7295
|
|
|
@@ -7175,7 +7428,8 @@ class OTCS:
|
|
|
7175
7428
|
"""Search and extract XML data from the transport package.
|
|
7176
7429
|
|
|
7177
7430
|
Args:
|
|
7178
|
-
zip_file_path (str):
|
|
7431
|
+
zip_file_path (str):
|
|
7432
|
+
Path to transport zip file.
|
|
7179
7433
|
extractions (list of dicts):
|
|
7180
7434
|
List of extraction values; dict needs to have two values:
|
|
7181
7435
|
- xpath: structure to find
|
|
@@ -7419,9 +7673,9 @@ class OTCS:
|
|
|
7419
7673
|
where_clauses (dict | None, optional):
|
|
7420
7674
|
Filter the results based on one or multiple where clauses.
|
|
7421
7675
|
TODO: NAME CONVENTION FOR THE FIELDS
|
|
7422
|
-
limit (int, optional):
|
|
7676
|
+
limit (int | None, optional):
|
|
7423
7677
|
The maximum number of result items.
|
|
7424
|
-
page (int, optional):
|
|
7678
|
+
page (int | None, optional):
|
|
7425
7679
|
The page number for a chunked result list.
|
|
7426
7680
|
|
|
7427
7681
|
Returns:
|
|
@@ -8393,11 +8647,11 @@ class OTCS:
|
|
|
8393
8647
|
Args:
|
|
8394
8648
|
workspace_id (int):
|
|
8395
8649
|
The ID of the workspace.
|
|
8396
|
-
external_system_id (str, optional):
|
|
8650
|
+
external_system_id (str | None, optional):
|
|
8397
8651
|
Identifier of the external system (None if no external system).
|
|
8398
|
-
bo_type (str, optional):
|
|
8652
|
+
bo_type (str | None, optional):
|
|
8399
8653
|
Business object type (None if no external system)
|
|
8400
|
-
bo_id (str, optional):
|
|
8654
|
+
bo_id (str | None, optional):
|
|
8401
8655
|
Business object identifier / key (None if no external system)
|
|
8402
8656
|
show_error (bool, optional):
|
|
8403
8657
|
Log an error if workspace cration fails. Otherwise log a warning.
|
|
@@ -9213,10 +9467,12 @@ class OTCS:
|
|
|
9213
9467
|
"""Get the Workspace roles.
|
|
9214
9468
|
|
|
9215
9469
|
Args:
|
|
9216
|
-
workspace_id (int):
|
|
9470
|
+
workspace_id (int):
|
|
9471
|
+
The ID of the workspace template or workspace.
|
|
9217
9472
|
|
|
9218
9473
|
Returns:
|
|
9219
|
-
dict | None:
|
|
9474
|
+
dict | None:
|
|
9475
|
+
Workspace Roles data or None if the request fails.
|
|
9220
9476
|
|
|
9221
9477
|
"""
|
|
9222
9478
|
|
|
@@ -9245,11 +9501,14 @@ class OTCS:
|
|
|
9245
9501
|
"""Get the Workspace members of a given role.
|
|
9246
9502
|
|
|
9247
9503
|
Args:
|
|
9248
|
-
workspace_id (int):
|
|
9249
|
-
|
|
9504
|
+
workspace_id (int):
|
|
9505
|
+
The ID of the workspace.
|
|
9506
|
+
role_id (int):
|
|
9507
|
+
The ID of the workspace role.
|
|
9250
9508
|
|
|
9251
9509
|
Returns:
|
|
9252
|
-
dict | None:
|
|
9510
|
+
dict | None:
|
|
9511
|
+
Workspace member data or None if the request fails.
|
|
9253
9512
|
|
|
9254
9513
|
"""
|
|
9255
9514
|
|
|
@@ -9283,13 +9542,18 @@ class OTCS:
|
|
|
9283
9542
|
"""Add member to a workspace role. Check that the user/group is not yet a member.
|
|
9284
9543
|
|
|
9285
9544
|
Args:
|
|
9286
|
-
workspace_id (int):
|
|
9287
|
-
|
|
9288
|
-
|
|
9289
|
-
|
|
9545
|
+
workspace_id (int):
|
|
9546
|
+
The ID of the workspace.
|
|
9547
|
+
role_id (int):
|
|
9548
|
+
The ID of the workspace role.
|
|
9549
|
+
member_id (int):
|
|
9550
|
+
The user ID or group ID.
|
|
9551
|
+
show_warning (bool, optional):
|
|
9552
|
+
If True logs a warning if member is already in role.
|
|
9290
9553
|
|
|
9291
9554
|
Returns:
|
|
9292
|
-
dict | None:
|
|
9555
|
+
dict | None:
|
|
9556
|
+
Workspace Role Membership or None if the request fails.
|
|
9293
9557
|
|
|
9294
9558
|
"""
|
|
9295
9559
|
|
|
@@ -9357,13 +9621,18 @@ class OTCS:
|
|
|
9357
9621
|
"""Remove a member from a workspace role. Check that the user is currently a member.
|
|
9358
9622
|
|
|
9359
9623
|
Args:
|
|
9360
|
-
workspace_id (int):
|
|
9361
|
-
|
|
9362
|
-
|
|
9363
|
-
|
|
9624
|
+
workspace_id (int):
|
|
9625
|
+
The ID of the workspace.
|
|
9626
|
+
role_id (int):
|
|
9627
|
+
The ID of the workspace role.
|
|
9628
|
+
member_id (int):
|
|
9629
|
+
The user or Group ID.
|
|
9630
|
+
show_warning (bool, optional):
|
|
9631
|
+
If True logs a warning if member is not in role.
|
|
9364
9632
|
|
|
9365
9633
|
Returns:
|
|
9366
|
-
dict | None:
|
|
9634
|
+
dict | None:
|
|
9635
|
+
Workspace Role Membership or None if the request fails.
|
|
9367
9636
|
|
|
9368
9637
|
"""
|
|
9369
9638
|
|
|
@@ -9431,12 +9700,16 @@ class OTCS:
|
|
|
9431
9700
|
"""Remove all members from a workspace role. Check that the user is currently a member.
|
|
9432
9701
|
|
|
9433
9702
|
Args:
|
|
9434
|
-
workspace_id (int):
|
|
9435
|
-
|
|
9436
|
-
|
|
9703
|
+
workspace_id (int):
|
|
9704
|
+
The ID of the workspace.
|
|
9705
|
+
role_id (int):
|
|
9706
|
+
The ID of the workspace role.
|
|
9707
|
+
show_warning (bool, optional):
|
|
9708
|
+
If True, logs a warning if member is not in role.
|
|
9437
9709
|
|
|
9438
9710
|
Returns:
|
|
9439
|
-
bool:
|
|
9711
|
+
bool:
|
|
9712
|
+
True if success or False if the request fails.
|
|
9440
9713
|
|
|
9441
9714
|
"""
|
|
9442
9715
|
|
|
@@ -9478,9 +9751,12 @@ class OTCS:
|
|
|
9478
9751
|
specifying whether to apply these permissions to the item itself, its sub-items, or both.
|
|
9479
9752
|
|
|
9480
9753
|
Args:
|
|
9481
|
-
workspace_id (int):
|
|
9482
|
-
|
|
9483
|
-
|
|
9754
|
+
workspace_id (int):
|
|
9755
|
+
The ID of the workspace for which the role permissions are being assigned.
|
|
9756
|
+
role_id (int):
|
|
9757
|
+
The ID of the role to which the permissions will be assigned.
|
|
9758
|
+
permissions (list):
|
|
9759
|
+
List of permissions to assign to the role. Valid permissions include:
|
|
9484
9760
|
- "see" : View the workspace
|
|
9485
9761
|
- "see_contents" : View contents of the workspace
|
|
9486
9762
|
- "modify" : Modify the workspace
|
|
@@ -9491,14 +9767,16 @@ class OTCS:
|
|
|
9491
9767
|
- "delete_versions" : Delete versions of the workspace
|
|
9492
9768
|
- "delete" : Delete the workspace
|
|
9493
9769
|
- "edit_permissions" : Modify permissions for the workspace
|
|
9494
|
-
apply_to (int, optional):
|
|
9770
|
+
apply_to (int, optional):
|
|
9771
|
+
Specifies the scope of permission assignment. Possible values:
|
|
9495
9772
|
- 0 = Apply to this item only
|
|
9496
9773
|
- 1 = Apply to sub-items only
|
|
9497
9774
|
- 2 = Apply to this item and its sub-items (default)
|
|
9498
9775
|
- 3 = Apply to this item and its immediate sub-items
|
|
9499
9776
|
|
|
9500
9777
|
Returns:
|
|
9501
|
-
dict | None:
|
|
9778
|
+
dict | None:
|
|
9779
|
+
Updated workspace role membership details or `None` if the request fails.
|
|
9502
9780
|
|
|
9503
9781
|
Notes:
|
|
9504
9782
|
- If `apply_to` is set to `2`, both the workspace and its sub-items will inherit the updated permissions.
|
|
@@ -9549,12 +9827,16 @@ class OTCS:
|
|
|
9549
9827
|
"""Update a workspace with a with a new icon (which is uploaded).
|
|
9550
9828
|
|
|
9551
9829
|
Args:
|
|
9552
|
-
workspace_id (int):
|
|
9553
|
-
|
|
9554
|
-
|
|
9830
|
+
workspace_id (int):
|
|
9831
|
+
The ID of the workspace to update the icon for.
|
|
9832
|
+
file_path (str):
|
|
9833
|
+
The path + filename of icon file.
|
|
9834
|
+
file_mimetype (str, optional):
|
|
9835
|
+
The mimetype of the image.
|
|
9555
9836
|
|
|
9556
9837
|
Returns:
|
|
9557
|
-
dict | None:
|
|
9838
|
+
dict | None:
|
|
9839
|
+
Node information or None if REST call fails.
|
|
9558
9840
|
|
|
9559
9841
|
"""
|
|
9560
9842
|
|
|
@@ -9878,12 +10160,12 @@ class OTCS:
|
|
|
9878
10160
|
Address of the URL item (if it is an URL item type).
|
|
9879
10161
|
category_data (dict | None, optional):
|
|
9880
10162
|
New category and attributes values.
|
|
9881
|
-
classifications (list):
|
|
10163
|
+
classifications (list | None, optional):
|
|
9882
10164
|
List of classification item IDs to apply to the new item.
|
|
9883
|
-
body (bool):
|
|
10165
|
+
body (bool, optional):
|
|
9884
10166
|
Should the payload be put in an body tag. Most V2 REST API methods
|
|
9885
10167
|
do require this but some not (like Scheduled Bots)
|
|
9886
|
-
**kwargs (dict):
|
|
10168
|
+
**kwargs (dict, optional):
|
|
9887
10169
|
Add additional attributes to the body of the POST request
|
|
9888
10170
|
|
|
9889
10171
|
Returns:
|
|
@@ -9971,9 +10253,9 @@ class OTCS:
|
|
|
9971
10253
|
Args:
|
|
9972
10254
|
parent_id (int):
|
|
9973
10255
|
The node the category should be applied to.
|
|
9974
|
-
subtype (int):
|
|
10256
|
+
subtype (int, optional):
|
|
9975
10257
|
The subtype of the new node. Default is document.
|
|
9976
|
-
category_ids (int | list[int]):
|
|
10258
|
+
category_ids (int | list[int], optional):
|
|
9977
10259
|
The ID of the category or a list of category IDs.
|
|
9978
10260
|
|
|
9979
10261
|
Returns:
|
|
@@ -10327,7 +10609,7 @@ class OTCS:
|
|
|
10327
10609
|
# end method definition
|
|
10328
10610
|
|
|
10329
10611
|
def get_web_report_parameters(self, nickname: str) -> list | None:
|
|
10330
|
-
"""Retrieve parameters of a Web Report in
|
|
10612
|
+
"""Retrieve parameters of a Web Report in OTCS.
|
|
10331
10613
|
|
|
10332
10614
|
These parameters are defined on the Web Report node (Properties -> Parameters).
|
|
10333
10615
|
|
|
@@ -10384,14 +10666,17 @@ class OTCS:
|
|
|
10384
10666
|
nickname: str,
|
|
10385
10667
|
web_report_parameters: dict | None = None,
|
|
10386
10668
|
) -> dict | None:
|
|
10387
|
-
"""Run a Web Report that is identified by its
|
|
10669
|
+
"""Run a Web Report that is identified by its nickname.
|
|
10388
10670
|
|
|
10389
10671
|
Args:
|
|
10390
|
-
nickname (str):
|
|
10391
|
-
|
|
10672
|
+
nickname (str):
|
|
10673
|
+
The nickname of the Web Reports node.
|
|
10674
|
+
web_report_parameters (dict, optional):
|
|
10675
|
+
Parameters of the Web Report (names + value pairs)
|
|
10392
10676
|
|
|
10393
10677
|
Returns:
|
|
10394
|
-
dict | None:
|
|
10678
|
+
dict | None:
|
|
10679
|
+
Response of the run Web Report request or None if the Web Report execution has failed.
|
|
10395
10680
|
|
|
10396
10681
|
"""
|
|
10397
10682
|
|
|
@@ -10403,7 +10688,7 @@ class OTCS:
|
|
|
10403
10688
|
request_header = self.request_form_header()
|
|
10404
10689
|
|
|
10405
10690
|
self.logger.debug(
|
|
10406
|
-
"Running Web Report with nickname -> %s; calling -> %s",
|
|
10691
|
+
"Running Web Report with nickname -> '%s'; calling -> %s",
|
|
10407
10692
|
nickname,
|
|
10408
10693
|
request_url,
|
|
10409
10694
|
)
|
|
@@ -10598,12 +10883,12 @@ class OTCS:
|
|
|
10598
10883
|
def assign_permission(
|
|
10599
10884
|
self,
|
|
10600
10885
|
node_id: int,
|
|
10601
|
-
assignee_type: str,
|
|
10602
|
-
assignee: int,
|
|
10603
10886
|
permissions: list,
|
|
10887
|
+
assignee_type: str,
|
|
10888
|
+
assignee: int = 0,
|
|
10604
10889
|
apply_to: int = 0,
|
|
10605
10890
|
) -> dict | None:
|
|
10606
|
-
"""Assign permissions to a user or group for an
|
|
10891
|
+
"""Assign permissions to a user or group for an Content Server item.
|
|
10607
10892
|
|
|
10608
10893
|
This method allows you to assign specified permissions to a user or group for a given
|
|
10609
10894
|
Content Server item (node). The permissions can be applied to the item itself, its sub-items,
|
|
@@ -10611,15 +10896,6 @@ class OTCS:
|
|
|
10611
10896
|
|
|
10612
10897
|
Args:
|
|
10613
10898
|
node_id (int): The ID of the Extended ECM item (node) to which permissions are being assigned.
|
|
10614
|
-
assignee_type (str): The type of assignee. This can be one of the following:
|
|
10615
|
-
- "owner": Permissions are assigned to the owner.
|
|
10616
|
-
- "group": Permissions are assigned to the owner group.
|
|
10617
|
-
- "public": Permissions are assigned to the public (all users).
|
|
10618
|
-
- "custom": Permissions are assigned to a specific user or group (specified by `assignee`).
|
|
10619
|
-
assignee (int):
|
|
10620
|
-
The ID of the user or group (referred to as "right ID").
|
|
10621
|
-
If `assignee` is 0 and `assignee_type` is "owner" or "group",
|
|
10622
|
-
the owner or group will not be changed.
|
|
10623
10899
|
permissions (list of str): A list of permissions to assign to the assignee. Valid permissions include:
|
|
10624
10900
|
- "see" : View the item
|
|
10625
10901
|
- "see_contents" : View the contents of the item
|
|
@@ -10631,6 +10907,15 @@ class OTCS:
|
|
|
10631
10907
|
- "delete_versions" : Delete versions of the item
|
|
10632
10908
|
- "delete" : Delete the item
|
|
10633
10909
|
- "edit_permissions" : Modify permissions for the item
|
|
10910
|
+
assignee_type (str): The type of assignee. This can be one of the following:
|
|
10911
|
+
- "owner": Permissions are assigned to the owner.
|
|
10912
|
+
- "group": Permissions are assigned to the owner group.
|
|
10913
|
+
- "public": Permissions are assigned to the public (all users).
|
|
10914
|
+
- "custom": Permissions are assigned to a specific user or group (specified by `assignee`).
|
|
10915
|
+
assignee (int):
|
|
10916
|
+
The ID of the user or group (referred to as "right ID").
|
|
10917
|
+
If `assignee` is 0 and `assignee_type` is "owner" or "group",
|
|
10918
|
+
the owner or group will not be changed.
|
|
10634
10919
|
apply_to (int, optional): The scope of the permission assignment. Possible values:
|
|
10635
10920
|
- 0 = Apply to this item only (default)
|
|
10636
10921
|
- 1 = Apply to sub-items only
|
|
@@ -10647,18 +10932,24 @@ class OTCS:
|
|
|
10647
10932
|
|
|
10648
10933
|
"""
|
|
10649
10934
|
|
|
10650
|
-
if not assignee_type or assignee_type not in
|
|
10651
|
-
"owner",
|
|
10652
|
-
"group",
|
|
10653
|
-
"public",
|
|
10654
|
-
"custom",
|
|
10655
|
-
]:
|
|
10935
|
+
if not assignee_type or assignee_type not in OTCS.PERMISSION_ASSIGNEE_TYPES:
|
|
10656
10936
|
self.logger.error(
|
|
10657
|
-
"Missing or wrong assignee type. Needs to be
|
|
10937
|
+
"Missing or wrong assignee type. Needs to be one of %s!", str(OTCS.PERMISSION_ASSIGNEE_TYPES)
|
|
10658
10938
|
)
|
|
10659
10939
|
return None
|
|
10660
10940
|
if assignee_type == "custom" and not assignee:
|
|
10661
|
-
self.logger.error("
|
|
10941
|
+
self.logger.error("Assignee type is 'custom' but permission assignee is missing!")
|
|
10942
|
+
return None
|
|
10943
|
+
|
|
10944
|
+
if any(permission not in OTCS.PERMISSION_TYPES for permission in permissions):
|
|
10945
|
+
illegal_permissions = [permission for permission in permissions if permission not in OTCS.PERMISSION_TYPES]
|
|
10946
|
+
self.logger.error(
|
|
10947
|
+
"Illegal permission%s -> %s! Allowed permissions are -> %s. Cannot assign permissions to node with ID -> %d.",
|
|
10948
|
+
"s" if len(illegal_permissions) > 1 else "",
|
|
10949
|
+
str(illegal_permissions),
|
|
10950
|
+
str(OTCS.PERMISSION_TYPES),
|
|
10951
|
+
node_id,
|
|
10952
|
+
)
|
|
10662
10953
|
return None
|
|
10663
10954
|
|
|
10664
10955
|
permission_post_data = {
|
|
@@ -10676,10 +10967,11 @@ class OTCS:
|
|
|
10676
10967
|
request_header = self.request_form_header()
|
|
10677
10968
|
|
|
10678
10969
|
self.logger.debug(
|
|
10679
|
-
"Assign permissions -> %s to item with ID -> %s; assignee type -> '%s'; calling -> %s",
|
|
10970
|
+
"Assign permissions -> %s to item with ID -> %s; assignee type -> '%s'; apply to -> '%d'; calling -> %s",
|
|
10680
10971
|
str(permissions),
|
|
10681
10972
|
str(node_id),
|
|
10682
10973
|
assignee_type,
|
|
10974
|
+
apply_to,
|
|
10683
10975
|
request_url,
|
|
10684
10976
|
)
|
|
10685
10977
|
|
|
@@ -10692,9 +10984,8 @@ class OTCS:
|
|
|
10692
10984
|
headers=request_header,
|
|
10693
10985
|
data={"body": json.dumps(permission_post_data)},
|
|
10694
10986
|
timeout=None,
|
|
10695
|
-
failure_message="Failed to assign custom permissions -> {} to item with ID -> {}".format(
|
|
10696
|
-
permissions,
|
|
10697
|
-
node_id,
|
|
10987
|
+
failure_message="Failed to assign 'custom' permissions -> {} to item with ID -> {} (apply to -> {})".format(
|
|
10988
|
+
permissions, node_id, apply_to
|
|
10698
10989
|
),
|
|
10699
10990
|
)
|
|
10700
10991
|
else:
|
|
@@ -10705,9 +10996,8 @@ class OTCS:
|
|
|
10705
10996
|
headers=request_header,
|
|
10706
10997
|
data={"body": json.dumps(permission_post_data)},
|
|
10707
10998
|
timeout=None,
|
|
10708
|
-
failure_message="Failed to assign
|
|
10709
|
-
permissions,
|
|
10710
|
-
node_id,
|
|
10999
|
+
failure_message="Failed to assign -> '{}' permissions -> {} to item with ID -> {} (apply to -> {})".format(
|
|
11000
|
+
assignee_type, permissions, node_id, apply_to
|
|
10711
11001
|
),
|
|
10712
11002
|
)
|
|
10713
11003
|
|