Sfoglia il codice sorgente

10.0.16 release

Former-commit-id: 93c17ee9f76b0c665b6faea8973edd894b4daac8
Gaudenz Alder 6 anni fa
parent
commit
7af088dd77

+ 16 - 0
ChangeLog

@@ -1,3 +1,19 @@
+02-JAN-2019: 10.0.16
+
+- Handles shadow change during catchup
+
+01-JAN-2019: 10.0.15
+
+- Fixes error logging
+
+01-JAN-2019: 10.0.14
+
+- Fixes possible timing issue
+
+29-DEC-2018: 10.0.13
+
+- Improved error handling for collaborative editing
+
 28-DEC-2018: 10.0.12
 
 - Fixes possible select of deleted page

+ 1 - 1
VERSION

@@ -1 +1 @@
-10.0.12
+10.0.16

+ 205 - 0
src/main/java/com/mxgraph/online/MSGraphAuthServlet.java

@@ -0,0 +1,205 @@
+/**
+ * Copyright (c) 2006-2019, JGraph Ltd
+ */
+package com.mxgraph.online;
+
+import java.io.BufferedReader;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@SuppressWarnings("serial")
+public class MSGraphAuthServlet extends HttpServlet
+{
+	public static final String DEV_CLIENT_ID = "c36dee60-2c6d-4b5f-b552-a7d21798ea52";
+	public static final String CLIENT_ID = "45c10911-200f-4e27-a666-9e9fca147395";
+
+	public static final String DEV_REDIRECT_URI = "https://test.draw.io/microsoft";
+	public static final String REDIRECT_URI = "https://www.draw.io/microsoft";
+
+	/**
+	 * Path component under war/ to locate development client secret file.
+	 */
+	public static final String DEV_CLIENT_SECRET_FILE_PATH = "/WEB-INF/msgraph_dev_client_secret";
+
+
+	/**
+	 * Path component under war/ to locate client secret file.
+	 */
+	public static final String CLIENT_SECRET_FILE_PATH = "/WEB-INF/msgraph_client_secret";
+
+	/**
+	 * 
+	 */
+	private static String DEV_CLIENT_SECRET = null;
+
+	/**
+	 * 
+	 */
+	private static String CLIENT_SECRET = null;
+
+	/**
+	 * @see HttpServlet#HttpServlet()
+	 */
+	public MSGraphAuthServlet()
+	{
+		super();
+	}
+
+	/**
+	 * Loads the key.
+	 */
+	protected void updateKeys()
+	{
+		if (DEV_CLIENT_SECRET == null)
+		{
+			try
+			{
+				DEV_CLIENT_SECRET = Utils
+						.readInputStream(getServletContext()
+								.getResourceAsStream(DEV_CLIENT_SECRET_FILE_PATH))
+						.replaceAll("\n", "");
+			}
+			catch (IOException e)
+			{
+				throw new RuntimeException("Dev client secret path invalid.");
+			}
+		}
+
+		if (CLIENT_SECRET == null)
+		{
+			try
+			{
+				CLIENT_SECRET = Utils
+						.readInputStream(getServletContext()
+								.getResourceAsStream(CLIENT_SECRET_FILE_PATH))
+						.replaceAll("\n", "");
+			}
+			catch (IOException e)
+			{
+				throw new RuntimeException("Client secret path invalid.");
+			}
+		}
+	}
+
+	/**
+	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
+	 */
+	protected void doGet(HttpServletRequest request,
+			HttpServletResponse response) throws ServletException, IOException
+	{
+		String code = request.getParameter("code");
+		String refreshToken = request.getParameter("refresh_token");
+		updateKeys();
+		
+		String secret, client, redirectUri;
+		
+		if ("127.0.0.1".equals(request.getServerName()))
+		{
+			secret = DEV_CLIENT_SECRET;
+			client = DEV_CLIENT_ID;
+			redirectUri = DEV_REDIRECT_URI;
+		}
+		else
+		{
+			secret = CLIENT_SECRET;
+			client = CLIENT_ID;
+			redirectUri = REDIRECT_URI;
+		}
+		
+
+		if (code == null && refreshToken == null)
+		{
+			response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+		}
+		else
+		{
+			String url = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
+			URL obj = new URL(url);
+			HttpURLConnection con = (HttpURLConnection) obj.openConnection();
+
+			con.setRequestMethod("POST");
+			con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
+
+			boolean jsonResponse = false;
+			StringBuilder urlParameters = new StringBuilder();
+			
+			urlParameters.append("client_id=");
+			urlParameters.append(client);
+			urlParameters.append("&redirect_uri=");
+			urlParameters.append(redirectUri);
+			urlParameters.append("&client_secret=");
+			urlParameters.append(secret);
+			
+			if (code != null)
+			{
+				urlParameters.append("&code=");
+				urlParameters.append(code);
+				urlParameters.append("&grant_type=authorization_code");
+			}
+			else
+			{
+				urlParameters.append("&refresh_token=");
+				urlParameters.append(refreshToken);
+				urlParameters.append("&grant_type=refresh_token");
+				jsonResponse = true;
+			}
+			
+			// Send post request
+			con.setDoOutput(true);
+			DataOutputStream wr = new DataOutputStream(con.getOutputStream());
+			wr.writeBytes(urlParameters.toString());
+			wr.flush();
+			wr.close();
+
+			BufferedReader in = new BufferedReader(
+					new InputStreamReader(con.getInputStream()));
+			String inputLine;
+			StringBuffer res = new StringBuffer();
+
+			//Call the opener callback function directly with the given json
+			if (!jsonResponse)
+			{
+				res.append("<!DOCTYPE html><html><head><script>");
+				res.append("if (window.opener != null && window.opener.onOneDriveCallback != null)"); 
+				res.append("{");
+				res.append("	window.opener.onOneDriveCallback("); //The following is a json containing access_token and redresh_token
+			}
+			
+			while ((inputLine = in.readLine()) != null)
+			{
+				res.append(inputLine);
+			}
+			in.close();
+
+			if (!jsonResponse)
+			{
+				res.append("	, window);");
+				res.append("}");
+				res.append("</script></head><body></body></html>");
+			}
+
+			response.setStatus(con.getResponseCode());
+			
+			OutputStream out = response.getOutputStream();
+
+			PrintWriter writer = new PrintWriter(out);
+
+			// Writes JavaScript code
+			writer.println(res.toString());
+
+			writer.flush();
+			writer.close();
+		}
+	}
+
+}

+ 0 - 0
src/main/webapp/WEB-INF/msgraph_client_secret


+ 1 - 0
src/main/webapp/WEB-INF/msgraph_dev_client_secret

@@ -0,0 +1 @@
+paFCJ4371-^cdthoVFCF1^=

+ 10 - 0
src/main/webapp/WEB-INF/web.xml

@@ -185,6 +185,16 @@
   <servlet-mapping>
     <servlet-name>LogServlet</servlet-name>
     <url-pattern>/log</url-pattern>
+  </servlet-mapping>
+    <servlet>
+    <description/>
+    <display-name>MSGraphAuthServlet</display-name>
+    <servlet-name>MSGraphAuthServlet</servlet-name>
+    <servlet-class>com.mxgraph.online.MSGraphAuthServlet</servlet-class>
+  </servlet>
+  <servlet-mapping>
+    <servlet-name>MSGraphAuthServlet</servlet-name>
+    <url-pattern>/microsoft</url-pattern>
   </servlet-mapping>
   <mime-mapping>
     <extension>css</extension>

+ 1 - 1
src/main/webapp/cache.manifest

@@ -1,7 +1,7 @@
 CACHE MANIFEST
 
 # THIS FILE WAS GENERATED. DO NOT MODIFY!
-# 12/28/2018 02:02 PM
+# 01/02/2019 11:59 AM
 
 app.html
 index.html?offline=1

File diff suppressed because it is too large
+ 30 - 30
src/main/webapp/js/app.min.js


File diff suppressed because it is too large
+ 30 - 30
src/main/webapp/js/atlas-viewer.min.js


File diff suppressed because it is too large
+ 507 - 507
src/main/webapp/js/atlas.min.js


+ 27 - 39
src/main/webapp/js/diagramly/DrawioFile.js

@@ -121,9 +121,8 @@ DrawioFile.prototype.reportEnabled = true;
  */
 DrawioFile.prototype.stats = {
 	joined: 0, /* number of join messages received */
-	reloads: 0, /* number of times the files was reloaded */
-	checksumErrors: 0, /* number of checksum errors in mergeFile */
-	mergeChecksumErrors: 0, /* number of checksum errors in merge */
+	reloads: 0, /* number of times the file was reloaded */
+	checksumErrors: 0, /* number of checksum errors */
 	bytesSent: 0, /* number of bytes send in messages */
 	bytesReceived: 0, /* number of bytes received in messages */
 	msgReceived: 0, /* number of messages received */
@@ -234,7 +233,8 @@ DrawioFile.prototype.mergeFile = function(file, success, error)
 			if (urlParams['test'] == '1')
 			{
 				EditorUi.debug('File.mergeFile', [this],
-					'patches', patches, 'backup', this.backupPatch,
+					'backup', this.backupPatch,
+					'patches', patches,
 					'checksum', current == checksum, checksum);
 			}
 			
@@ -275,11 +275,6 @@ DrawioFile.prototype.mergeFile = function(file, success, error)
 		this.inConflictState = true;
 		this.invalidChecksum = true;
 		
-		if (window.console != null && urlParams['test'] == '1')
-		{
-			console.log(e);
-		}
-
 		if (error != null)
 		{
 			error(e);
@@ -287,16 +282,7 @@ DrawioFile.prototype.mergeFile = function(file, success, error)
 
 		try
 		{
-			var user = this.getCurrentUser();
-			var uid = (user != null) ? this.ui.hashValue(user.id) : 'unknown';
-	
-			EditorUi.sendReport('Error in mergeFile ' + new Date().toISOString() + ':\n\n' +
-				'File=' + this.getId() + ' (' + this.getMode() + ')\n' +
-				((this.sync != null) ? ('Client=' + this.sync.clientId + '\n') : '') +
-				'User=' + uid + '\n' +
-				'Size=' + this.getSize() + '\n' +
-				'Sync=' + DrawioFile.SYNC + '\n\n' +
-				'Stack:\n' + e.stack);
+			this.sendErrorReport('Error in mergeFile', null, e);
 		}
 		catch (e2)
 		{
@@ -368,9 +354,9 @@ DrawioFile.prototype.checkShadow = function(shadow)
 		
 		this.sendErrorReport(
 			'Shadow is null or empty',
-			'Shadow: ' + ((shadow != null) ? shadow.length : 0) +
+			'Shadow: ' + ((shadow != null) ? shadow.length : 'null') +
 			'\nShadowPages: ' + ((this.shadowPages != null) ?
-				this.shadowPages.length : 0) +
+				this.shadowPages.length : 'null') +
 			'\nShadowData: ' + data);
 	}
 };
@@ -446,7 +432,7 @@ DrawioFile.prototype.checksumError = function(error, patches, details)
 /**
  * Adds the listener for automatically saving the diagram for local changes.
  */
-DrawioFile.prototype.sendErrorReport = function(title, details)
+DrawioFile.prototype.sendErrorReport = function(title, details, error)
 {
 	try
 	{
@@ -468,7 +454,7 @@ DrawioFile.prototype.sendErrorReport = function(title, details)
 			ext = filename.substring(dot);
 		}
 		
-		var stack = new Error().stack;
+		var stack = (error != null) ? error.stack : new Error().stack;
 		
 		EditorUi.sendReport(title + ' ' + new Date().toISOString() + ':' +
 			'\n\nBrowser=' + navigator.userAgent +
@@ -479,7 +465,7 @@ DrawioFile.prototype.sendErrorReport = function(title, details)
 			'\nSize=' + this.getSize() +
 			'\nSync=' + DrawioFile.SYNC +
 			'\n\nStats:\n' + JSON.stringify(this.stats, null, 2) +
-			((details != null) ? ('\n\n' + details) : '') + 
+			((details != null) ? ('\n\n' + details) : '') +
 			'\n\nStack:\n' + stack);
 	}
 	catch (e)
@@ -1141,15 +1127,16 @@ DrawioFile.prototype.installListeners = function()
  * Returns the location as a new object.
  * @type mx.Point
  */
-DrawioFile.prototype.addAllSavedStatus = function()
+DrawioFile.prototype.addAllSavedStatus = function(status)
 {
 	if (this.ui.statusContainer != null)
 	{
+		status = (status != null) ? status : mxUtils.htmlEntities(mxResources.get(this.allChangesSavedKey));
+		
 		if (this.constructor == DriveFile || this.constructor == DropboxFile)
 		{
 			this.ui.editor.setStatus('<div title="'+ mxUtils.htmlEntities(mxResources.get('revisionHistory')) +
-				'" style="text-decoration:underline;cursor:pointer;">' +
-				mxUtils.htmlEntities(mxResources.get(this.allChangesSavedKey)) + '</div>');
+				'" style="text-decoration:underline;cursor:pointer;">' + status + '</div>');
 			var links = this.ui.statusContainer.getElementsByTagName('div');
 			
 			if (links.length > 0)
@@ -1162,7 +1149,7 @@ DrawioFile.prototype.addAllSavedStatus = function()
 		}
 		else
 		{
-			this.ui.editor.setStatus(mxUtils.htmlEntities(mxResources.get(this.allChangesSavedKey)));
+			this.ui.editor.setStatus(status);
 		}
 	}
 };
@@ -1411,19 +1398,20 @@ DrawioFile.prototype.handleFileSuccess = function(saved)
 		{
 			this.fileChanged();
 		}
-		else if (this.sync != null)
-		{
-			this.sync.updateStatus();
-			
-			if (this.sync.remoteFileChanged)
-			{
-				this.sync.remoteFileChanged = false;
-				this.sync.fileChangedNotify();
-			}
-		}
 		else if (saved)
 		{
 			this.addAllSavedStatus();
+
+			if (this.sync != null)
+			{
+				this.sync.resetUpdateStatusThread();
+				
+				if (this.sync.remoteFileChanged)
+				{
+					this.sync.remoteFileChanged = false;
+					this.sync.fileChangedNotify();
+				}
+			}
 		}
 		else
 		{
@@ -1555,7 +1543,7 @@ DrawioFile.prototype.fileChanged = function()
 	
 	if (this.isAutosave())
 	{
-		this.ui.editor.setStatus(mxUtils.htmlEntities(mxResources.get('saving')) + '...');
+		this.addAllSavedStatus(mxUtils.htmlEntities(mxResources.get('saving')) + '...');
 		
 		this.autosave(this.autosaveDelay, this.maxAutosaveDelay, mxUtils.bind(this, function(resp)
 		{

+ 27 - 22
src/main/webapp/js/diagramly/DrawioFileSync.js

@@ -163,7 +163,8 @@ DrawioFileSync.prototype.start = function(resumed)
 					// Error listener must be installed before trying to create channel
 					this.pusherErrorListener = mxUtils.bind(this, function(err)
 					{
-						if (err.error.data.code === 4004)
+						if (err.error != null && err.error.data != null &&
+							err.error.data.code === 4004)
 						{
 							EditorUi.logError('Error: Pusher Limit', null, this.file.getId());
 						}
@@ -704,7 +705,15 @@ DrawioFileSync.prototype.catchup = function(etag, secret, success, error, abort)
 		
 		var doCatchup = mxUtils.bind(this, function()
 		{
-			if (abort == null || !abort())
+			// Ignores patch if shadow has changed
+			if (current != this.file.getCurrentEtag())
+			{
+				if (success != null)
+				{
+					success();
+				}
+			}
+			else if (abort == null || !abort())
 			{
 				mxUtils.get(this.cacheUrl + '?id=' + encodeURIComponent(this.channelId) +
 					'&from=' + encodeURIComponent(current) + '&to=' + encodeURIComponent(etag) +
@@ -713,7 +722,15 @@ DrawioFileSync.prototype.catchup = function(etag, secret, success, error, abort)
 				{
 					this.file.stats.bytesReceived += req.getText().length;	
 					
-					if (abort == null || !abort())
+					// Ignores patch if shadow has changed
+					if (current != this.file.getCurrentEtag())
+					{
+						if (success != null)
+						{
+							success();
+						}
+					}
+					else if (abort == null || !abort())
 					{
 						var checksum = null;
 						var temp = [];
@@ -859,7 +876,8 @@ DrawioFileSync.prototype.merge = function(patches, checksum, etag, success, erro
 			{
 				EditorUi.debug('Sync.merge', [this],
 					'from', this.file.getCurrentEtag(), 'to', etag,
-					'patches', patches, 'backup', this.file.backupPatch,
+					'backup', this.file.backupPatch,
+					'patches', patches,
 					'attempt', this.catchupRetryCount,
 					'checksum', checksum == current, checksum);
 			}
@@ -899,11 +917,6 @@ DrawioFileSync.prototype.merge = function(patches, checksum, etag, success, erro
 		this.file.inConflictState = true;
 		this.file.invalidChecksum = true;
 		
-		if (window.console != null && urlParams['test'] == '1')
-		{
-			console.log(e);
-		}
-
 		if (error != null)
 		{
 			error(e);
@@ -911,16 +924,7 @@ DrawioFileSync.prototype.merge = function(patches, checksum, etag, success, erro
 		
 		try
 		{
-			var user = this.file.getCurrentUser();
-			var uid = (user != null) ? this.ui.hashValue(user.id) : 'unknown';
-	
-			EditorUi.sendReport('Error in merge ' + new Date().toISOString() + ':\n\n' +
-				'File=' + this.file.getId() + ' (' + this.file.getMode() + ')\n' +
-				'Client=' + this.clientId + '\n' +
-				'User=' + uid + '\n' +
-				'Size=' + this.file.getSize() + '\n' +
-				'Sync=' + DrawioFile.SYNC + '\n\n' +
-				'Stack:\n' + e.stack);
+			this.file.sendErrorReport('Error in merge', null, e);
 		}
 		catch (e2)
 		{
@@ -994,6 +998,8 @@ DrawioFileSync.prototype.fileSaved = function(pages, lastDesc, success, error)
 	this.resetUpdateStatusThread();
 	this.catchupRetryCount = 0;
 	
+	console.log('fileSaved');
+	
 	if (this.isConnected() && !this.file.inConflictState && !this.redirectDialogShowing)
 	{
 		// Computes diff and checksum
@@ -1009,15 +1015,14 @@ DrawioFileSync.prototype.fileSaved = function(pages, lastDesc, success, error)
 		var secret = this.file.getDescriptorSecret(this.file.getDescriptor());
 		var etag = this.file.getDescriptorEtag(lastDesc);
 		var current = this.file.getCurrentEtag();
-
+		this.file.shadowPages = pages;
+		
 		mxUtils.post(this.cacheUrl, this.getIdParameters() +
 			'&from=' + encodeURIComponent(etag) + '&to=' + encodeURIComponent(current) +
 			'&msg=' + encodeURIComponent(msg) + ((secret != null) ? '&secret=' + encodeURIComponent(secret) : '') +
 			((data.length < this.maxCacheEntrySize) ? '&data=' + encodeURIComponent(data) : ''),
 			mxUtils.bind(this, function(req)
 		{
-			this.file.shadowPages = pages;
-			
 			if (req.getStatus() >= 200 && req.getStatus() <= 299)
 			{
 				if (success != null)

+ 6 - 0
src/main/webapp/js/diagramly/DriveClient.js

@@ -894,6 +894,12 @@ DriveClient.prototype.getXmlFile = function(resp, success, error, ignoreMime, re
 					}
 				}
 			}
+			// Checks for base64 encoded mxfile
+			else if (data.substring(0, 32) == 'data:image/png;base64,PG14ZmlsZS')
+			{
+				var temp = data.substring(22);
+				data = (window.atob && !mxClient.IS_SF) ? atob(temp) : Base64.decode(temp);
+			}
 			
 			success(new DriveFile(this.ui, data, resp));
 		}

+ 6 - 1
src/main/webapp/js/diagramly/GitHubClient.js

@@ -400,7 +400,12 @@ GitHubClient.prototype.createGitHubFile = function(org, repo, ref, data, asLibra
 	
 	if (data.encoding === 'base64')
 	{
-		if (/\.jpe?g$/i.test(data.name))
+		// Checks for base64 encoded mxfile
+		if (content.substring(0, 10) == 'PG14ZmlsZS')
+		{
+			content = (window.atob && !mxClient.IS_SF) ? atob(content) : Base64.decode(content);
+		}
+		else if (/\.jpe?g$/i.test(data.name))
 		{
 			content = 'data:image/jpeg;base64,' + content;
 		}

+ 38 - 32
src/main/webapp/js/diagramly/OneDriveClient.js

@@ -371,47 +371,53 @@ OneDriveClient.prototype.getFile = function(id, success, error, denyConvert, asL
 				{
 					window.clearTimeout(timeoutThread);
 		    	
-				    	if (acceptResponse)
-				    	{
-							var index = (binary) ? data.lastIndexOf(',') : -1;
-							var file = null;
-	
-							if (index > 0)
-							{
-								var xml = this.ui.extractGraphModelFromPng(data.substring(index + 1));
-								
-								if (xml != null && xml.length > 0)
-								{
-									data = xml;
-								}
-								else
-								{
-									// Imports as PNG image
-									file = new LocalFile(this.ui, data, meta.name, true);
-								}
-							}
+			    	if (acceptResponse)
+			    	{
+						var index = (binary) ? data.lastIndexOf(',') : -1;
+						var file = null;
+
+						if (index > 0)
+						{
+							var xml = this.ui.extractGraphModelFromPng(data.substring(index + 1));
 							
-							if (file != null)
-							{
-								success(file);
-							}
-							else if (asLibrary)
+							if (xml != null && xml.length > 0)
 							{
-								success(new OneDriveLibrary(this.ui, data, meta));
+								data = xml;
 							}
 							else
 							{
-								success(new OneDriveFile(this.ui, data, meta));
+								// Imports as PNG image
+								file = new LocalFile(this.ui, data, meta.name, true);
 							}
-				    	}
-	    			}), mxUtils.bind(this, function(req)
+						}
+						// Checks for base64 encoded mxfile
+						else if (data.substring(0, 32) == 'data:image/png;base64,PG14ZmlsZS')
+						{
+							var temp = data.substring(22);
+							data = (window.atob && !mxClient.IS_SF) ? atob(temp) : Base64.decode(temp);
+						}
+						
+						if (file != null)
+						{
+							success(file);
+						}
+						else if (asLibrary)
+						{
+							success(new OneDriveLibrary(this.ui, data, meta));
+						}
+						else
+						{
+							success(new OneDriveFile(this.ui, data, meta));
+						}
+			    	}
+    			}), mxUtils.bind(this, function(req)
 				{
 					window.clearTimeout(timeoutThread);
 			    	
-				    	if (acceptResponse)
-				    	{
-						error(this.parseRequestText(req));
-				    	}
+			    	if (acceptResponse)
+			    	{
+			    		error(this.parseRequestText(req));
+			    	}
 				}), binary || (meta.file != null && meta.file.mimeType != null &&
 					meta.file.mimeType.substring(0, 6) == 'image/'));
 			}

File diff suppressed because it is too large
+ 1 - 1
src/main/webapp/js/embed-static.min.js


File diff suppressed because it is too large
+ 1 - 1
src/main/webapp/js/reader.min.js


File diff suppressed because it is too large
+ 30 - 30
src/main/webapp/js/viewer.min.js