diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/master-data/data-model.xls b/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/master-data/data-model.xls
index 3ee993ae6e5fcd4df2a656c6551274769709d661..dc41839238990f7688c5a4b4f956986f3414f318 100644
Binary files a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/master-data/data-model.xls and b/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/master-data/data-model.xls differ
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/master-data/data-model.xls b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/master-data/data-model.xls
index 4f80487f892ef4976e6b18b21e387ed772b85e39..21bc5da6b913898b698b337c5eaa1dd604c75b92 100644
Binary files a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/master-data/data-model.xls and b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/master-data/data-model.xls differ
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/config/Profile.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/config/Profile.js
index b713b303923d04fa508d679c6db1851f4d2ce138..6027757010cb5d97163a8d04c21d03cdcbc93eae 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/config/Profile.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/config/Profile.js
@@ -61,7 +61,8 @@ $.extend(DefaultProfile.prototype, {
 				showVocabularyViewer : true,
 				showUserManager : true,
 				showUserProfile : true,
-				showResearchCollectionExportBuilder : false,
+			    // Not fully implemented yet.
+				// showResearchCollectionExportBuilder : false,
 				showZenodoExportBuilder : false,
 		}
 		
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/controllers/MainController.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/controllers/MainController.js
index 8c6bfbcf1f2791f064a86b0aff88d215f6bd5568..4a42b1c0c13a61c3ff253c9f5535a822f8707862 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/controllers/MainController.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/controllers/MainController.js
@@ -83,13 +83,35 @@ function MainController(profile) {
 	
 	//Functionality to keep state
 	this.backStack = [];
+
+	this.zenodoApiTokenKey = "personal-zenodo-api-token";
 	
 	//
 	// Validates and enters the app
 	//
-	
+
 	this.enterApp = function(data, username, password) {
+	    var _this = this;
+	    if(data && !username && !password) {
+	        this.openbisV1.listDataStores(function(result) {
+	            if(result && result.error && result.error.message) {
+	                var callback = function() {Util.unblockUI();};
+	                Util.showUserError(result.error.message, callback);
+	            } else {
+	                _this.initApp(data, username, password);
+	            }
+	        });
+	    } else {
+	        this.initApp(data, username, password);
+	    }
+	}
+
+	this.initApp = function(data, username, password) {
 		var localReference = this;
+		//
+		// Check
+		//
+
 		//
 		// Check Credentials
 		//
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/server/ServerFacade.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/server/ServerFacade.js
index 5fc84d5f807768cfcaf096ac497f5a33875fd4d8..cf273afe3bfe7883c1fbe5f6e7775c43a7243742 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/server/ServerFacade.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/server/ServerFacade.js
@@ -417,7 +417,7 @@ function ServerFacade(openbisServer) {
 			});
 	};
 
-    this.exportZenodo = function(entities, includeRoot, metadataOnly, userInformation, title, callbackFunction) {
+    this.exportZenodo = function(entities, includeRoot, metadataOnly, userInformation, title, accessToken, callbackFunction) {
         this.asyncExportZenodo({
             "method": "exportAll",
             "includeRoot": includeRoot,
@@ -427,6 +427,7 @@ function ServerFacade(openbisServer) {
             "originUrl": window.location.origin,
             "sessionToken": this.openbisServer.getSession(),
 			"submissionTitle": title,
+			"accessToken": accessToken
         }, callbackFunction, "zenodo-exports-api");
     };
 
@@ -451,6 +452,7 @@ function ServerFacade(openbisServer) {
 				options.withParameter("submissionUrl", parameters["submissionUrl"]);
 				options.withParameter("entities", parameters["entities"]);
 				options.withParameter("submissionTitle", parameters["submissionTitle"]);
+				options.withParameter("accessToken", parameters["accessToken"]);
 				options.withParameter("userId", parameters["userInformation"]["id"]);
 				options.withParameter("userEmail", parameters["userInformation"]["email"]);
 				options.withParameter("userFirstName", parameters["userInformation"]["firstName"]);
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SideMenu/SideMenuWidgetView.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SideMenu/SideMenuWidgetView.js
index ecd57517a2c01f717c852ea89b205c396594b486..8cbb61294a164f081712b1385f5ad793adc4eb3d 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SideMenu/SideMenuWidgetView.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SideMenu/SideMenuWidgetView.js
@@ -240,7 +240,8 @@ function SideMenuWidgetView(sideMenuWidgetController, sideMenuWidgetModel) {
             treeModelUtils.push({ title : jupyterNotebook, entityType: "NEW_JUPYTER_NOTEBOOK", key : "NEW_JUPYTER_NOTEBOOK", folder : false, lazy : false, view : "showNewJupyterNotebookCreator" });
         }
         
-        if(profile.mainMenu.showUserProfile && profile.isFileAuthenticationService && profile.isFileAuthenticationUser) {
+        if(profile.mainMenu.showUserProfile) {
+            // && profile.isFileAuthenticationService && profile.isFileAuthenticationUser
             var userProfileLink = _this.getLinkForNode("User Profile", "USER_PROFILE", "showUserProfilePage", null);
             treeModelUtils.push({ title : userProfileLink, entityType: "USER_PROFILE", key : "USER_PROFILE", folder : false, lazy : false, view : "showUserProfilePage", icon : "glyphicon glyphicon-user" });
         }
@@ -276,15 +277,16 @@ function SideMenuWidgetView(sideMenuWidgetController, sideMenuWidgetModel) {
                 });
             }
 
-            if (profile.mainMenu.showResearchCollectionExportBuilder) {
-                var researchCollectionExportBuilderLink = _this.getLinkForNode("Export to Research Collection",
-                        "EXPORT_TO_RESEARCH_COLLECTION", "showResearchCollectionExportPage", null);
-                treeModelExports.push({
-                    displayName: "Export to Research Collection", title: researchCollectionExportBuilderLink,
-                    entityType: "EXPORT_TO_RESEARCH_COLLECTION", key: "EXPORT_TO_RESEARCH_COLLECTION", folder: false, lazy: false,
-                    view: "showResearchCollectionExportPage", icon: "./img/research-collection-icon.png"
-                });
-            }
+            // Not fully implemented yet.
+            // if (profile.mainMenu.showResearchCollectionExportBuilder) {
+            //     var researchCollectionExportBuilderLink = _this.getLinkForNode("Export to Research Collection",
+            //             "EXPORT_TO_RESEARCH_COLLECTION", "showResearchCollectionExportPage", null);
+            //     treeModelExports.push({
+            //         displayName: "Export to Research Collection", title: researchCollectionExportBuilderLink,
+            //         entityType: "EXPORT_TO_RESEARCH_COLLECTION", key: "EXPORT_TO_RESEARCH_COLLECTION", folder: false, lazy: false,
+            //         view: "showResearchCollectionExportPage", icon: "./img/research-collection-icon.png"
+            //     });
+            // }
 
             if (profile.mainMenu.showZenodoExportBuilder) {
                 var zenodoExportBuilderLink = _this.getLinkForNode("Export to Zenodo", "EXPORT_TO_ZENODO", "showZenodoExportPage", null);
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/UserProfile/UserProfileController.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/UserProfile/UserProfileController.js
index 74c870c9621ff3375bbb3817d4d63ead3cee369c..93d3c3fc9e2ebfd73e007cdd00da66bee76928ac 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/UserProfile/UserProfileController.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/UserProfile/UserProfileController.js
@@ -18,6 +18,7 @@ function UserProfileController(mainController, mode) {
 	this._mainController = mainController;
 	this._userProfileModel = new UserProfileModel(mode);
 	this._userProfileView = new UserProfileView(this, this._userProfileModel);
+    this._zenodoApiTokenKey = this._mainController.zenodoApiTokenKey;
 
 	this.init = function(views) {
         this._userProfileView.repaint(views);
@@ -49,6 +50,8 @@ function UserProfileController(mainController, mode) {
 			return;
 		}
 		var userId = this._mainController.serverFacade.getUserId();
+
+		this.setSettingValue(this._zenodoApiTokenKey, userInformation.zenodoToken);
 		this._mainController.serverFacade.updateUserInformation(userId, userInformation, (function(ok) {
 			if (ok) {
 				Util.showInfo("Profile saved. You will be logged out automatically in order to reload the profile data upon login.", (function() {
@@ -69,4 +72,17 @@ function UserProfileController(mainController, mode) {
 		return errors;
 	}
 
+	this.isFileAuthentication = function() {
+		return this._mainController.profile.isFileAuthenticationService &&
+				this._mainController.profile.isFileAuthenticationUser;
+	}
+
+	this.getSettingValue = function (key, callback) {
+		this._mainController.serverFacade.getSetting(key, callback);
+	};
+
+	this.setSettingValue = function (key, value) {
+		this._mainController.serverFacade.setSetting(key, value);
+	};
+
 }
\ No newline at end of file
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/UserProfile/UserProfileView.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/UserProfile/UserProfileView.js
index 22e972b17ff4a1c0ed7cd41180acf7d7211b6d91..65d80e7574d388b5922b96ea0459bc8b35175128 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/UserProfile/UserProfileView.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/UserProfile/UserProfileView.js
@@ -21,6 +21,7 @@ function UserProfileView(userProfileController, userProfileModel) {
     this._$firstNameInput = null;
     this._$lastNameInput = null;
     this._$emailInput = null;
+    this._$zenodoToken = null;
 
 	this.repaint = function(views) {
 
@@ -71,14 +72,28 @@ function UserProfileView(userProfileController, userProfileModel) {
             this._$emailInput = $("<input>", { type : "text", class : "form-control" });
             this._$emailInput.val(getUserInformation.email);
             $formColumn.append(this._getFormGroup(this._$emailInput, "Email:"));
+            // personal Zenodo API token
+            this._$zenodoToken = $("<input>", { type : "text", class : "form-control" });
+
+            this._userProfileController.getSettingValue(this._userProfileController._zenodoApiTokenKey, (function (settingsValue) {
+                if (settingsValue) {
+                    this._$zenodoToken.val(settingsValue.trim());
+                }
+            }).bind(this));
+            $formColumn.append(this._getFormGroup(this._$zenodoToken, "Zenodo API Token:"));
+
             // disable in view mode
-            if (this._userProfileModel.mode === FormMode.VIEW) {
+            if (this._userProfileModel.mode === FormMode.VIEW ||
+                    !this._userProfileController.isFileAuthentication()) {
                 this._$firstNameInput.prop("disabled", true);
                 this._$lastNameInput.prop("disabled", true);
                 this._$emailInput.prop("disabled", true);
             }
-        }).bind(this));
 
+            if (this._userProfileModel.mode === FormMode.VIEW) {
+                this._$zenodoToken.prop("disabled", true);
+            }
+        }).bind(this));
     }
 
 	this._getOptionsMenu = function() {
@@ -96,6 +111,7 @@ function UserProfileView(userProfileController, userProfileModel) {
             firstName : this._$firstNameInput.val(),
             lastName : this._$lastNameInput.val(),
             email : this._$emailInput.val(),
+            zenodoToken : this._$zenodoToken.val()
         };
     }
 
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ZenodoExport/ZenodoExportController.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ZenodoExport/ZenodoExportController.js
index 22d8015cdae2798ad66dbae025a5c121076a69fe..fb99fc614e7ea5cb2e89a2a84a54680df5e6d190 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ZenodoExport/ZenodoExportController.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ZenodoExport/ZenodoExportController.js
@@ -15,17 +15,26 @@
  */
 
 function ZenodoExportController(parentController) {
-    var exportModel = new ZenodoExportModel();
-    var exportView = new ZenodoExportView(this, exportModel);
+    this.exportModel = null;
+    this.exportView = null;
+    this.zenodoApiTokenKey = parentController.zenodoApiTokenKey;
 
     this.init = function(views) {
-        exportView.repaint(views);
+        this.getSettingValue(this.zenodoApiTokenKey, (function (accessToken) {
+            if (accessToken && accessToken !== '') {
+                this.exportModel = new ZenodoExportModel(accessToken);
+                this.exportView = new ZenodoExportView(this, this.exportModel);
+                this.exportView.repaint(views);
+            } else {
+                Util.showError('Personal Zenodo API Token missing, please set it on your user profile.');
+            }
+        }).bind(this));
     };
 
     this.exportSelected = function() {
         var _this = this;
-        var selectedNodes = $(exportModel.tree).fancytree('getTree').getSelectedNodes();
-        var title = exportView.$titleTextBox.val().trim();
+        var selectedNodes = $(this.exportModel.tree).fancytree('getTree').getSelectedNodes();
+        var title = this.exportView.$titleTextBox.val().trim();
 
         var toExport = [];
         for (var eIdx = 0; eIdx < selectedNodes.length; eIdx++) {
@@ -41,8 +50,8 @@ function ZenodoExportController(parentController) {
             Util.showInfo('Not only spaces and the root should be selected. It will result in an empty export file.');
         } else {
             Util.blockUI();
-            this.getUserInformation(function(userInformation) {
-                mainController.serverFacade.exportZenodo(toExport, true, false, userInformation, title,
+            this.getUserInformation((function(userInformation) {
+                mainController.serverFacade.exportZenodo(toExport, true, false, userInformation, title, this.exportModel.accessToken,
                         function(operationExecutionPermId) {
                             _this.waitForOpExecutionResponse(operationExecutionPermId, function(error, result) {
                                 Util.unblockUI();
@@ -59,7 +68,7 @@ function ZenodoExportController(parentController) {
                                 }
                             });
                         });
-            });
+            }).bind(this));
         }
     };
 
@@ -112,4 +121,8 @@ function ZenodoExportController(parentController) {
             callback(userInformation);
         });
     };
+
+    this.getSettingValue = function (key, callback) {
+        parentController.serverFacade.getSetting(key, callback);
+    };
 }
\ No newline at end of file
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ZenodoExport/ZenodoExportModel.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ZenodoExport/ZenodoExportModel.js
index f555844b57e82e8c640965767f2077b1b66f213e..dc4f73489ca42ef5f9dc9cd1abe15ef67a0a8c35 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ZenodoExport/ZenodoExportModel.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ZenodoExport/ZenodoExportModel.js
@@ -14,5 +14,6 @@
  * limitations under the License.
  */
 
-function ZenodoExportModel() {
+function ZenodoExportModel(accessToken) {
+    this.accessToken = accessToken;
 }
\ No newline at end of file
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ZenodoExport/ZenodoExportView.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ZenodoExport/ZenodoExportView.js
index 833660f9406412a911d2006d59f9747ee194fca1..a2ae6996d23f4730a24de4e2ff05f4b6df87fae4 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ZenodoExport/ZenodoExportView.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ZenodoExport/ZenodoExportView.js
@@ -21,7 +21,7 @@ function ZenodoExportView(exportController, exportModel) {
 
         var $form = $("<div>");
         var $formColumn = $("<form>", {
-            'name': 'rcExportForm',
+            'name': 'zenodoExportForm',
             'role': 'form',
             'action': 'javascript:void(0);',
             'onsubmit': 'mainController.currentView.exportSelected();'
@@ -56,7 +56,7 @@ function ZenodoExportView(exportController, exportModel) {
         this.paintTitleTextBox($container);
 
         var $exportButton = $('<input>', { 'type': 'submit', 'class': 'btn btn-primary', 'value': 'Export Selected',
-            'onClick': '$("form[name=\'rcExportForm\']").submit()'});
+            'onClick': '$("form[name=\'zenodoExportForm\']").submit()'});
         $header.append($exportButton);
     };
 
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/zenodo-exports-api/plugin.properties b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/zenodo-exports-api/plugin.properties
index cc77ea6f8cfc5d2c91b4292696d89990276b2b7b..1e4e8fa3aa70869ce9c174f3bdcf7d2c5941224b 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/zenodo-exports-api/plugin.properties
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/zenodo-exports-api/plugin.properties
@@ -2,5 +2,4 @@ label = Zenodo Exports API
 class = ch.systemsx.cisd.openbis.dss.generic.server.plugins.jython.JythonIngestionService
 script-path = zenodoExports.py
 limit-data-size-megabytes=${zenodo-exports-api-limit-data-size-megabytes:4000}
-zenodoUrl=${zenodo-exports-api-zenodoUrl:https://localhost}
-accessToken=${zenodo-exports-api-accessToken}
\ No newline at end of file
+zenodoUrl=${zenodo-exports-api-zenodoUrl:https://localhost}
\ No newline at end of file
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/zenodo-exports-api/zenodoExports.py b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/zenodo-exports-api/zenodoExports.py
index be1dd798a3369d52923b64d6be25380fc00e7337..5922f0f8827de532880931ddc8150ef0501f88fc 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/zenodo-exports-api/zenodoExports.py
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/zenodo-exports-api/zenodoExports.py
@@ -93,7 +93,7 @@ def export(entities, tr, params):
 def sendToZenodo(tr, params, tempZipFilePath, entities):
     depositRootUrl = str(getConfigurationProperty(tr, 'zenodoUrl')) + '/api/deposit/depositions'
 
-    accessToken = str(getConfigurationProperty(tr, 'accessToken'))
+    accessToken = params.get('accessToken')
     operationLog.info('accessToken: %s' % accessToken)
 
     httpClient = None
@@ -225,7 +225,7 @@ class ZenodoCallable(object):
                     actionCompleted = True
                 elif publicationJson.get('submitted'):
                     operationLog.info('Publication #%d submitted. Registering metadata.' % publicationJson.get('id'))
-                    self.registerPublicationInOpenbis(publicationJson.get('metadata'))
+                    self.registerPublicationInOpenbis(publicationJson.get('metadata'), publicationJson.get('links'))
                     actionCompleted = True
                 else:
                     operationLog.info('Publication #%d not submitted yet.' % publicationJson.get('id'))
@@ -244,13 +244,13 @@ class ZenodoCallable(object):
         return actionCompleted
 
 
-    def registerPublicationInOpenbis(self, publicationMetadataJson):
+    def registerPublicationInOpenbis(self, publicationMetadataJson, publicationLinksJson):
         sessionToken = self.params.get('sessionToken')
         v3 = ServiceProvider.getV3ApplicationService()
         id = CustomASServiceCode('publication-api')
         options = CustomASServiceExecutionOptions() \
             .withParameter('method', 'insertPublication') \
-            .withParameter('publicationURL', self.selfUrl) \
+            .withParameter('publicationURL', publicationLinksJson.get('doi')) \
             .withParameter('openBISRelatedIdentifiers', self.permIdsStr) \
             .withParameter('name', publicationMetadataJson.get('title')) \
             .withParameter('publicationDescription', publicationMetadataJson.get('description')) \
diff --git a/pybis/src/python/CHANGELOG.md b/pybis/src/python/CHANGELOG.md
index 1c68708da418d638fa3158a6d438d9e08b63e341..2f0abd9b62c0f900166306e048abc5978f6c8f06 100644
--- a/pybis/src/python/CHANGELOG.md
+++ b/pybis/src/python/CHANGELOG.md
@@ -1,3 +1,16 @@
+## Changes with pybis-1.9.3
+
+* fixed documentation: add_members (not add_persons)
+* bugfix role assignments of groups
+
+## Changes with pybis-1.9.2
+
+* searches for datasets and samples are highly improved
+* search parameters can accept a code, an identifier or an openbis entity
+* searching for all datasets in a project now works
+* bugfixes
+
+
 ## Changes with pybis-1.9.1
 
 * bugfix: controlled vocabulary
diff --git a/pybis/src/python/README.md b/pybis/src/python/README.md
index 5a525c397433f583f80bd80189d97610a8ab7500..ef065b428f2ec16b9d9b00028f908a1a20cddc0e 100644
--- a/pybis/src/python/README.md
+++ b/pybis/src/python/README.md
@@ -126,9 +126,9 @@ group.assign_role(role='ADMIN', space='DEFAULT')
 group.get_roles() 
 group.revoke_role(role='ADMIN', space='DEFAULT')
 
-group.add_persons(['admin'])
-group.get_persons()
-group.del_persons(['admin'])
+group.add_members(['admin'])
+group.get_members()
+group.del_members(['admin'])
 group.delete()
 
 o.get_persons()
diff --git a/pybis/src/python/pybis/__init__.py b/pybis/src/python/pybis/__init__.py
index 4aa2b995675dc04f0874952732c359ada99bdd0f..c09faa979fdad428ea5009396b3390cdd526bfbe 100644
--- a/pybis/src/python/pybis/__init__.py
+++ b/pybis/src/python/pybis/__init__.py
@@ -1,7 +1,7 @@
 name = 'pybis'
 __author__ = 'Swen Vermeul'
 __email__ = 'swen@ethz.ch'
-__version__ = '1.9.1'
+__version__ = '1.9.3'
 
 from . import pybis
 from .pybis import Openbis
diff --git a/pybis/src/python/pybis/definitions.py b/pybis/src/python/pybis/definitions.py
index 681c47d4526a66a7faadfac3d081a8c8eec9cba2..ca0a43e785563549577e91d6a07968c7ea574d20 100644
--- a/pybis/src/python/pybis/definitions.py
+++ b/pybis/src/python/pybis/definitions.py
@@ -461,12 +461,12 @@ def get_fetchoption_for_entity(entity):
     except KeyError as e:
         return {}
 
-def get_type_for_entity(entity, action):
+def get_type_for_entity(entity, action, parents_or_children=''):
     if action not in "create update delete search".split():
         raise ValueError('unknown action: {}'.format(action))
 
     definition = openbis_definitions(entity)
-    if action in definition:
+    if action in definition and not parents_or_children:
         return definition[action]
     else:
         # try to guess type, according to the naming scheme
@@ -478,10 +478,16 @@ def get_type_for_entity(entity, action):
             "search": "SearchCriteria",
         }
         
-        return {
-            "@type": "as.dto.{}.{}.{}{}"
-            .format(entity.lower(), action, cap_entity, noun[action])
-        }
+        if parents_or_children:
+            return {
+                "@type": "as.dto.{}.{}.{}{}{}"
+                .format(entity.lower(), action, cap_entity, parents_or_children, noun[action])
+            }
+        else:
+            return {
+                "@type": "as.dto.{}.{}.{}{}"
+                .format(entity.lower(), action, cap_entity, noun[action])
+            }
 
 
 def get_method_for_entity(entity, action):
diff --git a/pybis/src/python/pybis/pybis.py b/pybis/src/python/pybis/pybis.py
index 398cf56cda8b98dd3afb248a5240373966886f75..d44a332a0219219e1c65b2ece10331a6a23e5e4c 100644
--- a/pybis/src/python/pybis/pybis.py
+++ b/pybis/src/python/pybis/pybis.py
@@ -381,9 +381,9 @@ def _subcriteria_for_tags(tags):
     if not isinstance(tags, list):
         tags = [tags]
 
-    criterias = []
+    criteria = []
     for tag in tags:
-        criterias.append({
+        criteria.append({
             "fieldName": "code",
             "fieldType": "ATTRIBUTE",
             "fieldValue": {
@@ -396,7 +396,7 @@ def _subcriteria_for_tags(tags):
     return {
         "@type": "as.dto.tag.search.TagSearchCriteria",
         "operator": "AND",
-        "criteria": criterias
+        "criteria": criteria
     }
 
 
@@ -423,14 +423,99 @@ def _subcriteria_for_properties(prop, val):
         }
     }
 
+def _subcriteria_for(thing, entity, parents_or_children='', operator='AND'):
+    """Returns the sub-search criteria for «thing», which can be either:
+    - a python object (sample, dataSet, experiment)
+    - a permId
+    - an identifier
+    - a code
+    """
+
+    if isinstance(thing, str):
+        if is_permid(thing):
+            return _subcriteria_for_permid(
+                thing, 
+                entity=entity,
+                parents_or_children=parents_or_children,
+                operator=operator
+            )
+        elif is_identifier(thing):
+            return _subcriteria_for_identifier(
+                thing, 
+                entity=entity,
+                parents_or_children=parents_or_children,
+                operator=operator
+            )
+        else:
+            # look for code
+            return _subcriteria_for_code_new(
+                thing,
+                entity=entity,
+                parents_or_children=parents_or_children,
+                operator=operator
+            )
+
+    elif isinstance(thing, list):
+        criteria = []
+        for element in thing:
+            crit = _subcriteria_for(element, entity, parents_or_children, operator)
+            criteria += crit["criteria"]
+
+        return {
+            "criteria": criteria,
+            "@type": crit["@type"],
+            "operator": "OR"
+        }
+    elif thing is None:
+        # we just need the type
+        search_type = get_type_for_entity(entity, 'search', parents_or_children)
+        return {
+            "criteria": [],
+            **search_type,
+            "operator": operator
+        }
+    else:
+        # we passed an object
+        return _subcriteria_for_permid(
+            thing.permId, 
+            entity=entity,
+            parents_or_children=parents_or_children,
+            operator=operator
+        )
+        
+
+def _subcriteria_for_identifier(ids, entity, parents_or_children='', operator='AND'):
+    if not isinstance(ids, list):
+        ids = [ids]
+
+    criteria = []
+    for id in ids:
+        criteria.append({
+            "@type": "as.dto.common.search.IdentifierSearchCriteria",
+            "fieldValue": {
+                "value": id,
+                "@type": "as.dto.common.search.StringEqualToValue"
+            },
+            "fieldType": "ATTRIBUTE",
+            "fieldName": "identifier"
+        })
+
+    search_type = get_type_for_entity(entity, 'search', parents_or_children)
+    return {
+        "criteria": criteria,
+        **search_type,
+        "operator": operator
+    }
+    return criteria
+
 
 def _subcriteria_for_permid(permids, entity, parents_or_children='', operator='AND'):
     if not isinstance(permids, list):
         permids = [permids]
 
-    criterias = []
+    criteria = []
     for permid in permids:
-        criterias.append({
+        criteria.append({
             "@type": "as.dto.common.search.PermIdSearchCriteria",
             "fieldValue": {
                 "value": permid,
@@ -440,14 +525,36 @@ def _subcriteria_for_permid(permids, entity, parents_or_children='', operator='A
             "fieldName": "code"
         })
 
-    criteria = {
-        "criteria": criterias,
-        "@type": "as.dto.{}.search.{}{}SearchCriteria".format(
-            entity.lower(), entity, parents_or_children
-        ),
+    search_type = get_type_for_entity(entity, 'search', parents_or_children)
+    return {
+        "criteria": criteria,
+        **search_type,
+        "operator": operator
+    }
+
+
+def _subcriteria_for_code_new(codes, entity, parents_or_children='', operator='AND'):
+    if not isinstance(codes, list):
+        codes = [codes]
+
+    criteria = []
+    for code in codes:
+        criteria.append({
+            "@type": "as.dto.common.search.CodeSearchCriteria",
+            "fieldValue": {
+                "value": code,
+                "@type": "as.dto.common.search.StringEqualToValue"
+            },
+            "fieldType": "ATTRIBUTE",
+            "fieldName": "code"
+        })
+
+    search_type = get_type_for_entity(entity, 'search', parents_or_children)
+    return {
+        "criteria": criteria,
+        **search_type,
         "operator": operator
     }
-    return criteria
 
 
 def _subcriteria_for_code(code, entity):
@@ -1028,7 +1135,7 @@ class Openbis:
                     else:
                         groupId = search_args[attr].code
                     sub_crit.append(
-                        _subcriteria_for_permid(groupId, 'AuthorizationGroup')
+                        _subcriteria_for_permid(groupId, 'authorizationGroup')
                     )
                 elif attr == 'role':
                     # TODO
@@ -1403,37 +1510,34 @@ class Openbis:
 
     def get_samples(
         self, identifier=None, code=None, permId=None,
-        space=None, project=None, experiment=None, type=None,
+        space=None, project=None, experiment=None, collection=None, type=None,
         start_with=None, count=None,
         withParents=None, withChildren=None, tags=None, props=None, **properties
     ):
         """ Get a list of all samples for a given space/project/experiment (or any combination)
         """
 
+        if collection is not None:
+            experiment = collection
+
         sub_criteria = []
 
-        # v3 API does not offer a search for identifiers. We need to do a combined search instead:
-        # space && code or
-        # space && project && code
         if identifier:
-            identifier = identifier.lstrip('/')
-            elements = identifier.split('/')
-            if len(elements) == 2:
-                space = elements[0]
-                code  = elements[1]
-            elif len(elements) == 3:
-                space = elements[0]
-                code  = elements[2]
-            else:
-                raise ValueError("{} is not a valid sample identifier.".format(identifier))
+            crit = _subcriteria_for(identifier, 'sample')
+            sub_criteria += crit['criteria']
 
         if space:
-            sub_criteria.append(_subcriteria_for_code(space, 'space'))
+            sub_criteria.append(_subcriteria_for(space, 'space'))
         if project:
-            proj_crit = _subcriteria_for_code(project, 'project')
-            sub_criteria.append(proj_crit)
+            sub_criteria.append(_subcriteria_for(project, 'project'))
         if experiment:
-            sub_criteria.append(_subcriteria_for_code(experiment, 'experiment'))
+            sub_criteria.append(_subcriteria_for(experiment, 'experiment'))
+
+        if withParents:
+            sub_criteria.append(_subcriteria_for(withParents, 'sample', 'Parents'))
+        if withChildren:
+            sub_criteria.append(_subcriteria_for(withChildren, 'sample', 'Children'))
+
         if properties is not None:
             for prop in properties:
                 sub_criteria.append(_subcriteria_for_properties(prop, properties[prop]))
@@ -1445,26 +1549,6 @@ class Openbis:
             sub_criteria.append(_criteria_for_code(code))
         if permId:
             sub_criteria.append(_common_search("as.dto.common.search.PermIdSearchCriteria", permId))
-        if withParents:
-            if not isinstance(withParents, list):
-                withParents = [withParents]
-            for parent in withParents:
-                sub_criteria.append(
-                    _gen_search_criteria({
-                        "sample": "SampleParents",
-                        "identifier": parent
-                    })
-                )
-        if withChildren:
-            if not isinstance(withChildren, list):
-                withChildren = [withChildren]
-            for child in withChildren:
-                sub_criteria.append(
-                    _gen_search_criteria({
-                        "sample": "SampleChildren",
-                        "identifier": child
-                    })
-                )
 
         criteria = {
             "criteria": sub_criteria,
@@ -1596,29 +1680,35 @@ class Openbis:
     def get_datasets(
         self, code=None, type=None, withParents=None, withChildren=None,
         start_with=None, count=None, kind=None,
-        status=None, sample=None, experiment=None, project=None,
+        status=None, sample=None, experiment=None, collection=None, project=None,
         tags=None, props=None, **properties
     ):
 
+        if 'object' in properties:
+            sample = properties['object']
+        if collection is not None:
+            experiment = collection
+
         sub_criteria = []
 
         if code:
             sub_criteria.append(_criteria_for_code(code))
         if type:
-            sub_criteria.append(_subcriteria_for_type(type, 'DataSet'))
+            sub_criteria.append(_subcriteria_for_type(type, 'dataSet'))
+
         if withParents:
-            sub_criteria.append(_subcriteria_for_permid(withParents, 'DataSet', 'Parents'))
+            sub_criteria.append(_subcriteria_for(withParents, 'dataSet', 'Parents'))
         if withChildren:
-            sub_criteria.append(_subcriteria_for_permid(withChildren, 'DataSet', 'Children'))
+            sub_criteria.append(_subcriteria_for(withChildren, 'dataSet', 'Children'))
 
         if sample:
-            sub_criteria.append(_subcriteria_for_code(sample, 'Sample'))
+            sub_criteria.append(_subcriteria_for(sample, 'sample'))
         if experiment:
-            sub_criteria.append(_subcriteria_for_code(experiment, 'Experiment'))
+            sub_criteria.append(_subcriteria_for(experiment, 'experiment'))
+
         if project:
-            exp_crit = _subcriteria_for_code(experiment, 'Experiment')
-            proj_crit = _subcriteria_for_code(project, 'Project')
-            exp_crit['criteria'] = []
+            exp_crit = _subcriteria_for(experiment, 'experiment')
+            proj_crit = _subcriteria_for(project, 'project')
             exp_crit['criteria'].append(proj_crit)
             sub_criteria.append(exp_crit)
         if tags:
diff --git a/pybis/src/python/setup.py b/pybis/src/python/setup.py
index 723fcda825c708e6a385739579d327aa8d44c80e..d98d25fa4d55669e55272c2d728a0b6a57241c5c 100644
--- a/pybis/src/python/setup.py
+++ b/pybis/src/python/setup.py
@@ -11,7 +11,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
 
 setup(
     name='PyBIS',
-    version= '1.9.1',
+    version= '1.9.3',
     author='Swen Vermeul • ID SIS • ETH Zürich',
     author_email='swen@ethz.ch',
     description='openBIS connection and interaction, optimized for using with Jupyter',
diff --git a/pybis/src/python/tests/conftest.py b/pybis/src/python/tests/conftest.py
index 677de709a3f316e1eb0806ec0ed2cf7e95f4388c..1568409e701a0c6e37da8fcab45941ae1cf6d83a 100644
--- a/pybis/src/python/tests/conftest.py
+++ b/pybis/src/python/tests/conftest.py
@@ -3,9 +3,12 @@ import time
 
 from pybis import Openbis
 
-openbis_url = 'https://localhost:8443'
-admin_username = 'admin'
-admin_password = 'changeit'
+#openbis_url = 'https://localhost:8443'
+#admin_username = 'admin'
+#admin_password = 'changeit'
+openbis_url = 'http://localhost:20000'
+admin_username = 'openbis_test_js'
+admin_password = 'password'
 
 @pytest.yield_fixture(scope="module")
 def openbis_instance():
diff --git a/pybis/src/python/tests/test_group.py b/pybis/src/python/tests/test_group.py
index 9e3268332131fe216aa8479ba01bd9125e8807d1..cb3e8dad9fd2cb8b55de3e054437e8e837d6dfeb 100644
--- a/pybis/src/python/tests/test_group.py
+++ b/pybis/src/python/tests/test_group.py
@@ -27,12 +27,12 @@ def test_crud_group(openbis_instance, group):
     changed_description = 'changed description of group ' + group.code
     group.description = changed_description
     group.save()
-    group_changed = openbis_instance.get_group(code=group.code)
+    group_changed = openbis_instance.get_group(group.code)
     assert group_changed.description == changed_description
 
     group.delete('test')
     with pytest.raises(ValueError):
-        group_not_exists = openbis_instance.get_group(code=group.code)
+        group_not_exists = openbis_instance.get_group(group.code)
         assert group_not_exists is None