Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ public Job(String jobId, String jobName, JobListener listener, long progressUpda
setStatus(Status.READY);
}

public void setId(String id) {
this.id = id;
}

public String getId() {
return id;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ String getKey() {
* is going on.
*/
final Queue<NotebookSocket> watcherSockets = Queues.newConcurrentLinkedQueue();

private Notebook notebook() {
return ZeppelinServer.notebook;
}
Expand Down Expand Up @@ -193,7 +193,7 @@ public void onMessage(NotebookSocket conn, String msg) {
if (StringUtils.isEmpty(conn.getUser())) {
addUserConnection(messagereceived.principal, conn);
}
AuthenticationInfo subject =
AuthenticationInfo subject =
new AuthenticationInfo(messagereceived.principal, messagereceived.ticket);

/** Lets be elegant here */
Expand Down Expand Up @@ -258,6 +258,9 @@ public void onMessage(NotebookSocket conn, String msg) {
case FOLDER_RENAME:
renameFolder(conn, userAndRoles, notebook, messagereceived);
break;
case UPDATE_PERSONALIZED_MODE:
updatePersonalizedMode(conn, userAndRoles, notebook, messagereceived);
break;
case COMPLETION:
completion(conn, userAndRoles, notebook, messagereceived);
break;
Expand Down Expand Up @@ -582,7 +585,21 @@ public void broadcastInterpreterBindings(String noteId, List settingList) {
}

public void broadcastParagraph(Note note, Paragraph p) {
broadcast(note.getId(), new Message(OP.PARAGRAPH).put("paragraph", p));
if (note.isPersonalizedMode()) {
broadcastParagraphs(p.getUserParagraphMap(), p);
} else {
broadcast(note.getId(), new Message(OP.PARAGRAPH).put("paragraph", p));
}
}

public void broadcastParagraphs(Map<String, Paragraph> userParagraphMap,
Paragraph defaultParagraph) {
if (null != userParagraphMap) {
for (String user : userParagraphMap.keySet()) {
multicastToUser(user,
new Message(OP.PARAGRAPH).put("paragraph", userParagraphMap.get(user)));
}
}
}

private void broadcastNewParagraph(Note note, Paragraph para) {
Expand Down Expand Up @@ -639,7 +656,7 @@ private void broadcastNoteListExcept(List<Map<String, String>> notesInfo,
multicastToUser(user, new Message(OP.NOTES_INFO).put("notes", notesInfo));
}
}

void permissionError(NotebookSocket conn, String op,
String userName,
Set<String> userAndRoles,
Expand Down Expand Up @@ -677,6 +694,10 @@ private void sendNote(NotebookSocket conn, HashSet<String> userAndRoles, Noteboo
return;
}
addConnectionToNote(note.getId(), conn);

if (note.isPersonalizedMode()) {
note = note.getUserNote(user);
}
conn.send(serializeMessage(new Message(OP.NOTE).put("note", note)));
sendAllAngularObjects(note, user, conn);
} else {
Expand Down Expand Up @@ -750,6 +771,32 @@ private void updateNote(NotebookSocket conn, HashSet<String> userAndRoles,
}
}

private void updatePersonalizedMode(NotebookSocket conn, HashSet<String> userAndRoles,
Notebook notebook, Message fromMessage) throws SchedulerException, IOException {
String noteId = (String) fromMessage.get("id");
String personalized = (String) fromMessage.get("personalized");
boolean isPersonalized = personalized.equals("true") ? true : false;

if (noteId == null) {
return;
}

NotebookAuthorization notebookAuthorization = notebook.getNotebookAuthorization();
if (!notebookAuthorization.isOwner(noteId, userAndRoles)) {
permissionError(conn, "persoanlized ", fromMessage.principal,
userAndRoles, notebookAuthorization.getOwners(noteId));
return;
}

Note note = notebook.getNote(noteId);
if (note != null) {
note.setPersonalizedMode(isPersonalized);
AuthenticationInfo subject = new AuthenticationInfo(fromMessage.principal);
note.persist(subject);
broadcastNote(note);
}
}

private void renameNote(NotebookSocket conn, HashSet<String> userAndRoles,
Notebook notebook, Message fromMessage)
throws SchedulerException, IOException {
Expand Down Expand Up @@ -895,34 +942,44 @@ private void removeNote(NotebookSocket conn, HashSet<String> userAndRoles,
broadcastNoteList(subject, userAndRoles);
}

private void updateParagraph(NotebookSocket conn, HashSet<String> userAndRoles,
Notebook notebook, Message fromMessage) throws IOException {
private void updateParagraph(NotebookSocket conn, HashSet<String> userAndRoles, Notebook notebook,
Message fromMessage) throws IOException {
String paragraphId = (String) fromMessage.get("id");
if (paragraphId == null) {
return;
}

Map<String, Object> params = (Map<String, Object>) fromMessage
.get("params");
Map<String, Object> config = (Map<String, Object>) fromMessage
.get("config");
Map<String, Object> params = (Map<String, Object>) fromMessage.get("params");
Map<String, Object> config = (Map<String, Object>) fromMessage.get("config");
String noteId = getOpenNoteId(conn);
final Note note = notebook.getNote(noteId);
NotebookAuthorization notebookAuthorization = notebook.getNotebookAuthorization();
AuthenticationInfo subject = new AuthenticationInfo(fromMessage.principal);
if (!notebookAuthorization.isWriter(noteId, userAndRoles)) {
permissionError(conn, "write", fromMessage.principal,
userAndRoles, notebookAuthorization.getWriters(noteId));
permissionError(conn, "write", fromMessage.principal, userAndRoles,
notebookAuthorization.getWriters(noteId));
return;
}

Paragraph p = note.getParagraph(paragraphId);

if (note.isPersonalizedMode()) {
p = p.getUserParagraphMap().get(subject.getUser());
}

p.settings.setParams(params);
p.setConfig(config);
p.setTitle((String) fromMessage.get("title"));
p.setText((String) fromMessage.get("paragraph"));
note.persist(subject);
broadcastParagraph(note, p);;

if (note.isPersonalizedMode()) {
Map<String, Paragraph> userParagraphMap =
note.getParagraph(paragraphId).getUserParagraphMap();
broadcastParagraphs(userParagraphMap, p);
} else {
broadcastParagraph(note, p);
}
}

private void cloneNote(NotebookSocket conn, HashSet<String> userAndRoles,
Expand Down Expand Up @@ -2003,7 +2060,7 @@ private void getEditorSetting(NotebookSocket conn, Message fromMessage)
return;
}

private void getInterpreterSettings(NotebookSocket conn, AuthenticationInfo subject)
private void getInterpreterSettings(NotebookSocket conn, AuthenticationInfo subject)
throws IOException {
List<InterpreterSetting> availableSettings = notebook().getInterpreterFactory().get();
conn.send(serializeMessage(new Message(OP.INTERPRETER_SETTINGS)
Expand All @@ -2016,7 +2073,7 @@ public void onMetaInfosReceived(String settingId, Map<String, String> metaInfos)
.get(settingId);
interpreterSetting.setInfos(metaInfos);
}

private void switchConnectionToWatcher(NotebookSocket conn, Message messagereceived)
throws IOException {
if (!isSessionAllowedToSwitchToWatcher(conn)) {
Expand All @@ -2030,19 +2087,19 @@ private void switchConnectionToWatcher(NotebookSocket conn, Message messagerecei
return;
}
watcherSockets.add(conn);

// remove this connection from regular zeppelin ws usage.
removeConnectionFromAllNote(conn);
connectedSockets.remove(conn);
removeUserConnection(conn.getUser(), conn);
}

private boolean isSessionAllowedToSwitchToWatcher(NotebookSocket session) {
String watcherSecurityKey = session.getRequest().getHeader(WatcherSecurityKey.HTTP_HEADER);
return !(StringUtils.isBlank(watcherSecurityKey)
|| !watcherSecurityKey.equals(WatcherSecurityKey.getKey()));
}

private void broadcastToWatchers(String noteId, String subject, Message message) {
synchronized (watcherSockets) {
if (watcherSockets.isEmpty()) {
Expand Down
17 changes: 17 additions & 0 deletions zeppelin-web/src/app/notebook/notebook-actionBar.html
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,23 @@ <h3>
tooltip-placement="bottom" tooltip="Export this note">
<i class="fa fa-download"></i>
</button>

<button type="button"
class="btn btn-primary btn-xs"
ng-if="ticket.principal && ticket.principal !== 'anonymous'"
ng-hide="viewOnly || note.config.personalizedMode !== 'true'"
ng-click="toggleNotePersonalizedMode()"
tooltip-placement="bottom" tooltip="Personal mode {{isOwner ? '' : '(owner can change)'}}">
<i class="fa fa-user"></i>
</button>
<button type="button"
class="btn btn-default btn-xs"
ng-if="ticket.principal && ticket.principal !== 'anonymous'"
ng-hide="viewOnly || note.config.personalizedMode === 'true'"
ng-click="toggleNotePersonalizedMode()"
tooltip-placement="bottom" tooltip="Collaboration mode {{isOwner ? '' : '(owner can change)'}}">
<i class="fa fa-users"></i>
</button>
</span>

<span class="labelBtn btn-group" role="group">
Expand Down
40 changes: 40 additions & 0 deletions zeppelin-web/src/app/notebook/notebook.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,7 @@
minimumInputLength: 3
};

$scope.setIamOwner();
angular.element('#selectOwners').select2(selectJson);
angular.element('#selectReaders').select2(selectJson);
angular.element('#selectWriters').select2(selectJson);
Expand Down Expand Up @@ -752,6 +753,39 @@
}
};

$scope.setIamOwner = function() {
if ($scope.permissions.owners.length > 0 &&
_.indexOf($scope.permissions.owners, $rootScope.ticket.principal) < 0) {
$scope.isOwner = false;
return false;
}
$scope.isOwner = true;
return true;
};

$scope.toggleNotePersonalizedMode = function() {
var personalizedMode = $scope.note.config.personalizedMode;
if ($scope.isOwner) {
BootstrapDialog.confirm({
closable: true,
title: 'Setting the result display',
message: function(dialog) {
var modeText = $scope.note.config.personalizedMode === 'true' ? 'collaborate' : 'personalize';
return 'Do you want to <span class="text-info">' + modeText + '</span> your analysis?';
},
callback: function(result) {
if (result) {
if ($scope.note.config.personalizedMode === undefined) {
$scope.note.config.personalizedMode = 'false';
}
$scope.note.config.personalizedMode = personalizedMode === 'true' ? 'false' : 'true';
websocketMsgSrv.updatePersonalizedMode($scope.note.id, $scope.note.config.personalizedMode);
}
}
});
}
};

var isSettingDirty = function() {
if (angular.equals($scope.interpreterBindings, $scope.interpreterBindingsOrig)) {
return false;
Expand Down Expand Up @@ -896,10 +930,16 @@

if ($scope.note === null) {
$scope.note = note;
} else {
$scope.note.config.personalizedMode = note.config.personalizedMode;
}
initializeLookAndFeel();
//open interpreter binding setting when there're none selected
getInterpreterBindings();
getPermissions();
var isPersonalized = $scope.note.config.personalizedMode;
isPersonalized = isPersonalized === undefined ? 'false' : isPersonalized;
$scope.note.config.personalizedMode = isPersonalized;
});

$scope.$on('$destroy', function() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -969,7 +969,7 @@
$scope.dirtyText = undefined;
$scope.originalText = angular.copy(data.paragraph.text);
} else { // if there're local update, keep it.
$scope.paragraph.text = $scope.dirtyText;
$scope.paragraph.text = data.paragraph.text;
}
} else {
$scope.paragraph.text = data.paragraph.text;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@
websocketEvents.sendNewEvent({op: 'NOTE_UPDATE', data: {id: noteId, name: noteName, config: noteConfig}});
},

updatePersonalizedMode: function(noteId, modeValue) {
websocketEvents.sendNewEvent({op: 'UPDATE_PERSONALIZED_MODE', data: {id: noteId, personalized: modeValue}});
},

renameNote: function(noteId, noteName) {
websocketEvents.sendNewEvent({op: 'NOTE_RENAME', data: {id: noteId, name: noteName}});
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,21 @@ private String getDefaultInterpreterName() {
return null != setting ? setting.getName() : StringUtils.EMPTY;
}

public boolean isPersonalizedMode() {
Object v = getConfig().get("personalizedMode");
return null != v && "true".equals(v);
}

public void setPersonalizedMode(Boolean value) {
String valueString = StringUtils.EMPTY;
if (value) {
valueString = "true";
} else {
valueString = "false";
}
getConfig().put("personalizedMode", valueString);
}

public String getId() {
return id;
}
Expand Down Expand Up @@ -666,6 +681,31 @@ void unpersist(AuthenticationInfo subject) throws IOException {
}


/**
* Return new note for specific user. this inserts and replaces user paragraph which doesn't
* exists in original paragraph
*
* @param user specific user
* @return new Note for the user
*/
public Note getUserNote(String user) {
Note newNote = new Note();
newNote.id = getId();
newNote.config = getConfig();
newNote.angularObjects = getAngularObjects();

Paragraph newParagraph;
for (Paragraph p : paragraphs) {
newParagraph = p.getUserParagraph(user);
if (null == newParagraph) {
newParagraph = p.cloneParagraphForUser(user);
}
newNote.paragraphs.add(newParagraph);
}

return newNote;
}

private void startDelayedPersistTimer(int maxDelaySec, final AuthenticationInfo subject) {
synchronized (this) {
if (delayedPersist != null) {
Expand Down
Loading