diff --git a/services/web/client/source/class/osparc/component/export/ExportDAG.js b/services/web/client/source/class/osparc/component/export/ExportDAG.js index b053a7cae0f..bb6b176b923 100644 --- a/services/web/client/source/class/osparc/component/export/ExportDAG.js +++ b/services/web/client/source/class/osparc/component/export/ExportDAG.js @@ -105,7 +105,7 @@ qx.Class.define("osparc.component.export.ExportDAG", { flex: 1 }); - // const shareWith = new osparc.component.export.ShareWith("exportGroup"); + // const shareWith = new osparc.component.export.ShareWith("exportDAG"); // this._add(shareWith); const exportBtn = this.__getExportBtn(); diff --git a/services/web/client/source/class/osparc/component/widget/NodesTree.js b/services/web/client/source/class/osparc/component/widget/NodesTree.js index 5c772ba1584..96d1d128364 100644 --- a/services/web/client/source/class/osparc/component/widget/NodesTree.js +++ b/services/web/client/source/class/osparc/component/widget/NodesTree.js @@ -102,7 +102,7 @@ qx.Class.define("osparc.component.widget.NodesTree", { enabled: false }); exportButton.addListener("execute", () => { - this.__exportGroup(); + this.__exportDAG(); }, this); osparc.utils.Utils.setIdToWidget(exportButton, "exportServicesBtn"); toolbar.add(exportButton); @@ -239,7 +239,7 @@ qx.Class.define("osparc.component.widget.NodesTree", { this.fireEvent("addNode"); }, - __exportGroup: function() { + __exportDAG: function() { const selectedItem = this.__getSelection(); if (selectedItem) { if (selectedItem.getIsContainer()) { diff --git a/services/web/client/source/class/osparc/data/Permissions.js b/services/web/client/source/class/osparc/data/Permissions.js index 6f00b10e795..58b8ed29c75 100644 --- a/services/web/client/source/class/osparc/data/Permissions.js +++ b/services/web/client/source/class/osparc/data/Permissions.js @@ -134,6 +134,9 @@ qx.Class.define("osparc.data.Permissions", { "user": [ "studies.user.read", "studies.user.create", + "studies.template.create", + "studies.template.update", + "studies.template.delete", "storage.datcore.read", "preferences.user.update", "preferences.apikey.create", @@ -155,9 +158,6 @@ qx.Class.define("osparc.data.Permissions", { "study.tag" ], "tester": [ - "studies.template.create", - "studies.template.update", - "studies.template.delete", "services.all.read", "preferences.role.update", "study.nodestree.uuid.read", diff --git a/services/web/client/source/class/osparc/desktop/StudyEditor.js b/services/web/client/source/class/osparc/desktop/StudyEditor.js index 0c76f7650af..71ff371e148 100644 --- a/services/web/client/source/class/osparc/desktop/StudyEditor.js +++ b/services/web/client/source/class/osparc/desktop/StudyEditor.js @@ -195,7 +195,7 @@ qx.Class.define("osparc.desktop.StudyEditor", { } const node = this.getStudy().getWorkbench().getNode(nodeId); if (node && node.isContainer()) { - const exportGroupView = new osparc.component.export.ExportGroup(node); + const exportDAGView = new osparc.component.export.ExportDAG(node); const window = new qx.ui.window.Window(this.tr("Export: ") + node.getLabel()).set({ appearance: "service-window", layout: new qx.ui.layout.Grow(), @@ -206,15 +206,15 @@ qx.Class.define("osparc.desktop.StudyEditor", { showMinimize: false, modal: true }); - window.add(exportGroupView); + window.add(exportDAGView); window.center(); window.open(); window.addListener("close", () => { - exportGroupView.tearDown(); + exportDAGView.tearDown(); }, this); - exportGroupView.addListener("finished", () => { + exportDAGView.addListener("finished", () => { window.close(); }, this); } diff --git a/services/web/server/src/simcore_service_webserver/projects/projects_handlers.py b/services/web/server/src/simcore_service_webserver/projects/projects_handlers.py index e85d6593f4e..4fa7db1fd61 100644 --- a/services/web/server/src/simcore_service_webserver/projects/projects_handlers.py +++ b/services/web/server/src/simcore_service_webserver/projects/projects_handlers.py @@ -17,7 +17,7 @@ from .projects_db import APP_PROJECT_DBAPI from .projects_exceptions import ProjectInvalidRightsError, ProjectNotFoundError -OVERRIDABLE_DOCUMENT_KEYS = ["name", "description", "thumbnail", "prjOwner"] +OVERRIDABLE_DOCUMENT_KEYS = ["name", "description", "thumbnail", "prjOwner", "accessRights"] # TODO: validate these against api/specs/webserver/v0/components/schemas/project-v0.0.1.json log = logging.getLogger(__name__) diff --git a/services/web/server/src/simcore_service_webserver/security_roles.py b/services/web/server/src/simcore_service_webserver/security_roles.py index 9a7267cc189..b7c4fd17a2f 100644 --- a/services/web/server/src/simcore_service_webserver/security_roles.py +++ b/services/web/server/src/simcore_service_webserver/security_roles.py @@ -47,6 +47,7 @@ "project.create", # "studies.user.create", "project.close", "project.delete", # "study.node.create", + "project.template.create", # "study.node.delete", # "study.node.rename", # "study.edge.create", @@ -67,7 +68,9 @@ ], "inherits": [UserRole.GUEST, UserRole.ANONYMOUS], }, - UserRole.TESTER: {"can": ["project.template.create",], "inherits": [UserRole.USER]}, + UserRole.TESTER: { + "can": [], + "inherits": [UserRole.USER]}, } # diff --git a/services/web/server/tests/unit/with_dbs/test_projects.py b/services/web/server/tests/unit/with_dbs/test_projects.py index 66e50236587..2fae668c508 100644 --- a/services/web/server/tests/unit/with_dbs/test_projects.py +++ b/services/web/server/tests/unit/with_dbs/test_projects.py @@ -283,7 +283,7 @@ async def test_new_project( "creationDate": now_str(), "lastChangeDate": now_str(), "thumbnail": "", - "accessRights": {}, + "accessRights": {"12": "some rights"}, "workbench": {}, "tags": [], } @@ -297,7 +297,8 @@ async def test_new_project( # updated fields assert default_project["uuid"] != new_project["uuid"] - assert default_project["prjOwner"] != logged_user["name"] + assert default_project["prjOwner"] != logged_user["email"] + assert new_project["prjOwner"] == logged_user["email"] assert to_datetime(default_project["creationDate"]) < to_datetime( new_project["creationDate"] ) @@ -351,6 +352,7 @@ async def test_new_project_from_template( # different ownership assert project["prjOwner"] == logged_user["email"] assert project["prjOwner"] != template_project["prjOwner"] + assert project["accessRights"] == template_project["accessRights"] # different timestamps assert to_datetime(template_project["creationDate"]) < to_datetime( @@ -403,6 +405,7 @@ async def test_new_project_from_template_with_body( "prjOwner": "", "creationDate": "2019-06-03T09:59:31.987Z", "lastChangeDate": "2019-06-03T09:59:31.987Z", + "accessRights": {"123": "some new access rights"}, "workbench": {}, "tags": [], } @@ -423,6 +426,9 @@ async def test_new_project_from_template_with_body( # different ownership assert project["prjOwner"] == logged_user["email"] assert project["prjOwner"] != template_project["prjOwner"] + # different access rights + assert project["accessRights"] != template_project["accessRights"] + assert project["accessRights"] == predefined["accessRights"] # different timestamps assert to_datetime(template_project["creationDate"]) < to_datetime( @@ -448,7 +454,7 @@ async def test_new_project_from_template_with_body( [ (UserRole.ANONYMOUS, web.HTTPUnauthorized), (UserRole.GUEST, web.HTTPForbidden), - (UserRole.USER, web.HTTPForbidden), + (UserRole.USER, web.HTTPCreated), (UserRole.TESTER, web.HTTPCreated), ], ) @@ -480,12 +486,83 @@ async def test_new_template_from_project( assert len(templates) == 1 assert templates[0] == template_project - # identical in all fields except UUIDs? - # api/specs/webserver/v0/components/schemas/project-v0.0.1.json - # assert_replaced(user_project, template_project) + assert template_project["name"] == user_project["name"] + assert template_project["description"] == user_project["description"] + assert template_project["prjOwner"] == logged_user["email"] + assert template_project["accessRights"] == user_project["accessRights"] + + # different timestamps + assert to_datetime(user_project["creationDate"]) < to_datetime( + template_project["creationDate"] + ) + assert to_datetime(user_project["lastChangeDate"]) < to_datetime( + template_project["lastChangeDate"] + ) + + # different uuids for project and nodes!? + assert template_project["uuid"] != user_project["uuid"] + + # check uuid replacement + for node_name in template_project["workbench"]: + try: + uuidlib.UUID(node_name) + except ValueError: + pytest.fail("Invalid uuid in workbench node {}".format(node_name)) + + # do the same with a body + predefined = { + "uuid": "", + "name": "My super duper new template", + "description": "Some lines from user", + "thumbnail": "", + "prjOwner": "", + "creationDate": "2019-06-03T09:59:31.987Z", + "lastChangeDate": "2019-06-03T09:59:31.987Z", + "workbench": {}, + "accessRights": {"12": "rwx"}, + "tags": [], + } + + resp = await client.post(url, json=predefined) + data, error = await assert_status(resp, expected) + + if not error: + template_project = data + # uses predefined + assert template_project["name"] == predefined["name"] + assert template_project["description"] == predefined["description"] + assert template_project["prjOwner"] == logged_user["email"] + assert template_project["accessRights"] == predefined["accessRights"] + + modified = [ + "prjOwner", + "creationDate", + "lastChangeDate", + "uuid", + "accessRights", + ] + + # different ownership + assert template_project["prjOwner"] == logged_user["email"] + assert template_project["prjOwner"] == user_project["prjOwner"] - # TODO: workbench nodes should not have progress?? - # TODO: check in detail all fields in a node + # different timestamps + assert to_datetime(user_project["creationDate"]) < to_datetime( + template_project["creationDate"] + ) + assert to_datetime(user_project["lastChangeDate"]) < to_datetime( + template_project["lastChangeDate"] + ) + + # different uuids for project and nodes!? + assert template_project["uuid"] != user_project["uuid"] + + # check uuid replacement + for node_name in template_project["workbench"]: + try: + uuidlib.UUID(node_name) + except ValueError: + pytest.fail("Invalid uuid in workbench node {}".format(node_name)) # PUT --------