11-11-2024 08:38 AM
Hello,
I am facing an issue where I'm attempting to utilize the put request to update a team specific layout using python. Here is the python code (scrubbed for anything personal):
import requests
from requests.auth import HTTPBasicAuth
import ssl
import os
import re
# Credentials and host configuration
fin_username = 'admin'
fin_password = 'password'
# Base URL for Finesse API
base_url = "https://finesse.cisco.api/finesse/api"
# Create a custom SSL context to avoid compatibility issues
ssl_context = ssl.create_default_context()
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2
# Disable SSL warnings (not recommended for production use)
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
# Function to update layout config for a specific team using PUT request
def update_team_layout_config():
try:
print("Starting update_team_layout_config...") # Debugging print statement
# Check if input file exists
file_path = 'updatedlayout.xml'
if not os.path.exists(file_path):
raise FileNotFoundError(f"Input file '{file_path}' not found.")
# Load data from input file
with open(file_path, 'r') as file:
data = file.read()
# Use regex to extract team ID and layout XML
team_match = re.search(r'"team":\s*(\d+)', data)
layout_match = re.search(r'"layoutxml":\s*(<.*)', data, re.DOTALL)
if not team_match:
raise ValueError("Missing 'team' key in the input file.")
if not layout_match:
raise ValueError("Missing 'layoutxml' key in the input file.")
team_id = team_match.group(1).strip()
layout_xml = layout_match.group(1).strip()
# Ensure the layout XML starts with a valid XML element
if not layout_xml.startswith("<"):
raise ValueError("Invalid XML format in 'layoutxml'.")
# Fix the XML by ensuring that quotes are properly placed around attributes
layout_xml = re.sub(r'(xmlns=)(\S+)', r'\1"\2"', layout_xml)
# Construct the PUT URL dynamically based on team ID
put_url = f"{base_url}/Team/{team_id}/LayoutConfig"
# Set up headers and payload
headers = {
'Content-Type': 'application/xml'
}
payload = f"""<TeamLayoutConfig>
<useDefault>false</useDefault>
<layoutxml>{layout_xml}
</layoutxml>
</TeamLayoutConfig>"""
# Print payload for debugging purposes
print("Payload being sent:")
print(payload)
# Perform PUT request
response = requests.put(put_url, auth=HTTPBasicAuth(fin_username, fin_password), headers=headers, data=payload,
verify=False)
# Handle response
if response.status_code == 200:
print("Successfully updated team layout config:")
print(response.text)
else:
print(f"Failed to update layout config: {response.status_code} {response.text}")
# Print response for debugging purposes
print("Response status code:", response.status_code)
print("Response headers:", response.headers)
print("Response text:", response.text)
except Exception as e:
print(f"An error occurred: {str(e)}")
# Main function to update layout config
def main():
print("Starting main function...") # Debugging print statement
update_team_layout_config()
if __name__ == "__main__":
main()
here is the xml file Im using:
Solved! Go to Solution.
11-13-2024 10:18 AM
Found a couple issues, one with the script which is fixed below:
import requests
from requests.auth import HTTPBasicAuth
import ssl
import os
import re
# Credentials and host configuration
fin_username = 'AdminAccount'
fin_password = 'AdminPassword'
# Base URL for Finesse API
base_url = "https://<finesse ip or hostname>/finesse/api"
# Create a custom SSL context to avoid compatibility issues
ssl_context = ssl.create_default_context()
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2
# Disable SSL warnings (not recommended for production use)
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
# Function to update layout config for a specific team using PUT request
def update_team_layout_config():
try:
print("Starting update_team_layout_config...") # Debugging print statement
# Check if input file exists
file_path = '<full path to>updatedlayout.xml'
if not os.path.exists(file_path):
raise FileNotFoundError(f"Input file '{file_path}' not found.")
# Load data from input file
with open(file_path, 'r') as file:
data = file.read()
# Use regex to extract team ID and layout XML
team_match = re.search(r'"team":\s*(\d+)', data)
layout_match = re.search(r'"layoutxml":\s*(<.*)', data, re.DOTALL)
if not team_match:
raise ValueError("Missing 'team' key in the input file.")
if not layout_match:
raise ValueError("Missing 'layoutxml' key in the input file.")
team_id = team_match.group(1).strip()
layout_xml = layout_match.group(1).strip()
# Ensure the layout XML starts with a valid XML element
if not layout_xml.startswith("<"):
raise ValueError("Invalid XML format in 'layoutxml'.")
# Fix the XML by ensuring that quotes are properly placed around attributes
layout_xml = re.sub(r'(xmlns=)"?([^\s>]+)"?', r'\1"\2"', layout_xml)
# Remove any extra quotes that may have been added incorrectly
layout_xml = re.sub(r'""', r'"', layout_xml)
# Construct the PUT URL dynamically based on team ID
put_url = f"{base_url}/Team/{team_id}/LayoutConfig"
# Set up headers and payload
headers = {
'Content-Type': 'application/xml'
}
payload = f"""<TeamLayoutConfig>
<useDefault>false</useDefault>
<layoutxml><![CDATA[{layout_xml}]]></layoutxml>
</TeamLayoutConfig>"""
# Print payload for debugging purposes
print("Payload being sent:")
print(payload)
# Perform PUT request
response = requests.put(put_url, auth=HTTPBasicAuth(fin_username, fin_password), headers=headers, data=payload,
verify=False)
# Handle response
if response.status_code == 200:
print("Successfully updated team layout config:")
print(response.text)
else:
print(f"Failed to update layout config: {response.status_code} {response.text}")
# Print response for debugging purposes
print("Response status code:", response.status_code)
print("Response headers:", response.headers)
print("Response text:", response.text)
except Exception as e:
print(f"An error occurred: {str(e)}")
# Main function to update layout config
def main():
print("Starting main function...") # Debugging print statement
update_team_layout_config()
if __name__ == "__main__":
main()
the second was the layoutxml file was missing things the team update Api page didn't say were required, those items were:
the configs, header, header columns and version sections are all required. The API page says this is all that's required but that's incorrect:
<TeamLayoutConfig>
<useDefault>false</useDefault>
<layoutxml>
<finesseLayout xmlns="http://www.cisco.com/vtg/finesse">
<layout>
<role>Agent</role>
...
</layout>
<layout>
<role>Supervisor</role>
...
</layout>
</finesseLayout>
</layoutxml>
</TeamLayoutConfig>
If you were to send only the above, you would receive a 400 error code saying the above sections were missing (I added them one at a time to see if all were required and they are). Once all of those were added with the appropriate content AND I fixed some of the URLs that had whitespace in them I'm happy to report this is now working smoothly.
Hope this helps someone in the future to avoid the pain I just endured. Happy coding.
Jason
11-13-2024 06:37 AM
I don't know if this is your issue, but I had problem doing API updates in PCCE if the update XML did not include the refURL and the changeStamp of the item being updated. changeStamp is used for concurrency to prevent a last update wins scenario.
11-13-2024 10:18 AM
Found a couple issues, one with the script which is fixed below:
import requests
from requests.auth import HTTPBasicAuth
import ssl
import os
import re
# Credentials and host configuration
fin_username = 'AdminAccount'
fin_password = 'AdminPassword'
# Base URL for Finesse API
base_url = "https://<finesse ip or hostname>/finesse/api"
# Create a custom SSL context to avoid compatibility issues
ssl_context = ssl.create_default_context()
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2
# Disable SSL warnings (not recommended for production use)
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
# Function to update layout config for a specific team using PUT request
def update_team_layout_config():
try:
print("Starting update_team_layout_config...") # Debugging print statement
# Check if input file exists
file_path = '<full path to>updatedlayout.xml'
if not os.path.exists(file_path):
raise FileNotFoundError(f"Input file '{file_path}' not found.")
# Load data from input file
with open(file_path, 'r') as file:
data = file.read()
# Use regex to extract team ID and layout XML
team_match = re.search(r'"team":\s*(\d+)', data)
layout_match = re.search(r'"layoutxml":\s*(<.*)', data, re.DOTALL)
if not team_match:
raise ValueError("Missing 'team' key in the input file.")
if not layout_match:
raise ValueError("Missing 'layoutxml' key in the input file.")
team_id = team_match.group(1).strip()
layout_xml = layout_match.group(1).strip()
# Ensure the layout XML starts with a valid XML element
if not layout_xml.startswith("<"):
raise ValueError("Invalid XML format in 'layoutxml'.")
# Fix the XML by ensuring that quotes are properly placed around attributes
layout_xml = re.sub(r'(xmlns=)"?([^\s>]+)"?', r'\1"\2"', layout_xml)
# Remove any extra quotes that may have been added incorrectly
layout_xml = re.sub(r'""', r'"', layout_xml)
# Construct the PUT URL dynamically based on team ID
put_url = f"{base_url}/Team/{team_id}/LayoutConfig"
# Set up headers and payload
headers = {
'Content-Type': 'application/xml'
}
payload = f"""<TeamLayoutConfig>
<useDefault>false</useDefault>
<layoutxml><![CDATA[{layout_xml}]]></layoutxml>
</TeamLayoutConfig>"""
# Print payload for debugging purposes
print("Payload being sent:")
print(payload)
# Perform PUT request
response = requests.put(put_url, auth=HTTPBasicAuth(fin_username, fin_password), headers=headers, data=payload,
verify=False)
# Handle response
if response.status_code == 200:
print("Successfully updated team layout config:")
print(response.text)
else:
print(f"Failed to update layout config: {response.status_code} {response.text}")
# Print response for debugging purposes
print("Response status code:", response.status_code)
print("Response headers:", response.headers)
print("Response text:", response.text)
except Exception as e:
print(f"An error occurred: {str(e)}")
# Main function to update layout config
def main():
print("Starting main function...") # Debugging print statement
update_team_layout_config()
if __name__ == "__main__":
main()
the second was the layoutxml file was missing things the team update Api page didn't say were required, those items were:
the configs, header, header columns and version sections are all required. The API page says this is all that's required but that's incorrect:
<TeamLayoutConfig>
<useDefault>false</useDefault>
<layoutxml>
<finesseLayout xmlns="http://www.cisco.com/vtg/finesse">
<layout>
<role>Agent</role>
...
</layout>
<layout>
<role>Supervisor</role>
...
</layout>
</finesseLayout>
</layoutxml>
</TeamLayoutConfig>
If you were to send only the above, you would receive a 400 error code saying the above sections were missing (I added them one at a time to see if all were required and they are). Once all of those were added with the appropriate content AND I fixed some of the URLs that had whitespace in them I'm happy to report this is now working smoothly.
Hope this helps someone in the future to avoid the pain I just endured. Happy coding.
Jason
Discover and save your favorite ideas. Come back to expert answers, step-by-step guides, recent topics, and more.
New here? Get started with these tips. How to use Community New member guide