Skip to content

Commit 69a9861

Browse files
authored
fix(client): use web login also for IESS (#166)
1 parent 76cb599 commit 69a9861

File tree

3 files changed

+119
-13
lines changed

3 files changed

+119
-13
lines changed

src/elmo/api/client.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@
99

1010
from .. import query as q
1111
from ..__about__ import __version__
12-
from ..systems import ELMO_E_CONNECT
12+
from ..systems import (
13+
ELMO_E_CONNECT,
14+
ELMO_E_CONNECT_WEB_LOGIN,
15+
IESS_METRONET,
16+
IESS_METRONET_WEB_LOGIN,
17+
)
1318
from ..utils import (
1419
_camel_to_snake_case,
1520
_sanitize_session_id,
@@ -53,14 +58,25 @@ def __init__(self, base_url=None, domain=None, session_id=None):
5358
self._session = Session()
5459
self._session_id = session_id
5560
self._panel = None
56-
self._web_login = base_url == ELMO_E_CONNECT
5761
self._lock = Lock()
5862

63+
# Web login is required for E-Connect and Metronet because, at the moment, the
64+
# Cloud API login does not register the client session in their backend, causing
65+
# updates to be not received by the client during the long-polling `has_updates`.
66+
domain_url = "" if self._domain == "default" else self._domain
67+
self._web_login = base_url in [ELMO_E_CONNECT, IESS_METRONET]
68+
if base_url == ELMO_E_CONNECT:
69+
self._web_login_url = f"{ELMO_E_CONNECT_WEB_LOGIN}/{domain_url}"
70+
elif base_url == IESS_METRONET:
71+
self._web_login_url = f"{IESS_METRONET_WEB_LOGIN}/{domain_url}"
72+
else:
73+
self._web_login_url = None
74+
5975
# Debug
6076
_LOGGER.debug(f"Client | Library version: {__version__}")
6177
_LOGGER.debug(f"Client | Router: {self._router._base_url}")
6278
_LOGGER.debug(f"Client | Domain: {self._domain}")
63-
_LOGGER.debug(f"Client | Web login: {self._web_login}")
79+
_LOGGER.debug(f"Client | Web login URL: {self._web_login_url}")
6480

6581
def auth(self, username, password):
6682
"""Authenticate the client and retrieves the access token. This method uses
@@ -104,19 +120,16 @@ def auth(self, username, password):
104120
data = redirect.json()
105121
self._session_id = data["SessionId"]
106122

123+
# Retrieve the session_id using the web login form
107124
if self._web_login:
108-
# Web login is required for Elmo E-Connect because, at the moment, the
109-
# e-Connect Cloud API login does not register the client session in the backend.
110-
# This prevents the client from attaching to server events (e.g. long polling updates).
111-
web_login_url = f"https://webservice.elmospa.com/{self._domain}"
112125
payload = {
113126
"IsDisableAccountCreation": "True",
114127
"IsAllowThemeChange": "True",
115128
"UserName": username,
116129
"Password": password,
117130
"RememberMe": "false",
118131
}
119-
web_response = self._session.post(web_login_url, data=payload)
132+
web_response = self._session.post(self._web_login_url, data=payload)
120133
web_response.raise_for_status()
121134
self._session_id = extract_session_id_from_html(web_response.text)
122135

src/elmo/systems.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
ELMO_E_CONNECT = "https://connect.elmospa.com"
2+
ELMO_E_CONNECT_WEB_LOGIN = "https://webservice.elmospa.com"
23
IESS_METRONET = "https://metronet.iessonline.com"
4+
IESS_METRONET_WEB_LOGIN = "https://metronet.iessonline.com"

tests/test_client.py

Lines changed: 96 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ def test_client_auth_redirect(server):
239239
assert len(server.calls) == 2
240240

241241

242-
def test_client_auth_redirect_web_login(server):
242+
def test_client_auth_redirect_web_login_econnect(server):
243243
"""Ensure web login session token is used when redirect is required.
244244
Regression test: https://github.com/palazzem/econnect-python/issues/158
245245
"""
@@ -279,6 +279,46 @@ def test_client_auth_redirect_web_login(server):
279279
assert client._session_id == "f8h23b4e-7a9f-4d3f-9b08-2769263ee33c"
280280

281281

282+
def test_client_auth_redirect_web_login_metronet(server):
283+
"""Ensure web login session token is used when redirect is required.
284+
Regression test: https://github.com/palazzem/econnect-python/issues/168
285+
"""
286+
redirect = """
287+
{
288+
"SessionId": "00000000-0000-0000-0000-000000000000",
289+
"Domain": "domain",
290+
"Redirect": true,
291+
"RedirectTo": "https://redirect.example.com"
292+
}
293+
"""
294+
login = """
295+
{
296+
"SessionId": "99999999-9999-9999-9999-999999999999",
297+
"Username": "test",
298+
"Domain": "domain",
299+
"Language": "en",
300+
"IsActivated": true,
301+
"IsConnected": true,
302+
"IsLoggedIn": false,
303+
"IsLoginInProgress": false,
304+
"CanElevate": true,
305+
"AccountId": 100,
306+
"IsManaged": false,
307+
"Redirect": false,
308+
"IsElevation": false
309+
}
310+
"""
311+
server.add(responses.GET, "https://metronet.iessonline.com/api/login", body=redirect, status=200)
312+
server.add(responses.GET, "https://redirect.example.com/api/login", body=login, status=200)
313+
server.add(responses.POST, "https://metronet.iessonline.com/domain", body=r.STATUS_PAGE, status=200)
314+
client = ElmoClient(base_url=IESS_METRONET, domain="domain")
315+
# Test
316+
assert client.auth("test", "test")
317+
assert len(server.calls) == 3
318+
assert client._router._base_url == "https://redirect.example.com"
319+
assert client._session_id == "f8h23b4e-7a9f-4d3f-9b08-2769263ee33c"
320+
321+
282322
def test_client_auth_infinite_redirect(server):
283323
"""Should prevent infinite redirects in the auth() call."""
284324
redirect = """
@@ -409,16 +449,67 @@ def test_client_auth_econnect_web_login(server):
409449
}
410450

411451

412-
def test_client_auth_econnect_web_login_metronet(server):
413-
"""Web login should NOT be used when accessing with Metronet.
452+
def test_client_auth_econnect_web_login_with_default_domain(server):
453+
"""Ensure API and Web login are executed when using e-Connect cloud API.
414454
Regression test: https://github.com/palazzem/econnect-python/issues/158
415455
"""
456+
server.add(responses.GET, "https://connect.elmospa.com/api/login", body=r.LOGIN, status=200)
457+
server.add(responses.POST, "https://webservice.elmospa.com/", body=r.STATUS_PAGE, status=200)
458+
client = ElmoClient(base_url=ELMO_E_CONNECT, domain="default")
459+
# Test
460+
client.auth("test", "test")
461+
assert len(server.calls) == 2
462+
request_body = dict(item.split("=") for item in server.calls[1].request.body.split("&"))
463+
assert client._session_id == "f8h23b4e-7a9f-4d3f-9b08-2769263ee33c"
464+
assert request_body == {
465+
"IsDisableAccountCreation": "True",
466+
"IsAllowThemeChange": "True",
467+
"UserName": "test",
468+
"Password": "test",
469+
"RememberMe": "false",
470+
}
471+
472+
473+
def test_client_auth_econnect_web_login_metronet(server):
474+
"""Web login must be used when accessing with Metronet.
475+
Regression test: https://github.com/palazzem/econnect-python/issues/186
476+
"""
416477
server.add(responses.GET, "https://metronet.iessonline.com/api/login", body=r.LOGIN, status=200)
478+
server.add(responses.POST, "https://metronet.iessonline.com/domain", body=r.STATUS_PAGE, status=200)
417479
client = ElmoClient(base_url=IESS_METRONET, domain="domain")
418480
# Test
419481
client.auth("test", "test")
420-
assert client._session_id == "00000000-0000-0000-0000-000000000000"
421-
assert len(server.calls) == 1
482+
assert len(server.calls) == 2
483+
request_body = dict(item.split("=") for item in server.calls[1].request.body.split("&"))
484+
assert client._session_id == "f8h23b4e-7a9f-4d3f-9b08-2769263ee33c"
485+
assert request_body == {
486+
"IsDisableAccountCreation": "True",
487+
"IsAllowThemeChange": "True",
488+
"UserName": "test",
489+
"Password": "test",
490+
"RememberMe": "false",
491+
}
492+
493+
494+
def test_client_auth_metronet_web_login_with_default_domain(server):
495+
"""Web login must be used when accessing with Metronet.
496+
Regression test: https://github.com/palazzem/econnect-python/issues/186
497+
"""
498+
server.add(responses.GET, "https://metronet.iessonline.com/api/login", body=r.LOGIN, status=200)
499+
server.add(responses.POST, "https://metronet.iessonline.com/", body=r.STATUS_PAGE, status=200)
500+
client = ElmoClient(base_url=IESS_METRONET, domain="default")
501+
# Test
502+
client.auth("test", "test")
503+
assert len(server.calls) == 2
504+
request_body = dict(item.split("=") for item in server.calls[1].request.body.split("&"))
505+
assert client._session_id == "f8h23b4e-7a9f-4d3f-9b08-2769263ee33c"
506+
assert request_body == {
507+
"IsDisableAccountCreation": "True",
508+
"IsAllowThemeChange": "True",
509+
"UserName": "test",
510+
"Password": "test",
511+
"RememberMe": "false",
512+
}
422513

423514

424515
def test_client_poll_with_changes(server):

0 commit comments

Comments
 (0)