OneDriveClient.js 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622
  1. /**
  2. * Copyright (c) 2006-2024, JGraph Ltd
  3. * Copyright (c) 2006-2024, draw.io AG
  4. */
  5. //Add a closure to hide the class private variables without changing the code a lot
  6. (function ()
  7. {
  8. var _token = null;
  9. window.OneDriveClient = function(editorUi, isExtAuth, inlinePicker, noLogout)
  10. {
  11. if (isExtAuth == null && window.urlParams != null && window.urlParams['extAuth'] == '1')
  12. {
  13. isExtAuth = true;
  14. }
  15. if (inlinePicker == null) //Use inline picker as default
  16. {
  17. inlinePicker = window.Editor != null? Editor.oneDriveInlinePicker : true;
  18. }
  19. if (noLogout == null && window.urlParams != null && window.urlParams['noLogoutOD'] == '1')
  20. {
  21. noLogout = true;
  22. }
  23. DrawioClient.call(this, editorUi, isExtAuth? 'oneDriveExtAuthInfo' : 'oneDriveAuthInfo');
  24. this.isExtAuth = isExtAuth;
  25. this.inlinePicker = inlinePicker;
  26. this.noLogout = noLogout;
  27. var authInfo = JSON.parse(this.token);
  28. if (authInfo != null)
  29. {
  30. this.endpointHint = authInfo.endpointHint != null ? authInfo.endpointHint.replace('/Documents', '/_layouts/15/onedrive.aspx') : authInfo.endpointHint;
  31. }
  32. };
  33. // Extends DrawioClient
  34. mxUtils.extend(OneDriveClient, DrawioClient);
  35. /**
  36. * Specifies if thumbnails should be enabled. Default is true.
  37. * LATER: If thumbnails are disabled, make sure to replace the
  38. * existing thumbnail with the placeholder only once.
  39. */
  40. OneDriveClient.prototype.clientId = window.DRAWIO_MSGRAPH_CLIENT_ID || ((window.location.hostname == 'test.draw.io') ?
  41. '95e4b4ed-ed5c-4a05-935b-b411b4562ef2' : '24b129a6-117b-4394-bdc8-3b9955e5cdef');
  42. OneDriveClient.prototype.clientId = window.location.hostname == 'app.diagrams.net' ?
  43. 'b5ff67d6-3155-4fca-965a-59a3655c4476' : OneDriveClient.prototype.clientId;
  44. OneDriveClient.prototype.clientId = window.location.hostname == 'viewer.diagrams.net' ?
  45. '417a451a-a343-4788-b6c1-901e63182565' : OneDriveClient.prototype.clientId;
  46. /**
  47. * OAuth 2.0 scopes for installing Drive Apps.
  48. */
  49. OneDriveClient.prototype.scopes = 'user.read files.readwrite.all sites.read.all';
  50. /**
  51. * OAuth 2.0 scopes for installing Drive Apps.
  52. */
  53. OneDriveClient.prototype.redirectUri = window.DRAWIO_SERVER_URL + 'microsoft';
  54. OneDriveClient.prototype.pickerRedirectUri = window.DRAWIO_SERVER_URL + 'onedrive3.html';
  55. /**
  56. * This is the default endpoint for personal accounts
  57. */
  58. OneDriveClient.prototype.defEndpointHint = 'api.onedrive.com';
  59. OneDriveClient.prototype.endpointHint = OneDriveClient.prototype.defEndpointHint;
  60. /**
  61. * Value for the root folder.
  62. */
  63. OneDriveClient.prototype.rootId = {id: 'root', name: 'root', parentReference: {driveId: 'me'}};
  64. /**
  65. * Executes the first step for connecting to Google Drive.
  66. */
  67. OneDriveClient.prototype.extension = '.drawio';
  68. /**
  69. * Executes the first step for connecting to Google Drive.
  70. */
  71. OneDriveClient.prototype.baseUrl = 'https://graph.microsoft.com/v1.0';
  72. OneDriveClient.prototype.authUrl = 'https://login.microsoftonline.com/' + (window.DRAWIO_MSGRAPH_TENANT_ID || 'common');
  73. /**
  74. * Empty function used when no callback is needed
  75. */
  76. OneDriveClient.prototype.emptyFn = function(){};
  77. /**
  78. * Authorizes the client, gets the userId and calls <open>.
  79. */
  80. OneDriveClient.prototype.invalidFilenameRegExs = [
  81. /[~"#%\*:<>\?\/\\{\|}]/,
  82. /^\.lock$/i,
  83. /^CON$/i,
  84. /^PRN$/i,
  85. /^AUX$/i,
  86. /^NUL$/i,
  87. /^COM\d$/i,
  88. /^LPT\d$/i,
  89. /^desktop\.ini$/i,
  90. /_vti_/i
  91. ];
  92. /**
  93. * Check if the file/folder name is valid
  94. */
  95. OneDriveClient.prototype.isValidFilename = function(filename)
  96. {
  97. if (filename == null || filename === '') return false;
  98. for (var i = 0; i < this.invalidFilenameRegExs.length; i++)
  99. {
  100. if (this.invalidFilenameRegExs[i].test(filename)) return false;
  101. }
  102. return true;
  103. };
  104. /**
  105. * Checks if the client is authorized and calls the next step.
  106. */
  107. OneDriveClient.prototype.get = function(url, onload, onerror)
  108. {
  109. var req = new mxXmlRequest(url, null, 'GET');
  110. req.setRequestHeaders = mxUtils.bind(this, function(request, params)
  111. {
  112. request.setRequestHeader('Authorization', 'Bearer ' + _token);
  113. });
  114. req.send(onload, onerror);
  115. return req;
  116. };
  117. /**
  118. * Checks if the client is authorized and calls the next step.
  119. */
  120. OneDriveClient.prototype.updateUser = function(success, error, failOnAuth)
  121. {
  122. var acceptResponse = true;
  123. var timeoutThread = window.setTimeout(mxUtils.bind(this, function()
  124. {
  125. acceptResponse = false;
  126. error({code: App.ERROR_TIMEOUT});
  127. }), this.ui.timeout);
  128. this.get(this.baseUrl + '/me', mxUtils.bind(this, function(req)
  129. {
  130. window.clearTimeout(timeoutThread);
  131. if (acceptResponse)
  132. {
  133. if (req.getStatus() < 200 || req.getStatus() >= 300)
  134. {
  135. if (!failOnAuth)
  136. {
  137. this.logout();
  138. this.authenticate(mxUtils.bind(this, function()
  139. {
  140. this.updateUser(success, error, true);
  141. }), error);
  142. }
  143. else
  144. {
  145. error({message: mxResources.get('accessDenied')});
  146. }
  147. }
  148. else
  149. {
  150. try
  151. {
  152. var data = JSON.parse(req.getText());
  153. this.setUser(new DrawioUser(data.id, data.mail, data.displayName));
  154. success();
  155. }
  156. catch (e)
  157. {
  158. error(e);
  159. }
  160. }
  161. }
  162. }), mxUtils.bind(this, function(err)
  163. {
  164. window.clearTimeout(timeoutThread);
  165. if (acceptResponse)
  166. {
  167. error(err);
  168. }
  169. }));
  170. };
  171. /**
  172. * Authorizes the client, gets the userId and calls <open>.
  173. */
  174. OneDriveClient.prototype.resetTokenRefresh = function(expires_in)
  175. {
  176. if (this.tokenRefreshThread != null)
  177. {
  178. window.clearTimeout(this.tokenRefreshThread);
  179. this.tokenRefreshThread = null;
  180. }
  181. // Starts timer to refresh token before it expires
  182. if (expires_in > 0)
  183. {
  184. this.tokenRefreshInterval = expires_in * 1000;
  185. this.tokenRefreshThread = window.setTimeout(mxUtils.bind(this, function()
  186. {
  187. //Get a new fresh accessToken
  188. this.authenticate(this.emptyFn, this.emptyFn, true);
  189. }), expires_in * 900);
  190. }
  191. };
  192. /**
  193. * Authorizes the client, gets the userId and calls <open>.
  194. */
  195. OneDriveClient.prototype.authenticate = function(success, error, failOnAuth)
  196. {
  197. if (this.isExtAuth)
  198. {
  199. window.parent.oneDriveAuth(mxUtils.bind(this, function(newAuthInfo)
  200. {
  201. this.updateAuthInfo(newAuthInfo, true, this.endpointHint == null, success, error);
  202. }), error, window.urlParams != null && urlParams['odAuthCancellable'] == '1');
  203. return;
  204. }
  205. var req = new mxXmlRequest(this.redirectUri + '?getState=1', null, 'GET');
  206. req.send(mxUtils.bind(this, function(req)
  207. {
  208. if (req.getStatus() >= 200 && req.getStatus() <= 299)
  209. {
  210. this.authenticateStep2(req.getText(), success, error, failOnAuth);
  211. }
  212. else if (error != null)
  213. {
  214. error(req);
  215. }
  216. }), error);
  217. };
  218. /**
  219. * Authorizes the client, gets the userId and calls <open>.
  220. */
  221. OneDriveClient.prototype.updateAuthInfo = function(newAuthInfo, remember, forceUserUpdate, success, error)
  222. {
  223. if (forceUserUpdate)
  224. {
  225. this.setUser(null);
  226. }
  227. _token = newAuthInfo.access_token;
  228. delete newAuthInfo.access_token; //Don't store access token
  229. newAuthInfo.expiresOn = Date.now() + newAuthInfo.expires_in * 1000;
  230. this.tokenExpiresOn = newAuthInfo.expiresOn;
  231. newAuthInfo.remember = remember;
  232. this.setPersistentToken(JSON.stringify(newAuthInfo), !remember);
  233. this.resetTokenRefresh(newAuthInfo.expires_in);
  234. if (forceUserUpdate)
  235. {
  236. //Find out the type of the account + endpoint
  237. this.getAccountTypeAndEndpoint(mxUtils.bind(this, function()
  238. {
  239. success();
  240. }), error);
  241. }
  242. else
  243. {
  244. success();
  245. }
  246. };
  247. /**
  248. * Authorizes the client, gets the userId and calls <open>.
  249. */
  250. OneDriveClient.prototype.authenticateStep2 = function(state, success, error, failOnAuth)
  251. {
  252. if (window.onOneDriveCallback == null)
  253. {
  254. var auth = mxUtils.bind(this, function()
  255. {
  256. var acceptAuthResponse = true;
  257. //Retry request with refreshed token
  258. var authInfo = JSON.parse(this.getPersistentToken(true));
  259. if (authInfo != null)
  260. {
  261. var req = new mxXmlRequest(this.redirectUri + '?state=' + encodeURIComponent('cId=' + this.clientId +
  262. '&domain=' + window.location.host + '&token=' + state), null, 'GET'); // To identify which app/domain is used
  263. req.send(mxUtils.bind(this, function(req)
  264. {
  265. if (req.getStatus() >= 200 && req.getStatus() <= 299)
  266. {
  267. try
  268. {
  269. this.updateAuthInfo(JSON.parse(req.getText()), authInfo.remember, false, success, error);
  270. }
  271. catch (e)
  272. {
  273. error({message: mxResources.get('authFailed'), retry: auth});
  274. }
  275. }
  276. else
  277. {
  278. this.clearPersistentToken();
  279. this.setUser(null);
  280. _token = null;
  281. // (Unauthorized) [e.g, invalid refresh token] or bad request
  282. if ((req.getStatus() == 401 || req.getStatus() == 400) && !failOnAuth)
  283. {
  284. auth();
  285. }
  286. else
  287. {
  288. error({message: mxResources.get('accessDenied'), retry: auth});
  289. }
  290. }
  291. }), error);
  292. }
  293. else
  294. {
  295. this.ui.showAuthDialog(this, true, mxUtils.bind(this, function(remember, authSuccess)
  296. {
  297. var url = this.authUrl + '/oauth2/v2.0/authorize' +
  298. '?client_id=' + this.clientId + '&response_type=code' +
  299. '&redirect_uri=' + encodeURIComponent(this.redirectUri) +
  300. '&scope=' + encodeURIComponent(this.scopes + (remember? ' offline_access' : '')) +
  301. '&state=' + encodeURIComponent('cId=' + this.clientId + '&domain=' + window.location.host + '&token=' + state); //To identify which app/domain is used
  302. var width = 525,
  303. height = 525,
  304. screenX = window.screenX,
  305. screenY = window.screenY,
  306. outerWidth = window.outerWidth,
  307. outerHeight = window.outerHeight;
  308. var left = screenX + Math.max(outerWidth - width, 0) / 2;
  309. var top = screenY + Math.max(outerHeight - height, 0) / 2;
  310. var features = ['width=' + width, 'height=' + height,
  311. 'top=' + top, 'left=' + left,
  312. 'status=no', 'resizable=yes',
  313. 'toolbar=no', 'menubar=no',
  314. 'scrollbars=yes'];
  315. var popup = window.open(url, 'odauth', features.join(','));
  316. if (popup != null)
  317. {
  318. window.onOneDriveCallback = mxUtils.bind(this, function(authInfo, authWindow)
  319. {
  320. if (acceptAuthResponse)
  321. {
  322. window.onOneDriveCallback = null;
  323. acceptAuthResponse = false;
  324. try
  325. {
  326. if (authInfo == null)
  327. {
  328. error({message: mxResources.get('accessDenied'), retry: auth});
  329. }
  330. else
  331. {
  332. if (authSuccess != null)
  333. {
  334. authSuccess();
  335. }
  336. this.updateAuthInfo(authInfo, remember, true, success, error);
  337. }
  338. }
  339. catch (e)
  340. {
  341. error(e);
  342. }
  343. finally
  344. {
  345. if (authWindow != null)
  346. {
  347. authWindow.close();
  348. }
  349. }
  350. }
  351. else if (authWindow != null)
  352. {
  353. authWindow.close();
  354. }
  355. });
  356. popup.focus();
  357. }
  358. }), mxUtils.bind(this, function()
  359. {
  360. if (acceptAuthResponse)
  361. {
  362. window.onOneDriveCallback = null;
  363. acceptAuthResponse = false;
  364. error({message: mxResources.get('accessDenied'), retry: auth});
  365. }
  366. }));
  367. }
  368. });
  369. auth();
  370. }
  371. else
  372. {
  373. error({code: App.ERROR_BUSY});
  374. }
  375. };
  376. /**
  377. * Authorizes the client, gets the userId and calls <open>.
  378. */
  379. OneDriveClient.prototype.getAccountTypeAndEndpoint = function(success, error)
  380. {
  381. this.get(this.baseUrl + '/me/drive/root', mxUtils.bind(this, function(req)
  382. {
  383. try
  384. {
  385. if (req.getStatus() >= 200 && req.getStatus() <= 299)
  386. {
  387. var resp = JSON.parse(req.getText());
  388. if (resp.webUrl.indexOf('.sharepoint.com') > 0)
  389. {
  390. //TODO Confirm this works with all sharepoint sites
  391. this.endpointHint = resp.webUrl.replace('/Documents', '/_layouts/15/onedrive.aspx');
  392. }
  393. else
  394. {
  395. this.endpointHint = this.defEndpointHint;
  396. }
  397. //Update authInfo with endpointHint
  398. var authInfo = JSON.parse(this.getPersistentToken(true));
  399. if (authInfo != null)
  400. {
  401. authInfo.endpointHint = this.endpointHint;
  402. this.setPersistentToken(JSON.stringify(authInfo), !authInfo.remember);
  403. }
  404. success();
  405. return;
  406. }
  407. }
  408. catch(e) {}
  409. //It is expected to work as this call immediately follows getting a fresh access token
  410. error({message: mxResources.get('unknownError') + ' (Code: ' + req.getStatus() + ')'});
  411. }), error);
  412. };
  413. /**
  414. * Checks if the client is authorized and calls the next step.
  415. */
  416. OneDriveClient.prototype.executeRequest = function(url, success, error)
  417. {
  418. var doExecute = mxUtils.bind(this, function(failOnAuth)
  419. {
  420. var acceptResponse = true;
  421. var timeoutThread = window.setTimeout(mxUtils.bind(this, function()
  422. {
  423. acceptResponse = false;
  424. error({code: App.ERROR_TIMEOUT, retry: doExecute});
  425. }), this.ui.timeout);
  426. this.get(url, mxUtils.bind(this, function(req)
  427. {
  428. window.clearTimeout(timeoutThread);
  429. if (acceptResponse)
  430. {
  431. // 404 (file not found) is a valid response for checkExists
  432. if ((req.getStatus() >= 200 && req.getStatus() <= 299) || req.getStatus() == 404)
  433. {
  434. if (this.user == null)
  435. {
  436. this.updateUser(this.emptyFn, this.emptyFn, true);
  437. }
  438. success(req);
  439. }
  440. // 400 is returns if wrong user for this file
  441. else if (!failOnAuth && (req.getStatus() === 401 || req.getStatus() === 400))
  442. {
  443. //Authorize again using the refresh token
  444. this.authenticate(function()
  445. {
  446. doExecute(true);
  447. }, error, failOnAuth);
  448. }
  449. else
  450. {
  451. error(this.parseRequestText(req));
  452. }
  453. }
  454. }), mxUtils.bind(this, function(err)
  455. {
  456. window.clearTimeout(timeoutThread);
  457. if (acceptResponse)
  458. {
  459. error(err);
  460. }
  461. }));
  462. });
  463. if (_token == null || this.tokenExpiresOn - Date.now() < 60000) //60 sec tolerance window
  464. {
  465. this.authenticate(function()
  466. {
  467. doExecute(true);
  468. }, error);
  469. }
  470. else
  471. {
  472. doExecute(false);
  473. }
  474. };
  475. /**
  476. * Checks if the client is authorized and calls the next step.
  477. */
  478. OneDriveClient.prototype.checkToken = function(fn, error)
  479. {
  480. if (_token == null || this.tokenRefreshThread == null || this.tokenExpiresOn - Date.now() < 60000)
  481. {
  482. this.authenticate(fn, (error != null) ? error : this.emptyFn);
  483. }
  484. else
  485. {
  486. fn();
  487. }
  488. };
  489. /**
  490. * Authorizes the client, gets the userId and calls <open>.
  491. */
  492. OneDriveClient.prototype.getItemRef = function(id)
  493. {
  494. var idParts = id.split('/');
  495. if (idParts.length > 1)
  496. {
  497. return {driveId: idParts[0], id: idParts[1]};
  498. }
  499. else
  500. {
  501. return {id: id};
  502. }
  503. };
  504. /**
  505. * Authorizes the client, gets the userId and calls <open>.
  506. */
  507. OneDriveClient.prototype.getItemURL = function(id, relative)
  508. {
  509. var idParts = id.split('/');
  510. if (idParts.length > 1)
  511. {
  512. var driveId = idParts[0];
  513. var itemId = idParts[1];
  514. return (relative? '' : this.baseUrl) + '/drives/' + driveId + (itemId == 'root' ? '/root' : '/items/' + itemId);
  515. }
  516. else
  517. {
  518. return (relative? '' : this.baseUrl) + '/me/drive/items/' + id;
  519. }
  520. };
  521. /**
  522. * Checks if the client is authorized and calls the next step.
  523. */
  524. OneDriveClient.prototype.getLibrary = function(id, success, error)
  525. {
  526. this.getFile(id, success, error, false, true);
  527. };
  528. /**
  529. * Workaround for added content to HTML files in Sharepoint.
  530. */
  531. OneDriveClient.prototype.removeExtraHtmlContent = function(data)
  532. {
  533. var idx = data.lastIndexOf('<html><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8"><meta name="Robots" ');
  534. if (idx > 0)
  535. {
  536. data = data.substring(0, idx);
  537. }
  538. return data;
  539. };
  540. /**
  541. * Checks if the client is authorized and calls the next step.
  542. */
  543. OneDriveClient.prototype.getFile = function(id, success, error, denyConvert, asLibrary)
  544. {
  545. asLibrary = (asLibrary != null) ? asLibrary : false;
  546. this.executeRequest(this.getItemURL(id), mxUtils.bind(this, function(req)
  547. {
  548. if (req.getStatus() >= 200 && req.getStatus() <= 299)
  549. {
  550. var meta = JSON.parse(req.getText());
  551. var binary = /\.png$/i.test(meta.name);
  552. // Handles .vsdx, Gliffy and PNG+XML files by creating a temporary file
  553. if (/\.v(dx|sdx?)$/i.test(meta.name) || /\.gliffy$/i.test(meta.name) ||
  554. /\.pdf$/i.test(meta.name) || (!this.ui.useCanvasForExport && binary))
  555. {
  556. var mimeType = (meta.file != null) ? meta.file.mimeType : null;
  557. this.ui.convertFile(meta['@microsoft.graph.downloadUrl'], meta.name, mimeType,
  558. this.extension, success, error);
  559. }
  560. else
  561. {
  562. var acceptResponse = true;
  563. var timeoutThread = window.setTimeout(mxUtils.bind(this, function()
  564. {
  565. acceptResponse = false;
  566. error({code: App.ERROR_TIMEOUT})
  567. }), this.ui.timeout);
  568. this.ui.editor.loadUrl(meta['@microsoft.graph.downloadUrl'], mxUtils.bind(this, function(data)
  569. {
  570. try
  571. {
  572. window.clearTimeout(timeoutThread);
  573. if (acceptResponse)
  574. {
  575. if (/\.html$/i.test(meta.name))
  576. {
  577. data = this.removeExtraHtmlContent(data);
  578. }
  579. var index = (binary) ? data.lastIndexOf(',') : -1;
  580. var file = null;
  581. if (index > 0)
  582. {
  583. var xml = this.ui.extractGraphModelFromPng(data);
  584. if (xml != null && xml.length > 0)
  585. {
  586. data = xml;
  587. }
  588. else
  589. {
  590. // Imports as PNG image
  591. file = new LocalFile(this.ui, data, meta.name, true);
  592. }
  593. }
  594. // Checks for base64 encoded mxfile
  595. else if (data.substring(0, 32) == 'data:image/png;base64,PG14ZmlsZS')
  596. {
  597. var temp = data.substring(22);
  598. data = (window.atob && !mxClient.IS_SF) ? atob(temp) : Base64.decode(temp);
  599. }
  600. if (Graph.fileSupport && new XMLHttpRequest().upload && this.ui.isRemoteFileFormat(data, meta['@microsoft.graph.downloadUrl']))
  601. {
  602. this.ui.parseFileData(data, mxUtils.bind(this, function(xhr)
  603. {
  604. try
  605. {
  606. if (xhr.readyState == 4)
  607. {
  608. if (xhr.status >= 200 && xhr.status <= 299)
  609. {
  610. success(new LocalFile(this.ui, xhr.responseText, meta.name + this.extension, true));
  611. }
  612. else if (error != null)
  613. {
  614. error({message: mxResources.get('errorLoadingFile')});
  615. }
  616. }
  617. }
  618. catch (e)
  619. {
  620. if (error != null)
  621. {
  622. error(e);
  623. }
  624. else
  625. {
  626. throw e;
  627. }
  628. }
  629. }), meta.name);
  630. }
  631. else
  632. {
  633. if (file != null)
  634. {
  635. success(file);
  636. }
  637. else if (asLibrary)
  638. {
  639. success(new OneDriveLibrary(this.ui, data, meta));
  640. }
  641. else
  642. {
  643. success(new OneDriveFile(this.ui, data, meta));
  644. }
  645. }
  646. }
  647. }
  648. catch (e)
  649. {
  650. if (error != null)
  651. {
  652. error(e);
  653. }
  654. else
  655. {
  656. throw e;
  657. }
  658. }
  659. }), mxUtils.bind(this, function(req)
  660. {
  661. window.clearTimeout(timeoutThread);
  662. if (acceptResponse)
  663. {
  664. error(this.parseRequestText(req));
  665. }
  666. }), binary || (meta.file != null && meta.file.mimeType != null &&
  667. ((meta.file.mimeType.substring(0, 6) == 'image/' &&
  668. meta.file.mimeType.substring(0, 9) != 'image/svg') ||
  669. meta.file.mimeType == 'application/pdf')));
  670. }
  671. }
  672. else
  673. {
  674. if (this.isExtAuth)
  675. {
  676. error({message: mxResources.get('fileNotFoundOrDenied'),
  677. ownerEmail: window.urlParams != null? urlParams['ownerEml'] : null});
  678. }
  679. else
  680. {
  681. error(this.parseRequestText(req));
  682. }
  683. }
  684. }), function(err)
  685. {
  686. if (error != null)
  687. {
  688. // Replaces ObjectHandle is Invalid error message
  689. if (err != null && err.error != null &&
  690. err.error.message === 'ObjectHandle is Invalid')
  691. {
  692. err.error.message = mxResources.get('fileNotFoundOrDenied');
  693. }
  694. error(err);
  695. }
  696. });
  697. };
  698. /**
  699. * Translates this point by the given vector.
  700. *
  701. * @param {number} dx X-coordinate of the translation.
  702. * @param {number} dy Y-coordinate of the translation.
  703. */
  704. OneDriveClient.prototype.renameFile = function(file, filename, success, error)
  705. {
  706. if (file != null && filename != null)
  707. {
  708. if (!this.isValidFilename(filename))
  709. {
  710. error({message: this.invalidFilenameRegExs[0].test(filename) ?
  711. mxResources.get('oneDriveCharsNotAllowed') : mxResources.get('oneDriveInvalidDeviceName')});
  712. return;
  713. }
  714. // TODO: How to force overwrite file with same name?
  715. this.checkExists(file.getParentId(), filename, false, mxUtils.bind(this, function(checked)
  716. {
  717. if (checked)
  718. {
  719. this.writeFile(this.getItemURL(file.getId()), JSON.stringify({name: filename}), 'PATCH', 'application/json', success, error);
  720. }
  721. else
  722. {
  723. error();
  724. }
  725. }));
  726. }
  727. };
  728. /**
  729. * Translates this point by the given vector.
  730. *
  731. * @param {number} dx X-coordinate of the translation.
  732. * @param {number} dy Y-coordinate of the translation.
  733. */
  734. OneDriveClient.prototype.moveFile = function(id, folderId, success, error)
  735. {
  736. //check that the source and destination are on the same drive
  737. var folderInfo = this.getItemRef(folderId);
  738. var fileInfo = this.getItemRef(id);
  739. if (folderInfo.driveId != fileInfo.driveId)
  740. {
  741. error({message: mxResources.get('cannotMoveOneDrive', null, 'Moving a file between accounts is not supported yet.')});
  742. }
  743. else
  744. {
  745. this.writeFile(this.getItemURL(id), JSON.stringify({parentReference: folderInfo}), 'PATCH', 'application/json', success, error);
  746. }
  747. };
  748. /**
  749. * Translates this point by the given vector.
  750. *
  751. * @param {number} dx X-coordinate of the translation.
  752. * @param {number} dy Y-coordinate of the translation.
  753. */
  754. OneDriveClient.prototype.insertLibrary = function(filename, data, success, error, folderId)
  755. {
  756. this.insertFile(filename, data, success, error, true, folderId);
  757. };
  758. /**
  759. * Translates this point by the given vector.
  760. *
  761. * @param {number} dx X-coordinate of the translation.
  762. * @param {number} dy Y-coordinate of the translation.
  763. */
  764. OneDriveClient.prototype.insertFile = function(filename, data, success, error, asLibrary, folderId)
  765. {
  766. if (!this.isValidFilename(filename))
  767. {
  768. error({message: this.invalidFilenameRegExs[0].test(filename) ?
  769. mxResources.get('oneDriveCharsNotAllowed') : mxResources.get('oneDriveInvalidDeviceName')});
  770. return;
  771. }
  772. asLibrary = (asLibrary != null) ? asLibrary : false;
  773. this.checkExists(folderId, filename, true, mxUtils.bind(this, function(checked)
  774. {
  775. if (checked)
  776. {
  777. var folder = '/me/drive/root';
  778. if (folderId != null)
  779. {
  780. folder = this.getItemURL(folderId, true);
  781. }
  782. var insertSuccess = mxUtils.bind(this, function(meta)
  783. {
  784. if (asLibrary)
  785. {
  786. success(new OneDriveLibrary(this.ui, data, meta));
  787. }
  788. else
  789. {
  790. success(new OneDriveFile(this.ui, data, meta));
  791. }
  792. });
  793. var url = this.baseUrl + folder + '/children/' + encodeURIComponent(filename) + '/content';
  794. //OneDrive has a limit on PUT API of 4MB, larger files needs to use the upload session method
  795. if (data.length >= 4000000 /*4MB*/)
  796. {
  797. //Create empty file first then upload. TODO Can we get an upload session for non-existing files?
  798. this.writeFile(url, '', 'PUT', null, mxUtils.bind(this, function(meta)
  799. {
  800. this.writeLargeFile(this.getItemURL(meta.id), data, insertSuccess, error);
  801. }), error);
  802. }
  803. else
  804. {
  805. this.writeFile(url, data, 'PUT', null, insertSuccess, error);
  806. }
  807. }
  808. else
  809. {
  810. error();
  811. }
  812. }))
  813. };
  814. /**
  815. * Translates this point by the given vector.
  816. *
  817. * @param {number} dx X-coordinate of the translation.
  818. * @param {number} dy Y-coordinate of the translation.
  819. */
  820. OneDriveClient.prototype.checkExists = function(parentId, filename, askReplace, fn)
  821. {
  822. var folder = '/me/drive/root';
  823. if (parentId != null)
  824. {
  825. folder = this.getItemURL(parentId, true);
  826. }
  827. this.executeRequest(this.baseUrl + folder + '/children/' + encodeURIComponent(filename), mxUtils.bind(this, function(req)
  828. {
  829. if (req.getStatus() == 404)
  830. {
  831. fn(true);
  832. }
  833. else
  834. {
  835. if (askReplace)
  836. {
  837. this.ui.spinner.stop();
  838. this.ui.confirm(mxResources.get('replaceIt', [filename]), function()
  839. {
  840. fn(true);
  841. }, function()
  842. {
  843. fn(false);
  844. });
  845. }
  846. else
  847. {
  848. this.ui.spinner.stop();
  849. this.ui.showError(mxResources.get('error'), mxResources.get('fileExists'), mxResources.get('ok'), function()
  850. {
  851. fn(false);
  852. });
  853. }
  854. }
  855. }), function(req)
  856. {
  857. fn(false);
  858. }, true);
  859. };
  860. /**
  861. * Translates this point by the given vector.
  862. *
  863. * @param {number} dx X-coordinate of the translation.
  864. * @param {number} dy Y-coordinate of the translation.
  865. */
  866. OneDriveClient.prototype.saveFile = function(file, success, error, etag)
  867. {
  868. try
  869. {
  870. var savedData = file.getData();
  871. var fn = mxUtils.bind(this, function(data)
  872. {
  873. var saveSuccess = mxUtils.bind(this, function(resp)
  874. {
  875. success(resp, savedData);
  876. });
  877. var url = this.getItemURL(file.getId());
  878. //OneDrive has a limit on PUT API of 4MB, larger files needs to use the upload session method
  879. if (data.length >= 4000000 /*4MB*/)
  880. {
  881. this.writeLargeFile(url, data, saveSuccess, error, etag);
  882. }
  883. else
  884. {
  885. this.writeFile(url + '/content/', data, 'PUT', null, saveSuccess, error, etag);
  886. }
  887. });
  888. if (this.ui.useCanvasForExport && /(\.png)$/i.test(file.meta.name))
  889. {
  890. var p = this.ui.getPngFileProperties(this.ui.fileNode);
  891. this.ui.getEmbeddedPng(mxUtils.bind(this, function(data)
  892. {
  893. fn(this.ui.base64ToBlob(data, 'image/png'));
  894. }), error, (this.ui.getCurrentFile() != file) ?
  895. savedData : null, p.scale, p.border);
  896. }
  897. else
  898. {
  899. fn(savedData);
  900. }
  901. }
  902. catch (e)
  903. {
  904. error(e);
  905. }
  906. };
  907. OneDriveClient.prototype.writeLargeFile = function(url, data, success, error, etag)
  908. {
  909. try
  910. {
  911. var chunkSize = 4 * 1024 * 1024; //4MB chunk;
  912. if (data != null)
  913. {
  914. var dataByteLength = (new TextEncoder().encode(data)).length;
  915. var uploadPart = mxUtils.bind(this, function(uploadUrl, index, byteIndex, retryCount)
  916. {
  917. try
  918. {
  919. retryCount = retryCount || 0;
  920. var acceptResponse = true;
  921. var timeoutThread = null;
  922. timeoutThread = window.setTimeout(mxUtils.bind(this, function()
  923. {
  924. acceptResponse = false;
  925. error({code: App.ERROR_TIMEOUT});
  926. }), this.ui.timeout);
  927. var part = data.substr(index, chunkSize);
  928. var partByteLength = (new TextEncoder().encode(part)).length;
  929. var req = new mxXmlRequest(uploadUrl, part, 'PUT');
  930. req.setRequestHeaders = mxUtils.bind(this, function(request, params)
  931. {
  932. request.setRequestHeader('Content-Range', 'bytes ' + byteIndex + '-' +
  933. (byteIndex + partByteLength - 1) + '/' + dataByteLength);
  934. });
  935. req.send(mxUtils.bind(this, function(req)
  936. {
  937. window.clearTimeout(timeoutThread);
  938. if (acceptResponse)
  939. {
  940. var status = req.getStatus();
  941. if (status >= 200 && status <= 299)
  942. {
  943. var nextByte = index + part.length;
  944. if (nextByte == data.length)
  945. {
  946. success(JSON.parse(req.getText()));
  947. }
  948. else
  949. {
  950. uploadPart(uploadUrl, nextByte, byteIndex + partByteLength, retryCount);
  951. }
  952. }
  953. else if (status >= 500 && status <= 599 && retryCount < 2) //Retry on server errors
  954. {
  955. retryCount++;
  956. uploadPart(uploadUrl, index, byteIndex, retryCount);
  957. }
  958. else
  959. {
  960. error(this.parseRequestText(req), req);
  961. }
  962. }
  963. }), mxUtils.bind(this, function(req)
  964. {
  965. window.clearTimeout(timeoutThread);
  966. if (acceptResponse)
  967. {
  968. error(this.parseRequestText(req));
  969. }
  970. }));
  971. }
  972. catch (e)
  973. {
  974. error(e);
  975. }
  976. });
  977. var doExecute = mxUtils.bind(this, function(failOnAuth)
  978. {
  979. try
  980. {
  981. var acceptResponse = true;
  982. var timeoutThread = null;
  983. try
  984. {
  985. timeoutThread = window.setTimeout(mxUtils.bind(this, function()
  986. {
  987. acceptResponse = false;
  988. error({code: App.ERROR_TIMEOUT});
  989. }), this.ui.timeout);
  990. }
  991. catch (e)
  992. {
  993. // Ignore window closed
  994. }
  995. var req = new mxXmlRequest(url + '/createUploadSession', '{}', 'POST');
  996. req.setRequestHeaders = mxUtils.bind(this, function(request, params)
  997. {
  998. request.setRequestHeader('Content-Type', 'application/json');
  999. request.setRequestHeader('Authorization', 'Bearer ' + _token);
  1000. if (etag != null)
  1001. {
  1002. request.setRequestHeader('If-Match', etag);
  1003. }
  1004. });
  1005. req.send(mxUtils.bind(this, function(req)
  1006. {
  1007. window.clearTimeout(timeoutThread);
  1008. if (acceptResponse)
  1009. {
  1010. if (req.getStatus() >= 200 && req.getStatus() <= 299)
  1011. {
  1012. var resp = JSON.parse(req.getText());
  1013. uploadPart(resp.uploadUrl, 0, 0);
  1014. }
  1015. else if (!failOnAuth && req.getStatus() === 401)
  1016. {
  1017. this.authenticate(function()
  1018. {
  1019. doExecute(true);
  1020. }, error, failOnAuth);
  1021. }
  1022. else
  1023. {
  1024. error(this.parseRequestText(req), req);
  1025. }
  1026. }
  1027. }), mxUtils.bind(this, function(req)
  1028. {
  1029. window.clearTimeout(timeoutThread);
  1030. if (acceptResponse)
  1031. {
  1032. error(this.parseRequestText(req));
  1033. }
  1034. }));
  1035. }
  1036. catch (e)
  1037. {
  1038. error(e);
  1039. }
  1040. });
  1041. if (_token == null || this.tokenExpiresOn - Date.now() < 60000) //60 sec tolerance window
  1042. {
  1043. this.authenticate(function()
  1044. {
  1045. doExecute(true);
  1046. }, error);
  1047. }
  1048. else
  1049. {
  1050. doExecute(false);
  1051. }
  1052. }
  1053. else
  1054. {
  1055. error({message: mxResources.get('unknownError')});
  1056. }
  1057. }
  1058. catch (e)
  1059. {
  1060. error(e);
  1061. }
  1062. };
  1063. /**
  1064. * Translates this point by the given vector.
  1065. *
  1066. * @param {number} dx X-coordinate of the translation.
  1067. * @param {number} dy Y-coordinate of the translation.
  1068. */
  1069. OneDriveClient.prototype.writeFile = function(url, data, method, contentType, success, error, etag)
  1070. {
  1071. try
  1072. {
  1073. if (url != null && data != null)
  1074. {
  1075. var doExecute = mxUtils.bind(this, function(failOnAuth)
  1076. {
  1077. try
  1078. {
  1079. var acceptResponse = true;
  1080. var timeoutThread = null;
  1081. try
  1082. {
  1083. timeoutThread = window.setTimeout(mxUtils.bind(this, function()
  1084. {
  1085. acceptResponse = false;
  1086. error({code: App.ERROR_TIMEOUT});
  1087. }), this.ui.timeout);
  1088. }
  1089. catch (e)
  1090. {
  1091. // Ignore window closed
  1092. }
  1093. var req = new mxXmlRequest(url, data, method);
  1094. req.setRequestHeaders = mxUtils.bind(this, function(request, params)
  1095. {
  1096. // Space deletes content type header. Specification says "text/plain"
  1097. // should work but returns an 415 Unsupported Media Type error
  1098. request.setRequestHeader('Content-Type', contentType || ' ');
  1099. //TODO This header is needed for moving a file between two different drives.
  1100. // Note: the response is empty when this header is used, also the server may take some time to really execute the request (i.e. async)
  1101. //request.setRequestHeader('Prefer', 'respond-async');
  1102. request.setRequestHeader('Authorization', 'Bearer ' + _token);
  1103. if (etag != null)
  1104. {
  1105. request.setRequestHeader('If-Match', etag);
  1106. }
  1107. });
  1108. req.send(mxUtils.bind(this, function(req)
  1109. {
  1110. window.clearTimeout(timeoutThread);
  1111. if (acceptResponse)
  1112. {
  1113. if (req.getStatus() >= 200 && req.getStatus() <= 299)
  1114. {
  1115. if (this.user == null)
  1116. {
  1117. this.updateUser(this.emptyFn, this.emptyFn, true);
  1118. }
  1119. success(JSON.parse(req.getText()));
  1120. }
  1121. else if (!failOnAuth && req.getStatus() === 401)
  1122. {
  1123. this.authenticate(function()
  1124. {
  1125. doExecute(true);
  1126. }, error, failOnAuth);
  1127. }
  1128. else
  1129. {
  1130. error(this.parseRequestText(req), req);
  1131. }
  1132. }
  1133. }), mxUtils.bind(this, function(req)
  1134. {
  1135. window.clearTimeout(timeoutThread);
  1136. if (acceptResponse)
  1137. {
  1138. error(this.parseRequestText(req));
  1139. }
  1140. }));
  1141. }
  1142. catch (e)
  1143. {
  1144. error(e);
  1145. }
  1146. });
  1147. if (_token == null || this.tokenExpiresOn - Date.now() < 60000) //60 sec tolerance window
  1148. {
  1149. this.authenticate(function()
  1150. {
  1151. doExecute(true);
  1152. }, error);
  1153. }
  1154. else
  1155. {
  1156. doExecute(false);
  1157. }
  1158. }
  1159. else
  1160. {
  1161. error({message: mxResources.get('unknownError')});
  1162. }
  1163. }
  1164. catch (e)
  1165. {
  1166. error(e);
  1167. }
  1168. };
  1169. /**
  1170. * Checks if the client is authorized and calls the next step.
  1171. */
  1172. OneDriveClient.prototype.parseRequestText = function(req)
  1173. {
  1174. var result = {message: mxResources.get('unknownError')};
  1175. try
  1176. {
  1177. result = JSON.parse(req.getText());
  1178. result.status = req.getStatus();
  1179. if (result.error)
  1180. {
  1181. result.error.status = result.status;
  1182. result.error.code = result.status;
  1183. }
  1184. }
  1185. catch (e)
  1186. {
  1187. // ignore
  1188. }
  1189. return result;
  1190. };
  1191. /**
  1192. * Checks if the client is authorized and calls the next step.
  1193. */
  1194. OneDriveClient.prototype.pickLibrary = function(fn)
  1195. {
  1196. this.pickFile(function(id)
  1197. {
  1198. // Ignores second argument
  1199. fn(id);
  1200. });
  1201. };
  1202. /**
  1203. * Checks if the client is authorized and calls the next step.
  1204. */
  1205. OneDriveClient.prototype.createInlinePicker = function(fn, foldersOnly, acceptAllFiles)
  1206. {
  1207. return mxUtils.bind(this, function()
  1208. {
  1209. var odPicker = null;
  1210. var div = document.createElement('div');
  1211. div.style.position = 'relative';
  1212. var dlg = new CustomDialog(this.ui, div, mxUtils.bind(this, function()
  1213. {
  1214. var item = odPicker.getSelectedItem();
  1215. if (item != null)
  1216. {
  1217. if (foldersOnly && typeof item.folder == 'object')
  1218. {
  1219. fn({value: [item]});
  1220. }
  1221. else if (!item.folder && this.ui.spinner.spin(document.body, mxResources.get('loading')))
  1222. {
  1223. var id = OneDriveFile.prototype.getIdOf(item);
  1224. this.executeRequest(this.getItemURL(id), mxUtils.bind(this, function(req)
  1225. {
  1226. this.ui.spinner.stop();
  1227. if (req.getStatus() >= 200 && req.getStatus() <= 299)
  1228. {
  1229. var meta = JSON.parse(req.getText());
  1230. fn(id, {value: [meta]});
  1231. }
  1232. else
  1233. {
  1234. this.ui.handleError({code: req.getStatus()});
  1235. }
  1236. }), mxUtils.bind(this, function(req)
  1237. {
  1238. this.ui.spinner.stop();
  1239. this.ui.handleError(req);
  1240. }));
  1241. }
  1242. return;
  1243. }
  1244. return mxResources.get('invalidSel', null, 'Invalid selection');
  1245. }), null, mxResources.get(foldersOnly? 'select' :'open'), null, null, null, null, true);
  1246. this.ui.showDialog(dlg.container, 550, 500, true, true);
  1247. //Set width/height of the picker container
  1248. div.style.width = dlg.container.parentNode.style.width;
  1249. div.style.height = (parseInt(dlg.container.parentNode.style.height) - 60) + 'px';
  1250. odPicker = new mxODPicker(div, null, mxUtils.bind(this, function(url, success, error, isAbsUrl)
  1251. {
  1252. this.executeRequest(isAbsUrl? url : this.baseUrl + url, function(req)
  1253. {
  1254. success(JSON.parse(req.getText()));
  1255. }, error);
  1256. }), mxUtils.bind(this, function(id, driveId, success, error)
  1257. {
  1258. this.executeRequest(this.baseUrl + '/drives/' + driveId + '/items/' + id, function(req)
  1259. {
  1260. success(JSON.parse(req.getText()));
  1261. }, error);
  1262. }), null, null, function(item)
  1263. {
  1264. if (foldersOnly) //Currently this is not called when in foldersOnly mode
  1265. {
  1266. fn({
  1267. value: [item]
  1268. });
  1269. }
  1270. else
  1271. {
  1272. fn(OneDriveFile.prototype.getIdOf(item));
  1273. }
  1274. },
  1275. mxUtils.bind(this, function(err)
  1276. {
  1277. this.ui.showError(mxResources.get('error'), err);
  1278. }), foldersOnly, null, null, null, null, acceptAllFiles);
  1279. });
  1280. };
  1281. /**
  1282. * Checks if the client is authorized and calls the next step.
  1283. */
  1284. OneDriveClient.prototype.pickFolder = function(fn, direct)
  1285. {
  1286. var errorFn = mxUtils.bind(this, function(e)
  1287. {
  1288. this.ui.showError(mxResources.get('error'), e && e.message? e.message : e);
  1289. });
  1290. var odSaveDlg = mxUtils.bind(this, function(direct)
  1291. {
  1292. var openSaveDlg = this.inlinePicker ?
  1293. this.createInlinePicker(fn, true) :
  1294. mxUtils.bind(this, function()
  1295. {
  1296. OneDrive.save(
  1297. {
  1298. clientId: this.clientId,
  1299. action: 'query',
  1300. openInNewWindow: true,
  1301. advanced:
  1302. {
  1303. 'endpointHint': mxClient.IS_IE11? null : this.endpointHint, //IE11 doen't work with our modified version, so, setting endpointHint disable using our token BUT will force relogin!
  1304. 'redirectUri': this.pickerRedirectUri,
  1305. 'queryParameters': 'select=id,name,parentReference',
  1306. 'accessToken': _token,
  1307. isConsumerAccount: false
  1308. },
  1309. success: mxUtils.bind(this, function(files)
  1310. {
  1311. fn(files);
  1312. //Update the token in case a login with a different user
  1313. if (mxClient.IS_IE11)
  1314. {
  1315. _token = files.accessToken;
  1316. }
  1317. }),
  1318. cancel: mxUtils.bind(this, function()
  1319. {
  1320. // do nothing
  1321. }),
  1322. error: errorFn
  1323. });
  1324. });
  1325. if (direct)
  1326. {
  1327. openSaveDlg();
  1328. }
  1329. else
  1330. {
  1331. this.ui.confirm(mxResources.get('useRootFolder'), mxUtils.bind(this, function()
  1332. {
  1333. fn({value: [this.rootId]});
  1334. }), openSaveDlg, mxResources.get('yes'), mxResources.get('noPickFolder') + '...', true);
  1335. }
  1336. if (this.user == null)
  1337. {
  1338. this.updateUser(this.emptyFn, this.emptyFn, true);
  1339. }
  1340. });
  1341. if (_token == null || this.tokenExpiresOn - Date.now() < 60000) //60 sec tolerance window
  1342. {
  1343. this.authenticate(mxUtils.bind(this, function()
  1344. {
  1345. // Direct only possible within user event
  1346. odSaveDlg(this.inlinePicker && direct);
  1347. }), errorFn);
  1348. }
  1349. else
  1350. {
  1351. odSaveDlg(direct);
  1352. }
  1353. };
  1354. /**
  1355. * Checks if the client is authorized and calls the next step.
  1356. */
  1357. OneDriveClient.prototype.pickFile = function(fn, acceptAllFiles)
  1358. {
  1359. fn = (fn != null) ? fn : mxUtils.bind(this, function(id)
  1360. {
  1361. this.ui.loadFile('W' + encodeURIComponent(id));
  1362. });
  1363. var errorFn = mxUtils.bind(this, function(e)
  1364. {
  1365. this.ui.showError(mxResources.get('error'), e && e.message? e.message : e);
  1366. });
  1367. var odOpenDlg = this.inlinePicker? this.createInlinePicker(fn, null, acceptAllFiles) :
  1368. mxUtils.bind(this, function()
  1369. {
  1370. OneDrive.open(
  1371. {
  1372. clientId: this.clientId,
  1373. action: 'query',
  1374. multiSelect: false,
  1375. advanced:
  1376. {
  1377. 'endpointHint': mxClient.IS_IE11? null : this.endpointHint, //IE11 doen't work with our modified version, so, setting endpointHint disable using our token BUT will force relogin!
  1378. 'redirectUri': this.pickerRedirectUri,
  1379. 'queryParameters': 'select=id,name,parentReference,webUrl', //We can also get @microsoft.graph.downloadUrl within this request but it will break the normal process
  1380. 'accessToken': _token,
  1381. isConsumerAccount: false
  1382. },
  1383. success: mxUtils.bind(this, function(files)
  1384. {
  1385. if (files != null && files.value != null && files.value.length > 0)
  1386. {
  1387. //Update the token in case a login with a different user
  1388. if (mxClient.IS_IE11)
  1389. {
  1390. _token = files.accessToken;
  1391. }
  1392. fn(OneDriveFile.prototype.getIdOf(files.value[0]), files);
  1393. }
  1394. }),
  1395. cancel: mxUtils.bind(this, function()
  1396. {
  1397. // do nothing
  1398. }),
  1399. error: errorFn
  1400. });
  1401. if (this.user == null)
  1402. {
  1403. this.updateUser(this.emptyFn, this.emptyFn, true);
  1404. }
  1405. });
  1406. if (_token == null || this.tokenExpiresOn - Date.now() < 60000) //60 sec tolerance window
  1407. {
  1408. this.authenticate(mxUtils.bind(this, function()
  1409. {
  1410. if (this.inlinePicker)
  1411. {
  1412. odOpenDlg();
  1413. }
  1414. else
  1415. {
  1416. this.ui.showDialog(new BtnDialog(this.ui, this, mxResources.get('open'), mxUtils.bind(this, function()
  1417. {
  1418. this.ui.hideDialog();
  1419. odOpenDlg();
  1420. })).container, 300, 140, true, true);
  1421. }
  1422. }), errorFn);
  1423. }
  1424. else
  1425. {
  1426. odOpenDlg();
  1427. }
  1428. };
  1429. /**
  1430. * Checks if the client is authorized and calls the next step.
  1431. */
  1432. OneDriveClient.prototype.logout = function()
  1433. {
  1434. if (isLocalStorage)
  1435. {
  1436. var check = localStorage.getItem('odpickerv7cache');
  1437. if (check != null && check.substring(0, 19) == '{"odsdkLoginHint":{')
  1438. {
  1439. localStorage.removeItem('odpickerv7cache');
  1440. }
  1441. }
  1442. window.open(this.authUrl + '/oauth2/v2.0/logout', 'logout', 'width=525,height=525,status=no,resizable=yes,toolbar=no,menubar=no,scrollbars=yes');
  1443. //Send to server to clear refresh token cookie
  1444. this.ui.editor.loadUrl(this.redirectUri + '?doLogout=1&state=' + encodeURIComponent('cId=' + this.clientId + '&domain=' + window.location.host));
  1445. this.clearPersistentToken();
  1446. this.setUser(null);
  1447. _token = null;
  1448. };
  1449. })();