732 lines
44 KiB
JavaScript
732 lines
44 KiB
JavaScript
"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;
|
|
}]);
|
|
})();
|