def __init__(self, parent=None, first_run=False): wx.Dialog.__init__(self, parent, title="Settings", style=wx.DEFAULT_DIALOG_STYLE) self._first_run = first_run self._sizer = wx.BoxSizer(wx.VERTICAL) self._defaults = {} self._sizer.Add(URLEntryPanel( self, default_url=read_config_option("baseurl")), flag=wx.EXPAND | wx.ALL, border=5) authorization_sizer = wx.BoxSizer(wx.HORIZONTAL) authorization_sizer.Add(ClientDetailsPanel( self, default_client_id=read_config_option("client_id"), default_client_secret=read_config_option("client_secret")), flag=wx.EXPAND | wx.RIGHT, border=2, proportion=1) authorization_sizer.Add(UserDetailsPanel( self, default_user=read_config_option("username"), default_pass=read_config_option("password")), flag=wx.EXPAND | wx.LEFT, border=2, proportion=1) self._sizer.Add(authorization_sizer, flag=wx.EXPAND | wx.ALL, border=5) self._sizer.Add(PostProcessingTaskPanel( self, default_post_process=read_config_option("completion_cmd")), flag=wx.EXPAND | wx.ALL, border=5) self._sizer.Add(DefaultDirectoryPanel( self, default_directory=read_config_option("default_dir"), monitor_directory=read_config_option("monitor_default_dir", expected_type=bool)), flag=wx.EXPAND | wx.ALL, border=5) self._sizer.Add(self.CreateSeparatedButtonSizer(flags=wx.OK), flag=wx.EXPAND | wx.ALL, border=5) self.SetSizerAndFit(self._sizer) self.Layout() pub.subscribe(self._field_changed, SettingsDialog.field_changed_topic) self.Bind(wx.EVT_CLOSE, self._on_close) self.Bind(wx.EVT_BUTTON, self._on_close, id=wx.ID_OK) threading.Thread(target=connect_to_irida).start()
def _get_default_directory(self): """Read the default directory from the configuration file, or, if the user has selected a directory manually, return the manually selected directory. Returns: A string containing the default directory to scan. """ if not self._selected_directory: return read_config_option("default_dir") else: return self._selected_directory
def _start_upload(self, *args, **kwargs): """Initiate uploading runs to the server. This will upload multiple runs simultaneously, one per thread. Args: event: the button event that initiated the method. """ post_processing_task = read_config_option("completion_cmd") logging.debug("Running upload for {}".format(str(self._discovered_runs))) pub.subscribe(self._post_processing_task_started, RunUploaderTopics.started_post_processing) self._upload_thread = RunUploader(api=self._api, runs=self._discovered_runs, post_processing_task=post_processing_task) # destroy the upload button once it's been clicked. self.Freeze() self._upload_sizer.Clear(True) self.Layout() self.Thaw() self._upload_thread.start()
def _post_processing_task_started(self): """Show a 'processing' message on the UI while the post processing task is executing.""" pub.unsubscribe(self._post_processing_task_started, RunUploaderTopics.started_post_processing) pub.subscribe(self._post_processing_task_completed, RunUploaderTopics.finished_post_processing) pub.subscribe(self._post_processing_task_failed, RunUploaderTopics.failed_post_processing) logging.info("Post-processing started, updating UI.") self.Freeze() self._post_processing_sizer = wx.BoxSizer(wx.HORIZONTAL) self._post_processing_placeholder = ProcessingPlaceholderText(self) self._post_processing_placeholder.SetFont(wx.Font(pointSize=18, family=wx.FONTFAMILY_DEFAULT, style=wx.NORMAL, weight=wx.FONTWEIGHT_BOLD, face="Segoe UI Symbol")) self._post_processing_text = wx.StaticText(self, label="Executing post-processing task.") self._post_processing_text.SetFont(wx.Font(18, wx.DEFAULT, wx.NORMAL, wx.BOLD)) self._post_processing_text.Wrap(350) self._post_processing_text.SetToolTipString("Executing command `{}`.".format(read_config_option("completion_cmd"))) self._post_processing_sizer.Add(self._post_processing_text, flag=wx.RIGHT, border=5, proportion=1) self._post_processing_sizer.Add(self._post_processing_placeholder, flag=wx.LEFT, border=5, proportion=0) self._sizer.Insert(0, self._post_processing_sizer, flag=wx.EXPAND | wx.ALL, border=5) self.Layout() self.Thaw()
def _settings_changed(self, api=None): """Reset the main display and attempt to connect to the server whenever the connection settings may have changed. Args: api: A placeholder for a complete api that's passed when the event is fired. """ # before doing anything, clear all of the children from the sizer and # also delete any windows attached (Buttons and stuff extend from Window!) self._sizer.Clear(deleteWindows=True) # and clear out the list of discovered runs that we might be uploading to the server. self._discovered_runs = [] # initialize the invalid sheets panel so that it can listen for events # before directory scanning starts, but hide it until we actually get # an error raised by the validation part. self._invalid_sheets_panel = InvalidSampleSheetsPanel(self, self._get_default_directory()) self._invalid_sheets_panel.Hide() should_monitor_directory = read_config_option("monitor_default_dir", expected_type=bool, default_value=False) if should_monitor_directory: automatic_upload_status_sizer = wx.BoxSizer(wx.HORIZONTAL) auto_upload_enabled_text = wx.StaticText(self, label=u"⇌ Automatic upload enabled.") auto_upload_enabled_text.SetFont(wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.BOLD)) auto_upload_enabled_text.SetForegroundColour(wx.Colour(51, 102, 255)) auto_upload_enabled_text.SetToolTipString("Monitoring {} for CompletedJobInfo.xml".format(self._get_default_directory())) self._sizer.Add(auto_upload_enabled_text, flag=wx.ALIGN_CENTER | wx.ALL, border=5) logging.info("Going to monitor default directory [{}] for new runs.".format(self._get_default_directory())) # topics to handle when monitoring a directory for automatic upload pub.subscribe(self._prepare_for_automatic_upload, DirectoryMonitorTopics.new_run_observed) pub.subscribe(self._start_upload, DirectoryMonitorTopics.finished_discovering_run) threading.Thread(target=monitor_directory, kwargs={"directory": self._get_default_directory()}).start() # run connecting in a different thread so we don't freeze up the GUI threading.Thread(target=self._connect_to_irida).start()
def connect_to_irida(): """Connect to IRIDA for online validation. Returns: A configured instance of API.apiCalls. """ client_id = read_config_option("client_id") client_secret = read_config_option("client_secret") baseURL = read_config_option("baseURL") username = read_config_option("username") password = read_config_option("password") try: # Several threads might be attempting to connect at the same time, so lock # the connection step, but **do not** block (acquire(False) means do not block) # and just return if someone else is already trying to connect. if lock.acquire(False): logging.info("About to try connecting to IRIDA.") api = ApiCalls(client_id, client_secret, baseURL, username, password) send_message(APIConnectorTopics.connection_success_topic, api=api) return api else: logging.info("Someone else is already trying to connect to IRIDA.") except ConnectionError as e: logging.info("Got a connection error when trying to connect to IRIDA.", exc_info=True) send_message(APIConnectorTopics.connection_error_url_topic, error_message=( "We couldn't connect to IRIDA at {}. The server might be down. Make " "sure that the connection address is correct (you can change the " "address by clicking on the 'Open Settings' button below) and try" " again, try again later, or contact an administrator." ).format(baseURL)) raise except (SyntaxError, ValueError) as e: logging.info("Connected, but the response was garbled.", exc_info=True) send_message(APIConnectorTopics.connection_error_url_topic, error_message=( "We couldn't connect to IRIDA at {}. The server is up, but I " "didn't understand the response. Make sure that the connection " "address is correct (you can change the address by clicking on " "the 'Open Settings' button below) and try again, try again" " later, or contact an administrator." ).format(baseURL)) raise except KeyError as e: logging.info("Connected, but the OAuth credentials are wrong.", exc_info=True) # this is credentials related, but let's try to figure out why the server # is telling us that we can't log in. message = str(e.message) if "Bad credentials" in message: topic = APIConnectorTopics.connection_error_user_credentials_topic # if we're getting bad credentials, then that means the API is allowing # us to try authenticate with a username and password, so our client id # and secret are both correct: send_message(APIConnectorTopics.connection_success_valid_client_secret) elif "clientId does not exist" in message: topic = APIConnectorTopics.connection_error_client_id_topic elif "Bad client credentials" in message: topic = APIConnectorTopics.connection_error_client_secret_topic # if we're getting a bad client secret message, that means that the # client ID is valid. send_message(APIConnectorTopics.connection_success_valid_client_id) else: topic = APIConnectorTopics.connection_error_credentials_topic send_message(topic, error_message=( "We couldn't connect to IRIDA at {}. The server is up, but it's " "reporting that your credentials are wrong. Click on the 'Open Settings'" " button below and check your credentials, then try again. If the " "connection still doesn't work, contact an administrator." ).format(baseURL)) # in spite of it all, this means that we're probably actually trying to connect # to a real IRIDA server, so let the settings dialog know that it can render # a success icon beside the URL send_message(APIConnectorTopics.connection_success_valid_url) raise except URLError as e: logging.info("Couldn't connect to IRIDA because the URL is invalid.", exc_info=True) send_message(APIConnectorTopics.connection_error_url_topic, error_message=( "We couldn't connect to IRIDA at {} because it isn't a valid URL. " "Click on the 'Open Settings' button below to enter a new URL and " "try again." ).format(baseURL)) raise except: logging.info("Some other kind of error happened.", exc_info=True) send_message(APIConnectorTopics.connection_error_topic, error_message=( "We couldn't connect to IRIDA at {} for an unknown reason. Click " "on the 'Open Settings' button below to check the URL and your " "credentials, then try again. If the connection still doesn't " "work, contact an administrator." ).format(baseURL)) raise finally: try: lock.release() except: pass
def _post_processing_task_failed(self): """Show a 'failed' message on the UI when the post processing task fails.""" pub.unsubscribe(self._post_processing_task_failed, RunUploaderTopics.failed_post_processing) pub.unsubscribe(self._post_processing_task_completed, RunUploaderTopics.finished_post_processing) logging.info("Post-processing failed, updating UI.") self.Freeze() self._post_processing_text.SetLabel("Post-processing task failed.") self._post_processing_text.SetToolTipString("Failed to execute command `{}`.".format(read_config_option("completion_cmd"))) self._post_processing_text.Wrap(350) self._post_processing_placeholder.SetError("Failed to execute command `{}`.".format(read_config_option("completion_cmd"))) self.Layout() self.Thaw()