Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Added code to handle "action" attribute of <Dial> verb #5

Merged
merged 2 commits into from

2 participants

@jayp

As I just recently needed to use the "action" attribute to get the duration of an outgoing call initiated via , I realized that Scwilio didn't have proper support for it.

This pull request remedies it.

@daggerrz daggerrz merged commit d193138 into daggerrz:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 13, 2011
  1. @jayp

    Changed Dial verb's onConnect attribute to onEnd

    jayp authored
    * Reversing incorrect change made in 9116b62
Commits on Dec 18, 2011
  1. @jayp
This page is out of date. Refresh to see the latest.
View
4 README.markdown
@@ -31,7 +31,7 @@ To generate some TwiML, put this in a handler of whatever web framework your're
Pause(10),
Play("http://foo.com/cowbell.mp3"),
Say("Dialing 8 8 8 8"),
- Dial(from = Phonenumber("+1999"), to = Phonenumber("+1888"), onConnect = Some("http://test"))
+ Dial(from = Phonenumber("+1999"), to = Phonenumber("+1888"), onEnd = Some("http://test"))
)
val stringResponse = TwiML(response).toString
// Write the response
@@ -124,4 +124,4 @@ service using a `Phone` implementation using the Unfiltered web framework (see S
}
## Actor API
-TBD
+TBD
View
57 core/src/main/scala/scwilio/callback/callbackevents.scala
@@ -64,7 +64,8 @@ object ActiveCall {
}
/**
- * Represents a completed call.
+ * Represents a completed call. It maybe an incoming call or an outgoing call
+ * originated via REST API.
*/
case class CompletedCall(
sid: String,
@@ -95,7 +96,58 @@ object CompletedCall {
case Some(s) => Some(Unknown(s))
case None => None
},
- p.get("CallDuration").getOrElse("0").toInt
+ p.get("CallDuration").getOrElse("0").toInt
+ )
+ }
+}
+
+/**
+ * Represents a completed an outgoing dial. This phone call is part of an
+ * existing active all, i.e., either an incoming call or an outgoing API call.
+ */
+case class CompletedOutgoingDial(
+ sid: String,
+ from: Phonenumber,
+ to: Phonenumber,
+ status: CompletedCallStatus,
+ answeredBy: Option[AnsweredBy],
+ duration: Int,
+ dialedCallSid: String,
+ dialedCallStatus: CompletedCallStatus,
+ dialedCallDuration: Int
+ ) extends Call with CallbackEvent
+
+object CompletedOutgoingDial {
+ def parse(p: Map[String, String]) = {
+ CompletedOutgoingDial(
+ p("CallSid"),
+ Phonenumber(p("From")),
+ Phonenumber(p("To")),
+ p.get("CallStatus") match {
+ case Some("completed") => Completed
+ case Some("busy") => Busy
+ case Some("no-answer") => NoAnswer
+ case Some("failed") => Failed
+ case Some(s) => Unknown(s)
+ case None => Unknown("no status")
+ },
+ p.get("AnsweredBy") match {
+ case Some("human") => Some(Human)
+ case Some("machine") => Some(Machine)
+ case Some(s) => Some(Unknown(s))
+ case None => None
+ },
+ p.get("CallDuration").getOrElse("0").toInt,
+ p("DialCallSid"),
+ p.get("DialCallStatus") match {
+ case Some("completed") => Completed
+ case Some("busy") => Busy
+ case Some("no-answer") => NoAnswer
+ case Some("failed") => Failed
+ case Some(s) => Unknown(s)
+ case None => Unknown("no status")
+ },
+ p.get("DialCallDuration").getOrElse("0").toInt
)
}
}
@@ -109,7 +161,6 @@ case object Ringing extends ActiveCallStatus
case object InProgress extends ActiveCallStatus
case object Ended extends ActiveCallStatus
-
/**
* Status of a completed call. For calls which originally were
* incoming, this will always be just Completed. For outgoing calls
View
5 core/src/main/scala/scwilio/callback/callbackmanager.scala
@@ -6,7 +6,8 @@ import scwilio.twiml._
object functions {
type CallbackFunc[T <: CallbackEvent, R] = (T) => R
type ActiveCallFunc = (ActiveCall) => VoiceResponse
- type DialOutcomeFunc = (CompletedCall) => Unit
+ type CallOutcomeFunc = (CompletedCall) => Unit
+ type OutgoingDialOutcomeFunc = (CompletedOutgoingDial) => VoiceResponse
// TODO: This is a hack. Used for waitUrl in ConnectToConfernce (which gives no params)
// Should have a noop or CID-only callback
@@ -48,4 +49,4 @@ trait InMemoryCallbackManager extends CallbackManager {
}
}
-}
+}
View
12 core/src/main/scala/scwilio/devices.scala
@@ -58,4 +58,14 @@ trait Phone { self: CallbackManager with Logging =>
}
}
-}
+ /**
+ * Callback when an outgoing dial (i.e., via <Dial/>) call ends.
+ */
+ def handleOutgoingDialEnded(fid: String, outcome: CompletedOutgoingDial) : VoiceResponse = {
+ log.debug("Outgoing dial ended: " + outcome)
+ getAndRemove[CompletedOutgoingDial, VoiceResponse](fid) match {
+ case Some(callback) => callback.apply(outcome)
+ case _ => Say("Sorry, an error has occured. Do not know how to handle this call.")
+ }
+ }
+}
View
2  core/src/main/scala/scwilio/twiml/TwiML.scala
@@ -34,7 +34,7 @@ object TwiML {
case dial: Dial =>
<Dial callerId={dial.from.toStandardFormat}
- action={optional(dial.onConnect)}
+ action={optional(dial.onEnd)}
timeout={dial.timeout.toString}>{dial.to.toStandardFormat}</Dial>
case conf: ConnectToConference =>
View
2  core/src/main/scala/scwilio/twiml/verbs.scala
@@ -25,7 +25,7 @@ object Verb {
case class Dial(
from: Phonenumber,
to: Phonenumber,
- onConnect: Option[String] = None,
+ onEnd: Option[String] = None,
timeout: Int = 30
) extends Verb
View
4 core/src/test/scala/scwilio/twiml/TwiMLSpec.scala
@@ -17,7 +17,7 @@ object TwiMLSpec extends Specification {
}
"generate correct XML for Dial verb - with action url" in {
- val r = Dial(from = Phonenumber("+1999"), to = Phonenumber("+1888"), onConnect=Some("http://url"))
+ val r = Dial(from = Phonenumber("+1999"), to = Phonenumber("+1888"), onEnd = Some("http://url"))
val ml = XML.loadString(TwiML(r).toString) // reload XML to remove whitespace
val expected = XML.loadString("""<Dial action="http://url" callerId="+1999" timeout="30">+1888</Dial>""")
ml must_== expected
@@ -29,7 +29,7 @@ object TwiMLSpec extends Specification {
Pause(),
Play("http://foo.com/cowbell.mp3"),
Say("Goodbye"),
- Dial(from = Phonenumber("+1999"), to = Phonenumber("+1888"), onConnect = Some("http://test")),
+ Dial(from = Phonenumber("+1999"), to = Phonenumber("+1888"), onEnd = Some("http://test")),
ConnectToConference("cid", Some("http://callback"), Some("http://wait"), muted = false, startOnEnter = false, endOnExit = false ),
Gather(timeout = 30, finishOnKey = '*', numDigits = 4, onGathered = Some("http://digits")),
Redirect("http://foo.com/")
View
27 unfiltered/src/main/scala/scwilio/uf/unfilteredphone.scala
@@ -27,16 +27,18 @@ class UnfilteredPhone(val absoluteUrlBase: String) extends Phone with InMemoryCa
case POST(Path(Seg("incoming" :: "voice" :: Nil)) & Params(p)) =>
handleIncomingCall(ActiveCall.parse(p))
- case POST(Path(Seg("callback" :: "noparam" :: fid :: Nil))) =>
+ case POST(Path(Seg("callback" :: "no-param" :: fid :: Nil))) =>
handleNoParam(fid)
- case POST(Path(Seg("callback" :: "callconnected" :: fid :: Nil)) & Params(p)) =>
+ case POST(Path(Seg("callback" :: "call-connected" :: fid :: Nil)) & Params(p)) =>
handleCallStatus(fid, ActiveCall.parse(p))
- case POST(Path(Seg("callback" :: "callended" :: fid :: Nil)) & Params(p)) =>
+ case POST(Path(Seg("callback" :: "call-ended" :: fid :: Nil)) & Params(p)) =>
handleCallEnded(fid, CompletedCall.parse(p))
Ok
+ case POST(Path(Seg("callback" :: "outgoing-dial-ended" :: fid :: Nil)) & Params(p)) =>
+ handleOutgoingDialEnded(fid, CompletedOutgoingDial.parse(p))
}
}
@@ -51,21 +53,20 @@ class UnfilteredPhone(val absoluteUrlBase: String) extends Phone with InMemoryCa
implicit def noParamCallFunc2UrlOpt(f: () => VoiceResponse) : Option[String] = {
def noParams(f: () => VoiceResponse)(x: ActiveCall) = f.apply
val callback = noParams(f) _
- makeUrl("/callback/noparam/" + register(callback))
+ makeUrl("/callback/no-param/" + register(callback))
}
- implicit def noParamCallFunc2Url(f: () => VoiceResponse) : String = {
+ implicit def noParamCallFunc2Url(f: () => VoiceResponse) : String =
noParamCallFunc2UrlOpt(f).get
- }
- implicit def activeCallFunc2Url(f: ActiveCallFunc) : Option[String] = {
- makeUrl("/callback/callconnected/" + register(f))
- }
+ implicit def activeCallFunc2Url(f: ActiveCallFunc) : Option[String] =
+ makeUrl("/callback/call-connected/" + register(f))
- implicit def dialOutcomeFunc2Url(f: DialOutcomeFunc) : Option[String] = f match {
- case g: DialOutcomeFunc => makeUrl("/callback/callended/" + register(g))
- case null => None
- }
+ implicit def callOutcomeFunc2Url(f: CallOutcomeFunc) : Option[String] =
+ makeUrl("/callback/call-ended/" + register(f))
+
+ implicit def redirectedCallOutcomeFunc2Url(f: OutgoingDialOutcomeFunc) : Option[String] =
+ makeUrl("/callback/outgoing-dial-ended/" + register(f))
}
}
Something went wrong with that request. Please try again.