/**
* Licensed Materials - Property of IBM
* IBM Cognos Products: Collaboration
* (C) Copyright IBM Corp. 2017, 2019
*
* US Government Users Restricted Rights - Use, duplication or disclosure
* restricted by GSA ADP Schedule Contract with IBM Corp.
*/
define([
'../../../lib/@waca/core-client/js/core-client/ui/core/Class',
'../../utils/CustomStatus',
'./SlackAuth',
'../../../nls/StringResources',
'../../utils/ImageUtils'
], function (Class, CustomStatus, SlackAuth, StringResources, ImageUtils) {
'use strict';
var SCOPE_BASIC = 'identity.basic';
var SlackClient = Class.extend( /** @lends SlackClient */ {
/**
* @desc A common object that calls backend REST APIs to handle Slack relevant operations
* @constructs SlackClient
* @extends Class
* @public
* @param {Object} glassContext - the Glass context
* @returns an object
*
* @example var slackClient = new SlackClient(glassContext);
*/
init: function (glassContext) {
SlackClient.inherited('init', this, arguments);
this.glassContext = glassContext;
this.slackAuth = new SlackAuth(glassContext);
},
/**
* Signs in to Slack.
* @instance
* @returns {promise} a JSON object
*/
signIn: function () {
return this.slackAuth.authWithSlack(SCOPE_BASIC);
},
/**
* Signs out of Slack
* @instance
* @param {string} uri the URI for signing out
* @returns {promise} a JSON object
*/
signOut: function (uri) {
return this.glassContext.getCoreSvc('fetch').get(uri, {}).then(function (response) {
return response.data;
});
},
_getWindowLocation: function() {
return window.location;
},
/**
* Returns the redirect URI that needs to be added to the Slack application
* @instance
* @returns {string} the redirect URI
*/
getRedirectUrl: function () {
return this.slackAuth.getRedirectUrl(this._getWindowLocation());
},
/**
* Revoke access token
* @instance
* @param {string} uri the URI for revoking
* @returns {promise} a JSON object
*/
revoke: function (uri) {
return this.glassContext.getCoreSvc('fetch').get(uri, {}).then(function (response) {
return response.data;
});
},
/**
* Sends messages to Slack. For message formatting, check out {@link https://api.slack.com/docs/message-formatting|message-formatting}.
* For <code>options.data.message</code> content, see also {@link https://api.slack.com/methods/chat.postMessage|chat.postMessage}
* @instance
* @param {object} options
* @param {string} options.url the url for sending screenshot
* @param {object} options.data contains {@code channel}, {@code message} and {@code dataUrl}
* @param {string} options.data.dataUrl screenshot data url
* @param {string} options.data.comment initial comment to add to screenshot
* @param {string} options.data.message a JSON object represents a message to send
* @returns {promise} a JSON object
*/
sendMessage: function (options) {
var data = options.data;
var payload = {
'channel': data.channel,
'comment': data.comment,
'message': data.message,
'filename': data.filename
};
var formData = new FormData();
formData.append('payload', JSON.stringify(payload));
var image = data['dataUrl'];
if (image) {
var base64ImageContent = image.replace(/^data:image\/(png|jpg);base64,/, '');
var blob = ImageUtils.base64ToBlob(base64ImageContent, 'image/png');
formData.append('file', blob);
} else {
formData.append('file', '');
}
return this.doMultipart({
url: options.url,
data: formData
});
},
/**
* Sends a multipart POST request
* @instance
* @param {object} options
* @param {string} options.url URL for sending requests
* @param {object} options.data form data
* @returns {promise} a JSON object
*/
doMultipart: function (options) {
var ajaxOptions = {
type: 'POST',
url: options.url,
cache: false,
contentType: false,
processData: false,
data: options.data
};
return this._doAjax(ajaxOptions);
},
/**
* Sends a GET request
* @instance
* @param {object} options
* @param {string} options.url URL for sending requests
* @param {object} options.data JSON object of params
* @returns {promise} a JSON object
*/
doGet: function (options) {
var ajaxOptions = {
type: 'GET',
url: options.url,
dataType: 'json',
data: {
'payload': JSON.stringify(options.data)
}
};
return this._doAjax(ajaxOptions);
},
/**
* Sends a POST request
* @instance
* @param {object} options
* @param {string} options.url URL for sending requests
* @param {object} options.data JSON object of POST body
* @returns {promise} a JSON object
*/
doPost: function (options) {
var ajaxOptions = {
type: 'POST',
url: options.url,
data: JSON.stringify(options.data),
contentType: 'application/json; charset=utf-8',
dataType: 'json'
};
return this._doAjax(ajaxOptions);
},
/**
* Translates Slack OAuth errors into text.
* @param data OAuth error response data
* @return {Error}
*/
createAuthError: function (data) {
var msg;
var showContactAdmin = false;
if (!data.error) {
return new Error(StringResources.get('error_auth_failure_generic'));
}
switch (data.error) {
case 'auth_cancelled':
msg = StringResources.get('error_auth_cancelled');
break;
case 'certificate_invalid':
msg = StringResources.get('error_certificate_invalid');
showContactAdmin = true;
break;
case 'internal_server_error':
msg = StringResources.get('error_server_internal');
showContactAdmin = true;
break;
case 'bad_client_secret':
msg = StringResources.get('error_bad_client_secret');
showContactAdmin = true;
break;
default:
msg = data.error;
break;
}
var error = new Error(StringResources.get('error_auth_failure', { error: msg }));
error.showContactAdmin = showContactAdmin;
return error;
},
/**
* Sends an HTTP request with given options. It will handle re-auth when access token is invalid.
* @instance
* @private
* @param {object} options AJAX options
* @returns {promise} a JSON response
*/
_doAjax: function (options) {
return this.glassContext.getCoreSvc('.Ajax')
.ajax(options)
.catch(function (error) {
if (error.jqXHR) {
var data = error.jqXHR.responseJSON;
switch (error.code) {
case CustomStatus.TOKEN_INVALID:
return this.slackAuth.authWithSlack(data)
.then(function (auth) {
if (auth.ok) {
return this._doAjax(options);
} else {
var error = this.createAuthError(auth);
error.code = auth.error;
return Promise.reject(error);
}
}.bind(this));
case CustomStatus.NOT_FOUND_ERROR:
error.message = StringResources.get('error_platform_not_found');
error.showContactAdmin = true;
break;
case CustomStatus.PROVIDER_CONFIG_ERROR:
error.message = StringResources.get('error_platform_config');
error.showContactAdmin = true;
break;
case CustomStatus.SERVICE_ERROR:
// translate slack provider errors into text
switch (data.error) {
case 'certificate_invalid':
error.message = StringResources.get('error_certificate_invalid');
error.showContactAdmin = true;
break;
case 'workspace_not_found':
error.message = StringResources.get('error_workspace_not_found');
error.showContactAdmin = true;
break;
case 'channel_not_found':
error.message = StringResources.get('error_channel_not_found');
break;
case 'not_in_channel':
error.message = StringResources.get('error_not_in_channel');
break;
case 'invalid_channel':
error.message = StringResources.get('error_invalid_channel');
break;
case 'is_archived':
error.message = StringResources.get('error_is_archived');
break;
case 'msg_too_long':
error.message = StringResources.get('error_msg_too_long');
break;
case 'cant_join':
error.message = StringResources.get('error_cant_join');
break;
case 'not_enough_users':
error.message = StringResources.get('error_not_enough_users');
break;
case 'fatal_error':
error.message = StringResources.get('error_service_down');
break;
default:
if (data.error && data.error.indexOf('ASSocket: timed out') === 0) {
error.message = StringResources.get('error_slack_timeout');
error.showContactAdmin = true;
} else {
error.message = StringResources.get('error_slack', data);
error.showContactAdmin = true;
}
break;
}
break;
}
}
throw error;
}.bind(this));
}
});
return SlackClient;
});