1 /** 2 * @fileOverview JavaScript representation of the Finesse User object 3 * 4 * @name finesse.restservices.User 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.User = finesse.restservices.RestBase.extend(/** @lends finesse.restservices.User.prototype */{ 16 17 _dialogs : null, 18 _wrapUpReasons : null, 19 _mediaPropertiesLayout : null, 20 21 /** 22 * @class 23 * JavaScript representation of a User object. Also exposes methods to operate 24 * on the object against the server. 25 * 26 * @param {Object} options 27 * An object with the following properties:<ul> 28 * <li><b>id:</b> The id of the object being constructed</li> 29 * <li><b>onLoad(this): (optional)</b> when the object is successfully loaded from the server</li> 30 * <li><b>onChange(this): (optional)</b> when an update notification of the object is received</li> 31 * <li><b>onAdd(this): (optional)</b> when a notification that the object is created is received</li> 32 * <li><b>onDelete(this): (optional)</b> when a notification that the object is deleted is received</li> 33 * <li><b>onError(rsp): (optional)</b> if loading of the object fails, invoked with the error response object:<ul> 34 * <li><b>status:</b> {Number} The HTTP status code returned</li> 35 * <li><b>content:</b> {String} Raw string of response</li> 36 * <li><b>object:</b> {Object} Parsed object of response</li> 37 * <li><b>error:</b> {Object} Wrapped exception that was caught:<ul> 38 * <li><b>errorType:</b> {String} Type of error that was caught</li> 39 * <li><b>errorMessage:</b> {String} Message associated with error</li> 40 * </ul></li> 41 * </ul></li> 42 * <li><b>parentObj: (optional)</b> The parent object</li></ul> 43 * @constructs finesse.restservices.User 44 **/ 45 init: function (options) { 46 this._super(options); 47 }, 48 49 /** 50 * @private 51 * Gets the REST class for the current object - this is the User object. 52 */ 53 getRestClass: function () { 54 return finesse.restservices.User; 55 }, 56 57 /** 58 * @private 59 * Gets the REST type for the current object - this is a "User". 60 */ 61 getRestType: function () { 62 return "User"; 63 }, 64 65 /** 66 * @private 67 * Returns whether this object supports subscriptions 68 */ 69 supportsSubscriptions: function () { 70 return true; 71 }, 72 73 /** 74 * Getter for the firstName of this User 75 * @returns {String} 76 * The firstName for this User 77 */ 78 getFirstName: function () { 79 this.isLoaded(); 80 return this.getData().firstName; 81 }, 82 83 /** 84 * Getter for the lastName of this User 85 * @returns {String} 86 * The lastName for this User 87 */ 88 getLastName: function () { 89 this.isLoaded(); 90 return this.getData().lastName; 91 }, 92 93 /** 94 * Getter for the extension of this User 95 * @returns {String} 96 * The extension, if any, of this User 97 */ 98 getExtension: function () { 99 this.isLoaded(); 100 return this.getData().extension; 101 }, 102 103 /** 104 * Is user an agent? 105 * @returns {boolean} if user has role of agent 106 */ 107 hasAgentRole: function () { 108 this.isLoaded(); 109 return this.hasRole("Agent"); 110 }, 111 112 /** 113 * Is user a supervisor? 114 * @returns {boolean} if user has role of supervisor 115 */ 116 hasSupervisorRole: function () { 117 this.isLoaded(); 118 return this.hasRole("Supervisor"); 119 }, 120 121 /** 122 * Checks to see if user has "theRole" 123 * @returns {boolean} 124 */ 125 hasRole: function (theRole) { 126 this.isLoaded(); 127 var result = false, i, roles, len; 128 129 roles = this.getData().roles.role; 130 len = roles.length; 131 if (typeof roles === 'string') { 132 if (roles === theRole) { 133 result = true; 134 } 135 } else { 136 for (i = 0; i < len ; i = i + 1) { 137 if (roles[i] === theRole) { 138 result = true; 139 break; 140 } 141 } 142 } 143 144 return result; 145 }, 146 147 /** 148 * Getter for the state of this User 149 * @returns {String} 150 * The current (or last fetched) state of this User 151 */ 152 getState: function () { 153 this.isLoaded(); 154 return this.getData().state; 155 }, 156 157 /** 158 * Getter for a Dialogs collection object that is associated with User. 159 * @returns {Dialogs} 160 * A Dialogs collection object. 161 */ 162 getDialogs: function (callbacks) { 163 var options = callbacks || {}; 164 options.parentObj = this; 165 this.isLoaded(); 166 167 if (this._dialogs === null) { 168 this._dialogs = new finesse.restservices.Dialogs(options); 169 } 170 171 return this._dialogs; 172 }, 173 174 /** 175 * Getter for a WrapUpReasons collection object that is associated with User. 176 * @param handlers 177 * @returns {WrapUpReasons} 178 * A WrapUpReasons collection object. 179 */ 180 getWrapUpReasons: function (callbacks) { 181 var options = callbacks || {}; 182 options.parentObj = this; 183 this.isLoaded(); 184 185 if (this._wrapUpReasons === null) { 186 this._wrapUpReasons = new finesse.restservices.WrapUpReasons(options); 187 } 188 189 return this._wrapUpReasons; 190 }, 191 192 /** 193 * Getter for a MediaPropertiesLayout object that is associated with User. 194 * @returns {finesse.restservices.MediaPropertiesLayout} 195 * The MediaPropertiesLayout object associated with this user 196 */ 197 getMediaPropertiesLayout: function (callbacks) { 198 var options = callbacks || {}; 199 options.parentObj = this; 200 options.id = this._id; 201 202 this.isLoaded(); 203 if (this._mediaPropertiesLayout === null) { 204 this._mediaPropertiesLayout = new finesse.restservices.MediaPropertiesLayout(options); 205 } 206 return this._mediaPropertiesLayout; 207 }, 208 209 /** 210 * Getter for the supervised Teams this User (Supervisor) supervises, if any 211 * @returns {Array} 212 * An array of teams supervised by this User (Supervisor) 213 */ 214 getSupervisedTeams: function () { 215 this.isLoaded(); 216 217 try { 218 return finesse.utilities.Utilities.getArray(this.getData().teams.Team); 219 } catch (e) { 220 return []; 221 } 222 223 }, 224 225 /** 226 * Perform an agent login for this user, associating him with the 227 * specified extension. 228 * @param {String} extension 229 * The extension to associate with this user 230 * @param {Object} handlers 231 * An object containing the following (optional) handlers for the request:<ul> 232 * <li><b>success(rsp):</b> A callback function for a successful request to be invoked with the following 233 * response object as its only parameter:<ul> 234 * <li><b>status:</b> {Number} The HTTP status code returned</li> 235 * <li><b>content:</b> {String} Raw string of response</li> 236 * <li><b>object:</b> {Object} Parsed object of response</li></ul> 237 * <li>A error callback function for an unsuccessful request to be invoked with the 238 * error response object as its only parameter:<ul> 239 * <li><b>status:</b> {Number} The HTTP status code returned</li> 240 * <li><b>content:</b> {String} Raw string of response</li> 241 * <li><b>object:</b> {Object} Parsed object of response (HTTP errors)</li> 242 * <li><b>error:</b> {Object} Wrapped exception that was caught:<ul> 243 * <li><b>errorType:</b> {String} Type of error that was caught</li> 244 * <li><b>errorMessage:</b> {String} Message associated with error</li> 245 * </ul></li> 246 * </ul> 247 * @returns {finesse.restservices.User} 248 * This User object to allow cascading 249 */ 250 login: function (extension, handlers) { 251 this.isLoaded(); 252 253 var contentBody = {}; 254 contentBody[this.getRestType()] = { 255 "state": finesse.restservices.User.States.LOGIN, 256 "extension": extension 257 }; 258 259 // Protect against null dereferencing of options allowing its (nonexistant) keys to be read as undefined 260 handlers = handlers || {}; 261 262 this.restRequest(this.getRestUrl(), { 263 method: 'PUT', 264 success: handlers.success, 265 error: handlers.error, 266 content: contentBody 267 }); 268 269 return this; // Allow cascading 270 }, 271 272 /** 273 * Perform an agent logout for this user. 274 * @param {String} reasonCode 275 * The reason this user is logging out. Pass null for no reason. 276 * @param {Object} handlers 277 * An object containing the following (optional) handlers for the request:<ul> 278 * <li><b>success(rsp):</b> A callback function for a successful request to be invoked with the following 279 * response object as its only parameter:<ul> 280 * <li><b>status:</b> {Number} The HTTP status code returned</li> 281 * <li><b>content:</b> {String} Raw string of response</li> 282 * <li><b>object:</b> {Object} Parsed object of response</li></ul> 283 * <li>A error callback function for an unsuccessful request to be invoked with the 284 * error response object as its only parameter:<ul> 285 * <li><b>status:</b> {Number} The HTTP status code returned</li> 286 * <li><b>content:</b> {String} Raw string of response</li> 287 * <li><b>object:</b> {Object} Parsed object of response (HTTP errors)</li> 288 * <li><b>error:</b> {Object} Wrapped exception that was caught:<ul> 289 * <li><b>errorType:</b> {String} Type of error that was caught</li> 290 * <li><b>errorMessage:</b> {String} Message associated with error</li> 291 * </ul></li> 292 * </ul> 293 * @returns {finesse.restservices.User} 294 * This User object to allow cascading 295 */ 296 logout: function (reasonCode, handlers) { 297 return this.setState("LOGOUT", reasonCode, handlers); 298 }, 299 300 /** 301 * Set the state of the user. 302 * @param {String} newState 303 * The state you are setting 304 * @param {ReasonCode} reasonCode 305 * The reason this user is logging out. Pass null for no reason. 306 * @param {Object} handlers 307 * An object containing the following (optional) handlers for the request:<ul> 308 * <li><b>success(rsp):</b> A callback function for a successful request to be invoked with the following 309 * response object as its only parameter:<ul> 310 * <li><b>status:</b> {Number} The HTTP status code returned</li> 311 * <li><b>content:</b> {String} Raw string of response</li> 312 * <li><b>object:</b> {Object} Parsed object of response</li></ul> 313 * <li>A error callback function for an unsuccessful request to be invoked with the 314 * error response object as its only parameter:<ul> 315 * <li><b>status:</b> {Number} The HTTP status code returned</li> 316 * <li><b>content:</b> {String} Raw string of response</li> 317 * <li><b>object:</b> {Object} Parsed object of response (HTTP errors)</li> 318 * <li><b>error:</b> {Object} Wrapped exception that was caught:<ul> 319 * <li><b>errorType:</b> {String} Type of error that was caught</li> 320 * <li><b>errorMessage:</b> {String} Message associated with error</li> 321 * </ul></li> 322 * </ul> 323 * @returns {finesse.restservices.User} 324 * This User object to allow cascading 325 */ 326 setState: function (newState, reasonCode, handlers) { 327 this.isLoaded(); 328 329 var options, contentBody = {}; 330 331 if (!reasonCode) { 332 contentBody[this.getRestType()] = { 333 "state": newState 334 }; 335 } else { 336 contentBody[this.getRestType()] = { 337 "state": newState, 338 "reasonCodeId": reasonCode.id 339 }; 340 } 341 342 // Protect against null dereferencing of options allowing its (nonexistant) keys to be read as undefined 343 handlers = handlers || {}; 344 345 options = { 346 method: 'PUT', 347 success: handlers.success, 348 error: handlers.error, 349 content: contentBody 350 }; 351 352 // After removing the selective 202 handling, we should be able to just use restRequest 353 this.restRequest(this.getRestUrl(), options); 354 355 return this; // Allow cascading 356 }, 357 358 /** 359 * Make call to a particular phone number. 360 * 361 * @param {String} The number to call 362 * @param {Object} handlers 363 * An object containing the following (optional) handlers for the request:<ul> 364 * <li><b>success(rsp):</b> A callback function for a successful request to be invoked with the following 365 * response object as its only parameter:<ul> 366 * <li><b>status:</b> {Number} The HTTP status code returned</li> 367 * <li><b>content:</b> {String} Raw string of response</li> 368 * <li><b>object:</b> {Object} Parsed object of response</li></ul> 369 * <li>A error callback function for an unsuccessful request to be invoked with the 370 * error response object as its only parameter:<ul> 371 * <li><b>status:</b> {Number} The HTTP status code returned</li> 372 * <li><b>content:</b> {String} Raw string of response</li> 373 * <li><b>object:</b> {Object} Parsed object of response (HTTP errors)</li> 374 * <li><b>error:</b> {Object} Wrapped exception that was caught:<ul> 375 * <li><b>errorType:</b> {String} Type of error that was caught</li> 376 * <li><b>errorMessage:</b> {String} Message associated with error</li> 377 * </ul></li> 378 * </ul> 379 */ 380 makeCall: function (number, handlers) { 381 this.isLoaded(); 382 383 this.getDialogs().createNewCallDialog(number, this.getExtension(), handlers); 384 385 return this; // Allow cascading 386 }, 387 388 /** 389 * Make a silent monitor call to a particular agent's phone number. 390 * 391 * @param number to call 392 * @param {Object} handlers 393 * An object containing the following (optional) handlers for the request:<ul> 394 * <li><b>success(rsp):</b> A callback function for a successful request to be invoked with the following 395 * response object as its only parameter:<ul> 396 * <li><b>status:</b> {Number} The HTTP status code returned</li> 397 * <li><b>content:</b> {String} Raw string of response</li> 398 * <li><b>object:</b> {Object} Parsed object of response</li></ul> 399 * <li>A error callback function for an unsuccessful request to be invoked with the 400 * error response object as its only parameter:<ul> 401 * <li><b>status:</b> {Number} The HTTP status code returned</li> 402 * <li><b>content:</b> {String} Raw string of response</li> 403 * <li><b>object:</b> {Object} Parsed object of response (HTTP errors)</li> 404 * <li><b>error:</b> {Object} Wrapped exception that was caught:<ul> 405 * <li><b>errorType:</b> {String} Type of error that was caught</li> 406 * <li><b>errorMessage:</b> {String} Message associated with error</li> 407 * </ul></li> 408 * </ul> 409 */ 410 makeSMCall: function (number, handlers) { 411 this.isLoaded(); 412 413 var actionType = "SILENT_MONITOR"; 414 415 this.getDialogs().createNewSuperviseCallDialog(number, this.getExtension(), actionType, handlers); 416 417 return this; // Allow cascading 418 }, 419 420 /** 421 * Returns true if the user is in the HOLD or TALKING state. 422 */ 423 isOnHoldOrTalking: function () { 424 var state = this.getState(); 425 return state && ((state === finesse.restservices.User.States.TALKING) || (state === finesse.restservices.User.States.HOLD)); 426 }, 427 428 /** 429 * Parses a uriString to retrieve the id portion 430 * @param {String} uriString 431 * @return {String} id 432 */ 433 _parseIdFromUriString : function (uriString) { 434 return finesse.utilities.Utilities.getId(uriString); 435 }, 436 437 /** 438 * Gets the user's Not Ready reason code. 439 * @return undefined if not set or indeterminate 440 */ 441 getNotReadyReasonCodeId : function () { 442 this.isLoaded(); 443 444 var reasoncodeIdResult, finesseServerReasonCodeId; 445 finesseServerReasonCodeId = this.getData().reasonCodeId; 446 447 //FinesseServer will give "-l" => we will set to undefined (for convenience) 448 if (finesseServerReasonCodeId !== "-1") { 449 reasoncodeIdResult = finesseServerReasonCodeId; 450 } 451 452 return reasoncodeIdResult; 453 }, 454 455 /** 456 * Performs a GET against the Finesse server looking up the reasonCodeId specified. 457 * @param {Object} handlers 458 * An object containing the following (optional) handlers for the request:<ul> 459 * <li><b>success(rsp):</b> A callback function for a successful request to be invoked with the following 460 * response object as its only parameter:<ul> 461 * <li><b>status:</b> {Number} The HTTP status code returned</li> 462 * <li><b>content:</b> {String} Raw string of response</li> 463 * <li><b>object:</b> {Object} Parsed object of response</li></ul> 464 * <li>A error callback function for an unsuccessful request to be invoked with the 465 * error response object as its only parameter:<ul> 466 * <li><b>status:</b> {Number} The HTTP status code returned</li> 467 * <li><b>content:</b> {String} Raw string of response</li> 468 * <li><b>object:</b> {Object} Parsed object of response (HTTP errors)</li> 469 * <li><b>error:</b> {Object} Wrapped exception that was caught:<ul> 470 * <li><b>errorType:</b> {String} Type of error that was caught</li> 471 * <li><b>errorMessage:</b> {String} Message associated with error</li> 472 * </ul></li> 473 * </ul> 474 * @param {String} reasonCodeId is the id for the reason code to lookup 475 */ 476 getReasonCodeById : function (handlers, reasonCodeId) 477 { 478 var self = this, contentBody, reasonCode, url; 479 contentBody = {}; 480 481 url = this.getRestUrl() + "/ReasonCode/" + reasonCodeId; 482 this.restRequest(url, { 483 method: 'GET', 484 success: function (rsp) { 485 reasonCode = { 486 uri: rsp.object.ReasonCode.uri, 487 label: rsp.object.ReasonCode.label, 488 id: self._parseIdFromUriString(rsp.object.ReasonCode.uri) 489 }; 490 handlers.success(reasonCode); 491 }, 492 error: function (rsp) { 493 handlers.error(rsp); 494 }, 495 content: contentBody 496 }); 497 }, 498 499 /** 500 * Performs a GET against Finesse server retrieving all the specified type of reason codes. 501 * @param {String} type (LOGOUT or NOT_READY) 502 * @param {Object} handlers 503 * An object containing the following (optional) handlers for the request:<ul> 504 * <li><b>success(rsp):</b> A callback function for a successful request to be invoked with the following 505 * response object as its only parameter:<ul> 506 * <li><b>status:</b> {Number} The HTTP status code returned</li> 507 * <li><b>content:</b> {String} Raw string of response</li> 508 * <li><b>object:</b> {Object} Parsed object of response</li></ul> 509 * <li>A error callback function for an unsuccessful request to be invoked with the 510 * error response object as its only parameter:<ul> 511 * <li><b>status:</b> {Number} The HTTP status code returned</li> 512 * <li><b>content:</b> {String} Raw string of response</li> 513 * <li><b>object:</b> {Object} Parsed object of response (HTTP errors)</li> 514 * <li><b>error:</b> {Object} Wrapped exception that was caught:<ul> 515 * <li><b>errorType:</b> {String} Type of error that was caught</li> 516 * <li><b>errorMessage:</b> {String} Message associated with error</li> 517 * </ul></li> 518 * </ul> 519 */ 520 _getReasonCodesByType : function (type, handlers) 521 { 522 var self = this, contentBody = {}, result = [], url, reasonCodes, i, reasonCodeArray; 523 524 url = this.getRestUrl() + "/ReasonCodes?category=" + type; 525 this.restRequest(url, { 526 method: 'GET', 527 success: function (rsp) { 528 reasonCodes = []; 529 530 reasonCodeArray = rsp.object.ReasonCodes.ReasonCode; 531 if (reasonCodeArray === undefined) { 532 reasonCodes = undefined; 533 } else if (reasonCodeArray[0] !== undefined) { 534 for (i = 0; i < reasonCodeArray.length; i = i + 1) { 535 reasonCodes[i] = { 536 label: rsp.object.ReasonCodes.ReasonCode[i].label, 537 id: self._parseIdFromUriString(rsp.object.ReasonCodes.ReasonCode[i].uri) 538 }; 539 } 540 } else { 541 reasonCodes[0] = { 542 label: rsp.object.ReasonCodes.ReasonCode.label, 543 id: self._parseIdFromUriString(rsp.object.ReasonCodes.ReasonCode.uri) 544 }; 545 } 546 handlers.success(reasonCodes); 547 }, 548 error: function (rsp) { 549 handlers.error(rsp); 550 }, 551 content: contentBody 552 }); 553 }, 554 555 /** 556 * Performs a GET against Finesse server retrieving all the Signout reason codes. 557 * @param {Object} handlers 558 * An object containing the following (optional) handlers for the request:<ul> 559 * <li><b>success(rsp):</b> A callback function for a successful request to be invoked with the following 560 * response object as its only parameter:<ul> 561 * <li><b>status:</b> {Number} The HTTP status code returned</li> 562 * <li><b>content:</b> {String} Raw string of response</li> 563 * <li><b>object:</b> {Object} Parsed object of response</li></ul> 564 * <li>A error callback function for an unsuccessful request to be invoked with the 565 * error response object as its only parameter:<ul> 566 * <li><b>status:</b> {Number} The HTTP status code returned</li> 567 * <li><b>content:</b> {String} Raw string of response</li> 568 * <li><b>object:</b> {Object} Parsed object of response (HTTP errors)</li> 569 * <li><b>error:</b> {Object} Wrapped exception that was caught:<ul> 570 * <li><b>errorType:</b> {String} Type of error that was caught</li> 571 * <li><b>errorMessage:</b> {String} Message associated with error</li> 572 * </ul></li> 573 * </ul> 574 */ 575 getSignoutReasonCodes : function (handlers) 576 { 577 this._getReasonCodesByType("LOGOUT", handlers); 578 }, 579 580 /** 581 * Performs a GET against Finesse server retrieving all the Not Ready reason codes. 582 * @param {Object} handlers 583 * An object containing the following (optional) handlers for the request:<ul> 584 * <li><b>success(rsp):</b> A callback function for a successful request to be invoked with the following 585 * response object as its only parameter:<ul> 586 * <li><b>status:</b> {Number} The HTTP status code returned</li> 587 * <li><b>content:</b> {String} Raw string of response</li> 588 * <li><b>object:</b> {Object} Parsed object of response</li></ul> 589 * <li>A error callback function for an unsuccessful request to be invoked with the 590 * error response object as its only parameter:<ul> 591 * <li><b>status:</b> {Number} The HTTP status code returned</li> 592 * <li><b>content:</b> {String} Raw string of response</li> 593 * <li><b>object:</b> {Object} Parsed object of response (HTTP errors)</li> 594 * <li><b>error:</b> {Object} Wrapped exception that was caught:<ul> 595 * <li><b>errorType:</b> {String} Type of error that was caught</li> 596 * <li><b>errorMessage:</b> {String} Message associated with error</li> 597 * </ul></li> 598 * </ul> 599 */ 600 getNotReadyReasonCodes : function (handlers) 601 { 602 this._getReasonCodesByType("NOT_READY", handlers); 603 } 604 605 }); 606 607 /** 608 * State constants 609 */ 610 finesse.restservices.User.States = { 611 LOGIN: "LOGIN", 612 LOGOUT: "LOGOUT", 613 NOT_READY: "NOT_READY", 614 READY: "READY", 615 RESERVED: "RESERVED", 616 TALKING: "TALKING", 617 HOLD: "HOLD", 618 WORK: "WORK", 619 WORK_READY: "WORK_READY" 620 }; 621