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 2016/11/09 18:04:43 UTC

zeppelin git commit: [ZEPPELIN-1029] Add rest api for paragraph config update

Repository: zeppelin
Updated Branches:
  refs/heads/master dbd81bf85 -> 24187b0a7


[ZEPPELIN-1029] Add rest api for paragraph config update

### What is this PR for?
This PR adds new end point for updating paragraph configuration

### What type of PR is it?
Improvement | Documentation

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

### How should this be tested?
Outline the steps to test the PR here.

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

Author: Mina Lee <mi...@apache.org>

Closes #1592 from minahlee/ZEPPELIN-1029 and squashes the following commits:

c8357ca [Mina Lee] Add rest api for paragraph config update


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

Branch: refs/heads/master
Commit: 24187b0a7584b09b74cddd44440cac4b62f5cd86
Parents: dbd81bf
Author: Mina Lee <mi...@apache.org>
Authored: Thu Nov 3 22:28:25 2016 +0900
Committer: Lee moon soo <mo...@apache.org>
Committed: Wed Nov 9 10:04:32 2016 -0800

----------------------------------------------------------------------
 docs/rest-api/rest-notebook.md                  | 127 ++++++++++++++++++-
 .../apache/zeppelin/rest/NotebookRestApi.java   |  33 +++++
 .../rest/exception/BadRequestException.java     |  47 +++++++
 .../zeppelin/rest/NotebookRestApiTest.java      |  27 +++-
 4 files changed, 230 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zeppelin/blob/24187b0a/docs/rest-api/rest-notebook.md
----------------------------------------------------------------------
diff --git a/docs/rest-api/rest-notebook.md b/docs/rest-api/rest-notebook.md
index 46f2cd1..d8ae117 100644
--- a/docs/rest-api/rest-notebook.md
+++ b/docs/rest-api/rest-notebook.md
@@ -809,6 +809,127 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple
   </table>
 
 <br/>
+### Update paragraph configuration
+  <table class="table-configuration">
+    <col width="200">
+    <tr>
+      <td>Description</td>
+      <td>This ```PUT``` method update paragraph configuration using given id so that user can change paragraph setting such as graph type, show or hide editor/result and paragraph size, etc. You can update certain fields you want, for example you can update <code>colWidth</code> field only by sending request with payload <code>{"colWidth": 12.0}</code>.
+      </td>
+    </tr>
+    <tr>
+      <td>URL</td>
+      <td>```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/paragraph/[paragraphId]/config```</td>
+    </tr>
+    <tr>
+      <td>Success code</td>
+      <td>200</td>
+    </tr>
+    <tr>
+      <td>Bad Request code</td>
+      <td>400</td>
+    </tr>
+    <tr>
+      <td>Forbidden code</td>
+      <td>403</td>
+    </tr>
+    <tr>
+      <td>Not Found code</td>
+      <td>404</td>
+    </tr>
+    <tr>
+      <td>Fail code</td>
+      <td>500</td>
+    </tr>
+    <tr>
+      <td>sample JSON input</td>
+      <td><pre>
+{
+  "colWidth": 6.0,
+  "graph": {
+    "mode": "lineChart",
+    "height": 200.0,
+    "optionOpen": false,
+    "keys": [
+      {
+        "name": "age",
+        "index": 0.0,
+        "aggr": "sum"
+      }
+    ],
+    "values": [
+      {
+        "name": "value",
+        "index": 1.0,
+        "aggr": "sum"
+      }
+    ],
+    "groups": [],
+    "scatter": {}
+  },
+  "editorHide": true,
+  "editorMode": "ace/mode/markdown",
+  "tableHide": false
+}</pre></td>
+    </tr>
+    <tr>
+      <td>sample JSON response</td>
+      <td><pre>
+{
+  "status":"OK",
+  "message":"",
+  "body":{
+    "text":"%sql \nselect age, count(1) value\nfrom bank \nwhere age \u003c 30 \ngroup by age \norder by age",
+    "config":{
+      "colWidth":6.0,
+      "graph":{
+        "mode":"lineChart",
+        "height":200.0,
+        "optionOpen":false,
+        "keys":[
+          {
+            "name":"age",
+            "index":0.0,
+            "aggr":"sum"
+          }
+        ],
+        "values":[
+          {
+            "name":"value",
+            "index":1.0,
+            "aggr":"sum"
+          }
+        ],
+        "groups":[],
+        "scatter":{}
+      },
+      "tableHide":false,
+      "editorMode":"ace/mode/markdown",
+      "editorHide":true
+    },
+    "settings":{
+      "params":{},
+      "forms":{}
+    },
+    "apps":[],
+    "jobName":"paragraph_1423500782552_-1439281894",
+    "id":"20150210-015302_1492795503",
+    "result":{
+      "code":"SUCCESS",
+      "type":"TABLE",
+      "msg":"age\tvalue\n19\t4\n20\t3\n21\t7\n22\t9\n23\t20\n24\t24\n25\t44\n26\t77\n27\t94\n28\t103\n29\t97\n"
+    },
+    "dateCreated":"Feb 10, 2015 1:53:02 AM",
+    "dateStarted":"Jul 3, 2015 1:43:17 PM",
+    "dateFinished":"Jul 3, 2015 1:43:23 PM",
+    "status":"FINISHED",
+    "progressUpdateIntervalMs":500
+  }
+}</pre></td>
+    </tr>
+  </table>
+
+<br/>
 ### Move a paragraph to the specific index
   <table class="table-configuration">
     <col width="200">
@@ -835,7 +956,6 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple
     </tr>
   </table>
 
-
 <br/>
 ### Delete a paragraph
   <table class="table-configuration">
@@ -934,7 +1054,8 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple
       <td> Fail code</td>
       <td> 500 </td>
     </tr>
-    <td>sample JSON input</td>
+    <tr>
+      <td>sample JSON input</td>
       <td><pre>
 {
   "paragraphs": [
@@ -961,6 +1082,7 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple
   "config": {},
   "info": {}
 }</pre></td>
+    </tr>
     <tr>
       <td>sample JSON response</td>
       <td><pre>
@@ -970,7 +1092,6 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple
   "body": "2AZPHY918"
 }</pre></td>
     </tr>
-    </tr>
   </table>
 
 <br />

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/24187b0a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java
index 52f7d11..1f03b64 100644
--- a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java
@@ -42,6 +42,7 @@ import org.apache.zeppelin.notebook.Note;
 import org.apache.zeppelin.notebook.Notebook;
 import org.apache.zeppelin.notebook.NotebookAuthorization;
 import org.apache.zeppelin.notebook.Paragraph;
+import org.apache.zeppelin.rest.exception.BadRequestException;
 import org.apache.zeppelin.rest.exception.NotFoundException;
 import org.apache.zeppelin.rest.exception.ForbiddenException;
 import org.apache.zeppelin.rest.message.CronRequest;
@@ -451,6 +452,38 @@ public class NotebookRestApi {
     return new JsonResponse<>(Status.OK, "", p).build();
   }
 
+  @PUT
+  @Path("{noteId}/paragraph/{paragraphId}/config")
+  @ZeppelinApi
+  public Response updateParagraphConfig(@PathParam("noteId") String noteId,
+      @PathParam("paragraphId") String paragraphId, String message) throws IOException {
+    String user = SecurityUtils.getPrincipal();
+    LOG.info("{} will update paragraph config {} {}", user, noteId, paragraphId);
+
+    Note note = notebook.getNote(noteId);
+    checkIfNoteIsNotNull(note);
+    checkIfUserCanWrite(noteId, "Insufficient privileges you cannot update this paragraph config");
+    Paragraph p = note.getParagraph(paragraphId);
+    checkIfParagraphIsNotNull(p);
+
+    Map<String, Object> newConfig = gson.fromJson(message, HashMap.class);
+    if (newConfig == null || newConfig.isEmpty()) {
+      LOG.warn("{} is trying to update paragraph {} of note {} with empty config",
+          user, paragraphId, noteId);
+      throw new BadRequestException("paragraph config cannot be empty");
+    }
+    Map<String, Object> origConfig = p.getConfig();
+    for (String key : newConfig.keySet()) {
+      origConfig.put(key, newConfig.get(key));
+    }
+
+    p.setConfig(origConfig);
+    AuthenticationInfo subject = new AuthenticationInfo(user);
+    note.persist(subject);
+
+    return new JsonResponse<>(Status.OK, "", p).build();
+  }
+
   /**
    * Move paragraph REST API
    *

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/24187b0a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/exception/BadRequestException.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/exception/BadRequestException.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/exception/BadRequestException.java
new file mode 100644
index 0000000..944cedc
--- /dev/null
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/exception/BadRequestException.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.rest.exception;
+
+import org.apache.zeppelin.utils.ExceptionUtils;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+
+import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
+
+/**
+ * BadRequestException handler for WebApplicationException.
+ */
+public class BadRequestException extends WebApplicationException {
+
+  public BadRequestException() {
+    super(ExceptionUtils.jsonResponse(BAD_REQUEST));
+  }
+
+  private static Response badRequestJson(String message) {
+    return ExceptionUtils.jsonResponseContent(BAD_REQUEST, message);
+  }
+
+  public BadRequestException(Throwable cause, String message) {
+    super(cause, badRequestJson(message));
+  }
+
+  public BadRequestException(String message) {
+    super(badRequestJson(message));
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/24187b0a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookRestApiTest.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookRestApiTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookRestApiTest.java
index 15b6903..0fdb810 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookRestApiTest.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookRestApiTest.java
@@ -94,7 +94,7 @@ public class NotebookRestApiTest extends AbstractTestRestApi {
     Note note2 = ZeppelinServer.notebook.createNote(anonymous);
     // Set only writers
     jsonRequest = "{\"readers\":[],\"owners\":[]," +
-            "\"writers\":[\"admin-team\"]}";
+        "\"writers\":[\"admin-team\"]}";
     put = httpPut("/notebook/" + note2.getId() + "/permissions/", jsonRequest);
     assertThat("test update method:", put, isAllowed());
     put.releaseConnection();
@@ -175,7 +175,32 @@ public class NotebookRestApiTest extends AbstractTestRestApi {
     //cleanup
     ZeppelinServer.notebook.removeNote(note1.getId(), anonymous);
     ZeppelinServer.notebook.removeNote(clonedNoteId, anonymous);
+  }
+
+  @Test
+  public void testUpdateParagraphConfig() throws IOException {
+    Note note = ZeppelinServer.notebook.createNote(anonymous);
+    String noteId = note.getId();
+    Paragraph p = note.addParagraph();
+    assertNull(p.getConfig().get("colWidth"));
+    String paragraphId = p.getId();
+    String jsonRequest = "{\"colWidth\": 6.0}";
+
+    PutMethod put = httpPut("/notebook/" + noteId + "/paragraph/" + paragraphId +"/config", jsonRequest);
+    assertThat("test testUpdateParagraphConfig:", put, isAllowed());
 
+    Map<String, Object> resp = gson.fromJson(put.getResponseBodyAsString(), new TypeToken<Map<String, Object>>() {
+    }.getType());
+    Map<String, Object> respBody = (Map<String, Object>) resp.get("body");
+    Map<String, Object> config = (Map<String, Object>) respBody.get("config");
+    put.releaseConnection();
+
+    assertEquals(config.get("colWidth"), 6.0);
+    note = ZeppelinServer.notebook.getNote(noteId);
+    assertEquals(note.getParagraph(paragraphId).getConfig().get("colWidth"), 6.0);
+
+    //cleanup
+    ZeppelinServer.notebook.removeNote(noteId, anonymous);
   }
 
   @Test