diff --git a/docs/rest-api/rest-notebook.md b/docs/rest-api/rest-notebook.md
index 1e49d1ed912..46f2cd1dd69 100644
--- a/docs/rest-api/rest-notebook.md
+++ b/docs/rest-api/rest-notebook.md
@@ -493,7 +493,7 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple
| Description |
- This ```POST``` method runs the paragraph synchronously by given note and paragraph id. This API can return SUCCESS or ERROR depending on the outcome of the paragraph execution
+ | This ```POST``` method runs the paragraph synchronously by given note and paragraph id. This API can return SUCCESS or ERROR depending on the outcome of the paragraph execution
|
@@ -972,3 +972,39 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple
+
+
+### Clear all paragraph result
+
+
+
+ | Description |
+ This ```PUT``` method clear all paragraph results from note of given id.
+ |
+
+
+ | URL |
+ ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/clear``` |
+
+
+ | Success code |
+ 200 |
+
+
+ | Forbidden code |
+ 401 |
+
+
+ | Not Found code |
+ 404 |
+
+
+ | Fail code |
+ 500 |
+
+
+ | sample JSON response |
+ {"status": "OK"} |
+
+
+
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 5b27d0e6842..52f7d116150 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
@@ -43,7 +43,7 @@
import org.apache.zeppelin.notebook.NotebookAuthorization;
import org.apache.zeppelin.notebook.Paragraph;
import org.apache.zeppelin.rest.exception.NotFoundException;
-import org.apache.zeppelin.rest.exception.UnauthorizedException;
+import org.apache.zeppelin.rest.exception.ForbiddenException;
import org.apache.zeppelin.rest.message.CronRequest;
import org.apache.zeppelin.rest.message.NewNoteRequest;
import org.apache.zeppelin.rest.message.NewParagraphRequest;
@@ -124,7 +124,7 @@ private void checkIfUserIsOwner(String noteId, String errorMsg) {
userAndRoles.add(SecurityUtils.getPrincipal());
userAndRoles.addAll(SecurityUtils.getRoles());
if (!notebookAuthorization.isOwner(userAndRoles, noteId)) {
- throw new UnauthorizedException(errorMsg);
+ throw new ForbiddenException(errorMsg);
}
}
@@ -136,7 +136,7 @@ private void checkIfUserCanWrite(String noteId, String errorMsg) {
userAndRoles.add(SecurityUtils.getPrincipal());
userAndRoles.addAll(SecurityUtils.getRoles());
if (!notebookAuthorization.hasWriteAuthorization(userAndRoles, noteId)) {
- throw new UnauthorizedException(errorMsg);
+ throw new ForbiddenException(errorMsg);
}
}
@@ -148,7 +148,7 @@ private void checkIfUserCanRead(String noteId, String errorMsg) {
userAndRoles.add(SecurityUtils.getPrincipal());
userAndRoles.addAll(SecurityUtils.getRoles());
if (!notebookAuthorization.hasReadAuthorization(userAndRoles, noteId)) {
- throw new UnauthorizedException(errorMsg);
+ throw new ForbiddenException(errorMsg);
}
}
@@ -516,6 +516,27 @@ public Response deleteParagraph(@PathParam("noteId") String noteId,
return new JsonResponse(Status.OK, "").build();
}
+ /**
+ * Clear result of all paragraphs REST API
+ *
+ * @param noteId ID of Note
+ * @return JSON with status.ok
+ */
+ @PUT
+ @Path("{noteId}/clear")
+ @ZeppelinApi
+ public Response clearAllParagraphOutput(@PathParam("noteId") String noteId)
+ throws IOException {
+ LOG.info("clear all paragraph output of note {}", noteId);
+ checkIfUserCanWrite(noteId, "Insufficient privileges you cannot clear this note");
+
+ Note note = notebook.getNote(noteId);
+ checkIfNoteIsNotNull(note);
+ note.clearAllParagraphOutput();
+
+ return new JsonResponse(Status.OK, "").build();
+ }
+
/**
* Run note jobs REST API
*
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/exception/UnauthorizedException.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/exception/ForbiddenException.java
similarity index 71%
rename from zeppelin-server/src/main/java/org/apache/zeppelin/rest/exception/UnauthorizedException.java
rename to zeppelin-server/src/main/java/org/apache/zeppelin/rest/exception/ForbiddenException.java
index 7b968abaddc..04deb4227b5 100644
--- a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/exception/UnauthorizedException.java
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/exception/ForbiddenException.java
@@ -17,6 +17,7 @@
package org.apache.zeppelin.rest.exception;
import static javax.ws.rs.core.Response.Status.FORBIDDEN;
+import static javax.ws.rs.core.Response.Status.UNAUTHORIZED;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
@@ -27,24 +28,24 @@
* UnauthorizedException handler for WebApplicationException.
*
*/
-public class UnauthorizedException extends WebApplicationException {
+public class ForbiddenException extends WebApplicationException {
private static final long serialVersionUID = 4394749068760407567L;
- private static final String UNAUTHORIZED_MSG = "Authorization required";
+ private static final String FORBIDDEN_MSG = "Not allowed to access";
- public UnauthorizedException() {
- super(unauthorizedJson(UNAUTHORIZED_MSG));
+ public ForbiddenException() {
+ super(forbiddenJson(FORBIDDEN_MSG));
}
- private static Response unauthorizedJson(String message) {
+ private static Response forbiddenJson(String message) {
return ExceptionUtils.jsonResponseContent(FORBIDDEN, message);
}
- public UnauthorizedException(Throwable cause, String message) {
- super(cause, unauthorizedJson(message));
+ public ForbiddenException(Throwable cause, String message) {
+ super(cause, forbiddenJson(message));
}
- public UnauthorizedException(String message) {
- super(unauthorizedJson(message));
+ public ForbiddenException(String message) {
+ super(forbiddenJson(message));
}
}
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 3e137b8bc2d..6cba5367481 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
@@ -228,6 +228,9 @@ public void onMessage(NotebookSocket conn, String msg) {
case PARAGRAPH_CLEAR_OUTPUT:
clearParagraphOutput(conn, userAndRoles, notebook, messagereceived);
break;
+ case PARAGRAPH_CLEAR_ALL_OUTPUT:
+ clearAllParagraphOutput(conn, userAndRoles, notebook, messagereceived);
+ break;
case NOTE_UPDATE:
updateNote(conn, userAndRoles, notebook, messagereceived);
break;
@@ -822,6 +825,25 @@ private void cloneNote(NotebookSocket conn, HashSet userAndRoles,
broadcastNoteList(subject, userAndRoles);
}
+ private void clearAllParagraphOutput(NotebookSocket conn, HashSet userAndRoles,
+ Notebook notebook, Message fromMessage)
+ throws IOException {
+ final String noteId = (String) fromMessage.get("id");
+ if (StringUtils.isBlank(noteId)) {
+ return;
+ }
+ Note note = notebook.getNote(noteId);
+ NotebookAuthorization notebookAuthorization = notebook.getNotebookAuthorization();
+ if (!notebookAuthorization.isWriter(noteId, userAndRoles)) {
+ permissionError(conn, "clear output", fromMessage.principal,
+ userAndRoles, notebookAuthorization.getOwners(noteId));
+ return;
+ }
+
+ note.clearAllParagraphOutput();
+ broadcastNote(note);
+ }
+
protected Note importNote(NotebookSocket conn, HashSet userAndRoles,
Notebook notebook, Message fromMessage)
throws IOException {
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java
index 6d103372987..2ff8d40b3de 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java
@@ -539,7 +539,7 @@ public static void ps() {
/** Status code matcher */
- protected Matcher super HttpMethodBase> isForbiden() { return responsesWith(403); }
+ protected Matcher super HttpMethodBase> isForbidden() { return responsesWith(403); }
protected Matcher super HttpMethodBase> isAllowed() {
return responsesWith(200);
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 36b0f1c97b3..15b69030ce1 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
@@ -18,15 +18,14 @@
package org.apache.zeppelin.rest;
import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.PutMethod;
+import org.apache.zeppelin.interpreter.InterpreterResult;
import org.apache.zeppelin.notebook.Note;
-import org.apache.zeppelin.notebook.NotebookAuthorization;
-import org.apache.zeppelin.notebook.NotebookAuthorizationInfoSaving;
+import org.apache.zeppelin.notebook.Paragraph;
import org.apache.zeppelin.server.ZeppelinServer;
import org.apache.zeppelin.user.AuthenticationInfo;
import org.junit.AfterClass;
@@ -37,12 +36,11 @@
import org.junit.runners.MethodSorters;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
/**
@@ -179,6 +177,43 @@ public void testCloneNote() throws IOException {
ZeppelinServer.notebook.removeNote(clonedNoteId, anonymous);
}
+
+ @Test
+ public void testClearAllParagraphOutput() throws IOException {
+ // Create note and set result explicitly
+ Note note = ZeppelinServer.notebook.createNote(anonymous);
+ Paragraph p1 = note.addParagraph();
+ InterpreterResult result = new InterpreterResult(InterpreterResult.Code.SUCCESS, InterpreterResult.Type.TEXT, "result");
+ p1.setResult(result);
+
+ Paragraph p2 = note.addParagraph();
+ p2.setReturn(result, new Throwable());
+
+ // clear paragraph result
+ PutMethod put = httpPut("/notebook/" + note.getId() + "/clear", "");
+ LOG.info("test clear paragraph output response\n" + put.getResponseBodyAsString());
+ assertThat(put, isAllowed());
+ put.releaseConnection();
+
+ // check if paragraph results are cleared
+ GetMethod get = httpGet("/notebook/" + note.getId() + "/paragraph/" + p1.getId());
+ assertThat(get, isAllowed());
+ Map resp1 = gson.fromJson(get.getResponseBodyAsString(), new TypeToken