DashboardContentService.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. 'use strict';
  2. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  3. /**
  4. * Licensed Materials - Property of IBM
  5. * IBM Business Analytics (C) Copyright IBM Corp. 2020
  6. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  7. */
  8. /**
  9. * @class DashboardContentService
  10. * @hideconstructor
  11. *
  12. * @classdesc
  13. * CA dashboard content service oprations: getAncestors, onSaveAsSuccess, Save, SaveAs, SaveThumbnail
  14. */
  15. define(['../../dashboard/glass/util/SaveActionUtil', '../../app/util/GlassUtil', '../../app/nls/StringResources', '../../dashboard/loader/DeploymentReferencesUtil'], function (SaveActionUtil, GlassUtil, StringResources, DeploymentReferencesUtil) {
  16. return function () {
  17. function DashboardContentService() {
  18. _classCallCheck(this, DashboardContentService);
  19. }
  20. DashboardContentService.prototype.initialize = function initialize(glassContext) {
  21. this._glassContext = glassContext;
  22. return Promise.resolve();
  23. };
  24. /**
  25. * Given a dashboard board Id or Url, return the dashboard's parent path information (Ancestors)
  26. * @async
  27. * @param {Object} spec - JSON object that is used to locate a dashboard object
  28. * spec.id - board id
  29. * spec.url - url of the dashboard
  30. * spec.url is used only when avaiable, otherwise spec.id is used.
  31. * @return {Promise<Array>} - resolved with an array of parent path ancestors.
  32. * The array is null when there is no id specified or when an error occurred while retrieving them
  33. */
  34. DashboardContentService.prototype.getAncestors = function getAncestors() {
  35. var _this = this;
  36. var spec = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  37. var id = spec.id,
  38. url = spec.url;
  39. if (!id && !url) {
  40. return Promise.resolve(null);
  41. } else {
  42. return this._getContentService().then(function (oContentService) {
  43. var server_URL = url || oContentService.getBaseObjectsURL() + '/' + id;
  44. var options = { data: { fields: 'ancestors' } };
  45. return oContentService.get(server_URL, options);
  46. }).then(function (result) {
  47. return Promise.resolve(result ? result.data[0].ancestors || null : null);
  48. }).catch(function (error) {
  49. _this._logError('Error retrieving ancestors:', error);
  50. return null;
  51. });
  52. }
  53. };
  54. /**
  55. * Given the id or url of a dashboard, return the dashboard information
  56. * @param {String} boardId - dashboard Id
  57. * @param {String} boardUrl - dashboard Url (search path)
  58. * @returns {Promise<Object>} - Resolved dashboard information { id, name, searchPath, permissions, boardSpec }
  59. */
  60. DashboardContentService.prototype.getDashboard = function getDashboard(boardId, boardUrl) {
  61. var _this2 = this;
  62. var url = boardUrl || 'v1/objects/' + boardId;
  63. var options = {
  64. dataType: 'json',
  65. data: {
  66. 'fields': ['defaultName', 'specification', 'searchPath', 'deploymentReferences.ancestors', 'deploymentReferences.defaultName', 'deploymentReferences.id', 'deploymentReferences.type', 'deploymentReferences.searchPath'].join(',')
  67. },
  68. MRUInfo: {}
  69. };
  70. return this._getBoardSpecFromContentSvc(url, options).then(function (response) {
  71. return _this2._handleBoardSpecResponse(response);
  72. });
  73. };
  74. /**
  75. * Callback of Save As success
  76. * Given a dashboard board id or a dashboard url, return the dashboard spec
  77. * @async
  78. * @param {Object} spec - JSON object that is used to locate a dashboard object
  79. * spec.id - board id
  80. * spec.url - url of the dashboard
  81. * spec.url is used only when avaiable, otherwise spec.id is used.
  82. * @return {Promise<Object>} - resolved with dashboard information of permissions and boardId
  83. * @example
  84. * permissions is an array that contains elements such as "execute", "read", "setPolicy", "traverse", "write"
  85. */
  86. DashboardContentService.prototype.onSaveAsSuccess = function onSaveAsSuccess() {
  87. var spec = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  88. var id = spec.id,
  89. url = spec.url;
  90. if (!id && !url) {
  91. return Promise.resolve(null);
  92. } else {
  93. return this._getContentService().then(function (oContentService) {
  94. var server_URL = url || oContentService.getBaseObjectsURL() + '/' + id;
  95. var oGetOptions = {
  96. dataType: 'json',
  97. data: {
  98. 'fields': 'defaultName,specification'
  99. },
  100. MRUInfo: {}
  101. };
  102. return oContentService.get(server_URL, oGetOptions);
  103. }).then(function (response) {
  104. var data = response && response.data && response.data.length > 0 ? response.data[0] : {};
  105. return Promise.resolve({
  106. permissions: data.permissions,
  107. id: data.id
  108. });
  109. });
  110. }
  111. };
  112. /**
  113. * Update an existing Dashboard object
  114. * @async
  115. * @param {DashboardAPI} dashboard api
  116. * @return {Promise<Object>} Resolved object is the saved spec
  117. * @example when failed, the promise will reject an XHR request object
  118. {
  119. readyState: 4
  120. getResponseHeader: ƒ (e)
  121. getAllResponseHeaders: ƒ ()
  122. setRequestHeader: ƒ (e,t)
  123. overrideMimeType: ƒ (e)
  124. statusCode: ƒ (e)
  125. ..
  126. }
  127. *
  128. */
  129. DashboardContentService.prototype.saveDashboard = function saveDashboard(dashboard, assetId) {
  130. var _this3 = this;
  131. var spec = dashboard.getFeature('Serializer').toJSON();
  132. var cmSpec = this._getCMSpec(spec, dashboard);
  133. return new Promise(function (resolve, reject) {
  134. _this3._getContentService().then(function (oContentService) {
  135. return oContentService.put('v1/objects/' + assetId + '?ignoreInvalidObjectReference=true', {
  136. contentType: 'application/json',
  137. processData: false,
  138. dataType: 'application/json',
  139. data: JSON.stringify(cmSpec),
  140. MRUInfo: {} //A necessary property to support MRU
  141. }).fail(function (deferred, request) {
  142. reject(request);
  143. }).then(function () {
  144. resolve({ 'savedSpec': cmSpec.specification, 'status': 'success' });
  145. });
  146. });
  147. });
  148. };
  149. /**
  150. * CREATE a new Dashboard object
  151. * @async
  152. * @param {DashboardAPI} dashboard api
  153. * @param {string} name of the dashboard
  154. * @param {string} url of the dashboard's parent
  155. * @param {boolean} True means save as an existing dashboard
  156. * @return {Promise<Object>}
  157. * @exmaple when failed, the promise rejects an error object like below
  158. * {
  159. 'status': 'fail',
  160. 'saveRequest': request,
  161. 'cmSpec': cmSpec
  162. }
  163. */
  164. DashboardContentService.prototype.saveAsDashboard = function saveAsDashboard(dashboard, name, url, overwrite) {
  165. var ajaxService = GlassUtil.getAjaxService(this._glassContext);
  166. //enable the 'more' button containing the set as home if it is not already enabled
  167. var moreButton = this._glassContext.appController.findPlugin('com.ibm.bi.glass.common.operations');
  168. if (moreButton && !moreButton.isEnabled) {
  169. moreButton.enable();
  170. }
  171. return SaveActionUtil.saveAs({ ajaxService: ajaxService, name: name, url: url, dashboard: dashboard, overwrite: overwrite });
  172. };
  173. /**
  174. * Save the thumbnail image into a Databoard Object
  175. * @async
  176. * @param {Object} spec
  177. * spec.thumbnailDataUri - base64 encoded PNG
  178. * spec.id - board Id of a dashboard
  179. * @return {Promise<Object>}
  180. */
  181. DashboardContentService.prototype.saveThumbnail = function saveThumbnail() {
  182. var _this4 = this;
  183. var spec = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  184. var thumbnailDataUri = spec.thumbnailDataUri,
  185. id = spec.id;
  186. var dataUriParts = thumbnailDataUri && thumbnailDataUri.split(',');
  187. if (!dataUriParts || dataUriParts.length != 2) {
  188. this._logError('Invalid thumbnail returned from Thumbnail service.');
  189. return;
  190. }
  191. if (!id) {
  192. this._logError('Dashboard id is undefined when generating thumbnail.');
  193. return;
  194. }
  195. return this._getContentService().then(function (oContentService) {
  196. return _this4._getAjaxService().post(oContentService.getBaseObjectsURL() + '/' + id + '/items?updateAction=update', {
  197. contentType: 'application/json',
  198. processData: false,
  199. dataType: 'text',
  200. data: JSON.stringify({
  201. defaultName: 'thumbnail',
  202. type: 'graphic',
  203. dataType: 'image/png',
  204. data: dataUriParts[1]
  205. })
  206. });
  207. });
  208. };
  209. /**
  210. * Process board spec response from content service.
  211. * @private
  212. * @param {Object} response - The response of a successful board spec request to content service
  213. * @return {Promise<Object>} - Resolved with a JSON object that contains the dashboard informaiton
  214. * @example
  215. {
  216. boardSpec: {xxx},
  217. boardId: 'i12345678',
  218. permissions: ['execute','read','setPolicy','traverse', 'write'],
  219. searchPath: 'CAMID("LDAP:u:uid=hmiller,ou=people")/folder[@name=\'My Folders\']/exploration[@name=\'New dashboard1\']',
  220. name: 'New dashboard1'
  221. }
  222. */
  223. DashboardContentService.prototype._handleBoardSpecResponse = function _handleBoardSpecResponse(response) {
  224. //No response data
  225. if (response.data.length === 0) {
  226. return Promise.reject({
  227. code: 'notFound',
  228. message: StringResources.get('noDashboardFound')
  229. });
  230. }
  231. //No read and execute permissions
  232. var permissions = response.data[0].permissions;
  233. if (!this._hasPermission(permissions)) {
  234. return Promise.reject({
  235. code: 'noPermission',
  236. message: StringResources.get('noDashboardPermission')
  237. });
  238. }
  239. // should never have a dashboard with null spec... but just in case
  240. var responseData = response.data[0];
  241. var specAsString = responseData.specification || '{}';
  242. var boardSpec = JSON.parse(specAsString);
  243. boardSpec._meta = {
  244. bundleID: responseData.id
  245. };
  246. //Update deployment reference
  247. DeploymentReferencesUtil.updateIds(boardSpec, responseData.deploymentReferences);
  248. boardSpec.features = boardSpec.features || {};
  249. boardSpec.features.ContentStoreReferences = responseData.deploymentReferences;
  250. return Promise.resolve({
  251. boardSpec: boardSpec,
  252. boardId: responseData.id,
  253. permissions: responseData.permissions,
  254. searchPath: responseData.searchPath,
  255. name: responseData.defaultName
  256. });
  257. };
  258. DashboardContentService.prototype._hasPermission = function _hasPermission(permissions) {
  259. if (Array.isArray(permissions) && permissions.length) {
  260. return ['read', 'execute'].every(function (permission) {
  261. return permissions.indexOf(permission) !== -1;
  262. });
  263. }
  264. return false;
  265. };
  266. /**
  267. * Fetches the board spec using the content service.
  268. * Wrapping the Content Service JQuery deferred in a native Promise to obtain some predictable error handling
  269. * @param {String} url - URL of dashboard resource to fetch
  270. * @param {String} options - Options to pass into the get request
  271. * @return {Promise<object>} - A Promise which is resolved once the board spec is fetched
  272. * when failed, it rejects with the error status, error code and error messages.
  273. */
  274. DashboardContentService.prototype._getBoardSpecFromContentSvc = function _getBoardSpecFromContentSvc(url, options) {
  275. var _this5 = this;
  276. return new Promise(function (resolve, reject) {
  277. _this5._getContentService().then(function (contentSvc) {
  278. contentSvc.get(url, options).done(resolve).fail(function (ajaxdfd, jqXHR, textStatus) {
  279. reject({
  280. status: jqXHR.status,
  281. code: textStatus,
  282. message: StringResources.get('noDashboardFound')
  283. });
  284. });
  285. });
  286. });
  287. };
  288. /**
  289. *This function is overriden in StoryContentSerivce
  290. *@private
  291. *@param {Object} spec - board spec of a dashboard
  292. *@return the dashboard CM spec
  293. */
  294. DashboardContentService.prototype._getCMSpec = function _getCMSpec(spec, dashboard) {
  295. var boardModel = dashboard.getFeature('internal').getBoardModel();
  296. return SaveActionUtil.getCMSpec(spec, boardModel, false);
  297. };
  298. DashboardContentService.prototype._logError = function _logError(errMsg) {
  299. this._glassContext.getCoreSvc('.Logger').error(errMsg);
  300. };
  301. DashboardContentService.prototype._getContentService = function _getContentService() {
  302. return this._glassContext.getSvc('.Content');
  303. };
  304. DashboardContentService.prototype._getAjaxService = function _getAjaxService() {
  305. return this._glassContext.services.ajax;
  306. };
  307. DashboardContentService.prototype._getDashboardApi = function _getDashboardApi() {
  308. return this._getCurrentView().getDashboardApi();
  309. };
  310. DashboardContentService.prototype._getCurrentView = function _getCurrentView() {
  311. return this._glassContext.appController.currentAppView.currentContentView;
  312. };
  313. return DashboardContentService;
  314. }();
  315. });
  316. //# sourceMappingURL=DashboardContentService.js.map