1 /** 2 * @fileOverview JavaScript representation of the Finesse Dialog object. 3 * 4 * @name finesse.restservices.Dialog 5 * @requires finesse.clientservices.ClientServices 6 * @requires Class 7 * @requires finesse.FinesseBase 8 * @requires finesse.restservices.RestBase 9 */ 10 11 var finesse = finesse || {}; 12 finesse.restservices = finesse.restservices || {}; 13 14 /** @private */ 15 finesse.restservices.Dialog = finesse.restservices.RestBase.extend(/** @lends finesse.restservices.Dialog.prototype */{ 16 17 /** 18 * @class 19 * JavaScript representation of a Dialog object. Also exposes methods to operate 20 * on the object against the server. 21 * 22 * @param {Object} options 23 * An object with the following properties:<ul> 24 * <li><b>id:</b> The id of the object being constructed</li> 25 * <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li> 26 * <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li> 27 * <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li> 28 * <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li> 29 * <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul> 30 * <li><b>status:</b> {Number} The HTTP status code returned</li> 31 * <li><b>content:</b> {String} Raw string of response</li> 32 * <li><b>object:</b> {Object} Parsed object of response</li> 33 * <li><b>error:</b> {Object} Wrapped exception that was caught:<ul> 34 * <li><b>errorType:</b> {String} Type of error that was caught</li> 35 * <li><b>errorMessage:</b> {String} Message associated with error</li> 36 * </ul></li> 37 * </ul></li> 38 * <li><b>parentObj: (optional)</b> The parent object</li></ul> 39 * @constructs finesse.restservices.Dialog 40 **/ 41 init: function (options) { 42 this._super(options); 43 }, 44 45 /** 46 * @private 47 * Gets the REST class for the current object - this is the Dialog class. 48 * @returns {Object} The Dialog class. 49 */ 50 getRestClass: function () { 51 return finesse.restservices.Dialog; 52 }, 53 54 //constant for agent device 55 _agentDeviceType: "AGENT_DEVICE", 56 57 /** 58 * @private 59 * Gets the REST type for the current object - this is a "Dialog". 60 * @returns {String} The Dialog string. 61 */ 62 getRestType: function () { 63 return "Dialog"; 64 }, 65 66 /** 67 * @private 68 * Override default to indicate that this object doesn't support making 69 * requests. 70 */ 71 supportsRequests: false, 72 73 /** 74 * @private 75 * Override default to indicate that this object doesn't support subscriptions. 76 */ 77 supportsSubscriptions: false, 78 79 /** 80 * Getter for the DNIS. 81 * @returns {String} The DNIS. 82 */ 83 getDNIS: function () { 84 this.isLoaded(); 85 return this.getData().DNIS; 86 }, 87 88 /** 89 * Getter for the from address. 90 * @returns {String} The from address. 91 */ 92 getFromAddress: function () { 93 this.isLoaded(); 94 return this.getData().fromAddress; 95 }, 96 97 /** 98 * Getter for the to address. 99 * @returns {String} The to address. 100 */ 101 getToAddress: function () { 102 this.isLoaded(); 103 return this.getData().toAddress; 104 }, 105 /** 106 * Getter for the media type. 107 * @returns {String} The media type. 108 */ 109 getMediaType: function () { 110 this.isLoaded(); 111 return this.getData().mediaType; 112 }, 113 /** 114 * Getter for the uri. 115 * @returns {String} The uri. 116 */ 117 getDialogUri: function () { 118 this.isLoaded(); 119 return this.getData().uri; 120 }, 121 122 /** 123 * Getter for the callType. 124 * @returns {String} The callType. 125 */ 126 getCallType: function () { 127 this.isLoaded(); 128 return this.getData().mediaProperties.callType; 129 }, 130 131 /** 132 * Getter for the Dialog state. 133 * @returns {String} The Dialog state. 134 */ 135 getState: function () { 136 this.isLoaded(); 137 return this.getData().state; 138 }, 139 140 /** 141 * Retrieves a list of participants within the Dialog object. 142 * @returns {Object} List of 143 */ 144 getParticipants: function () { 145 this.isLoaded(); 146 var participants = this.getData().participants.Participant; 147 //Due to the nature of the XML->JSO converter library, a single 148 //element in the XML array will be considered to an object instead of 149 //a real array. This will handle those cases to ensure that an array is 150 //always returned. 151 152 return finesse.utilities.Utilities.getArray(participants); 153 }, 154 155 /** 156 * Determines the droppable participants. A droppable participant is a participant that is an agent extension. 157 * (It is not a CTI Route Point, IVR Port, or the caller) 158 * 159 * @param filterExtension used to remove a single extension from the list 160 * @returns participants which is an array of all participants which can be dropped 161 */ 162 getDroppableParticipants: function (filterExtension) { 163 this.isLoaded(); 164 var droppableParticipants = [], participants, index, idx, filterExtensionToRemove = "", callStateOk, part; 165 166 participants = this.getParticipants(); 167 168 if (filterExtension) 169 { 170 filterExtensionToRemove = filterExtension; 171 } 172 173 //Loop through all the participants to remove non-agents & remove filterExtension 174 //We could have removed filterExtension using splice, but we have to iterate through 175 //the list anyway. 176 for(idx=0;idx<participants.length;idx=idx+1) 177 { 178 part = participants[idx]; 179 180 //Skip the filterExtension 181 if (part.mediaAddress !== filterExtensionToRemove) 182 { 183 callStateOk = this._isParticipantStateDroppable(part); 184 185 //Remove non-agents & make sure callstate 186 if (callStateOk === true && part.mediaAddressType === this._agentDeviceType) 187 { 188 droppableParticipants.push(part); 189 } 190 } 191 } 192 193 return finesse.utilities.Utilities.getArray(droppableParticipants); 194 }, 195 196 _isParticipantStateDroppable : function (part) 197 { 198 var isParticipantStateDroppable = false; 199 if (part.state === finesse.restservices.Dialog.States.ACTIVE || part.state === finesse.restservices.Dialog.States.ACCEPTED || part.state === finesse.restservices.Dialog.States.HELD) 200 { 201 isParticipantStateDroppable = true; 202 } 203 204 return isParticipantStateDroppable; 205 }, 206 207 /** 208 * Is the participant droppable 209 * 210 * @param participantExt 211 * @returns boolean 212 */ 213 isParticipantDroppable : function (participantExt) { 214 var droppableParticipants = null, isDroppable = false, idx, part, callStateOk; 215 216 droppableParticipants = this.getDroppableParticipants(); 217 218 if (droppableParticipants) 219 { 220 for(idx=0;idx<droppableParticipants.length;idx=idx+1) 221 { 222 part = droppableParticipants[idx]; 223 224 if (part.mediaAddress === participantExt) 225 { 226 callStateOk = this._isParticipantStateDroppable(part); 227 228 //Remove non-agents & make sure callstate 229 if (callStateOk === true && part.mediaAddressType === this._agentDeviceType) 230 { 231 isDroppable = true; 232 break; 233 } 234 } 235 } 236 } 237 238 return isDroppable; 239 }, 240 241 /** 242 * Retrieves a list of media properties a.k.a. call variables from the dialog object 243 * @returns {Object} Map of call variables; names mapped to values 244 */ 245 getMediaProperties: function () { 246 247 var mpData, resultMap = {}; 248 249 this.isLoaded(); 250 251 mpData = this.getData().mediaProperties; 252 253 if (mpData) { 254 255 if (this.getState() !== finesse.restservices.Dialog.States.INITIATING) { 256 257 if (mpData.callvariables && mpData.callvariables.CallVariable) { 258 jQuery.each(mpData.callvariables.CallVariable, function (i, callVariable) { 259 resultMap[callVariable.name] = callVariable.value; 260 }); 261 } 262 263 } 264 265 if (mpData.wrapUpReason) { 266 resultMap.wrapUpReason = mpData.wrapUpReason; 267 } 268 269 } 270 271 return resultMap; 272 }, 273 274 /** 275 * @private 276 * Invoke a request to the server given a content body and handlers. 277 * 278 * @param {Object} contentBody 279 * A JS object containing the body of the action request. 280 * @param {Object} handlers 281 * An object containing the following (optional) handlers for the request:<ul> 282 * <li><b>success(rsp):</b> A callback function for a successful request to be invoked with the following 283 * response object as its only parameter:<ul> 284 * <li><b>status:</b> {Number} The HTTP status code returned</li> 285 * <li><b>content:</b> {String} Raw string of response</li> 286 * <li><b>object:</b> {Object} Parsed object of response</li></ul> 287 * <li>A error callback function for an unsuccessful request to be invoked with the 288 * error response object as its only parameter:<ul> 289 * <li><b>status:</b> {Number} The HTTP status code returned</li> 290 * <li><b>content:</b> {String} Raw string of response</li> 291 * <li><b>object:</b> {Object} Parsed object of response (HTTP errors)</li> 292 * <li><b>error:</b> {Object} Wrapped exception that was caught:<ul> 293 * <li><b>errorType:</b> {String} Type of error that was caught</li> 294 * <li><b>errorMessage:</b> {String} Message associated with error</li> 295 * </ul></li> 296 * </ul> 297 */ 298 _makeRequest: function (contentBody, handlers) { 299 // Protect against null dereferencing of options allowing its 300 // (nonexistant) keys to be read as undefined 301 handlers = handlers || {}; 302 303 this.restRequest(this.getRestUrl(), { 304 method: 'PUT', 305 success: handlers.success, 306 error: handlers.error, 307 content: contentBody 308 }); 309 }, 310 311 /** 312 * Invoke a consult call out to a destination. 313 * 314 * @param {String} mediaAddress 315 * The media address of the user performing the consult call. 316 * @param {String} toAddress 317 * The destination address of the consult call. 318 * @param {Object} handlers 319 * An object containing the following (optional) handlers for the request:<ul> 320 * <li><b>success(rsp):</b> A callback function for a successful request to be invoked with the following 321 * response object as its only parameter:<ul> 322 * <li><b>status:</b> {Number} The HTTP status code returned</li> 323 * <li><b>content:</b> {String} Raw string of response</li> 324 * <li><b>object:</b> {Object} Parsed object of response</li></ul> 325 * <li>A error callback function for an unsuccessful request to be invoked with the 326 * error response object as its only parameter:<ul> 327 * <li><b>status:</b> {Number} The HTTP status code returned</li> 328 * <li><b>content:</b> {String} Raw string of response</li> 329 * <li><b>object:</b> {Object} Parsed object of response (HTTP errors)</li> 330 * <li><b>error:</b> {Object} Wrapped exception that was caught:<ul> 331 * <li><b>errorType:</b> {String} Type of error that was caught</li> 332 * <li><b>errorMessage:</b> {String} Message associated with error</li> 333 * </ul></li> 334 * </ul> 335 */ 336 makeConsultCall: function (mediaAddress, toAddress, handlers) { 337 this.isLoaded(); 338 var contentBody = {}; 339 contentBody[this.getRestType()] = { 340 "targetMediaAddress": mediaAddress, 341 "toAddress": toAddress, 342 "requestedAction": finesse.restservices.Dialog.Actions.CONSULT_CALL 343 }; 344 this._makeRequest(contentBody, handlers); 345 return this; // Allow cascading 346 }, 347 348 /** 349 * Invoke a single step transfer request. 350 * 351 * @param {String} mediaAddress 352 * The media address of the user performing the single step transfer. 353 * @param {String} toAddress 354 * The destination address of the single step transfer. 355 * @param {Object} handlers 356 * An object containing the following (optional) handlers for the request:<ul> 357 * <li><b>success(rsp):</b> A callback function for a successful request to be invoked with the following 358 * response object as its only parameter:<ul> 359 * <li><b>status:</b> {Number} The HTTP status code returned</li> 360 * <li><b>content:</b> {String} Raw string of response</li> 361 * <li><b>object:</b> {Object} Parsed object of response</li></ul> 362 * <li>A error callback function for an unsuccessful request to be invoked with the 363 * error response object as its only parameter:<ul> 364 * <li><b>status:</b> {Number} The HTTP status code returned</li> 365 * <li><b>content:</b> {String} Raw string of response</li> 366 * <li><b>object:</b> {Object} Parsed object of response (HTTP errors)</li> 367 * <li><b>error:</b> {Object} Wrapped exception that was caught:<ul> 368 * <li><b>errorType:</b> {String} Type of error that was caught</li> 369 * <li><b>errorMessage:</b> {String} Message associated with error</li> 370 * </ul></li> 371 * </ul> 372 */ 373 initiateDirectTransfer: function (mediaAddress, toAddress, handlers) { 374 this.isLoaded(); 375 var contentBody = {}; 376 contentBody[this.getRestType()] = { 377 "targetMediaAddress": mediaAddress, 378 "toAddress": toAddress, 379 "requestedAction": finesse.restservices.Dialog.Actions.TRANSFER_SST 380 }; 381 this._makeRequest(contentBody, handlers); 382 return this; // Allow cascading 383 }, 384 385 /** 386 * Update this dialog's wrap-up reason. 387 * 388 * @param {String} wrapUpReason 389 * The new wrap-up reason for this dialog 390 * @param {Object} handlers 391 * An object containing the following (optional) handlers for the request:<ul> 392 * <li><b>success(rsp):</b> A callback function for a successful request to be invoked with the following 393 * response object as its only parameter:<ul> 394 * <li><b>status:</b> {Number} The HTTP status code returned</li> 395 * <li><b>content:</b> {String} Raw string of response</li> 396 * <li><b>object:</b> {Object} Parsed object of response</li></ul> 397 * <li>A error callback function for an unsuccessful request to be invoked with the 398 * error response object as its only parameter:<ul> 399 * <li><b>status:</b> {Number} The HTTP status code returned</li> 400 * <li><b>content:</b> {String} Raw string of response</li> 401 * <li><b>object:</b> {Object} Parsed object of response (HTTP errors)</li> 402 * <li><b>error:</b> {Object} Wrapped exception that was caught:<ul> 403 * <li><b>errorType:</b> {String} Type of error that was caught</li> 404 * <li><b>errorMessage:</b> {String} Message associated with error</li> 405 * </ul></li> 406 * </ul> 407 */ 408 updateWrapUpReason: function (wrapUpReason, options) 409 { 410 this.isLoaded(); 411 var mediaProperties = 412 { 413 "wrapUpReason": wrapUpReason 414 }; 415 416 options = options || {}; 417 options.content = {}; 418 options.content[this.getRestType()] = 419 { 420 "mediaProperties": mediaProperties, 421 "requestedAction": finesse.restservices.Dialog.Actions.UPDATE_CALL_DATA 422 }; 423 options.method = "PUT"; 424 this.restRequest(this.getRestUrl(), options); 425 426 return this; 427 }, 428 429 /** 430 * Invoke a request to server based on the action given. 431 * @param {String} mediaAddress 432 * The media address of the user performing the consult call. 433 * @param {String} action 434 * The action string indicating the action to invoke on dialog. 435 * @param {Object} handlers 436 * An object containing the following (optional) handlers for the request:<ul> 437 * <li><b>success(rsp):</b> A callback function for a successful request to be invoked with the following 438 * response object as its only parameter:<ul> 439 * <li><b>status:</b> {Number} The HTTP status code returned</li> 440 * <li><b>content:</b> {String} Raw string of response</li> 441 * <li><b>object:</b> {Object} Parsed object of response</li></ul> 442 * <li>A error callback function for an unsuccessful request to be invoked with the 443 * error response object as its only parameter:<ul> 444 * <li><b>status:</b> {Number} The HTTP status code returned</li> 445 * <li><b>content:</b> {String} Raw string of response</li> 446 * <li><b>object:</b> {Object} Parsed object of response (HTTP errors)</li> 447 * <li><b>error:</b> {Object} Wrapped exception that was caught:<ul> 448 * <li><b>errorType:</b> {String} Type of error that was caught</li> 449 * <li><b>errorMessage:</b> {String} Message associated with error</li> 450 * </ul></li> 451 * </ul> 452 * @private 453 */ 454 requestAction: function (mediaAddress, action, handlers) { 455 this.isLoaded(); 456 var contentBody = {}; 457 contentBody[this.getRestType()] = { 458 "targetMediaAddress": mediaAddress, 459 "requestedAction": action 460 }; 461 this._makeRequest(contentBody, handlers); 462 return this; // Allow cascading 463 }, 464 465 /** 466 * Wrapper around "requestAction" to request PARTICIPANT_DROP action. 467 * 468 * @param targetMediaAddress is the address to drop 469 * @param handlers to be invoked on success/error 470 * @private 471 */ 472 dropParticipant: function (targetMediaAddress, handlers) { 473 this.requestAction(targetMediaAddress, finesse.restservices.Dialog.Actions.PARTICIPANT_DROP, handlers); 474 }, 475 476 /** 477 * Invoke a request to server based on the action given. 478 * @param {String} mediaAddress 479 * @param {String} action 480 * The action string indicating the action to invoke on dialog. 481 * @param {Object} [handlers] 482 * A set of handlers invoked when async response comes back. 483 * @param {Function} [handlers.success] 484 * The success handler when request is successful. 485 * @param {Function} [hanlders.error] 486 * The error handler when request has errors. 487 * @private 488 */ 489 sendDTMFRequest: function (mediaAddress, handlers, digit) { 490 this.isLoaded(); 491 var contentBody = {}; 492 contentBody[this.getRestType()] = { 493 "targetMediaAddress": mediaAddress, 494 "requestedAction": "SEND_DTMF", 495 "actionParams": { 496 "ActionParam": { 497 "name": "dtmfString", 498 "value": digit 499 } 500 } 501 }; 502 this._makeRequest(contentBody, handlers); 503 return this; // Allow cascading 504 } 505 }); 506 507 /** 508 * Possible dialog state constants. 509 */ 510 finesse.restservices.Dialog.States = { 511 ALERTING: "ALERTING", 512 INITIATING: "INITIATING", 513 ACTIVE: "ACTIVE", 514 DROPPED: "DROPPED", 515 HELD: "HELD", 516 INITIATED: "INITIATED", 517 FAILED: "FAILED", 518 INACTIVE: "INACTIVE", 519 WRAP_UP: "WRAP_UP", 520 ACCEPTED: "ACCEPTED" 521 }; 522 523 /** 524 * Possible dialog state reasons code constants. 525 */ 526 finesse.restservices.Dialog.ReasonStates = { 527 BUSY: "BUSY", 528 BAD_DESTINATION: "BAD_DESTINATION", 529 OTHER: "OTHER", 530 DEVICE_RESOURCE_NOT_AVAILABLE : "DEVICE_RESOURCE_NOT_AVAILABLE" 531 }; 532 533 /** 534 * Possible participant actions constants. 535 */ 536 finesse.restservices.Dialog.Actions = { 537 DROP: "DROP", 538 ANSWER: "ANSWER", 539 HOLD: "HOLD", 540 BARGE_CALL: "BARGE_CALL", 541 PARTICIPANT_DROP: "PARTICIPANT_DROP", 542 MAKE_CALL: "MAKE_CALL", 543 RETRIEVE: "RETRIEVE", 544 CONSULT_CALL: "CONSULT_CALL", 545 TRANSFER: "TRANSFER", 546 TRANSFER_SST: "TRANSFER_SST", 547 CONFERENCE: "CONFERENCE", 548 UPDATE_CALL_DATA: "UPDATE_CALL_DATA", 549 DTMF : "SEND_DTMF", 550 ACCEPT: "ACCEPT", 551 REJECT: "REJECT", 552 CLOSE : "CLOSE" 553 }; 554