Name
global.CAFUnfurlUtil
Description
No description available
Script
var CAFUnfurlUtil = Class.create();
(function() {
CAFUnfurlUtil.prototype = {
initialize: function(providerChannelIdentityId, channelUserId, urlOrText) {
this.isPrecheckSuccessful = this.preCheck(providerChannelIdentityId, channelUserId, urlOrText);
if(this.isPrecheckSuccessful) {
this.providerChannelIdentityId = providerChannelIdentityId;
this.channelUserId = channelUserId;
this.customAdapterScriptAPI = new sn_cs.CustomAdapterScriptObject();
this.allowedHostnameHelper = new global.AllowedHostnameHelper();
}
},
isUnfurlingAllowed: function() {
return !!this.isPrecheckSuccessful;
},
getUnfurlMetadata: function(unfurlMetadataExtractionOptions) {
if (!this.isUnfurlingAllowed()) {
return {};
}
unfurlMetadataExtractionOptions = unfurlMetadataExtractionOptions || {};
var logger = getLogger();
var logContext = null;
try {
logContext = new sn_log.GlideLogContext({ 'conversation': this.lastConversation.conversation_id });
var unfurlMetadata = callUnfurlMetadataAPI.call(this, {
url: this.urlToUnfurl,
provider_channel_identity_id: this.providerChannelIdentityId,
channel_user_id: this.channelUserId,
conversation_id: this.lastConversation.conversation_id,
device_type: this.lastConversation.device_type
});
if(!unfurlMetadata) {
return {};
}
return unfurlMetadata;
} finally {
if(logContext) {
logContext.clear();
}
}
},
getHtmlTitle: function(titleExtractionOptions) {
if (!this.isUnfurlingAllowed()) {
return '';
}
titleExtractionOptions = titleExtractionOptions || {};
titleExtractionOptions.save_to_cache = (titleExtractionOptions.save_to_cache !== false) ? true : false;
var logger = getLogger();
var logContext = null;
try {
logContext = new sn_log.GlideLogContext({ 'conversation': this.lastConversation.conversation_id });
var htmlTitle = callHtmlTitleAPI.call(this, {
url: this.urlToUnfurl,
provider_channel_identity_id: this.providerChannelIdentityId,
channel_user_id: this.channelUserId,
conversation_id: this.lastConversation.conversation_id,
device_type: this.lastConversation.device_type
});
if(!!htmlTitle && titleExtractionOptions.save_to_cache) {
updateCacheWithFields.call(this, this.urlToUnfurl, this.lastConversation.device_type, { title : htmlTitle });
}
return htmlTitle;
} catch(e) {
logger.error("[CAFUnfurlUtil] Error in fetching html title for url {0} => {1}", this.urlToUnfurl, e.message);
} finally {
if(logContext) {
logContext.clear();
}
}
},
preCheck: function(providerChannelIdentityId, channelUserId, urlOrText) {
var logger = getLogger();
if(!providerChannelIdentityId) {
logger.error("[CAFUnfurlUtil] empty_provider_channel_identity: ignoring unfurling. provider channel identity id should not be empty");
return false;
}
if(!channelUserId) {
logger.error("[CAFUnfurlUtil] empty_channel_user_id: ignoring unfurling. channel user id should not be empty");
return false;
}
var logContext;
try {
logContext = new sn_log.GlideLogContext({ providerUserId : channelUserId });
if(!urlOrText) {
logger.warn("[CAFUnfurlUtil] empty_text: ignoring unfurling, url or text passed is empty.");
return false;
}
if(!isGlobalUnfurlingEnabled()) {
logger.info("[CAFUnfurlUtil] global_unfurling_disabled: ignoring unfurling. global unfurling property is not enabled.", providerChannelIdentityId, channelUserId);
return false;
}
if(!isChannelLevelUnfurlingEnabled(providerChannelIdentityId, logger)) {
logger.info("[CAFUnfurlUtil] channel_unfurling_disabled: ignoring unfurling. unfurling is disabled for the provider channel identity: {0}", providerChannelIdentityId);
return false;
}
var urlsInText = getUrlsFromText(urlOrText);
if(!Array.isArray(urlsInText) || !urlsInText.length) {
logger.debug("[CAFUnfurlUtil] no_url_in_text: ignoring unfurling. no urls in the passed in text \"{0}\"", urlOrText);
return false;
}
var urlToUnfurl = getUrlForUnfurlingFromUrls(urlsInText, logger);
if(!urlToUnfurl) {
logger.debug("[CAFUnfurlUtil] no_allowed_url_to_unfurl: no url is allowed for unfurling in the passed in text \"{0}\"", urlOrText);
return false;
}
// store url to unfurl in the object. This is used when the actual api's are called.
this.urlToUnfurl = urlToUnfurl;
var lastConversationDetails = getLastConversationDetails(providerChannelIdentityId, channelUserId, logger);
if(!lastConversationDetails.conversation_id) {
logger.debug("[CAFUnfurlUtil] no_conversation_exists: ignoring unfurling. No conversation exists for the channel user id: {0}", channelUserId);
return false;
}
// store last conversation in the object. This is used when the actual api's are called.
this.lastConversation = lastConversationDetails;
return true;
} finally {
if(logContext) {
logContext.clear();
}
}
},
type: 'CAFUnfurlUtil'
};
function isGlobalUnfurlingEnabled(logger) {
var isGlobalUnfurlingEnabled = gs.getProperty("com.glide.cs.enable_link_unfurling", true);
return parseBoolean(isGlobalUnfurlingEnabled);
}
function isChannelLevelUnfurlingEnabled(providerChannelIdentityId, logger) {
var isChannelLevelUnfurlingEnabled = getCustomAdapterProperty("enable_link_unfurling", providerChannelIdentityId, logger);
return parseBoolean(isChannelLevelUnfurlingEnabled);
}
function parseBoolean(val) {
return val == '1' || val =='true' || val == true;
}
function getCustomAdapterProperty(name, providerChannelIdentityId, logger) {
try {
var property = sn_cs.VASystemObject.getCustomAdapterPropertyWithHierarchy(name, providerChannelIdentityId);
if(!property || (property == "null")) {
return '';
}
return property;
} catch(e) {
logger.error("[CAFUnfurlUtil] error_in_fetching_caf_property: error in fetching custom adapter property \"{0}\" for provider channel identity: \"{1}\" => {2}", name, providerChannelIdentityId, e.message);
return '';
}
}
function getLastConversationDetails(providerChannelIdentityId, channelUserId, logger) {
try {
var conversationDetailsJson = new sn_cs.CustomAdapterScriptObject().getLastConversationDetails(providerChannelIdentityId, channelUserId);
var conversationDetails = safeParse(conversationDetailsJson, {});
return conversationDetails;
} catch(e) {
logger.error("[CAFUnfurlUtil] error_in_fetching_last_conversation: Error in fetching last conversation for channel user \"{0}\" and provider channel identity \"{1}\" => {2}", channelUserId, providerChannelIdentityId, e.message);
return {};
}
}
function getUrlsFromText(urlOrText) {
var urlListJson = new sn_cs.CustomAdapterScriptObject().getUrlsFromText(urlOrText);
var urls = safeParse(urlListJson);
return urls;
}
function getUrlForUnfurlingFromUrls(urls, logger) {
var allowedHostnameHelper = new global.AllowedHostnameHelper();
var urlToUnfurl = '';
for(var i = 0; i < urls.length; i++) {
var url = urls[i];
url = getTargetUrlFromClickMetricsUrl.call(this, url);
if(allowedHostnameHelper.isURLAllowedForUnfurling(url)) {
urlToUnfurl = url;
break;
} else {
logger.debug("[CAFUnfurlUtil] host_not_allowed: hostname is not allowed for unfurling for url => {0}", url);
}
}
return urlToUnfurl;
}
function getTargetUrlFromClickMetricsUrl(link) {
var TARGET_URL_PARAM = "target_url=";
var VA_LINK = "va_link.do?token=";
if (link.indexOf(VA_LINK) < 0) {
// if the url is not click metrics url, then return the original url
return link;
}
var targetUrl = link.substring(link.indexOf(TARGET_URL_PARAM) + TARGET_URL_PARAM.length);
targetUrl = decodeURIComponent(targetUrl);
return targetUrl;
}
function getLogger() {
return new sn_log.GlideLogger("com.glide.cs.link_unfurling.CAFUnfurlUtil", {
app: 'CI',
track: 'CCCIF Link Unfurling',
layer: 'Script'
}, ['app', 'track', 'layer', 'providerUserId', 'conversation']);
}
function callUnfurlMetadataAPI(unfurlAPIInputs) {
if(!unfurlAPIInputs) {
return {};
}
var unfurlAPIInputsJson = JSON.stringify(unfurlAPIInputs);
var unfurlMetadataJson = new sn_cs.CustomAdapterScriptObject().getUnfurlMetadata(unfurlAPIInputsJson);
var unfurlMetadata = safeParse(unfurlMetadataJson);
return unfurlMetadata;
}
function callHtmlTitleAPI(unfurlAPIInputs) {
if(!unfurlAPIInputs) {
return '';
}
var unfurlAPIInputsJson = JSON.stringify(unfurlAPIInputs);
var htmlTitle = new sn_cs.CustomAdapterScriptObject().getHtmlTitle(unfurlAPIInputsJson);
return isEmptyString(htmlTitle) ? '' : htmlTitle;
}
function updateCacheWithFields(url, deviceType, fieldsToUpdate) {
var unfurlingCacheUtils = new global.UrlUnfurlingCacheUtils();
var cachedDataJson = unfurlingCacheUtils.getDataFromCache(this.urlToUnfurl, this.lastConversation.device_type);
var cachedData = safeParse(cachedDataJson, {});
var cachedUnfurledData = safeParse(cachedData.url_unfurl_data, {});
Object.keys(fieldsToUpdate).forEach(function(key, index) {
if(fieldsToUpdate.hasOwnProperty(key)) {
cachedUnfurledData[key] = fieldsToUpdate[key];
}
});
var cachedUnfurledDataJson = JSON.stringify(cachedUnfurledData);
unfurlingCacheUtils.saveToCacheIfEnabled(this.urlToUnfurl, cachedUnfurledDataJson, this.lastConversation.device_type);
}
function isEmptyString(val) {
return !val || (val == 'null') || (val == 'undefined');
}
function safeParse(text, defaultValue) {
defaultValue = defaultValue || {};
if(!text) {
return defaultValue;
}
if (isObject(text)) {
return text;
}
if (isString(text)) {
try {
return JSON.parse(text);
} catch (e) {
return defaultValue;
}
} else {
return defaultValue;
}
}
function isString(str) {
return (Object.prototype.toString.call(str) === '[object String]');
}
function isObject(obj) {
return ((typeof obj) === 'object');
}
})();
Sys ID
9694c251c3651110abf99bc8a840ddff