diff --git a/docs/getting-started.qmd b/docs/getting-started.qmd index ca1c1da2..745b52ad 100644 --- a/docs/getting-started.qmd +++ b/docs/getting-started.qmd @@ -13,25 +13,39 @@ Please start **iBridges-Gui** by typing `ibridges-gui` on your terminal and hit ## Configuring iBridges-Gui +To connect to the server you need a configuration file, a so-called `irods_environment.json`. +You can create one for yourself using templates, editing default settings we provide for you or simply create such a file. + +### Installing iRODS server templates +We have created a plugin system to automatically create the environment file for you. +Please follow the [documentation](https://ibridges.readthedocs.io/en/latest/cli.html) how to set it up. + +### Creating an iRODS configuration file + When you start iBridges you will find in the upper drop-down menu `Connect` and `Configure`. ![](screenshots/start_ibridges.png){width=50% fig-align="center"} -Before we start iBridges for the first time let us check and create a valid configuration file; Click on `Configure -> Add Configuration`. +Let us check or create a valid configuration file; Click on `Configure -> Add Configuration`. ![](screenshots/add_check_config.png){width=75% fig-align="center"} -If you already stored an `irods_environment.json` in the directory `~/.irods` (Windows `C:\Users\\.irods`) then you can use the drop-down menu (little downward arrow) to load the configuration. +#### Existing configuration files +In the drop-down menu you will find previously created iRODS environments, they start with `irods_environment` and end with `.json`. Select the one you want to check. -If you do not have an iRODS configuration yet, click on the button `New Config`. +#### Creating a configuration from a template +If you do not have an iRODS configuration yet, and you installed a plugin (see above) you can select a configuration template from the drop-down menu. +You will have to add your username and save as `irods_environment.json`. +#### Creating a new configuration +To create a new environment click on the button `New Config`. You should see now something like: ![](screenshots/add_new_config.png){width=75% fig-align="center"} Click the `Check` button to find out whether you can make a connection to the iRODS server. If you get error messages, adjust the contents accordingly. If you are unsure, please contact your iRODS service provider. -Once the check runs through fine click the `Save` or `Save as` button. This will store the adjusted configuration in the correct directory on you laptop so that we can use it for the login (See Section below). +Once the check runs through fine click the `Save` or `Save as` button. This will store the adjusted configuration in the correct directory on your laptop so that we can use it for the login (See Section below). ## Start an iRODS session diff --git a/ibridgesgui/__main__.py b/ibridgesgui/__main__.py index 02b23297..6f7f56ef 100755 --- a/ibridgesgui/__main__.py +++ b/ibridgesgui/__main__.py @@ -48,7 +48,7 @@ def __init__(self, app_name): "tabSync": self.init_sync_tab, "tabSearch": self.init_search_tab, "tabInfo": self.init_info_tab, - "tabLog": self.init_log_tab + "tabLog": self.init_log_tab, } self.session = None @@ -61,7 +61,6 @@ def __init__(self, app_name): self.action_check_configuration.triggered.connect(self.inspect_env_file) self.tab_widget.setCurrentIndex(0) - def disconnect(self): """Close iRODS session.""" self.error_label.clear() diff --git a/ibridgesgui/config.py b/ibridgesgui/config.py index b9c69585..8f45a6b0 100644 --- a/ibridgesgui/config.py +++ b/ibridgesgui/config.py @@ -10,6 +10,7 @@ from typing import Union from ibridges.session import Session +from irods.auth.pam import PamLoginException from irods.connection import PlainTextPAMPasswordError from irods.exception import ( CAT_INVALID_AUTHENTICATION, @@ -204,6 +205,12 @@ def check_irods_config(ienv: Union[Path, dict]) -> str: return repr(err) except AttributeError as err: return repr(err) + except PamLoginException as err: + # irods4.3+ specific + return f'Adjust "irods_authentication_scheme" {err.args}' + except ModuleNotFoundError as err: + # irods4.3+ uses string in authenticationscheme as class + return f'"irods_authentication_scheme": "{err.name}" does not exist' except PlainTextPAMPasswordError: return ( diff --git a/ibridgesgui/login.py b/ibridgesgui/login.py index 07b110cf..e7a9f9c4 100644 --- a/ibridgesgui/login.py +++ b/ibridgesgui/login.py @@ -68,6 +68,17 @@ def close(self): """Abort login.""" self.done(0) + def _check_home(self, session): + if not IrodsPath(session).collection_exists(): + return False + return True + + def _check_resource(self, session): + resc = Resources(session).get_resource(session.default_resc) + if resc.parent is not None: + return False + return True + def login_function(self): """Connect to iRODS server with gathered info.""" self.error_label.clear() @@ -86,8 +97,17 @@ def login_function(self): session.home, ) session.write_pam_password() - self.session_dict["session"] = session - set_last_ienv_path(env_file.name) + if self._check_home(session) and self._check_resource(session): + self.session_dict["session"] = session + set_last_ienv_path(env_file.name) + self.close() + elif not self._check_home(session): + self.error_label.setText(f'"irods_home": "{session.home}" does not exist.') + elif not self._check_resource(session): + self.error_label.setText( + f'"irods_default_resource": "{session.default_resc}" not writeable.' + ) + except LoginError: self.error_label.setText("irods_environment.json not setup correctly.") self.logger.error("irods_environment.json not setup correctly.") @@ -99,35 +119,10 @@ def login_function(self): "Cannot connect to server. Check Internet, host name and port." ) self.logger.exception("Network error.") + except ResourceDoesNotExist: + self.error_label.setText('"irods_default_resource" does not exist.') + self.logger.exception("Default resource does not exist.") except Exception as err: log_path = Path("~/.ibridges") self.logger.exception("Failed to login: %s", repr(err)) self.error_label.setText(f"Login failed, consult the log file(s) in {log_path}") - - #check irods_home - fail_home = True - if not IrodsPath(self.session_dict["session"]).collection_exists(): - self.error_label.setText(f'"irods_home": "{session.home}" does not exist.') - self.logger.error("irods_home does not exist.") - else: - fail_home = False - - #check existance of default resource - fail_resc = True - try: - resc = Resources(self.session_dict["session"]).get_resource(session.default_resc) - if resc.parent is None: - fail_resc = False - else: - self.error_label.setText(f'"default_resource": "{session.default_resc}" not valid.') - except ResourceDoesNotExist: - self.error_label.setText( - f'"default_resource": "{session.default_resc}" does not exist.') - self.logger.error("Default resource does not exist.") - except AttributeError: - self.error_label.setText(f'"default_resource": "{session.default_resc}" not valid.') - - if fail_resc or fail_home: - del self.session_dict["session"] - else: - self.close() diff --git a/ibridgesgui/logviewer.py b/ibridgesgui/logviewer.py index 70dfb782..f3e06efd 100644 --- a/ibridgesgui/logviewer.py +++ b/ibridgesgui/logviewer.py @@ -25,7 +25,7 @@ def __init__(self, text_browser): def emit(self, record): """Emit when new logging accurs.""" - msg = self.format(record)+"\n" + msg = self.format(record) + "\n" self.append_plain_text.emit(msg) @@ -44,7 +44,7 @@ def __init__(self, logger): self.log_label.setText(str(CONFIG_DIR)) self.log_text = QTextEditLogger(self.log_browser) self.log_text.setFormatter( - logging.Formatter( - '%(asctime)s %(levelname)s %(module)s %(funcName)s %(message)s')) + logging.Formatter("%(asctime)s %(levelname)s %(module)s %(funcName)s %(message)s") + ) self.logger.addHandler(self.log_text) self.logger.setLevel(logging.DEBUG) diff --git a/ibridgesgui/popup_widgets.py b/ibridgesgui/popup_widgets.py index ffc1f7d4..4cad60c6 100644 --- a/ibridgesgui/popup_widgets.py +++ b/ibridgesgui/popup_widgets.py @@ -140,11 +140,16 @@ def __init__(self, logger, env_path): self.logger = logger self.env_path = env_path self.setWindowTitle("Create, edit and inspect iRODS environment") + + providers = get_environment_providers() + self.templates = { + f"Template - {key} ({descr})": key + for p in providers + for key, descr in p.descriptions.items() + } self._init_env_box() - self._init_template_box() - self.envbox.activated.connect(self.load_env) - self.template_box.activated.connect(self.load_template) + self.envbox.activated.connect(self.load) self.new_button.clicked.connect(self.create_env) self.check_button.clicked.connect(self.check_env) self.save_button.clicked.connect(self.save_env) @@ -156,36 +161,30 @@ def _init_env_box(self): env_jsons = [""] + [path.name for path in self.env_path.glob("irods_environment*json")] if len(env_jsons) != 0: self.envbox.addItems(env_jsons) - self.envbox.setCurrentIndex(0) - - def _init_template_box(self): - self.template_box.clear() - providers = get_environment_providers() - - if len(providers) == 0: - self.template_box.hide() - return + self.envbox.addItems(self.templates.keys()) + self.envbox.setCurrentIndex(0) - templates = [key+": "+descr for p in providers - for key, descr in p.descriptions.items()] - if len(templates) > 0: - self.template_box.addItems(templates) - self.template_box.setCurrentIndex(0) + def load(self): + """Decide whether load template or irods env.""" + selected = self.envbox.currentText() + if selected.startswith("Template - "): + self.load_template(self.templates[selected]) + else: + self.load_env(self.env_path.joinpath(selected)) - def load_template(self): + def load_template(self, template_key): """Load environment template into text field.""" self.error_label.clear() - template = self.template_box.currentText() - key = template.split(": ")[0] - env_json = find_environment_provider(get_environment_providers(), key).\ - environment_json(key, "USERNAME").split("\n") + provider = find_environment_provider(get_environment_providers(), template_key) + env_json = provider.environment_json( + template_key, *[q.upper() for q in provider.questions] + ).split("\n") populate_textfield(self.env_field, env_json) self.error_label.setText("Please fill in your user name.") - def load_env(self): + def load_env(self, env_file): """Load json into text field.""" self.error_label.clear() - env_file = self.env_path.joinpath(self.envbox.currentText()) try: content = json.dumps( _read_json(env_file), sort_keys=True, indent=4, separators=(",", ": ") diff --git a/ibridgesgui/ui_files/configCheck.py b/ibridgesgui/ui_files/configCheck.py index 2b34f6a9..821f123c 100644 --- a/ibridgesgui/ui_files/configCheck.py +++ b/ibridgesgui/ui_files/configCheck.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'ibridgesgui/ui_files/configCheck.ui' # -# Created by: PyQt6 UI code generator 6.4.2 +# Created by: PyQt6 UI code generator 6.6.1 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -56,10 +56,6 @@ def setupUi(self, Dialog): self.envbox = QtWidgets.QComboBox(parent=Dialog) self.envbox.setObjectName("envbox") self.horizontalLayout.addWidget(self.envbox) - self.template_box = QtWidgets.QComboBox(parent=Dialog) - self.template_box.setObjectName("template_box") - self.template_box.addItem("") - self.horizontalLayout.addWidget(self.template_box) self.new_button = QtWidgets.QPushButton(parent=Dialog) self.new_button.setObjectName("new_button") self.horizontalLayout.addWidget(self.new_button) @@ -105,7 +101,6 @@ def setupUi(self, Dialog): def retranslateUi(self, Dialog): _translate = QtCore.QCoreApplication.translate Dialog.setWindowTitle(_translate("Dialog", "Dialog")) - self.template_box.setItemText(0, _translate("Dialog", "Server Templates")) self.new_button.setText(_translate("Dialog", "New Config")) self.check_button.setText(_translate("Dialog", "Check")) self.save_button.setText(_translate("Dialog", "Save")) diff --git a/ibridgesgui/ui_files/configCheck.ui b/ibridgesgui/ui_files/configCheck.ui index 743eed07..3cf79655 100644 --- a/ibridgesgui/ui_files/configCheck.ui +++ b/ibridgesgui/ui_files/configCheck.ui @@ -57,15 +57,6 @@ QTabWidget#info_tabs - - - - - Server Templates - - - -