diff --git a/QOpenScienceFramework/__init__.py b/QOpenScienceFramework/__init__.py index 6fe76ae..e9ef345 100644 --- a/QOpenScienceFramework/__init__.py +++ b/QOpenScienceFramework/__init__.py @@ -1,4 +1,4 @@ -__version__ = "1.1.8" +__version__ = "1.2.0" __author__ = "Daniel Schreij" import os diff --git a/QOpenScienceFramework/widgets/osfexplorer.py b/QOpenScienceFramework/widgets/osfexplorer.py index c14b027..b889ed5 100644 --- a/QOpenScienceFramework/widgets/osfexplorer.py +++ b/QOpenScienceFramework/widgets/osfexplorer.py @@ -351,6 +351,14 @@ def create_context_menu(self, item): if data['type'] == 'nodes': return None + user_has_write_permissions = False + try: + user_has_write_permissions = "write" in \ + data["attributes"]["current_user_permissions"] + except AttributeError as e: + raise osf.OSFInvalidResponse('Could not retrieve permission info: ' + '{}'.format(e)) + if data['type'] == 'files': kind = data["attributes"]["kind"] @@ -364,23 +372,31 @@ def create_context_menu(self, item): menu = QtWidgets.QMenu(self.tree) - # Actions only allowd on files + # Actions only allowed on files if kind == "file": menu.addAction(self.download_icon, _(u"Download file"), self._clicked_download_file) # Actions only allowed on folders if kind == "folder": - menu.addAction(self.upload_icon, _(u"Upload file to folder"), + upload_action = menu.addAction(self.upload_icon, _(u"Upload file to folder"), self.__clicked_upload_file) - menu.addAction(self.new_folder_icon, _(u"Create new folder"), + newfolder_action = menu.addAction(self.new_folder_icon, _(u"Create new folder"), self.__clicked_new_folder) menu.addAction(self.refresh_icon, _(u"Refresh contents"), self.__clicked_partial_refresh) + if not user_has_write_permissions: + upload_action.setDisabled(True) + newfolder_action.setDisabled(True) + # Only allow deletion of files and subfolders of repos if kind == "file" or not item_is_repo: - menu.addAction(self.delete_icon, _(u"Delete"), self.__clicked_delete) + delete_action = menu.addAction(self.delete_icon, _(u"Delete"), + self.__clicked_delete) + + if not user_has_write_permissions: + delete_action.setDisabled(True) return menu @@ -572,7 +588,11 @@ def set_folder_properties(self, data): level = "Public" else: level = "Private" - self.properties["Type"][1].setText(level + " " + attributes["category"]) + access_level = "" + if not "write" in attributes["current_user_permissions"]: + access_level = " (read only)" + self.properties["Type"][1].setText(level + " " + \ + attributes["category"] + access_level) elif "name" in attributes and "kind" in attributes: self.properties["Name"][1].setText(attributes["name"]) self.properties["Type"][1].setText(attributes["kind"]) @@ -700,13 +720,20 @@ def __slot_currentItemChanged(self, item, col): self.abort_preview.emit() data = item.data(0, QtCore.Qt.UserRole) + + user_has_write_permissions = "write" in \ + data["attributes"]["current_user_permissions"] + if data['type'] == 'nodes': name = data["attributes"]["title"] - if data["attributes"]["public"]: - access = "public " + if not user_has_write_permissions: + kind = "readonly " + data["attributes"]["category"] else: - access = "private " - kind = access + data["attributes"]["category"] + if data["attributes"]["public"]: + access = "public " + else: + access = "private " + kind = access + data["attributes"]["category"] if data['type'] == 'files': name = data["attributes"]["name"] kind = data["attributes"]["kind"] @@ -714,22 +741,31 @@ def __slot_currentItemChanged(self, item, col): pm = self.tree.get_icon(kind, name).pixmap(self.preview_size) self.image_space.setPixmap(pm) - if kind == "file": + if kind == "file": self.set_file_properties(data) self.download_button.setDisabled(False) self.upload_button.setDisabled(True) - self.delete_button.setDisabled(False) self.new_folder_button.setDisabled(True) + if user_has_write_permissions: + self.delete_button.setDisabled(False) + else: + self.delete_button.setDisabled(True) + elif kind == "folder": self.set_folder_properties(data) - self.new_folder_button.setDisabled(False) + if user_has_write_permissions: + self.new_folder_button.setDisabled(False) + self.upload_button.setDisabled(False) + else: + self.new_folder_button.setDisabled(True) + self.upload_button.setDisabled(True) + self.download_button.setDisabled(True) - self.upload_button.setDisabled(False) # Check if the parent node is a project # If so the current 'folder' must be a storage provider (e.g. dropbox) # which should not be allowed to be deleted. parent_data = item.parent().data(0, QtCore.Qt.UserRole) - if parent_data['type'] == 'nodes': + if parent_data['type'] == 'nodes' or not user_has_write_permissions: self.delete_button.setDisabled(True) else: self.delete_button.setDisabled(False) diff --git a/QOpenScienceFramework/widgets/projecttree.py b/QOpenScienceFramework/widgets/projecttree.py index c15c79a..1c807e5 100644 --- a/QOpenScienceFramework/widgets/projecttree.py +++ b/QOpenScienceFramework/widgets/projecttree.py @@ -323,11 +323,8 @@ def get_icon(self, datatype, name): 's3' : 'web-microsoft-onedrive', } - if datatype.lower() in ['public project','private project']: - # return QtGui.QIcon.fromTheme( - # 'gbrainy', - # QtGui.QIcon(osf_logo_path) - # ) + if datatype.lower() in ['public project','private project', \ + 'readonly project']: if datatype.lower() == 'public project': return qta.icon('fa.cube', 'fa.globe', options=[ @@ -335,6 +332,13 @@ def get_icon(self, datatype, name): {'scale_factor': 0.75, 'offset': (0.2, 0.20), 'color': 'green'}]) + elif datatype.lower() == "readonly project": + return qta.icon('fa.cube', 'fa.lock', + options=[ + {}, + {'scale_factor': 0.75, + 'offset': (0.2, 0.20), + 'color': 'red'}]) else: return qta.icon('fa.cube') @@ -485,13 +489,27 @@ def add_item(self, parent, data): # Create item item = QtWidgets.QTreeWidgetItem(parent, values) - # Set icon - icon = self.get_icon(icon_type, name) - item.setIcon(0, icon) + # Copy permission data of project to child elements + if kind != "project" and parent: + try: + parent_data = parent.data(0, QtCore.Qt.UserRole) + if parent_data and "current_user_permissions" in parent_data["attributes"]: + data["attributes"]["current_user_permissions"] = \ + parent_data["attributes"]["current_user_permissions"] + except AttributeError as e: + raise osf.OSFInvalidResponse("Could not obtain permission data: {}".format(e)) + elif kind == "project": + # Show a lock icon if project has read-only permissions + if not "write" in data["attributes"]["current_user_permissions"]: + icon_type = "readonly project" # Add data item.setData(0, QtCore.Qt.UserRole, data) + # Set icon + icon = self.get_icon(icon_type, name) + item.setIcon(0, icon) + return item, kind def populate_tree(self, reply, parent=None): @@ -555,6 +573,26 @@ def populate_tree(self, reply, parent=None): if req: self.active_requests.append(req) + # Check if there are linked projects. + if kind == "project": + try: + linked_projects_entrypoint = entry['relationships']['linked_nodes']\ + ['links']['related']['href'] + except AttributeError as e: + raise osf.OSFInvalidResponse("Invalid api call for getting " + "linked projects: {}".format(e)) + + linked_projects_entrypoint += "?page[size]={}".format(self.ITEMS_PER_PAGE) + req = self.manager.get( + linked_projects_entrypoint, + self.populate_tree, + item, + errorCallback=self.__cleanup_reply + ) + # If something went wrong, req should be None + if req: + self.active_requests.append(req) + # If the results are paginated, see if there is another page that needs # to be processed try: