Husein | 2019-11-06 14:42:24 UTC | #1
Dear All
We have follow this document => https://developer.mypurecloud.com/api/tutorials/recordings-downloader/index.html?language=csharp&step=1
to download recording file from purecloud, And get this error in this step conversationsApi.PostAnalyticsConversationsDetailsQuery(new ConversationQuery(Interval: myinterval));
Error => Message=Error calling PostAnalyticsConversationsDetailsQuery: The specified value is not a valid Host header string.
We update this myinterval with = @"2019-10-29T01:00:00/2019-10-29T23:00:00"; Please advise
Below the script that we use
using PureCloudPlatform.Client.V2.Api; using PureCloudPlatform.Client.V2.Client; using PureCloudPlatform.Client.V2.Extensions; using PureCloudPlatform.Client.V2.Model; using PureCloudPlatform.Client.V2; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net; using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks;
namespace Recordings { class Program { static void Main(string[] args) { Console.Write("Enter Client ID: "); //string clientId = Console.ReadLine(); string clientId = "ae930735-f5fc-43b4-835a-f622c2fc4146"; Console.Write("Enter Client Secret: "); //string clientSecret = Console.ReadLine(); string clientSecret = "W8gONrOy1yEss67Tu4wjD_p4nMz5ah4-3EwTISxWLlM";
// Get the Date Interval Console.Write("Enter Date Interval (YYYY-MM-DDThh:mm:ss/YYYY-MM-DDThh:mm:ss): "); //string interval = Console.ReadLine(); string myinterval = @"2019-10-29T01:00:00.000Z/2019-10-29T23:00:00.000Z";
Console.WriteLine("Working...");
// Configure SDK Settings string accessToken = GetToken(clientId, clientSecret); PureCloudPlatform.Client.V2.Client.Configuration.Default.AccessToken = accessToken;
// Instantiate APIs ConversationsApi conversationsApi = new ConversationsApi();
// Create folder that will store all the downloaded recordings string path = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); path = path.Substring(0, path.LastIndexOf("bin")); path = path + "\\Recordings"; System.IO.Directory.CreateDirectory(path + "\\Recordings");
// Call conversation API, pass date inputted to extract conversationIds needed //conversationsApi.Configuration.Username = ""; //conversationsApi.Configuration.Password = ""; //conversationsApi.Configuration.UserAgent = ""; conversationsApi.Configuration.TempFolderPath = path; var query = new ConversationQuery(); query.Interval = myinterval; query.Order = ConversationQuery.OrderEnum.Asc; query.Paging = new PagingSpec(25, 1); var api = new AnalyticsApi(); conversationsApi.Configuration.AddDefaultHeader("Content-Type", "application/json"); conversationsApi.Configuration.AddDefaultHeader("Host", "https://api.mypurecloud.com.au"); AnalyticsConversationQueryResponse resp= api.PostAnalyticsConversationsDetailsQuery(query); //conversationsApi.Configuration.AddDefaultHeader() AnalyticsConversationQueryResponse conversationDetails = conversationsApi.PostAnalyticsConversationsDetailsQuery(query); // Pass conversation details to function //extractConversationDetails(conversationDetails);
// Final Output Console.WriteLine("DONE");
if (Debugger.IsAttached) { Console.ReadKey(); } }
/// <summary> /// Format conversation details to object inside and array. Get every mediatype per conversation /// </summary> /// <param name="conversationDetails"></param> /// <returns></returns> private static void extractConversationDetails(AnalyticsConversationQueryResponse conversationDetails) { // Push all conversationId from conversationDetails to conversationIds foreach (var conversationDetail in conversationDetails.Conversations) { getRecordingMetaData(conversationDetail.ConversationId); } }
/// <summary> /// Generate recordingId for every conversationId /// </summary> /// <param name="conversationId"></param> /// <returns></returns> private static void getRecordingMetaData(string conversationId) { RecordingApi recordingApi = new RecordingApi(); List<Recording> recordingsData = recordingApi.GetConversationRecordingmetadata(conversationId);
// Pass recordingsMetadata to a function iterateRecordingsData(recordingsData); }
/// <summary> /// Iterate through every result, check if there are one or more recordingIds in every conversation /// </summary> /// <param name="recordingsData"></param> /// <returns></returns> private static void iterateRecordingsData(List<Recording> recordingsData) { foreach (var iterateRecordings in recordingsData) { getSpecificRecordings(iterateRecordings); } }
/// <summary> /// Plot conversationId and recordingId to request for batchDownload Recordings /// </summary> /// <param name="iterateRecordings"></param> /// <returns></returns> private static void getSpecificRecordings(Recording iterateRecordings) { List<BatchDownloadRequest> batchRequest = new List<BatchDownloadRequest>(); BatchDownloadRequest batchDownloadRequest = new BatchDownloadRequest(ConversationId: iterateRecordings.ConversationId, RecordingId: iterateRecordings.Id); batchRequest.Add(batchDownloadRequest);
// Create the batch job with the request list BatchDownloadJobSubmission batchSubmission = new BatchDownloadJobSubmission(BatchDownloadRequestList: batchRequest);
BatchDownloadJobSubmissionResult recordingBatchRequestId = new BatchDownloadJobSubmissionResult(); RecordingApi recordingApi = new RecordingApi(); recordingBatchRequestId = recordingApi.PostRecordingBatchrequests(batchSubmission);
recordingStatus(recordingBatchRequestId); }
/// <summary> /// Check status of generating url for downloading, if the result is still unavailble. The function will be called again until the result is available. /// </summary> /// <param name="recordingBatchRequestId"></param> /// <returns></returns> private static void recordingStatus(BatchDownloadJobSubmissionResult recordingBatchRequestId) { BatchDownloadJobStatusResult getRecordingBatchRequestData = new BatchDownloadJobStatusResult(); RecordingApi recordingApi = new RecordingApi(); getRecordingBatchRequestData = recordingApi.GetRecordingBatchrequest(recordingBatchRequestId.Id);
if (getRecordingBatchRequestData.ExpectedResultCount == getRecordingBatchRequestData.ResultCount) { // Pass the getRecordingBatchRequestData to getExtension function getExtension(getRecordingBatchRequestData); } else { Thread.Sleep(5000); recordingStatus(recordingBatchRequestId); } }
/// <summary> /// Get extension of every recordings /// </summary> /// <param name="getRecordingBatchRequestData"></param> /// <returns></returns> private static void getExtension(BatchDownloadJobStatusResult getRecordingBatchRequestData) { // Store the contentType to a variable that will be used later to determine the extension of recordings. string contentType = getRecordingBatchRequestData.Results[0].ContentType; // Split the text and gets the extension that will be used for the recording string ext = contentType.Split('/').Last();
createDirectory(ext, getRecordingBatchRequestData); }
/// <summary> /// Generate directory for recordings that will be downloaded /// </summary> /// <param name="ext"></param> /// <param name="getRecordingBatchRequestData"></param> /// <returns></returns> private static void createDirectory(string ext, BatchDownloadJobStatusResult getRecordingBatchRequestData) { Console.WriteLine("Processing please wait...");
string conversationId = getRecordingBatchRequestData.Results[0].ConversationId; string recordingId = getRecordingBatchRequestData.Results[0].RecordingId; string url = getRecordingBatchRequestData.Results[0].ResultUrl;
string path = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); path = path.Substring(0, path.LastIndexOf("bin")); System.IO.Directory.CreateDirectory(path + "\\Recordings\\" + conversationId + "_" + recordingId);
downloadRecording(url, ext, path + "\\Recordings\\" + conversationId + "_" + recordingId); }
/// <summary> /// Download recordings /// </summary> /// <param name="url"></param> /// <param name="ext"></param> /// <param name="targetDirectory"></param> /// <returns></returns> private static void downloadRecording(string url, string ext, string targetDirectory) { // string downloadFile = conversationId + '_' + recordingId + '.' + ext; string filename = targetDirectory.Substring(targetDirectory.LastIndexOf('\\') + 1, 73);
using (WebClient wc = new WebClient()) wc.DownloadFile(url, targetDirectory + "\\" + filename + "." + ext); }
/// <summary> /// Request client credentials token from PureCloud /// </summary> /// <param name="clientId"></param> /// <param name="clientSecret"></param> /// <returns></returns> private static string GetToken(string clientId, string clientSecret) { Configuration.Default.ApiClient.RestClient.BaseHost = "https://api.mypurecloud.com.au"; Uri myUri = new Uri("https://api.mypurecloud.com.au", UriKind.Absolute); Configuration.Default.ApiClient.RestClient.BaseUrl = myUri;
var accessTokenInfo = Configuration.Default.ApiClient.PostToken(clientId, clientSecret, "api.mypurecloud.com.au");
string token = accessTokenInfo.AccessToken;
return token; } } }
tim.smith | 2019-11-06 15:10:32 UTC | #2
Husein, post:1, topic:6426
conversationsApi.Configuration.AddDefaultHeader("Host", "https://api.mypurecloud.com.au");
I'm guessing the error is caused by that. You definitely shouldn't be setting the host header and generally shouldn't be manually setting any headers at all (including content-type). If you're trying to set the environment for the SDK, you should use the documented method: https://developer.mypurecloud.com/api/rest/client-libraries/dotnet/index.html#setting_the_environment
fahmi | 2019-11-07 01:27:35 UTC | #3
Hi Smith,
I am Husein Team. I just want to make it clear, the header that I added because we get some error "The specified value is not a valid Host header string." that's why I added the header but the result is the same. Please advice to solve error "The specified value is not a valid Host header string." on that codes.
besides that I set the interval string as "2019-10-29T01:00:00.000Z/2019-10-29T23:00:00.000Z" this is the valid format ?
Thanks,
Fahmi.
tim.smith | 2019-11-07 16:01:15 UTC | #4
Please remove the custom headers and try setting the environment and obtaining an auth token using the documented methods. The code above isn't doing either of those things correctly.
tim.smith | 2019-11-07 16:02:18 UTC | #5
fahmi, post:3, topic:6426
besides that I set the interval string as "2019-10-29T01:00:00.000Z/2019-10-29T23:00:00.000Z" this is the valid format ?
Looks right at a glance, but you should validate your query using the Analytics Query Builder https://developer.mypurecloud.com/developer-tools/#/analytics-query-builder
Husein | 2019-11-12 08:57:39 UTC | #6
Hi Smith
Now we can download the recording file,
Thanks
Husein
system | 2019-12-13 09:10:44 UTC | #7
This topic was automatically closed 31 days after the last reply. New replies are no longer allowed.
This post was migrated from the old Developer Forum.
ref: 6426