You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zeppelin.apache.org by mo...@apache.org on 2017/01/10 18:33:51 UTC

zeppelin git commit: [ZEPPELIN-1910] DON'T show the same dialogs multiple times when don't have permission for run all paragraphs (BUG)

Repository: zeppelin
Updated Branches:
  refs/heads/master d96a14913 -> a89cb1047


[ZEPPELIN-1910] DON'T show the same dialogs multiple times when don't have permission for run all paragraphs (BUG)

### What is this PR for?

DON't show the multiple same dialog when user doesn't have permission for **Run all paragraphs** inside a note

#### Implementation details

- Introduce new websocket message `RUN_ALL_PARAGRAPHS` since we need to broadcast *bringing dialog* message only once
(We did same thing about `CLEAR_ALL_PARAGRAPHS`)
- Refactor `NotebookServer.runParagraph` to avoid duplication
- Add necessary functions to backend and frontend

### What type of PR is it?
[Bug Fix]

### Todos

Fixed at once

### What is the Jira issue?
[ZEPPELIN-1910](https://issues.apache.org/jira/browse/ZEPPELIN-1910)

### How should this be tested?

1. Set permission to a note
2. Enable shiro and login as an user **who doens't have write permission**
3. Click *Run all paragraphs* button

### Screenshots (if appropriate)

#### 1. Before

![bug-multiple-dialog](https://cloud.githubusercontent.com/assets/4968473/21704503/440a9774-d3fd-11e6-8e41-fcad71c5c9e7.gif)

#### 2. After

![run-all-after-fixed](https://cloud.githubusercontent.com/assets/4968473/21704488/304fd578-d3fd-11e6-9f6e-d64c82c508df.gif)

### Questions:
* Does the licenses files need update? - NO
* Is there breaking changes for older versions? - NO
* Does this needs documentation? - NO

Author: 1ambda <1a...@gmail.com>

Closes #1852 from 1ambda/ZEPPELIN-1910/run-all-para-bring-multi-dialog and squashes the following commits:

837b7be [1ambda] fix: func name in ParagraphActionsIT
c200585 [1ambda] fix: zeppeiln-web test for runNote
284e8e6 [1ambda] fix: Multiple dialog when don't have permission for run all para


Project: http://git-wip-us.apache.org/repos/asf/zeppelin/repo
Commit: http://git-wip-us.apache.org/repos/asf/zeppelin/commit/a89cb104
Tree: http://git-wip-us.apache.org/repos/asf/zeppelin/tree/a89cb104
Diff: http://git-wip-us.apache.org/repos/asf/zeppelin/diff/a89cb104

Branch: refs/heads/master
Commit: a89cb1047059a3eb01a9f2b9f5caae4aee6835a1
Parents: d96a149
Author: 1ambda <1a...@gmail.com>
Authored: Sun Jan 8 18:58:52 2017 +0900
Committer: Lee moon soo <mo...@apache.org>
Committed: Tue Jan 10 10:33:44 2017 -0800

----------------------------------------------------------------------
 .../apache/zeppelin/socket/NotebookServer.java  | 88 ++++++++++++++++----
 .../integration/ParagraphActionsIT.java         |  2 +-
 .../src/app/notebook/notebook-actionBar.html    |  2 +-
 .../src/app/notebook/notebook.controller.js     | 13 ++-
 .../websocketEvents/websocketMsg.service.js     | 10 +++
 zeppelin-web/test/spec/controllers/notebook.js  |  2 +-
 .../zeppelin/notebook/socket/Message.java       |  3 +-
 7 files changed, 96 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zeppelin/blob/a89cb104/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
index 878bad8..6e58e3d 100644
--- a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
@@ -36,6 +36,7 @@ import javax.servlet.http.HttpServletRequest;
 
 import com.google.common.base.Strings;
 import com.google.common.collect.Sets;
+import com.google.gson.*;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.vfs2.FileSystemException;
 import org.apache.zeppelin.conf.ZeppelinConfiguration;
@@ -85,8 +86,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.collect.Queues;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
 import com.google.gson.reflect.TypeToken;
 
 /**
@@ -263,6 +262,9 @@ public class NotebookServer extends WebSocketServlet
           case RUN_PARAGRAPH:
             runParagraph(conn, userAndRoles, notebook, messagereceived);
             break;
+          case RUN_ALL_PARAGRAPHS:
+            runAllParagraphs(conn, userAndRoles, notebook, messagereceived);
+            break;
           case CANCEL_PARAGRAPH:
             cancelParagraph(conn, userAndRoles, notebook, messagereceived);
             break;
@@ -1534,8 +1536,46 @@ public class NotebookServer extends WebSocketServlet
     p.abort();
   }
 
-  private void runParagraph(NotebookSocket conn, HashSet<String> userAndRoles, Notebook notebook,
+  private void runAllParagraphs(NotebookSocket conn, HashSet<String> userAndRoles,
+                                Notebook notebook,
       Message fromMessage) throws IOException {
+    final String noteId = (String) fromMessage.get("noteId");
+    if (StringUtils.isBlank(noteId)) {
+      return;
+    }
+
+    Note note = notebook.getNote(noteId);
+    NotebookAuthorization notebookAuthorization = notebook.getNotebookAuthorization();
+    if (!notebookAuthorization.isWriter(noteId, userAndRoles)) {
+      permissionError(conn, "run all paragraphs", fromMessage.principal, userAndRoles,
+          notebookAuthorization.getOwners(noteId));
+      return;
+    }
+
+    List<Map<String, Object>> paragraphs =
+        gson.fromJson(String.valueOf(fromMessage.data.get("paragraphs")),
+            new TypeToken<List<Map<String, Object>>>() {}.getType());
+
+    for (Map<String, Object> raw : paragraphs) {
+      String paragraphId = (String) raw.get("id");
+      if (paragraphId == null) {
+        continue;
+      }
+
+      String text = (String) raw.get("paragraph");
+      String title = (String) raw.get("title");
+      Map<String, Object> params = (Map<String, Object>) raw.get("params");
+      Map<String, Object> config = (Map<String, Object>) raw.get("config");
+
+      Paragraph p = setParagraphUsingMessage(note, fromMessage,
+          paragraphId, text, title, params, config);
+
+      persistAndExecuteSingleParagraph(conn, note, p);
+    }
+  }
+
+  private void runParagraph(NotebookSocket conn, HashSet<String> userAndRoles, Notebook notebook,
+                            Message fromMessage) throws IOException {
     final String paragraphId = (String) fromMessage.get("id");
     if (paragraphId == null) {
       return;
@@ -1550,30 +1590,29 @@ public class NotebookServer extends WebSocketServlet
       return;
     }
 
-    Paragraph p = note.getParagraph(paragraphId);
     String text = (String) fromMessage.get("paragraph");
-    p.setText(text);
-    p.setTitle((String) fromMessage.get("title"));
-    AuthenticationInfo subject =
-        new AuthenticationInfo(fromMessage.principal, fromMessage.ticket);
-    p.setAuthenticationInfo(subject);
-
+    String title = (String) fromMessage.get("title");
     Map<String, Object> params = (Map<String, Object>) fromMessage.get("params");
-    p.settings.setParams(params);
     Map<String, Object> config = (Map<String, Object>) fromMessage.get("config");
-    p.setConfig(config);
+    Paragraph p = setParagraphUsingMessage(note, fromMessage, paragraphId,
+        text, title, params, config);
+
+    persistAndExecuteSingleParagraph(conn, note, p);
+  }
 
+  private void persistAndExecuteSingleParagraph(NotebookSocket conn,
+                                                Note note, Paragraph p) throws IOException {
     // if it's the last paragraph and empty, let's add a new one
     boolean isTheLastParagraph = note.isLastParagraph(p.getId());
-    if (!(text.trim().equals(p.getMagic()) ||
-        Strings.isNullOrEmpty(text)) &&
+    if (!(p.getText().trim().equals(p.getMagic()) ||
+        Strings.isNullOrEmpty(p.getText())) &&
         isTheLastParagraph) {
-      Paragraph newPara = note.addParagraph(subject);
+      Paragraph newPara = note.addParagraph(p.getAuthenticationInfo());
       broadcastNewParagraph(note, newPara);
     }
 
     try {
-      note.persist(subject);
+      note.persist(p.getAuthenticationInfo());
     } catch (FileSystemException ex) {
       LOG.error("Exception from run", ex);
       conn.send(serializeMessage(new Message(OP.ERROR_INFO).put("info",
@@ -1584,7 +1623,7 @@ public class NotebookServer extends WebSocketServlet
     }
 
     try {
-      note.run(paragraphId);
+      note.run(p.getId());
     } catch (Exception ex) {
       LOG.error("Exception from run", ex);
       if (p != null) {
@@ -1595,6 +1634,21 @@ public class NotebookServer extends WebSocketServlet
     }
   }
 
+  private Paragraph setParagraphUsingMessage(Note note, Message fromMessage, String paragraphId,
+                                             String text, String title, Map<String, Object> params,
+                                             Map<String, Object> config) {
+    Paragraph p = note.getParagraph(paragraphId);
+    p.setText(text);
+    p.setTitle(title);
+    AuthenticationInfo subject =
+        new AuthenticationInfo(fromMessage.principal, fromMessage.ticket);
+    p.setAuthenticationInfo(subject);
+    p.settings.setParams(params);
+    p.setConfig(config);
+
+    return p;
+  }
+
   private void sendAllConfigurations(NotebookSocket conn, HashSet<String> userAndRoles,
       Notebook notebook) throws IOException {
     ZeppelinConfiguration conf = notebook.getConf();

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/a89cb104/zeppelin-server/src/test/java/org/apache/zeppelin/integration/ParagraphActionsIT.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/integration/ParagraphActionsIT.java b/zeppelin-server/src/test/java/org/apache/zeppelin/integration/ParagraphActionsIT.java
index f939579..d93a6e5 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/integration/ParagraphActionsIT.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/integration/ParagraphActionsIT.java
@@ -241,7 +241,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
           driver.findElement(By.xpath(getParagraphXPath(1) + "//span[@class='icon-control-play shortcut-icon']")).isDisplayed(), CoreMatchers.equalTo(false)
       );
 
-      driver.findElement(By.xpath(".//*[@id='main']//button[@ng-click='runNote()']")).sendKeys(Keys.ENTER);
+      driver.findElement(By.xpath(".//*[@id='main']//button[contains(@ng-click, 'runAllParagraphs')]")).sendKeys(Keys.ENTER);
       ZeppelinITUtils.sleep(1000, true);
       driver.findElement(By.xpath("//div[@class='modal-dialog'][contains(.,'Run all paragraphs?')]" +
           "//div[@class='modal-footer']//button[contains(.,'OK')]")).click();

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/a89cb104/zeppelin-web/src/app/notebook/notebook-actionBar.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/notebook/notebook-actionBar.html b/zeppelin-web/src/app/notebook/notebook-actionBar.html
index 4249f21..99d7d7a 100644
--- a/zeppelin-web/src/app/notebook/notebook-actionBar.html
+++ b/zeppelin-web/src/app/notebook/notebook-actionBar.html
@@ -24,7 +24,7 @@ limitations under the License.
       <span class="labelBtn btn-group">
       <button type="button"
               class="btn btn-default btn-xs"
-              ng-click="runNote()"
+              ng-click="runAllParagraphs(note.id)"
               ng-class="{'disabled':isNoteRunning()}"
               tooltip-placement="bottom" tooltip="Run all paragraphs"
               ng-disabled="revisionView">

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/a89cb104/zeppelin-web/src/app/notebook/notebook.controller.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/notebook/notebook.controller.js b/zeppelin-web/src/app/notebook/notebook.controller.js
index 82b070a..b1b5447 100644
--- a/zeppelin-web/src/app/notebook/notebook.controller.js
+++ b/zeppelin-web/src/app/notebook/notebook.controller.js
@@ -286,16 +286,23 @@
       }
     };
 
-    $scope.runNote = function() {
+    $scope.runAllParagraphs = function(noteId) {
       BootstrapDialog.confirm({
         closable: true,
         title: '',
         message: 'Run all paragraphs?',
         callback: function(result) {
           if (result) {
-            _.forEach($scope.note.paragraphs, function(n, key) {
-              angular.element('#' + n.id + '_paragraphColumn_main').scope().runParagraph(n.text);
+            const paragraphs = $scope.note.paragraphs.map(p => {
+              return {
+                id: p.id,
+                title: p.title,
+                paragraph: p.text,
+                config: p.config,
+                params: p.settings.params
+              };
             });
+            websocketMsgSrv.runAllParagraphs(noteId, paragraphs);
           }
         }
       });

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/a89cb104/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js b/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js
index 24bbc17..1fb5f74 100644
--- a/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js
+++ b/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js
@@ -173,6 +173,16 @@
         });
       },
 
+      runAllParagraphs: function(noteId, paragraphs) {
+        websocketEvents.sendNewEvent({
+          op: 'RUN_ALL_PARAGRAPHS',
+          data: {
+            noteId: noteId,
+            paragraphs: JSON.stringify(paragraphs)
+          }
+        });
+      },
+
       removeParagraph: function(paragraphId) {
         websocketEvents.sendNewEvent({op: 'PARAGRAPH_REMOVE', data: {id: paragraphId}});
       },

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/a89cb104/zeppelin-web/test/spec/controllers/notebook.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/test/spec/controllers/notebook.js b/zeppelin-web/test/spec/controllers/notebook.js
index ec8ec97..f4a420b 100644
--- a/zeppelin-web/test/spec/controllers/notebook.js
+++ b/zeppelin-web/test/spec/controllers/notebook.js
@@ -35,7 +35,7 @@ describe('Controller: NotebookCtrl', function() {
     scope.note = noteMock;
   });
 
-  var functions = ['getCronOptionNameFromValue', 'removeNote', 'runNote', 'saveNote', 'toggleAllEditor',
+  var functions = ['getCronOptionNameFromValue', 'removeNote', 'runAllParagraphs', 'saveNote', 'toggleAllEditor',
     'showAllEditor', 'hideAllEditor', 'toggleAllTable', 'hideAllTable', 'showAllTable', 'isNoteRunning',
     'killSaveTimer', 'startSaveTimer', 'setLookAndFeel', 'setCronScheduler', 'setConfig', 'updateNoteName',
     'openSetting', 'closeSetting', 'saveSetting', 'toggleSetting'];

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/a89cb104/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/socket/Message.java
----------------------------------------------------------------------
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/socket/Message.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/socket/Message.java
index d123020..162baf8 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/socket/Message.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/socket/Message.java
@@ -171,7 +171,8 @@ public class Message {
     PARAGRAPH_ADDED,              // [s-c] paragraph is added
     PARAGRAPH_REMOVED,            // [s-c] paragraph deleted
     PARAGRAPH_MOVED,              // [s-c] paragraph moved
-    NOTE_UPDATED                  // [s-c] paragraph updated(name, config)
+    NOTE_UPDATED,                 // [s-c] paragraph updated(name, config)
+    RUN_ALL_PARAGRAPHS            // [c-s] run all paragraphs
   }
 
   public static final Message EMPTY = new Message(null);