def test_get_user_info_return_empty_string_when_nothing_is_returned(self): api = Api() api._Api__request = MagicMock() api._Api__request.return_value = {} m_config.Config.get.return_value = "" exp = "" obs = api.get_user_info() self.assertEqual(exp, obs)
def test_get_user_info_from_config(self): username = "******" api = Api() api._Api__request = MagicMock() api._Api__request.return_value = {"username": "******"} m_config.Config.get.return_value = username obs = api.get_user_info() self.assertEqual(username, obs)
def test_get_user_info_from_api(self): username = "******" api = Api() api._Api__request = MagicMock() api._Api__request.return_value = {"username": username} m_config.Config.get.return_value = "" m_constants.SESSION.get.side_effect = MagicMock() m_constants.SESSION.get().status_code = http.HTTPStatus.OK obs = api.get_user_info() self.assertEqual(username, obs)
class Window(Gtk.ApplicationWindow): __gtype_name__ = "Window" HeaderBar = Gtk.Template.Child() header_sync = Gtk.Template.Child() header_installed = Gtk.Template.Child() header_search = Gtk.Template.Child() menu_about = Gtk.Template.Child() menu_preferences = Gtk.Template.Child() menu_logout = Gtk.Template.Child() window_library = Gtk.Template.Child() def __init__(self, name): Gtk.ApplicationWindow.__init__(self, title=name) self.api = Api() self.show_installed_only = False self.search_string = "" self.offline = False # Set library self.library = Library(self, self.api) self.window_library.add(self.library) # Set the icon icon = GdkPixbuf.Pixbuf.new_from_file(LOGO_IMAGE_PATH) self.set_default_icon_list([icon]) # Show the window self.show_all() # Create the thumbnails directory if not os.path.exists(THUMBNAIL_DIR): os.makedirs(THUMBNAIL_DIR) # Interact with the API self.__authenticate() self.HeaderBar.set_subtitle(self.api.get_user_info()) self.sync_library() @Gtk.Template.Callback("filter_library") def filter_library(self, switch, _=""): self.library.filter_library(switch) @Gtk.Template.Callback("on_menu_preferences_clicked") def show_preferences(self, button): preferences_window = Preferences(self) preferences_window.run() preferences_window.destroy() @Gtk.Template.Callback("on_menu_about_clicked") def show_about(self, button): about_window = About(self) about_window.run() about_window.destroy() @Gtk.Template.Callback("on_menu_logout_clicked") def logout(self, button): # Unset everything which is specific to this user self.HeaderBar.set_subtitle("") Config.unset("username") Config.unset("refresh_token") self.hide() # Show the login screen self.__authenticate() self.HeaderBar.set_subtitle(self.api.get_user_info()) self.sync_library() self.show_all() @Gtk.Template.Callback("on_header_sync_clicked") def sync_library(self, _=""): if self.library.offline: self.__authenticate() self.library.update_library() def reset_library(self): self.library.reset() """ The API remembers the authentication token and uses it The token is not valid for a long time """ def __authenticate(self): url = None if Config.get("stay_logged_in"): token = Config.get("refresh_token") else: Config.unset("username") Config.unset("refresh_token") token = None # Make sure there is an internet connection if not self.api.can_connect(): return authenticated = self.api.authenticate(refresh_token=token, login_code=url) while not authenticated: login_url = self.api.get_login_url() redirect_url = self.api.get_redirect_url() login = Login(login_url=login_url, redirect_url=redirect_url, parent=self) response = login.run() login.hide() if response == Gtk.ResponseType.DELETE_EVENT: Gtk.main_quit() exit(0) if response == Gtk.ResponseType.NONE: result = login.get_result() authenticated = self.api.authenticate(refresh_token=token, login_code=result) Config.set("refresh_token", authenticated)
class Window(Gtk.ApplicationWindow): __gtype_name__ = "Window" HeaderBar = Gtk.Template.Child() header_sync = Gtk.Template.Child() header_installed = Gtk.Template.Child() header_search = Gtk.Template.Child() menu_about = Gtk.Template.Child() menu_preferences = Gtk.Template.Child() menu_logout = Gtk.Template.Child() window_library = Gtk.Template.Child() def __init__(self, name="Minigalaxy"): Gtk.ApplicationWindow.__init__(self, title=name) self.api = Api() self.search_string = "" self.offline = False # Set library self.library = Library(self, self.api) self.window_library.add(self.library) self.header_installed.set_active(Config.get("installed_filter")) # Set the icon icon = GdkPixbuf.Pixbuf.new_from_file(LOGO_IMAGE_PATH) self.set_default_icon_list([icon]) # Show the window if Config.get("keep_window_maximized"): self.maximize() self.show_all() # Create the thumbnails directory if not os.path.exists(THUMBNAIL_DIR): os.makedirs(THUMBNAIL_DIR, mode=0o755) # Interact with the API self.__authenticate() self.HeaderBar.set_subtitle(self.api.get_user_info()) self.sync_library() @Gtk.Template.Callback("filter_library") def filter_library(self, switch, _=""): self.library.filter_library(switch) Config.set("installed_filter", switch.get_active()) @Gtk.Template.Callback("on_menu_preferences_clicked") def show_preferences(self, button): preferences_window = Preferences(self) preferences_window.run() preferences_window.destroy() @Gtk.Template.Callback("on_menu_about_clicked") def show_about(self, button): about_window = About(self) about_window.run() about_window.destroy() @Gtk.Template.Callback("on_menu_logout_clicked") def logout(self, button): # Unset everything which is specific to this user self.HeaderBar.set_subtitle("") Config.unset("username") Config.unset("refresh_token") self.hide() # Show the login screen self.__authenticate() self.HeaderBar.set_subtitle(self.api.get_user_info()) self.sync_library() self.show_all() @Gtk.Template.Callback("on_window_state_event") def on_window_state_event(self, widget, event): if event.new_window_state & Gdk.WindowState.MAXIMIZED: Config.set("keep_window_maximized", True) else: Config.set("keep_window_maximized", False) @Gtk.Template.Callback("on_header_sync_clicked") def sync_library(self, _=""): if self.library.offline: self.__authenticate() self.library.update_library() def reset_library(self): self.library.reset() def update_library(self): self.library.update_library() def show_error(self, text, secondary_text=""): dialog = Gtk.MessageDialog( parent=self, modal=True, destroy_with_parent=True, message_type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK, text=text ) if secondary_text: dialog.format_secondary_text(secondary_text) dialog.run() dialog.destroy() def show_question(self, text, secondary_text=""): dialog = Gtk.MessageDialog( parent=self, flags=Gtk.DialogFlags.MODAL, message_type=Gtk.MessageType.WARNING, buttons=Gtk.ButtonsType.OK_CANCEL, message_format=text ) if secondary_text: dialog.format_secondary_text(secondary_text) response = dialog.run() dialog.destroy() return response == Gtk.ResponseType.OK """ The API remembers the authentication token and uses it The token is not valid for a long time """ def __authenticate(self): url = None if Config.get("stay_logged_in"): token = Config.get("refresh_token") else: Config.unset("username") Config.unset("refresh_token") token = None # Make sure there is an internet connection if not self.api.can_connect(): return authenticated = self.api.authenticate(refresh_token=token, login_code=url) while not authenticated: login_url = self.api.get_login_url() redirect_url = self.api.get_redirect_url() login = Login(login_url=login_url, redirect_url=redirect_url, parent=self) response = login.run() login.hide() if response == Gtk.ResponseType.DELETE_EVENT: Gtk.main_quit() exit(0) if response == Gtk.ResponseType.NONE: result = login.get_result() authenticated = self.api.authenticate(login_code=result) Config.set("refresh_token", authenticated)
class Window(Gtk.ApplicationWindow): __gtype_name__ = "Window" HeaderBar = Gtk.Template.Child() header_sync = Gtk.Template.Child() header_installed = Gtk.Template.Child() header_search = Gtk.Template.Child() menu_about = Gtk.Template.Child() menu_preferences = Gtk.Template.Child() menu_logout = Gtk.Template.Child() library = Gtk.Template.Child() def __init__(self, name): Gtk.ApplicationWindow.__init__(self, title=name) self.config = Config() self.api = Api(self.config) self.show_installed_only = False self.search_string = "" self.offline = False # Set the icon icon = GdkPixbuf.Pixbuf.new_from_file(LOGO_IMAGE_PATH) self.set_default_icon_list([icon]) # Create the thumbnails directory if not os.path.exists(THUMBNAIL_DIR): os.makedirs(THUMBNAIL_DIR) # Check if the user unset to stay logged in Preference and refresh token if self.api.config.get("stay_logged_in") is None: self.config.set("stay_logged_in", True) elif not self.api.config.get("stay_logged_in"): self.config.unset("username") self.config.unset("refresh_token") # Interact with the API self.__authenticate() self.HeaderBar.set_subtitle(self.api.get_user_info()) self.sync_library() self.show_all() @Gtk.Template.Callback("on_header_sync_clicked") def sync_library(self, button=None): # Make a list with the game tiles which are already loaded current_tiles = [] for child in self.library.get_children(): tile = child.get_children()[0] current_tiles.append(tile) # Recheck online status if button and self.offline: self.__authenticate() add_tiles_thread = threading.Thread(target=self.__add_tiles, args=[current_tiles]) add_tiles_thread.daemon = True add_tiles_thread.start() @Gtk.Template.Callback("on_header_installed_state_set") def show_installed_only_triggered(self, switch, state): self.show_installed_only = state self.library.set_filter_func(self.__filter_library_func) @Gtk.Template.Callback("on_header_search_changed") def search(self, widget): self.search_string = widget.get_text() self.library.set_filter_func(self.__filter_library_func) @Gtk.Template.Callback("on_menu_preferences_clicked") def show_preferences(self, button): preferences_window = Preferences(self, self.config) preferences_window.run() preferences_window.destroy() @Gtk.Template.Callback("on_menu_about_clicked") def show_about(self, button): about_window = About(self) about_window.run() about_window.destroy() @Gtk.Template.Callback("on_menu_logout_clicked") def logout(self, button): # Unset everything which is specific to this user self.HeaderBar.set_subtitle("") self.config.unset("username") self.config.unset("refresh_token") self.hide() # Show the login screen self.__authenticate() self.HeaderBar.set_subtitle(self.api.get_user_info()) self.sync_library() self.show_all() def refresh_game_install_states(self, path_changed=False): installed_games = self.__get_installed_games() for child in self.library.get_children(): tile = child.get_children()[0] if path_changed: tile.install_dir = "" # Check if game isn't installed already for installed_game in installed_games: if installed_game["name"] == tile.game.name: tile.install_dir = installed_game["dir"] break tile.load_state() self.filter_library() def filter_library(self): self.library.set_filter_func(self.__filter_library_func) def __filter_library_func(self, child): tile = child.get_children()[0] if not tile.installed and self.offline: return False if tile.installed and self.show_installed_only or not self.show_installed_only: if self.search_string.lower() in str(tile).lower(): return True else: return False else: return False def sort_library(self): self.library.set_sort_func(self.__sort_library_func) def __sort_library_func(self, child1, child2): tile1 = child1.get_children()[0] tile2 = child2.get_children()[0] return tile2 < tile1 def __update_library_view(self): self.sort_library() self.filter_library() self.library.show_all() def __add_tiles(self, current_tiles): # Refresh games list from API games = [] if not self.offline: try: games = self.api.get_library() except: GLib.idle_add(self.__show_error, _("Failed to retrieve library"), _("Couldn't connect to GOG servers")) self.offline = True # Get installed games installed_games = self.__get_installed_games() # Only add games if they aren't already in the list. Otherwise just reload their state if not self.offline: for game in games: not_found = True for tile in current_tiles: if self.__games_match(tile.game.name, game.name): not_found = False tile.game = game break if not_found: # Check if game is already installed install_dir = "" for installed_game in installed_games: if installed_game["name"] == game.name: print("Found game: {}".format(game.name)) install_dir = installed_game["dir"] break # Create the game tile GLib.idle_add(self.__add_tile, game, install_dir) else: for game in installed_games: not_found = True for tile in current_tiles: if tile.game.name == game["name"]: not_found = False break if not_found: # Create the game tile GLib.idle_add(self.__add_tile, Game(game["name"], 0, ""), game["dir"]) GLib.idle_add(self.__update_library_view) def __show_error(self, text, subtext): dialog = Gtk.MessageDialog(message_type=Gtk.MessageType.ERROR, parent=self, modal=True, buttons=Gtk.ButtonsType.CLOSE, text=text) dialog.format_secondary_text(subtext) dialog.run() dialog.destroy() def __add_tile(self, game, install_dir): # Create the game tile gametile = GameTile( parent=self, game=game, api=self.api, install_dir=install_dir, ) gametile.load_state() # Update the library self.library.add(gametile) self.__update_library_view() def __get_installed_games(self) -> dict: games = [] directories = os.listdir(self.config.get("install_dir")) for directory in directories: full_path = os.path.join(self.config.get("install_dir"), directory) if not os.path.isdir(full_path): continue # Make sure the gameinfo file exists gameinfo = os.path.join(full_path, "gameinfo") if not os.path.isfile(gameinfo): continue with open(gameinfo, 'r') as file: name = file.readline() games.append({'name': name.strip(), 'dir': full_path}) file.close() return games def __clean_game_name(self, name): return re.sub('[^A-Za-z0-9]+', '', name).lower() def __games_match(self, name1, name2): name1_clean = self.__clean_game_name(name1) name2_clean = self.__clean_game_name(name2) return name1_clean == name2_clean """ The API remembers the authentication token and uses it The token is not valid for a long time """ def __authenticate(self): url = None token = self.config.get("refresh_token") # Make sure there is an internet connection, but only once if self.api.can_connect(): self.offline = False else: if token: self.offline = True dialog = Gtk.MessageDialog( message_type=Gtk.MessageType.ERROR, parent=self, modal=True, buttons=Gtk.ButtonsType.OK, text=_("Couldn't connect to GOG servers")) dialog.format_secondary_text( _("Minigalaxy is now running in offline mode")) dialog.run() dialog.destroy() return else: dialog = Gtk.MessageDialog( message_type=Gtk.MessageType.ERROR, parent=self, modal=True, buttons=Gtk.ButtonsType.CLOSE, text=_("Couldn't connect to GOG servers")) dialog.format_secondary_text( _("Try again with an active internet connection")) dialog.run() dialog.destroy() exit(1) return authenticated = self.api.authenticate(refresh_token=token, login_code=url) while not authenticated: login_url = self.api.get_login_url() redirect_url = self.api.get_redirect_url() login = Login(login_url=login_url, redirect_url=redirect_url, parent=self) response = login.run() login.hide() if response == Gtk.ResponseType.DELETE_EVENT: Gtk.main_quit() exit(0) if response == Gtk.ResponseType.NONE: result = login.get_result() authenticated = self.api.authenticate(refresh_token=token, login_code=result) self.config.set("refresh_token", authenticated)