mirror of
https://github.com/apache/zeppelin
synced 2026-05-24 09:38:26 +00:00
Merge branch 'master' into ZEPPELIN-732-up
This commit is contained in:
commit
7451479d71
12 changed files with 234 additions and 49 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -39,6 +39,8 @@ zeppelin-web/bower_components
|
|||
**nbproject/
|
||||
**node/
|
||||
|
||||
#R
|
||||
/r/lib/
|
||||
|
||||
# project level
|
||||
/logs/
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ import org.quartz.CronExpression;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
|
@ -127,9 +128,29 @@ public class NotebookRestApi {
|
|||
return new JsonResponse<>(Status.FORBIDDEN, ownerPermissionError(userAndRoles,
|
||||
notebookAuthorization.getOwners(noteId))).build();
|
||||
}
|
||||
notebookAuthorization.setOwners(noteId, permMap.get("owners"));
|
||||
notebookAuthorization.setReaders(noteId, permMap.get("readers"));
|
||||
notebookAuthorization.setWriters(noteId, permMap.get("writers"));
|
||||
|
||||
HashSet readers = permMap.get("readers");
|
||||
HashSet owners = permMap.get("owners");
|
||||
HashSet writers = permMap.get("writers");
|
||||
// Set readers, if writers and owners is empty -> set to user requesting the change
|
||||
if (readers != null && !readers.isEmpty()) {
|
||||
if (writers.isEmpty()) {
|
||||
writers = Sets.newHashSet(SecurityUtils.getPrincipal());
|
||||
}
|
||||
if (owners.isEmpty()) {
|
||||
owners = Sets.newHashSet(SecurityUtils.getPrincipal());
|
||||
}
|
||||
}
|
||||
// Set writers, if owners is empty -> set to user requesting the change
|
||||
if ( writers != null && !writers.isEmpty()) {
|
||||
if (owners.isEmpty()) {
|
||||
owners = Sets.newHashSet(SecurityUtils.getPrincipal());
|
||||
}
|
||||
}
|
||||
|
||||
notebookAuthorization.setReaders(noteId, readers);
|
||||
notebookAuthorization.setWriters(noteId, writers);
|
||||
notebookAuthorization.setOwners(noteId, owners);
|
||||
LOG.debug("After set permissions {} {} {}",
|
||||
notebookAuthorization.getOwners(noteId),
|
||||
notebookAuthorization.getReaders(noteId),
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ public class ZeppelinServer extends Application {
|
|||
}
|
||||
|
||||
private static void setupNotebookServer(WebAppContext webapp,
|
||||
ZeppelinConfiguration conf) {
|
||||
ZeppelinConfiguration conf) {
|
||||
notebookWsServer = new NotebookServer();
|
||||
String maxTextMessageSize = conf.getWebsocketMaxTextMessageSize();
|
||||
final ServletHolder servletHolder = new ServletHolder(notebookWsServer);
|
||||
|
|
@ -217,9 +217,6 @@ public class ZeppelinServer extends Application {
|
|||
ServletContextHandler.SESSIONS);
|
||||
|
||||
webapp.addServlet(servletHolder, "/ws/*");
|
||||
webapp.addFilter(new FilterHolder(CorsFilter.class), "/*",
|
||||
EnumSet.allOf(DispatcherType.class));
|
||||
|
||||
}
|
||||
|
||||
private static SslContextFactory getSslContextFactory(ZeppelinConfiguration conf) {
|
||||
|
|
@ -266,7 +263,7 @@ public class ZeppelinServer extends Application {
|
|||
}
|
||||
|
||||
private static WebAppContext setupWebAppContext(ContextHandlerCollection contexts,
|
||||
ZeppelinConfiguration conf) {
|
||||
ZeppelinConfiguration conf) {
|
||||
|
||||
WebAppContext webApp = new WebAppContext();
|
||||
webApp.setContextPath(conf.getServerContextPath());
|
||||
|
|
|
|||
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
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.PutMethod;
|
||||
import org.apache.zeppelin.notebook.Note;
|
||||
import org.apache.zeppelin.notebook.NotebookAuthorization;
|
||||
import org.apache.zeppelin.notebook.NotebookAuthorizationInfoSaving;
|
||||
import org.apache.zeppelin.server.ZeppelinServer;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Test;
|
||||
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.assertThat;
|
||||
|
||||
/**
|
||||
* Zeppelin notebook rest api tests
|
||||
*/
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
public class NotebookRestApiTest extends AbstractTestRestApi {
|
||||
Gson gson = new Gson();
|
||||
|
||||
@BeforeClass
|
||||
public static void init() throws Exception {
|
||||
AbstractTestRestApi.startUp();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void destroy() throws Exception {
|
||||
AbstractTestRestApi.shutDown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPermissions() throws IOException {
|
||||
Note note1 = ZeppelinServer.notebook.createNote();
|
||||
// Set only readers
|
||||
String jsonRequest = "{\"readers\":[\"admin-team\"],\"owners\":[]," +
|
||||
"\"writers\":[]}";
|
||||
PutMethod put = httpPut("/notebook/" + note1.getId() + "/permissions/", jsonRequest);
|
||||
LOG.info("testPermissions response\n" + put.getResponseBodyAsString());
|
||||
assertThat("test update method:", put, isAllowed());
|
||||
put.releaseConnection();
|
||||
|
||||
|
||||
GetMethod get = httpGet("/notebook/" + note1.getId() + "/permissions/");
|
||||
assertThat(get, isAllowed());
|
||||
Map<String, Object> resp = gson.fromJson(get.getResponseBodyAsString(), new TypeToken<Map<String, Object>>() {
|
||||
}.getType());
|
||||
Map<String, Set<String>> authInfo = (Map<String, Set<String>>) resp.get("body");
|
||||
|
||||
// Check that both owners and writers is set to the princpal if empty
|
||||
assertEquals(authInfo.get("readers"), Lists.newArrayList("admin-team"));
|
||||
assertEquals(authInfo.get("owners"), Lists.newArrayList("anonymous"));
|
||||
assertEquals(authInfo.get("writers"), Lists.newArrayList("anonymous"));
|
||||
get.releaseConnection();
|
||||
|
||||
|
||||
Note note2 = ZeppelinServer.notebook.createNote();
|
||||
// Set only writers
|
||||
jsonRequest = "{\"readers\":[],\"owners\":[]," +
|
||||
"\"writers\":[\"admin-team\"]}";
|
||||
put = httpPut("/notebook/" + note2.getId() + "/permissions/", jsonRequest);
|
||||
assertThat("test update method:", put, isAllowed());
|
||||
put.releaseConnection();
|
||||
|
||||
get = httpGet("/notebook/" + note2.getId() + "/permissions/");
|
||||
assertThat(get, isAllowed());
|
||||
resp = gson.fromJson(get.getResponseBodyAsString(), new TypeToken<Map<String, Object>>() {
|
||||
}.getType());
|
||||
authInfo = (Map<String, Set<String>>) resp.get("body");
|
||||
// Check that owners is set to the princpal if empty
|
||||
assertEquals(authInfo.get("owners"), Lists.newArrayList("anonymous"));
|
||||
assertEquals(authInfo.get("writers"), Lists.newArrayList("admin-team"));
|
||||
get.releaseConnection();
|
||||
|
||||
|
||||
// Test clear permissions
|
||||
jsonRequest = "{\"readers\":[],\"owners\":[],\"writers\":[]}";
|
||||
put = httpPut("/notebook/" + note2.getId() + "/permissions/", jsonRequest);
|
||||
put.releaseConnection();
|
||||
get = httpGet("/notebook/" + note2.getId() + "/permissions/");
|
||||
assertThat(get, isAllowed());
|
||||
resp = gson.fromJson(get.getResponseBodyAsString(), new TypeToken<Map<String, Object>>() {
|
||||
}.getType());
|
||||
authInfo = (Map<String, Set<String>>) resp.get("body");
|
||||
|
||||
assertEquals(authInfo.get("readers"), Lists.newArrayList());
|
||||
assertEquals(authInfo.get("writers"), Lists.newArrayList());
|
||||
assertEquals(authInfo.get("owners"), Lists.newArrayList());
|
||||
get.releaseConnection();
|
||||
//cleanup
|
||||
ZeppelinServer.notebook.removeNote(note1.getId());
|
||||
ZeppelinServer.notebook.removeNote(note2.getId());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -354,6 +354,11 @@ module.exports = function (grunt) {
|
|||
cwd: '<%= yeoman.app %>',
|
||||
dest: '<%= yeoman.dist %>',
|
||||
src: ['app/**/*.html', 'components/**/*.html']
|
||||
}, {
|
||||
expand: true,
|
||||
cwd: 'bower_components/datatables/media/images',
|
||||
src: '{,*/}*.{png,jpg,jpeg,gif}',
|
||||
dest: '<%= yeoman.dist %>/images'
|
||||
}, {
|
||||
expand: true,
|
||||
cwd: '.tmp/images',
|
||||
|
|
|
|||
|
|
@ -30,7 +30,9 @@
|
|||
"ngtoast": "~2.0.0",
|
||||
"ng-focus-if": "~1.0.2",
|
||||
"bootstrap3-dialog": "bootstrap-dialog#~1.34.7",
|
||||
"floatThead": "~1.3.2"
|
||||
"floatThead": "~1.3.2",
|
||||
"datatables.net-bs": "~1.10.11",
|
||||
"datatables.net-buttons-bs": "~1.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"angular-mocks": "1.5.0"
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ limitations under the License.
|
|||
<div
|
||||
id="p{{paragraph.id}}_resize"
|
||||
ng-if="!paragraph.config.helium.activeApp"
|
||||
style='padding-bottom: 5px;'
|
||||
resize='{"allowresize": "{{!asIframe && !viewOnly}}", "graphType": "{{getResultType()}}"}'
|
||||
resizable on-resize="resizeParagraph(width, height);">
|
||||
<div ng-include src="'app/notebook/paragraph/paragraph-graph.html'"></div>
|
||||
|
|
|
|||
|
|
@ -1324,40 +1324,55 @@ angular.module('zeppelinWebApp')
|
|||
return '&#'+i.charCodeAt(0)+';';
|
||||
});
|
||||
}
|
||||
html += ' <td>'+formatTableContent(v)+'</td>';
|
||||
html += ' <td>'+formatTableContent(v)+'</td>';
|
||||
}
|
||||
html += ' </tr>';
|
||||
}
|
||||
html += ' </tbody>';
|
||||
html += '</table>';
|
||||
|
||||
angular.element('#p' + $scope.paragraph.id + '_table').html(html);
|
||||
var tableDomEl = angular.element('#p' + $scope.paragraph.id + '_table');
|
||||
tableDomEl.html(html);
|
||||
var oTable = tableDomEl.children(1).DataTable({
|
||||
paging: false,
|
||||
info: false,
|
||||
autoWidth: false,
|
||||
lengthChange: false,
|
||||
searching: false,
|
||||
dom: '<>'
|
||||
});
|
||||
|
||||
if ($scope.paragraph.result.msgTable.length > 10000) {
|
||||
angular.element('#p' + $scope.paragraph.id + '_table').css('overflow', 'scroll');
|
||||
// set table height
|
||||
var height = $scope.paragraph.config.graph.height;
|
||||
angular.element('#p' + $scope.paragraph.id + '_table').css('height', height);
|
||||
tableDomEl.css({
|
||||
'overflow': 'scroll',
|
||||
'height': $scope.paragraph.config.graph.height
|
||||
});
|
||||
} else {
|
||||
|
||||
var dataTable = angular.element('#p' + $scope.paragraph.id + '_table .table');
|
||||
dataTable.floatThead({
|
||||
scrollContainer: function (dataTable) {
|
||||
return angular.element('#p' + $scope.paragraph.id + '_table');
|
||||
scrollContainer: function(dataTable) {
|
||||
return tableDomEl;
|
||||
}
|
||||
});
|
||||
angular.element('#p' + $scope.paragraph.id + '_table .table').on('remove', function () {
|
||||
angular.element('#p' + $scope.paragraph.id + '_table .table').floatThead('destroy');
|
||||
|
||||
dataTable.on('remove', function () {
|
||||
dataTable.floatThead('destroy');
|
||||
});
|
||||
|
||||
angular.element('#p' + $scope.paragraph.id + '_table').css('position', 'relative');
|
||||
angular.element('#p' + $scope.paragraph.id + '_table').css('height', '100%');
|
||||
angular.element('#p' + $scope.paragraph.id + '_table').perfectScrollbar('destroy');
|
||||
angular.element('#p' + $scope.paragraph.id + '_table').perfectScrollbar();
|
||||
tableDomEl.css({
|
||||
'position': 'relative',
|
||||
'height': '100%'
|
||||
});
|
||||
tableDomEl.perfectScrollbar('destroy')
|
||||
.perfectScrollbar({minScrollbarLength: 20});
|
||||
|
||||
angular.element('.ps-scrollbar-y-rail').css('z-index', '1002');
|
||||
|
||||
// set table height
|
||||
var psHeight = $scope.paragraph.config.graph.height;
|
||||
angular.element('#p' + $scope.paragraph.id + '_table').css('height', psHeight);
|
||||
angular.element('#p' + $scope.paragraph.id + '_table').perfectScrollbar('update');
|
||||
tableDomEl.css('height', psHeight);
|
||||
tableDomEl.perfectScrollbar('update');
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -52,6 +52,21 @@
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
table.dataTable {
|
||||
margin-top: 0px !important;
|
||||
margin-bottom: 6px !important;
|
||||
}
|
||||
|
||||
table.dataTable.table-condensed > thead > tr > th {
|
||||
padding-right: 28px;
|
||||
}
|
||||
|
||||
table.dataTable.table-condensed .sorting:after,
|
||||
table.dataTable.table-condensed .sorting_asc:after,
|
||||
table.dataTable.table-condensed .sorting_desc:after {
|
||||
right: 12px;
|
||||
}
|
||||
|
||||
.graphContainer {
|
||||
position: relative;
|
||||
margin-bottom: 5px;
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ limitations under the License.
|
|||
<link rel="stylesheet" href="bower_components/highlightjs/styles/github.css" />
|
||||
<link rel="stylesheet" href="bower_components/ngtoast/dist/ngToast.css" />
|
||||
<link rel="stylesheet" href="bower_components/bootstrap3-dialog/dist/css/bootstrap-dialog.min.css" />
|
||||
<link rel="stylesheet" href="bower_components/datatables.net-bs/css/dataTables.bootstrap.css" />
|
||||
<link rel="stylesheet" href="bower_components/datatables.net-buttons-bs/css/buttons.bootstrap.css" />
|
||||
<!-- endbower -->
|
||||
<link rel="stylesheet" href="bower_components/jquery-ui/themes/base/all.css" />
|
||||
<!-- endbuild -->
|
||||
|
|
@ -132,6 +134,14 @@ limitations under the License.
|
|||
<script src="bower_components/bootstrap3-dialog/dist/js/bootstrap-dialog.min.js"></script>
|
||||
<script src="bower_components/floatThead/dist/jquery.floatThead.js"></script>
|
||||
<script src="bower_components/floatThead/dist/jquery.floatThead.min.js"></script>
|
||||
<script src="bower_components/datatables.net/js/jquery.dataTables.js"></script>
|
||||
<script src="bower_components/datatables.net-bs/js/dataTables.bootstrap.js"></script>
|
||||
<script src="bower_components/datatables.net-buttons/js/dataTables.buttons.js"></script>
|
||||
<script src="bower_components/datatables.net-buttons/js/buttons.colVis.js"></script>
|
||||
<script src="bower_components/datatables.net-buttons/js/buttons.flash.js"></script>
|
||||
<script src="bower_components/datatables.net-buttons/js/buttons.html5.js"></script>
|
||||
<script src="bower_components/datatables.net-buttons/js/buttons.print.js"></script>
|
||||
<script src="bower_components/datatables.net-buttons-bs/js/buttons.bootstrap.js"></script>
|
||||
<!-- endbower -->
|
||||
<!-- endbuild -->
|
||||
<!-- build:js({.tmp,src}) scripts/scripts.js -->
|
||||
|
|
|
|||
|
|
@ -110,16 +110,10 @@ public class NotebookAuthorization {
|
|||
noteAuthInfo.put("owners", new LinkedHashSet(entities));
|
||||
noteAuthInfo.put("readers", new LinkedHashSet());
|
||||
noteAuthInfo.put("writers", new LinkedHashSet());
|
||||
authInfo.put(noteId, noteAuthInfo);
|
||||
} else {
|
||||
Set<String> existingEntities = noteAuthInfo.get("owners");
|
||||
if (existingEntities == null) {
|
||||
noteAuthInfo.put("owners", new LinkedHashSet(entities));
|
||||
} else {
|
||||
existingEntities.clear();
|
||||
existingEntities.addAll(entities);
|
||||
}
|
||||
noteAuthInfo.put("owners", new LinkedHashSet(entities));
|
||||
}
|
||||
authInfo.put(noteId, noteAuthInfo);
|
||||
saveToFile();
|
||||
}
|
||||
|
||||
|
|
@ -130,16 +124,10 @@ public class NotebookAuthorization {
|
|||
noteAuthInfo.put("owners", new LinkedHashSet());
|
||||
noteAuthInfo.put("readers", new LinkedHashSet(entities));
|
||||
noteAuthInfo.put("writers", new LinkedHashSet());
|
||||
authInfo.put(noteId, noteAuthInfo);
|
||||
} else {
|
||||
Set<String> existingEntities = noteAuthInfo.get("readers");
|
||||
if (existingEntities == null) {
|
||||
noteAuthInfo.put("readers", new LinkedHashSet(entities));
|
||||
} else {
|
||||
existingEntities.clear();
|
||||
existingEntities.addAll(entities);
|
||||
}
|
||||
noteAuthInfo.put("readers", new LinkedHashSet(entities));
|
||||
}
|
||||
authInfo.put(noteId, noteAuthInfo);
|
||||
saveToFile();
|
||||
}
|
||||
|
||||
|
|
@ -150,16 +138,10 @@ public class NotebookAuthorization {
|
|||
noteAuthInfo.put("owners", new LinkedHashSet());
|
||||
noteAuthInfo.put("readers", new LinkedHashSet());
|
||||
noteAuthInfo.put("writers", new LinkedHashSet(entities));
|
||||
authInfo.put(noteId, noteAuthInfo);
|
||||
} else {
|
||||
Set<String> existingEntities = noteAuthInfo.get("writers");
|
||||
if (existingEntities == null) {
|
||||
noteAuthInfo.put("writers", new LinkedHashSet(entities));
|
||||
} else {
|
||||
existingEntities.clear();
|
||||
existingEntities.addAll(entities);
|
||||
}
|
||||
noteAuthInfo.put("writers", new LinkedHashSet(entities));
|
||||
}
|
||||
authInfo.put(noteId, noteAuthInfo);
|
||||
saveToFile();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import java.io.IOException;
|
|||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.zeppelin.conf.ZeppelinConfiguration;
|
||||
import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars;
|
||||
|
|
@ -486,6 +487,13 @@ public class NotebookTest implements JobListenerFactory{
|
|||
assertEquals(notebookAuthorization.isWriter(note.id(),
|
||||
new HashSet<String>(Arrays.asList("user1"))), true);
|
||||
|
||||
// Test clearing of permssions
|
||||
notebookAuthorization.setReaders(note.id(), Sets.<String>newHashSet());
|
||||
assertEquals(notebookAuthorization.isReader(note.id(),
|
||||
new HashSet<String>(Arrays.asList("user2"))), true);
|
||||
assertEquals(notebookAuthorization.isReader(note.id(),
|
||||
new HashSet<String>(Arrays.asList("user3"))), true);
|
||||
|
||||
notebook.removeNote(note.id());
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue