Skip to content

Commit

Permalink
version 0.31
Browse files Browse the repository at this point in the history
  • Loading branch information
FriendsOfGalaxy committed Nov 15, 2019
1 parent 89d4428 commit f746eb1
Show file tree
Hide file tree
Showing 7 changed files with 206 additions and 7 deletions.
62 changes: 62 additions & 0 deletions src/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,3 +383,65 @@ def parse_timestamp(product_info_xml) -> Timestamp:
except (ET.ParseError, AttributeError, ValueError):
logging.exception("Can not parse backend response: %s", await response.text())
raise UnknownBackendResponse()

async def get_favorite_games(self, user_id):
response = await self._http_client.get("{base_api}/atom/users/{user_id}/privacySettings/FAVORITEGAMES".format(
base_api=self._get_api_host(),
user_id=user_id
))

'''
<?xml version="1.0" encoding="UTF-8"?>
<privacySettings>
<privacySetting>
<userId>1008620950926</userId>
<category>FAVORITEGAMES</category>
<payload>OFB-EAST:48217;OFB-EAST:109552409;DR:119971300</payload>
</privacySetting>
</privacySettings>
'''

try:
content = await response.text()
payload_xml = ET.ElementTree(ET.fromstring(content)).find("privacySetting/payload")
if payload_xml is None or payload_xml.text is None:
# No games tagged, if on object evaluates to false
return []

favorite_games = set(payload_xml.text.split(';'))

return favorite_games
except (ET.ParseError, AttributeError, ValueError):
logging.exception("Can not parse backend response: %s", await response.text())
raise UnknownBackendResponse()

async def get_hidden_games(self, user_id):
response = await self._http_client.get("{base_api}/atom/users/{user_id}/privacySettings/HIDDENGAMES".format(
base_api=self._get_api_host(),
user_id=user_id
))

'''
<?xml version="1.0" encoding="UTF-8"?>
<privacySettings>
<privacySetting>
<userId>1008620950926</userId>
<category>HIDDENGAMES</category>
<payload>1.0|OFB-EAST:109552409;OFB-EAST:109552409</payload>
</privacySetting>
</privacySettings>
'''

try:
content = await response.text()
payload_xml = ET.ElementTree(ET.fromstring(content)).find("privacySetting/payload")
if payload_xml is None or payload_xml.text is None:
# No games tagged, if on object evaluates to false
return []
payload_text = payload_xml.text.replace('1.0|', '')
hidden_games = set(payload_text.split(';'))

return hidden_games
except (ET.ParseError, AttributeError, ValueError):
logging.exception("Can not parse backend response: %s", await response.text())
raise UnknownBackendResponse()
35 changes: 31 additions & 4 deletions src/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
AccessDenied, AuthenticationRequired, InvalidCredentials, UnknownBackendResponse, UnknownError
)
from galaxy.api.plugin import create_and_run_plugin, Plugin
from galaxy.api.types import Achievement, Authentication, FriendInfo, Game, GameTime, LicenseInfo, NextStep
from galaxy.api.types import Achievement, Authentication, FriendInfo, Game, GameTime, LicenseInfo, NextStep, GameLibrarySettings

from backend import AuthenticatedHttpClient, MasterTitleId, OfferId, OriginBackendClient, Timestamp
from local_games import get_local_content_path, LocalGames
from uri_scheme_handler import is_uri_handler_installed
from version import __version__

import re

def is_windows():
return platform.system().lower() == "windows"
Expand All @@ -38,6 +38,14 @@ def is_windows():
"&redirect_uri=https://www.origin.com/views/login.html",
"end_uri_regex": r"^https://www\.origin\.com/views/login\.html.*"
}
def regex_pattern(regex):
return ".*" + re.escape(regex) + ".*"

JS = {regex_pattern(r"originX/login?execution"): [
r'''
document.getElementById("rememberMe").click();
'''
]}

MultiplayerId = NewType("MultiplayerId", str)
AchievementsImportContext = namedtuple("AchievementsImportContext", ["owned_games", "achievements"])
Expand Down Expand Up @@ -97,7 +105,7 @@ async def authenticate(self, stored_credentials=None):
stored_cookies = stored_credentials.get("cookies") if stored_credentials else None

if not stored_cookies:
return NextStep("web_session", AUTH_PARAMS)
return NextStep("web_session", AUTH_PARAMS,js=JS)

return await self._do_authenticate(stored_cookies)

Expand All @@ -111,7 +119,6 @@ async def get_owned_games(self):
self._check_authenticated()

owned_offers = await self._get_owned_offers()

games = []
for offer in owned_offers:
game = Game(
Expand Down Expand Up @@ -304,6 +311,26 @@ async def get_game_time(self, game_id: OfferId, last_played_games: Any) -> GameT
logging.exception("Failed to import game times")
raise UnknownBackendResponse(str(e))

async def prepare_game_library_settings_context(self, game_ids: List[str]) -> Any:
self._check_authenticated()
hidden_games = await self._backend_client.get_hidden_games(self._user_id)
favorite_games = await self._backend_client.get_favorite_games(self._user_id)

library_context = {}
for game_id in game_ids:
library_context[game_id] = {'hidden': game_id in hidden_games, 'favorite': game_id in favorite_games}
return library_context

async def get_game_library_settings(self, game_id: str, context: Any) -> GameLibrarySettings:
if not context:
# Unable to retrieve context
return GameLibrarySettings(game_id, None, None)
game_library_settings = context.get(game_id)
if game_library_settings is None:
# Able to retrieve context but game is not in its values -> It doesnt have any tags or hidden status set
return GameLibrarySettings(game_id, [], False)
return GameLibrarySettings(game_id, ['favorite'] if game_library_settings['favorite'] else [], game_library_settings['hidden'])

def game_times_import_complete(self):
if self._persistent_cache_updated:
self.push_cache()
Expand Down
2 changes: 1 addition & 1 deletion src/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.30"
__version__ = "0.31"
2 changes: 2 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ def backend_client():
mock.get_owned_games = AsyncMock()
mock.get_friends = AsyncMock()
mock.get_lastplayed_games = MagicMock()
mock.get_hidden_games = AsyncMock()
mock.get_favorite_games = AsyncMock()

return mock

Expand Down
1 change: 1 addition & 0 deletions tests/integration_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def test_integration():
"ImportOwnedGames",
"ImportAchievements",
"ImportInstalledGames",
"ImportGameLibrarySettings",
"LaunchGame",
"InstallGame",
"ShutdownPlatformClient",
Expand Down
4 changes: 2 additions & 2 deletions tests/test_authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from galaxy.api.types import Authentication, NextStep

from plugin import AUTH_PARAMS
from plugin import AUTH_PARAMS, JS


def test_no_stored_credentials(plugin, http_client, backend_client):
Expand All @@ -22,7 +22,7 @@ def test_no_stored_credentials(plugin, http_client, backend_client):

with patch.object(plugin, "store_credentials") as store_credentials:
result = loop.run_until_complete(plugin.authenticate())
assert result == NextStep("web_session", AUTH_PARAMS)
assert result == NextStep("web_session", AUTH_PARAMS, js=JS)

credentials = {
"cookies": cookies,
Expand Down
107 changes: 107 additions & 0 deletions tests/test_game_library_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import pytest
from galaxy.api.errors import AuthenticationRequired
from galaxy.api.types import GameLibrarySettings
from galaxy.unittest.mock import async_return_value

GAME_IDS = ['DR:119971300', 'OFB-EAST:48217', 'OFB-EAST:109552409', 'Origin.OFR.50.0002694']

BACKEND_HIDDEN_RESPONSE = '''
<?xml version="1.0" encoding="UTF-8"?>
<privacySettings>
<privacySetting>
<userId>1008620950926</userId>
<category>HIDDENGAMES</category>
<payload>Origin.OFR.50.0002694;OFB-EAST:109552409</payload>
</privacySetting>
</privacySettings>
'''

BACKEND_FAVORITES_RESPONSE = '''
<?xml version="1.0" encoding="UTF-8"?>
<privacySettings>
<privacySetting>
<userId>1008620950926</userId>
<category>FAVORITEGAMES</category>
<payload>OFB-EAST:48217;OFB-EAST:109552409;DR:119971300</payload>
</privacySetting>
</privacySettings>
'''

FAVORITE_GAMES = {'OFB-EAST:48217', 'OFB-EAST:109552409', 'DR:119971300'}
HIDDEN_GAMES = {'Origin.OFR.50.0002694', 'OFB-EAST:109552409'}

GAME_LIBRARY_CONTEXT = {
'OFB-EAST:48217': {
'hidden': False,
'favorite': True
},
'OFB-EAST:109552409': {
'hidden': True,
'favorite': True
},
'DR:119971300': {
'hidden': False,
'favorite': True
},
'Origin.OFR.50.0002694': {
'hidden': True,
'favorite': False
}
}

GAME_LIBRARY_SETTINGS = GameLibrarySettings('OFB-EAST:48217', ['favorite'], False)


@pytest.mark.asyncio
async def test_not_authenticated(plugin, http_client):
http_client.is_authenticated.return_value = False
with pytest.raises(AuthenticationRequired):
await plugin.prepare_game_library_settings_context([])


@pytest.mark.asyncio
async def test_prepare_library_settings_context(
authenticated_plugin,
backend_client,
user_id,

):
backend_client.get_favorite_games.return_value = FAVORITE_GAMES
backend_client.get_hidden_games.return_value = HIDDEN_GAMES

assert GAME_LIBRARY_CONTEXT == await authenticated_plugin.prepare_game_library_settings_context(GAME_IDS)

backend_client.get_favorite_games.assert_called_once_with(user_id)
backend_client.get_hidden_games.assert_called_once_with(user_id)


@pytest.mark.asyncio
async def test_get_favorite_games(
backend_client,
user_id,
http_client,
):
http_client.get.return_value = async_return_value(BACKEND_FAVORITES_RESPONSE)

assert FAVORITE_GAMES == await backend_client.get_favorite_games(user_id)


@pytest.mark.asyncio
async def test_get_hidden_games(
backend_client,
user_id,
http_client,
):
http_client.get.return_value = async_return_value(BACKEND_HIDDEN_RESPONSE)

assert HIDDEN_GAMES == await backend_client.get_hidden_games(user_id)


@pytest.mark.asyncio
async def test_get_game_library_settings(
authenticated_plugin,
):
assert GAME_LIBRARY_SETTINGS == await authenticated_plugin.get_game_library_settings('OFB-EAST:48217', GAME_LIBRARY_CONTEXT)



0 comments on commit f746eb1

Please sign in to comment.