Skip to content

Commit da5f4ba

Browse files
authored
Merge pull request #50 from Bandwidth/DX-2470
DX-2470 add modifyCallBxml Functionality
2 parents 79810de + 1546a35 commit da5f4ba

File tree

8 files changed

+279
-86
lines changed

8 files changed

+279
-86
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System.Xml.Serialization;
2+
3+
namespace Bandwidth.Standard.Voice.Bxml
4+
{
5+
/// <summary>
6+
/// Bxml class for Bandwidth XML
7+
/// </summary>
8+
[XmlRoot(ElementName = "Bxml")]
9+
public class BXML : Root
10+
{
11+
public BXML() : base()
12+
{
13+
_serializer = new XmlSerializer(typeof(BXML), "");
14+
}
15+
16+
public BXML(params IVerb[] verbs) : base(verbs)
17+
{
18+
_serializer = new XmlSerializer(typeof(BXML), "");
19+
}
20+
}
21+
}
Lines changed: 8 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,20 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.IO;
4-
using System.Text;
5-
using System.Text.RegularExpressions;
6-
using System.Xml;
7-
using System.Xml.Schema;
81
using System.Xml.Serialization;
92

103
namespace Bandwidth.Standard.Voice.Bxml
114
{
12-
/// <summary>
13-
/// Response class for Bandwidth XML
14-
/// </summary>
15-
[XmlRoot(Namespace = "")]
16-
public class Response : IXmlSerializable
17-
{
18-
private static readonly XmlSerializer Serializer = new XmlSerializer(typeof (Response), "");
19-
private readonly List<IVerb> _list = new List<IVerb>();
20-
21-
private static readonly Regex XML_REGEX = new Regex("&lt;([a-zA-Z//].*?)&gt;");
22-
23-
private static readonly Regex SPEAK_SENTENCE_REGEX = new Regex("<SpeakSentence.*?>.*?<\\/SpeakSentence>");
24-
25-
/// <summary>
26-
/// Default constructor
27-
/// </summary>
28-
public Response()
29-
{
30-
}
31-
32-
/// <summary>
33-
/// Constructor with verbs
34-
/// </summary>
35-
/// <param name="verbs">verbs to be added to response</param>
36-
public Response(params IVerb[] verbs)
37-
{
38-
_list.AddRange(verbs);
39-
}
40-
41-
XmlSchema IXmlSerializable.GetSchema() => null;
42-
43-
void IXmlSerializable.ReadXml(XmlReader reader)
44-
{
45-
throw new NotImplementedException();
46-
}
47-
48-
void IXmlSerializable.WriteXml(XmlWriter writer)
49-
{
50-
var ns = new XmlSerializerNamespaces();
51-
ns.Add("", "");
52-
foreach (var verb in _list)
53-
{
54-
var serializer = new XmlSerializer(verb.GetType(), "");
55-
serializer.Serialize(writer, verb, ns);
56-
}
57-
}
58-
595
/// <summary>
60-
/// Add new verb to response
6+
/// Bxml response class for Bandwidth XML
617
/// </summary>
62-
/// <param name="verb">verb instance</param>
63-
public void Add(IVerb verb)
8+
public class Response : Root
649
{
65-
_list.Add(verb);
66-
}
67-
68-
69-
70-
/// <summary>
71-
/// Returns BXML for response without escaped SSML
72-
/// </summary>
73-
/// <returns>Generated XML string</returns>
74-
public string ToBXML()
10+
public Response() : base()
7511
{
76-
77-
string str = "";
78-
using (var writer = new Utf8StringWriter { NewLine = "" })
79-
{
80-
Serializer.Serialize(writer, this);
81-
str = writer.ToString();
82-
}
83-
84-
MatchEvaluator matchEvaluator = new MatchEvaluator(match =>
85-
XML_REGEX.Replace(match.Value, "<$1>")
86-
);
87-
88-
return SPEAK_SENTENCE_REGEX.Replace(str, matchEvaluator);
12+
_serializer = new XmlSerializer(typeof(Response), "");
8913
}
9014

91-
private class Utf8StringWriter : StringWriter
92-
{
93-
public override Encoding Encoding => Encoding.UTF8;
15+
public Response(params IVerb[] verbs) : base(verbs)
16+
{
17+
_serializer = new XmlSerializer(typeof(Response), "");
18+
}
9419
}
95-
}
9620
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Text;
5+
using System.Text.RegularExpressions;
6+
using System.Xml;
7+
using System.Xml.Schema;
8+
using System.Xml.Serialization;
9+
10+
namespace Bandwidth.Standard.Voice.Bxml
11+
{
12+
/// <summary>
13+
/// Bxml class for Bandwidth XML
14+
/// </summary>
15+
public abstract class Root : IXmlSerializable
16+
{
17+
internal static XmlSerializer _serializer;
18+
private readonly List<IVerb> _list = new List<IVerb>();
19+
20+
private static readonly Regex s_xmlRegex = new Regex("&lt;([a-zA-Z//].*?)&gt;");
21+
22+
private static readonly Regex s_speakSentenceRegex = new Regex("<SpeakSentence.*?>.*?<\\/SpeakSentence>");
23+
24+
/// <summary>
25+
/// Default constructor
26+
/// </summary>
27+
public Root()
28+
{
29+
30+
}
31+
32+
/// <summary>
33+
/// Constructor with verbs
34+
/// </summary>
35+
/// <param name="verbs">verbs to be added to response</param>
36+
public Root(params IVerb[] verbs)
37+
{
38+
_list.AddRange(verbs);
39+
}
40+
41+
XmlSchema IXmlSerializable.GetSchema() => null;
42+
43+
void IXmlSerializable.ReadXml(XmlReader reader)
44+
{
45+
throw new NotImplementedException();
46+
}
47+
48+
void IXmlSerializable.WriteXml(XmlWriter writer)
49+
{
50+
var ns = new XmlSerializerNamespaces();
51+
ns.Add("", "");
52+
foreach (var verb in _list)
53+
{
54+
var serializer = new XmlSerializer(verb.GetType(), "");
55+
serializer.Serialize(writer, verb, ns);
56+
}
57+
}
58+
59+
/// <summary>
60+
/// Add new verb to response
61+
/// </summary>
62+
/// <param name="verb">verb instance</param>
63+
public void Add(IVerb verb)
64+
{
65+
_list.Add(verb);
66+
}
67+
68+
/// <summary>
69+
/// Returns BXML for response without escaped SSML
70+
/// </summary>
71+
/// <returns>Generated XML string</returns>
72+
public string ToBXML()
73+
{
74+
75+
string str = "";
76+
using (var writer = new Utf8StringWriter { NewLine = "" })
77+
{
78+
_serializer.Serialize(writer, this);
79+
str = writer.ToString();
80+
}
81+
82+
MatchEvaluator matchEvaluator = new MatchEvaluator(match =>
83+
s_xmlRegex.Replace(match.Value, "<$1>")
84+
);
85+
86+
return s_speakSentenceRegex.Replace(str, matchEvaluator);
87+
}
88+
89+
private class Utf8StringWriter : StringWriter
90+
{
91+
public override Encoding Encoding => Encoding.UTF8;
92+
}
93+
}
94+
}

Bandwidth.Standard/Voice/Controllers/APIController.cs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,116 @@ public async Task ModifyCallAsync(
370370
this.ValidateResponse(response, context);
371371
}
372372

373+
/// <summary>
374+
/// Replaces an active call's BXML document.
375+
/// </summary>
376+
/// <param name="accountId">Required parameter: Example: .</param>
377+
/// <param name="callId">Required parameter: Example: .</param>
378+
/// <param name="body">Required parameter: Example: .</param>
379+
public void ModifyCallBxml(
380+
string accountId,
381+
string callId,
382+
string body)
383+
{
384+
Task t = this.ModifyCallBxmlAsync(accountId, callId, body);
385+
ApiHelper.RunTaskSynchronously(t);
386+
}
387+
388+
/// <summary>
389+
/// Interrupts and replaces an active call's BXML document.
390+
/// </summary>
391+
/// <param name="accountId">Required parameter: Example: .</param>
392+
/// <param name="callId">Required parameter: Example: .</param>
393+
/// <param name="body">Required parameter: Example: .</param>
394+
/// <param name="cancellationToken"> cancellationToken. </param>
395+
/// <returns>Returns the void response from the API call.</returns>
396+
public async Task ModifyCallBxmlAsync(
397+
string accountId,
398+
string callId,
399+
string body,
400+
CancellationToken cancellationToken = default)
401+
{
402+
// the base uri for api requests.
403+
string baseUri = this.Config.GetBaseUri(Server.VoiceDefault);
404+
405+
// prepare query string for API call.
406+
StringBuilder queryBuilder = new StringBuilder(baseUri);
407+
queryBuilder.Append("/api/v2/accounts/{accountId}/calls/{callId}/bxml");
408+
409+
// process optional template parameters.
410+
ApiHelper.AppendUrlWithTemplateParameters(queryBuilder, new Dictionary<string, object>()
411+
{
412+
{ "accountId", accountId },
413+
{ "callId", callId },
414+
});
415+
416+
// append request with appropriate headers and parameters
417+
var headers = new Dictionary<string, string>()
418+
{
419+
{ "user-agent", this.UserAgent },
420+
{ "content-type", "application/xml; charset=utf-8" },
421+
};
422+
423+
// append body params.
424+
var bodyText = body;
425+
426+
// prepare the API call request to fetch the response.
427+
HttpRequest httpRequest = this.GetClientInstance().PutBody(queryBuilder.ToString(), headers, bodyText);
428+
429+
if (this.HttpCallBack != null)
430+
{
431+
this.HttpCallBack.OnBeforeHttpRequestEventHandler(this.GetClientInstance(), httpRequest);
432+
}
433+
434+
httpRequest = await this.AuthManagers["voice"].ApplyAsync(httpRequest).ConfigureAwait(false);
435+
436+
// invoke request and get response.
437+
HttpStringResponse response = await this.GetClientInstance().ExecuteAsStringAsync(httpRequest, cancellationToken).ConfigureAwait(false);
438+
HttpContext context = new HttpContext(httpRequest, response);
439+
if (this.HttpCallBack != null)
440+
{
441+
this.HttpCallBack.OnAfterHttpResponseEventHandler(this.GetClientInstance(), response);
442+
}
443+
444+
if (response.StatusCode == 400)
445+
{
446+
throw new ApiErrorException("Something's not quite right... Your request is invalid. Please fix it before trying again.", context);
447+
}
448+
449+
if (response.StatusCode == 401)
450+
{
451+
throw new ApiException("Your credentials are invalid. Please use your Bandwidth dashboard credentials to authenticate to the API.", context);
452+
}
453+
454+
if (response.StatusCode == 403)
455+
{
456+
throw new ApiErrorException("User unauthorized to perform this action.", context);
457+
}
458+
459+
if (response.StatusCode == 404)
460+
{
461+
throw new ApiErrorException("The resource specified cannot be found or does not belong to you.", context);
462+
}
463+
464+
if (response.StatusCode == 415)
465+
{
466+
throw new ApiErrorException("We don't support that media type. If a request body is required, please send it to us as `application/xml`.", context);
467+
}
468+
469+
if (response.StatusCode == 429)
470+
{
471+
throw new ApiErrorException("You're sending requests to this endpoint too frequently. Please slow your request rate down and try again.", context);
472+
}
473+
474+
if (response.StatusCode == 500)
475+
{
476+
throw new ApiErrorException("Something unexpected happened. Please try again.", context);
477+
}
478+
479+
// handle errors defined at the API level.
480+
this.ValidateResponse(response, context);
481+
}
482+
373483
/// <summary>
374484
/// Pauses or resumes a recording.
375485
/// </summary>

Bandwidth.Standard/Voice/Models/MachineDetectionConfiguration.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ public class MachineDetectionConfiguration
2828
private string password;
2929
private string fallbackUsername;
3030
private string fallbackPassword;
31-
private double? machineSpeechEndThreshold;
3231
private Dictionary<string, bool> shouldSerialize = new Dictionary<string, bool>
3332
{
3433
{ "callbackUrl", false },

Bandwidth.StandardTests/PhoneNumberLookup/LookupTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,4 @@ public async Task GetTnLookupResultAsync()
8888
Assert.Null(resultResponse.Data.Result.First().MobileNetworkCode);
8989
}
9090
}
91-
}
91+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using Bandwidth.Standard.Voice.Bxml;
2+
using Xunit;
3+
4+
namespace Bandwidth.StandardTests.Voice.Bxml
5+
{
6+
public class BxmlTests
7+
{
8+
9+
[Fact]
10+
public void EmptyBxmlTest()
11+
{
12+
var bxml = new BXML();
13+
Assert.Equal("<?xml version=\"1.0\" encoding=\"utf-8\"?><Bxml />", bxml.ToBXML());
14+
}
15+
16+
[Fact]
17+
public void RingAnswerCallResponseToBXMLShouldBeFalse()
18+
{
19+
var ring = new Ring();
20+
ring.AnswerCall = false;
21+
22+
var bxml = new BXML(ring);
23+
24+
Assert.Equal("<?xml version=\"1.0\" encoding=\"utf-8\"?><Bxml> <Ring duration=\"5\" answerCall=\"false\" /></Bxml>", bxml.ToBXML());
25+
}
26+
}
27+
}

0 commit comments

Comments
 (0)