Esempio n. 1
0
class SettingsDialog(QDialog):
    """Dialog with plugin settings."""

    PRODUCTION_API_URL = "https://api.3di.live"
    STAGING_API_URL = "https://api.staging.3di.live"
    DEFAULT_UPLOAD_TIMEOUT = 45

    settings_changed = pyqtSignal()

    def __init__(self, iface, parent=None):
        QDialog.__init__(self, parent)
        plugin_dir = os.path.dirname(os.path.realpath(__file__))
        ui_filepath = os.path.join(plugin_dir, "ui", "settings.ui")
        self.ui = uic.loadUi(ui_filepath, self)
        self.iface = iface
        self.settings_communication = UICommunication(
            self.iface, "3Di Models and Simulations Settings")
        self.api_url = None
        self.wss_url = None
        self.upload_timeout = None
        self.working_dir = None
        self.browse_pb.clicked.connect(self.set_working_directory)
        self.set_pak_pb.clicked.connect(self.set_personal_api_key)
        self.obtain_pak_pb.clicked.connect(self.obtain_personal_api_key)
        self.ui.defaults_pb.clicked.connect(self.restore_defaults)
        self.ui.cancel_pb.clicked.connect(self.reject)
        self.ui.save_pb.clicked.connect(self.accept)
        self.load_settings()

    @staticmethod
    def get_3di_auth():
        """Getting 3Di credentials from the QGIS Authorization Manager."""
        settings = QSettings()
        authcfg = settings.value("threedi/authcfg", None)
        auth_manager = QgsApplication.authManager()
        cfg = QgsAuthMethodConfig()
        auth_manager.loadAuthenticationConfig(authcfg, cfg, True)
        username = cfg.config("username")
        password = cfg.config("password")
        return username, password

    @staticmethod
    def set_3di_auth(personal_api_key, username="******"):
        """Setting 3Di credentials in the QGIS Authorization Manager."""
        settings = QSettings()
        authcfg = settings.value("threedi/authcfg", None)
        cfg = QgsAuthMethodConfig()
        auth_manager = QgsApplication.authManager()
        auth_manager.setMasterPassword()
        auth_manager.loadAuthenticationConfig(authcfg, cfg, True)

        if cfg.id():
            cfg.setConfig("username", username)
            cfg.setConfig("password", personal_api_key)
            auth_manager.updateAuthenticationConfig(cfg)
        else:
            cfg.setMethod("Basic")
            cfg.setName("3Di Personal Api Key")
            cfg.setConfig("username", username)
            cfg.setConfig("password", personal_api_key)
            auth_manager.storeAuthenticationConfig(cfg)
            settings.setValue("threedi/authcfg", cfg.id())

    def set_personal_api_key(self):
        """Setting active Personal API Key."""
        pak, accept = QInputDialog.getText(self, "Personal API Key",
                                           "Paste your Personal API Key:")
        if accept is False:
            return
        self.set_3di_auth(pak)
        self.set_personal_api_key_label(True)

    @staticmethod
    def obtain_personal_api_key():
        """Open website where user can get his Personal API Key."""
        webbrowser.open("https://management.3di.live/personal_api_keys/")

    def set_personal_api_key_label(self, personal_api_key_available):
        """Setting Personal API Key label text."""
        if personal_api_key_available:
            label_txt = """<html><head/><body><p><span style=" color:#00aa00;">
            ✓ Available</span></p></body></html>"""
        else:
            label_txt = """<html><head/><body><p><span style=" color:#ff0000;">
            ✕ Not found</span></p></body></html>"""
        self.pak_label.setText(label_txt)

    def set_working_directory(self):
        """Set working directory path widget."""
        work_dir = QFileDialog.getExistingDirectory(
            self, "Select Working Directory", self.working_dir)
        if work_dir:
            try:
                self.try_to_write(work_dir)
            except (PermissionError, OSError):
                self.settings_communication.bar_warn(
                    "Can't write to the selected location. Please select a folder to which you have write permission."
                )
                return
            self.working_dir_le.setText(work_dir)

    def load_settings(self):
        """Loading plugin settings from QSettings."""
        self.api_url = QSettings().value("threedi/api_url",
                                         self.PRODUCTION_API_URL,
                                         type=str)
        self.wss_url = self.api_url.replace("https:",
                                            "wss:").replace("http:", "ws:")
        self.api_url_le.setText(self.api_url)
        self.working_dir = QSettings().value("threedi/working_dir",
                                             "",
                                             type=str)
        self.working_dir_le.setText(self.working_dir)
        self.upload_timeout = QSettings().value("threedi/upload_timeout",
                                                self.DEFAULT_UPLOAD_TIMEOUT,
                                                type=int)
        username, password = self.get_3di_auth()
        if password:
            self.set_personal_api_key_label(True)
        else:
            self.set_personal_api_key_label(False)

    def save_settings(self):
        """Saving plugin settings in QSettings."""
        self.api_url = self.api_url_le.text()
        self.working_dir = self.working_dir_le.text()
        self.upload_timeout = self.upload_timeout_sb.value()
        QSettings().setValue("threedi/api_url", self.api_url)
        QSettings().setValue("threedi/working_dir", self.working_dir)
        QSettings().setValue("threedi/upload_timeout", self.upload_timeout)

    def settings_are_valid(self):
        """Check validity of the settings."""
        if not self.working_dir or not os.path.exists(self.working_dir):
            working_dir_txt = self.working_dir_le.text()
            if not working_dir_txt or not os.path.exists(working_dir_txt):
                self.settings_communication.bar_warn(
                    "Missing or invalid working directory. Please set it up before running the plugin."
                )
                return False
            else:
                return True
        else:
            return True

    @staticmethod
    def try_to_write(working_dir):
        """Try to write and remove an empty text file into given location."""
        test_filename = f"{uuid4()}.txt"
        test_file_path = os.path.join(working_dir, test_filename)
        with open(test_file_path, "w") as test_file:
            test_file.write("")
        os.remove(test_file_path)

    def default_working_dir(self):
        """Return default working directory location."""
        user_dir = os.path.expanduser("~")
        try:
            threedi_working_dir = os.path.join(user_dir, "Documents", "3Di")
            os.makedirs(threedi_working_dir, exist_ok=True)
            self.try_to_write(threedi_working_dir)
        except (PermissionError, OSError):
            threedi_working_dir = gettempdir()
        return threedi_working_dir

    def restore_defaults(self):
        """Restoring default settings values."""
        self.api_url_le.setText(self.PRODUCTION_API_URL)
        self.working_dir_le.setText(self.default_working_dir() or "")
        self.upload_timeout_sb.setValue(self.DEFAULT_UPLOAD_TIMEOUT)

    def accept(self):
        """Accepting changes and closing dialog."""
        if self.settings_are_valid():
            self.save_settings()
            self.load_settings()
            self.settings_changed.emit()
            super().accept()

    def reject(self):
        """Rejecting changes and closing dialog."""
        self.load_settings()
        if self.settings_are_valid():
            super().reject()

    def exec_(self):
        """Opening settings dialog."""
        self.load_settings()
        super().exec_()