"use strict"; /** * Jabber connection and data transport Class * */ (function () { 'use strict'; angular.module('myitsmApp') .factory("chatService", ['chatDefaults', 'userModel', '$q', '$resource', 'idService', '$timeout', '$interval', '$log', function (chatDefaults, userModel, $q, $resource, idService, $timeout, $interval, $log) { var JabberService; //List of REST calls used by the Chat functionality var resource = $resource('/smartit/rest/chat/:action/:jid:subAction/:roomId', { action: "@action", jid: "@jid", subAction: "@subAction", roomId: "@roomId" }, { //Retrieve social profiles by JIDs list. getSocialProfileByJID: { method: "GET", params: { action: 'profiles', fields: "jid,elementId,displayName,lastName,firstName,thumbnail" } }, //Creates a relation between existing XMPP room and Ticket instance and sends message stanza to all users inside the room assignChatRoom: { method: "POST", params: { action: "assign" } }, //Retrieve relation data of the XMPP room by it's jid getRoomAssignments: { method: 'GET', params: { action: "assignment" }, isArray: false, transformResponse: function (data) { return (!data || _.isEmpty(data)) ? { assignmentData: null } : { assignmentData: JSON.parse(data) }; } }, //Deletes room relation info from database and sends message with updated relation data to all conversation participants removeRoomAssignment: { method: 'DELETE', params: { action: "removeassignment" } }, saveChatLogToTicketWorknote: { method: "POST", params: { action: 'save' }, isArray: false, transformResponse: function (data) { return { success: !data, error: data }; } }, requestConversationsHistoryForCurrentUser: { method: "GET", isArray: true, params: { action: 'history', subAction: 'conversations' } }, getChatCredentials: { method: 'GET', params: { action: 'credentials' } }, getTicketsBulk: { method: "POST", url: "/smartit/rest/bulkupdate/details", isArray: true } }); JabberService = { openChatConnection: function (options) { if (JabberService.chatServerIsDisabled) { var deferred = $q.defer(); $timeout(function () { deferred.reject('Chat server not installed'); }, 100); return deferred.promise; } _.each(chatDefaults.additional_namespaces, function (ns) { Strophe.addNamespace(ns.name, ns.def); }); return resource.getChatCredentials().$promise .then(function (credentials) { if (credentials.boshUrl) { return new JabberService.Connection(credentials, options); } else { JabberService.chatServerIsDisabled = true; var deferred = $q.defer(); $timeout(function () { deferred.reject('Chat server not installed'); }, 100); return deferred.promise; } }); }, activeConnection: {}, defaultOptions: chatDefaults, generateFullJID: function (type, name, customDomain) { var domain = customDomain; if (typeof (domain) == 'undefined') { domain = JabberService.defaultOptions.domain; } if (type == 'User') { return name + "@" + domain; } if (type == 'UserList') { angular.forEach(name, function (val, key) { name[key] = val + "@" + domain; }); return name; } else if (type == 'ChatRoom') { var uuid = idService.getRandomId(); return (name ? name : uuid) + "@" + JabberService.activeConnection.options.conference_service_name; } }, runCallback: function (cbName, context, args) { var defaultCallbacks = JabberService.callbacks, callback = defaultCallbacks[cbName]; return callback.apply(context, args); }, resolvePromise: function (promiseId, resolveData) { var pendingPromises = JabberService.activeConnection.pendingPromises; if (pendingPromises[promiseId] && pendingPromises[promiseId].hasOwnProperty('resolve')) { JabberService.activeConnection.pendingPromises[promiseId].resolve(resolveData); delete JabberService.activeConnection.pendingPromises[promiseId]; } }, listeners: { onPresence: function (presXML) { // console.log("INBOUND Presence: ",Strophe.serialize(presXML)); var $presXML = $(presXML), from = presXML.getAttribute('from') || "", type = presXML.getAttribute("type") || "", xElements = presXML.getElementsByTagName('x'); if (type == 'subscribed') return true; if (type == 'subscribe') return this.handleSubscriptionRequest(presXML, from); //Handling case when user's Connection status changed if (xElements.length == 0) { var status, manualStatus, userId = Strophe.getNodeFromJid(from); //User become unavailable, but connections from other resources can be still active if (type == 'unavailable') { var chatRooms = this.conn['muc'].rooms; this.userSessions[userId] = _.without(this.userSessions[userId], from); _.each(chatRooms, function (room) { if (room.userSessions && room.userSessions[userId]) { var sessionIndex = room.userSessions[userId].indexOf(from); if (sessionIndex >= 0) { room.userSessions[userId].splice(sessionIndex, 1); } } }); if (this.userSessions[userId] && this.userSessions[userId].length > 0) { return true; } status = EntityVO.CHAT_STATUS_OFFLINE; } else { if (!presXML.childNodes.length) { status = EntityVO.CHAT_STATUS_ONLINE; } else { var statusNodes = $presXML.find("status"), showNodes = $presXML.find("show"); //If presence stanza contains status node, user status was changed manually, so all resources should inherit it manualStatus = statusNodes.text(); status = showNodes.length > 0 ? showNodes.text() : EntityVO.CHAT_STATUS_ONLINE; } userId = Strophe.getNodeFromJid(from); this.userSessions[userId] = _.union(this.userSessions[userId], [from]); } this.options.userCallbacks.presence(from, status, manualStatus); return true; } else { JabberService.listeners.onMUCPresence.apply(this, arguments); } return true; }, onMUCPresence: function (presXML) { var self = this, $presXML = $(presXML), id = presXML.getAttribute('id') || "", from = presXML.getAttribute('from') || "", type = presXML.getAttribute("type") || "", $xElements = $presXML.find('x'); _.each($xElements, function (xElem) { var ns = xElem.getAttribute('xmlns'); if (ns && ns.match(Strophe.NS.MUC)) { var roomName = from.split("/")[0], room = self.conn['muc'].rooms[roomName]; if (xElem.getElementsByTagName('destroy').length > 0) { self.options.userCallbacks.chatRoomChanges(room, { type: 'destroy', data: { roomId: roomName } }); return true; } var userItems = xElem.getElementsByTagName('item'), affiliation = userItems[0] ? userItems[0].getAttribute('affiliation') : null, jid = userItems[0] ? userItems[0].getAttribute('jid') : "", userId = jid ? Strophe.getNodeFromJid(jid) : null, evt = (type == 'unavailable') ? 'leave' : 'enter'; if (self.pendingPromises[id]) { JabberService.resolvePromise(id, room); } if (type != 'unavailable') { if (!room.userSessions[userId] || (room.userSessions[userId] && room.userSessions[userId].length == 0)) { room.userSessions[userId] = [jid]; } else { room.userSessions[userId] = _.union(room.userSessions[userId], [jid]); return true; } } else { //When unavailable presence received, this automatically means that all user resources have left chat if (room.userSessions[userId]) { room.userSessions[userId] = []; } } if (jid) self.options.userCallbacks.chatRoomChanges(room, { type: 'roster', data: { jid: jid, eventType: evt, roomId: roomName, affiliation: affiliation } }); } }); return true; }, onMessage: function (msg) { // console.log("INBOUND Message: ",Strophe.serialize(msg)); var self = this, $msg = $(msg), inviteQuery = "[xmlns='" + Strophe.NS['INVITE'] + "']", delayQuery = "[xmlns='" + Strophe.NS['DELAY'] + "']", inviteNS = $msg.find(inviteQuery).length > 0 ? true : false, delayNS = $msg.find(delayQuery); messageType = msg.getAttribute('type'); if (messageType == 'headline') { var threadQuery = msg.getElementsByTagName('thread'), fromAttr = msg.getAttribute('from'); if (threadQuery.length > 0 && fromAttr != this.conn.jid) { var roomId = threadQuery[0].getAttribute('parent'); roomId && this.joinChat(roomId) .then(function (room) { self.options.userCallbacks.roomAutoJoin(room); }); } } if (messageType == 'groupchat') { //After openfire upgrade, server is sending subject even if blank as per below defect fixed in openfire //https://igniterealtime.atlassian.net/browse/OF-1853 //Subject is not stored in openfire by SmartIT so discarding the same. if ($msg.has('subject').length) { return true; } var from = msg.getAttribute('from').split("/"), senderNick = from[1], roomName = from[0], room = this.conn.muc.rooms[roomName], message = $msg.text(), messageData; if (message.indexOf("smart-it-connection") >= 0 || message.indexOf("smart-it-disconnection") >= 0) { var messageType = (message.indexOf("smart-it-connection") >= 0) ? "smart-it-connection" : "smart-it-disconnection", chatParent = JSON.parse(message.replace(messageType + ":", "")); this.options.userCallbacks.chatRoomChanges(room, { type: messageType.split("-").pop(), data: chatParent }); return true; } if (delayNS.length > 0) { var senderJID = delayNS[0].getAttribute('from') && delayNS[0].getAttribute('from').split("/")[0], tStamp = delayNS[0].getAttribute('stamp'); messageData = { author: { jid: senderJID }, created: tStamp, text: $msg.text() }; } !messageData ? messageData = { author: { nick: senderNick }, text: message } : angular.noop(); if (this.options.userCallbacks) this.options.userCallbacks.message(messageData, roomName); } if (inviteNS && !window.opener) { JabberService.listeners.onInvite.apply(this, arguments); } return true; }, onInvite: function (msg) { var $msg = $(msg); var xquery = $msg.find("[xmlns='" + Strophe.NS['INVITE'] + "']"); if (!xquery.length) { return true; } var roomName = Strophe.getBareJidFromJid(xquery[0].getAttribute('jid')), inviteJSON = { from: msg.getAttribute('from'), roomId: roomName }; if (this.options.userCallbacks) { this.options.userCallbacks.invite(inviteJSON); } return true; }, onRosterUpdate: function (iq) { // console.log("Roster update", +Strophe.serialize(iq)); var self = this, items = iq.getElementsByTagName("item"), rosterUpdates = { removed: [], added: [] }; _.each(items, function (item) { var jid = item.getAttribute('jid'), subscription = item.getAttribute('subscription'); if (subscription == 'remove') { rosterUpdates.removed.push(jid); var room = self.conn['muc'].rooms[jid]; room && self.leaveChatRoom(room); if (window.opener) window.close(); } else rosterUpdates.added.push(jid); }); this.options.userCallbacks.rosterUpdates(rosterUpdates); // this.conn.send($iq({type: 'result', id: $(iq).attr('id')})); return true; // console.log("onRosterUpdate",iq); }, onPingReceived: function (ping) { this.conn.ping.pong(ping); return true; } }, callbacks: { connectionState: function (status, condition) { switch (status) { case Strophe.Status.CONNECTING: $log.log("STROPHE CONNECTION: Initiating BOSH session"); break; case Strophe.Status.AUTHENTICATING: $log.log("STROPHE CONNECTION: BOSH session initiated, authenticating user"); break; case Strophe.Status.CONNECTED: if (this.reconnecting) { this.resendItems = _.clone(this.conn.cm.element_queue); } this.chatConnReconnectTimeOut = 100; this.options.userCallbacks.connectionState('connected'); JabberService.runCallback('connected', this, [status, condition]); break; case Strophe.Status.CONNFAIL: case Strophe.Status.AUTHFAIL: case Strophe.Status.ERROR: if (status == Strophe.Status.AUTHFAIL) { $log.log("User authorization failed"); } this.pendingPromises.disconnect.resolve(status, condition); break; case Strophe.Status.DISCONNECTED: $log.log('Strophe is disconnected.'); this.options.userCallbacks.connectionState('disconnected'); this.chatConnReconnectTimeOut = this.chatConnReconnectTimeOut + 100; if (this.conn.auto_reconnect) { this.chatConnReconnectTimeOut = this.chatConnReconnectTimeOut + 100; var obj = this; this.reconnecting = false; $timeout(function () { obj.reconnect(); }, this.chatConnReconnectTimeOut); } else { this.pendingPromises.disconnect.resolve(status, condition); } break; } }, connected: function () { this.reconnectAttempts = 0; this.conn.addHandler(JabberService.listeners.onPresence.bind(this), null, 'presence'); this.conn.addHandler(JabberService.listeners.onMessage.bind(this), null, 'message'); this.conn.addHandler(JabberService.listeners.onRosterUpdate.bind(this), Strophe.NS.ROSTER, 'iq', "set"); this.conn.ping.addPingHandler(JabberService.listeners.onPingReceived.bind(this)); this.conn.send($pres().tree()); if (this.reconnecting) { $log.log("Strophe has reconnected successfully!"); if (this.resendItems && this.resendItems.length > 0) { this.resendLostStanzas(); } if (this.reconnectInterval) { $interval.cancel(this.reconnectInterval); this.reconnectInterval = null; } this.reconnecting = false; } else { this.pendingPromises.connectionState.resolve(this); } if (!window.opener) this.getUserRoster(true); $log.log("Strophe is connected!"); }, requestSuccess: function (respXML) { // console.log("XMPP IQ Stanza(response): ",Strophe.serialize(respXML)); var responseJSON = JabberService.activeConnection.xmlTool.xml2json(respXML), reqId = responseJSON._id, normalizedResponse = {}; _.map(responseJSON, _.bind(function (item, key) { if (key.indexOf("_") < 0) { var respData; //TODO: minimize xmlTool usage. Maybe it will be better to parse only part of xml that has NS match switch (item._xmlns) { case Strophe.NS['SMARTITIQ']: this.queryResponse = { data: item.__text, name: item._name }; break; case Strophe.NS['DISCO_ITEMS']: case Strophe.NS['DISCO_INFO']: var resArr = [].concat((item.identity || []), (item.feature || []), (item.item || [])); this.queryResponse = { data: resArr, node: item._node }; this.queryResponse.name = (item._xmlns == Strophe.NS.DISCO_INFO) ? 'DISCO_INFO' : 'DISCO_ITEM'; break; case Strophe.NS['MUC_OWNER']: // var respData = item.destroy || (new Strophe.x.Form.fromXML(respXML)); respData = item.destroy || JabberService.activeConnection.conn.x.parseFromResult(respXML); this.queryResponse = { data: respData, name: 'MUC_OWNER' }; break; case Strophe.NS['MUC_ADMIN']: this.queryResponse = { data: item.item, name: 'MUC_ADMIN' }; break; case Strophe.NS['SEARCH']: respData = JabberService.activeConnection.conn.x.parseFromResult(respXML); this.queryResponse = { data: respData, name: 'SEARCH' }; break; case Strophe.NS['ROSTER']: this.queryResponse = { data: item.item, name: 'ROSTER' }; break; case Strophe.NS['ARCHIVE']: this.queryResponse = { data: item, name: 'ARCHIVE' }; break; } } else { item ? this[key] = item : angular.noop(); } }, normalizedResponse)); JabberService.resolvePromise(reqId, normalizedResponse); return true; }, requestError: function (errorXML) { // console.log("Error", errorXML); var id = errorXML.getAttribute('id'), errorItems = errorXML.getElementsByTagName('error'), errors = []; _.each(errorItems, function (errorDOM) { var errorItem = { type: errorDOM.getAttribute('type'), code: errorDOM.getAttribute('code'), details: [] }, errorDetailNodes = errorDOM.hasChildNodes() ? errorDOM.childNodes : []; _.each(errorDetailNodes, function (detailsNode) { var detail = { name: detailsNode.nodeName, ns: detailsNode.getAttribute('xmlns') }; errorItem.details.push(detail); }); errors.push(errorItem); }); if (JabberService.activeConnection.pendingPromises[id]) { JabberService.activeConnection.pendingPromises[id].reject(errors); delete JabberService.activeConnection.pendingPromises[id]; } return errors; } } }; JabberService.Connection = function (credentials, options) { this.xmlTool = new X2JS({ attributePrefix: "" }); this.options = angular.extend(JabberService.defaultOptions, options); this.options.domain = credentials.domain; this.options.conference_service_name += this.options.domain; this.pendingPromises = { connectionState: $q.defer(), disconnect: $q.defer() }; this.conn = new Strophe.Connection(credentials.boshUrl); this.conn.connect(JabberService.generateFullJID('User', credentials.JID) + "/" + idService.getRandomId(), credentials.password, JabberService.callbacks.connectionState.bind(this)); /*Redefinition of core methods*/ this.conn._sendIQ = this.conn.sendIQ; this.conn.sendIQ = this.sendIQDefered.bind(this); this.conn.getUniqueId = idService.getRandomId; this.conn.auto_reconnect = true; this.reconnectAttempts = 0; this.maxReconnects = 5; this.reconnectTimeout = 1000; this.chatConnReconnectTimeOut = 100; this.userSessions = {}; // Debug // this.conn.rawInput = function (data) {console.log('INBOUND: ', data)}; // this.conn.rawOutput = function (data) { console.log('SEND: ' + data); }; Strophe.log = function (lvl, msg) { if ([Strophe.LogLevel.ERROR, Strophe.LogLevel.FATAL].indexOf(lvl) >= 0) { $log.log("STROPHE LOG: " + msg); } }; JabberService.activeConnection = this; this.beforeUnload = function (e) { this.conn.auto_reconnect = false; this.conn.options.sync = true; this.conn.flush(); this.conn.disconnect('logout'); }; window.onbeforeunload = this.beforeUnload.bind(this); // window.onbeforeunload = this.detachSession.bind(this); }; JabberService.Connection.prototype = { detachSession: function () { this.conn.pause(); if (sessionStorage) { var chatSession = { sid: this.conn.sid || this.conn._proto.sid, rid: this.conn.rid || this.conn._proto.rid, jid: this.conn.jid }; sessionStorage['chatSession'] = JSON.stringify(chatSession); } }, reconnect: function () { if (this.reconnectAttempts >= this.maxReconnects && !this.reconnectInterval) { this.reconnectInterval = $interval(this.reconnectTimeout, this.reconnect()); return true; } this.conn.lastReconnect = new Date().toISOString(); if (!this.reconnecting) { this.reconnecting = true; this.conn.connect(this.conn.jid, this.conn.pass, this.conn.connect_callback, this.conn.wait, this.conn.hold, this.conn.route); } this.reconnectAttempts++; }, //TODO: develop a overriding function for Strophe core method send, which will be checking args for specific value and will be creating deferred object sendIQDefered: function () { var uuid = idService.getRandomId(), args = Array.prototype.slice.call(arguments, 0), $iq = args[0]; if (typeof ($iq.tree) === "function") { $iq = $iq.tree(); } $iq.setAttribute("id", uuid); if (!args[1]) { args[1] = JabberService.callbacks.requestSuccess.bind(this); } if (!args[2]) { args[2] = JabberService.callbacks.requestError.bind(this); } // console.log("SENDING STANZA IQ,",Strophe.serialize($iq)) this.conn._sendIQ.apply(this.conn, args); this.pendingPromises[uuid] = $q.defer(); return this.pendingPromises[uuid].promise; }, setUserPresence: function (presence) { var pres = $pres(); //online case - sending empty presence stanza switch (presence.toLowerCase()) { case EntityVO.CHAT_STATUS_AWAY: pres.c('show').t(EntityVO.CHAT_STATUS_AWAY) .up().c('status').t(EntityVO.CHAT_STATUS_AWAY); break; case EntityVO.CHAT_STATUS_OFFLINE: pres = $pres({ xmlns: Strophe.NS.CLIENT, type: 'unavailable' }).c('status').t(EntityVO.CHAT_STATUS_OFFLINE); break; default: pres.c('status').t(EntityVO.CHAT_STATUS_ONLINE); } this.conn.send(pres); }, getUserRoster: function (checkRooms) { var iq = $iq({ type: 'get' }).c('query', { xmlns: Strophe.NS['ROSTER'] }), self = this, joinActiveRooms = checkRooms; return this.sendIQDefered(iq, JabberService.callbacks.requestSuccess, JabberService.callbacks.requestError) .then(function (resp) { if (!(resp && resp.queryResponse)) return; joinActiveRooms ? self.processRoomsInRoster(resp.queryResponse.data) : angular.noop(); return resp.queryResponse; }); }, addToRoster: function (jid) { var self = this, iq = $iq({ type: 'set' }).c('query', { xmlns: Strophe.NS['ROSTER'] }) .c('item', { jid: jid, name: jid.split("@")[0] }) .c('group', {}, 'conversations'); // console.log("ADDING ROOM TO ROSTER: ", Strophe.serialize(iq)); this.sendIQDefered(iq, JabberService.callbacks.requestSuccess, JabberService.callbacks.requestError) .then(function () { var pres = $pres({ to: jid, type: 'subscribe' }); self.conn.send(pres); }); }, removeRoosterItemByJID: function (jid) { var iq = $iq({ type: "set" }) .c("query", { xmlns: Strophe.NS.ROSTER }) .c("item", { jid: jid, subscription: "remove" }); // console.log("REMOVING ROOM FROM ROSTER: ", Strophe.serialize(iq)); return this.sendIQDefered(iq, JabberService.callbacks.requestSuccess, JabberService.callbacks.requestError); }, processRoomsInRoster: function (roster) { if (!roster) return; var self = this, activeRooms = _.filter([].concat(roster), { group: 'conversations' }); activeRooms.forEach(function (roomInfo) { var jid = roomInfo._jid; jid && self.conn['disco'].info(jid, null, JabberService.callbacks.requestSuccess, JabberService.callbacks.requestError.bind(self)) .then(function (roomInfo) { // console.log("Room discovery info",roomInfo); var roomAlreadyExists = (!!self.conn['muc'].rooms[jid]), history_attr; if (self.conn.lastReconnect) { history_attr = { since: self.conn.lastReconnect }; } self.joinChat(jid, history_attr).then(function (room) { !roomAlreadyExists && self.options.userCallbacks.roomAutoJoin(room); }); }) .catch(function (error) { // console.log("Error while discovering room", error); self.removeRoosterItemByJID(jid); }); }); }, handleSubscriptionRequest: function (xml, from) { var pres = $pres({ to: from.split("/")[0], from: this.conn.authzid, type: 'subscribed' }); return this.conn.send(pres); }, checkPresence: function (payload) { var isUsersList = (payload instanceof Array) ? true : false, reqName = isUsersList ? 'bulkPresenceRequest' : 'presenceRequest', request = isUsersList ? JSON.stringify({ jids: payload }) : JSON.stringify({ jid: payload }); var iq = $iq({ type: 'get' }) .c('smart-it-iq', { xmlns: Strophe.NS['SMARTITIQ'], name: reqName }, request); return this.sendIQDefered(iq, JabberService.callbacks.requestSuccess, JabberService.callbacks.requestError) .then(function (resp) { var data = resp.queryResponse.data; return JSON.parse(data || "{}"); }); }, createChatRoom: function (invitee) { var self = this, roomName = JabberService.generateFullJID('ChatRoom'), nickName = userModel.userFullData.fullName.replace(/\s/g, "_") || this.conn.authcid.split("_")[0] + "_" + this.options.resource, inviteId = invitee; var mucRoom = this.conn.muc.createRoom(roomName, nickName); this.conn.flush(); var roomConfigIQ = this.generateRoomConfigStanza(mucRoom.name, this.options.chatroom_default_config); return this.sendIQDefered(roomConfigIQ, JabberService.callbacks.requestSuccess, JabberService.callbacks.requestError) .then(function () { self.notifyAllResources({ type: 'new_room', jid: mucRoom.name }); if (inviteId) { mucRoom.directInvite(JabberService.generateFullJID('User', inviteId)); self.conn.flush(); } var participants = _.map(mucRoom.roster, 'jid'); self.sendArchiveMessage(mucRoom.name, self.conn.jid, participants); self.addToRoster(mucRoom.name); return mucRoom; }); }, generateRoomConfigStanza: function (roomJid, configFields) { var iq; iq = $iq({ to: roomJid, type: "set" }).c("query", { xmlns: Strophe.NS.MUC_OWNER }); iq.c("x", { xmlns: "jabber:x:data", type: "submit" }); iq.c('field', { 'var': 'FORM_TYPE' }).c('value').t('http://jabber.org/protocol/muc#roomconfig').up().up(); _.each(configFields, function (value, key) { iq.c('field', { 'var': 'muc#roomconfig_' + key }).c('value').t("" + value).up().up(); }); return iq.tree(); }, notifyAllResources: function (notification) { if (notification.type == 'new_room') { var msg = $msg({ to: this.conn.authzid, type: 'headline' }) .c('body').t(notification.type).up() .c('thread', { parent: notification.jid }); this.conn.send(msg); } }, sendArchiveMessage: function (roomId, inviterJID, inviteesJID) { var inviteesList = (inviteesJID instanceof Array) ? inviteesJID : [inviteesJID], request = { chatRoomId: roomId, notification: 'smart-it-start:' + JSON.stringify({ inviterJid: inviterJID, inviteesJids: inviteesList }) }, iq = $iq({ type: 'get' }) .c('smart-it-iq', { xmlns: Strophe.NS['SMARTITIQ'], name: 'chatRoomNotification' }, JSON.stringify(request)); this.sendIQDefered(iq, JabberService.callbacks.requestSuccess, JabberService.callbacks.requestError) .then(function (resp) { var data = resp.queryResponse.data; return JSON.parse(data || "{}"); }); }, inviteUserToChatRoom: function (user, room) { room.directInvite(JabberService.generateFullJID('User', user.jid)); }, joinChat: function (roomName, history_attr) { var uuid = idService.getRandomId(), nickName = userModel.userFullData.fullName.replace(/\s/g, "_") || this.conn.authcid.split("_")[0] + "_" + this.options.resource; this.pendingPromises[uuid] = $q.defer(); this.conn['muc'].join(roomName, nickName, null, null, null, null, (history_attr || null), uuid); return this.pendingPromises[uuid].promise; }, leaveChatRoom: function (room, skipStatusNode) { var pres = $pres({ to: room.name + "/" + room.nick, from: Strophe.getBareJidFromJid(this.conn.jid), type: 'unavailable' }).tree(); pres.removeAttribute('xmlns'); // console.log("LEAVE ROOM PRESENCE: ",pres) this.conn.send(pres); }, destroyChatRoom: function (room) { var iq = $iq({ to: room.name, type: 'set' }).c("query", { xmlns: Strophe.NS['MUC_OWNER'] }) .c('destroy').c("reason", "Owner request"); return this.sendIQDefered(iq, JabberService.callbacks.requestSuccess, JabberService.callbacks.requestError) .then(function (response) { }) .catch(function (err) { // console.log("Error while deleting a room", err); }); }, getUserProfileByJID: function (JIDs) { if (!JIDs) return $q.when(1); return resource.getSocialProfileByJID({ jids: JSON.stringify(JIDs) }).$promise.then(function (response) { if (response && response.items) { return response.items; } }); }, assignChatRoom: function (room, parent) { var roomName = room.name.split("@")[0]; var request = { chatRoom: roomName, objectType: parent.type, objectId: parent.id, classId: parent.additionalInformation ? parent.additionalInformation.classId : parent.classId }; return resource.assignChatRoom(request, null).$promise.then(function (error) { return room; }); }, getRoomAssignments: function (room) { var roomId = Strophe.getNodeFromJid(room.name); return resource.getRoomAssignments({ jid: roomId }).$promise; }, removeChatAssignment: function (room) { var roomId = Strophe.getNodeFromJid(room.name); return resource.removeRoomAssignment({ jid: roomId }).$promise; }, saveChatLogToTicketWorknote: function (room, ticketId, ticketType) { var roomId = Strophe.getNodeFromJid(room.name); return resource.saveChatLogToTicketWorknote({ jid: roomId }, null).$promise; // return resource.saveChatLogToTicketWorknote({roomJid: roomId,objectId: ticketId, objectType: ticketType}, null).$promise; }, requestConversationsHistoryForCurrentUser: function (params) { return resource.requestConversationsHistoryForCurrentUser(params).$promise; }, getArchivedConversationById: function (convId) { var payload = { conversationId: convId }; var iq = $iq({ type: 'get' }) .c('smart-it-iq', { xmlns: Strophe.NS['SMARTITIQ'], name: 'archiveMessagesRequest' }, JSON.stringify(payload)); return this.sendIQDefered(iq) .then(function (resp) { var data = resp.queryResponse.data; return data; }); }, getTicketDetailsBulk: function (idList) { var payload = { ids: idList }; return resource.getTicketsBulk(payload).$promise .then(function (ticketList) { return _.groupBy(ticketList, 'id'); }); }, resendLostStanzas: function () { this.conn.cm.onDequeueElement = this.resolveResendPromise.bind(this); this.conn.cm.resendStanzas(this.resendItems); }, resolveResendPromise: function (respXML) { var itemId = respXML.getAttribute('id'), promise = this.pendingPromises[itemId]; if (promise) { JabberService.callbacks.requestSuccess.call(this, respXML); } } }; return JabberService; }]); })();