Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client id parameter #4

Merged
merged 7 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/source/sample.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,13 @@ ONCatLoginDialog
The `ONCatLoginDialog` can be imported and used separate from the `ONCatLogin` widget to give developers
the ability to customize the login process. In order to use the `ONCatLoginDialog`, you must have an
instance of the `pyoncat.ONCat` agent.

If you chose to use the `ONCatLogin` widget instead, the agent is already created for you.
In this case, a `key` or `client_id` are required to be passed by the user application. If `key` (application name)
is passed, the client_id is retrieved from the configuration, provided it exists. If the client_id is
provided, it uses this instead. If both are provided, client_id is used for oncat client id tasks, e.g. agent creation,
and the key is only used to create a human-readbale filename for saving the user's authentication token.

The `ONCatLoginDialog` requires the agent to be passed in as an argument.
The agent is used to authenticate the user and manage the connection to the ONCat server.
At a minimum the agent must be initialized with the ONCat server URL, flow, and the client ID.
Expand Down
27 changes: 20 additions & 7 deletions src/pyoncatqt/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,9 @@ class ONCatLogin(QGroupBox):

Params
------
key : str, required
client_id : str, optional
The client_id is an ONCat client ID. Defaults to None. client_id is required or key is required
key : str, optional
The key used to retrieve ONCat client ID from configuration. Defaults to None.
parent : QWidget, optional
The parent widget.
Expand Down Expand Up @@ -181,12 +183,16 @@ class ONCatLogin(QGroupBox):

connection_updated = Signal(bool)

def __init__(self: QGroupBox, key: str = None, parent: QWidget = None, **kwargs: Dict[str, Any]) -> None:
def __init__(
self: QGroupBox, *, client_id: str = None, key: str = None, parent: QWidget = None, **kwargs: Dict[str, Any]
) -> None:
"""
Initialize the ONCatLogin widget.

Params
------
client_id : str, optional
The client_id is an ONCat client ID. Defaults to None.
key : str, optional
The key used to retrieve ONCat client ID from configuration. Defaults to None.
parent : QWidget, optional
Expand Down Expand Up @@ -215,11 +221,18 @@ def __init__(self: QGroupBox, key: str = None, parent: QWidget = None, **kwargs:
# OnCat agent

self.oncat_url = get_data("login.oncat", "oncat_url")
self.client_id = get_data("login.oncat", f"{key}_id")
if not self.client_id:
raise ValueError(f"Invalid module {key}. No OnCat client Id is found for this application.")
if client_id is not None:
self.client_id = client_id
elif key is not None:
self.client_id = get_data("login.oncat", f"{key}_id")
else:
raise ValueError(f"Invalid module {key}. No OnCat client Id is found or provided for this application.")

self.token_path = os.path.abspath(f"{os.path.expanduser('~')}/.pyoncatqt/{key}_token.json")
# use the partial client id to generate the filename
token_filename = f"{self.client_id[0:8]}_token.json"
if key:
token_filename = f"{key}_token.json"
self.token_path = os.path.abspath(f"{os.path.expanduser('~')}/.pyoncatqt/{token_filename}")

self.agent = pyoncat.ONCat(
self.oncat_url,
Expand All @@ -241,7 +254,6 @@ def update_connection_status(self: QGroupBox) -> None:
else:
self.status_label.setText("ONCat: Disconnected")
self.status_label.setStyleSheet("color: red")

self.connection_updated.emit(self.is_connected)

@property
Expand All @@ -254,6 +266,7 @@ def is_connected(self: QGroupBox) -> bool:
bool
True if connected, False otherwise.
"""

try:
self.agent.Facility.list()
return True
Expand Down
70 changes: 69 additions & 1 deletion tests/test_login_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,81 @@ def test_login_dialog_creation() -> None:
assert isinstance(dialog.button_cancel, QPushButton)


def test_login(qtbot: pytest.fixture) -> None:
def test_login_key(qtbot: pytest.fixture) -> None:
dialog = ONCatLogin(key="test")
dialog.login_dialog = ONCatLoginDialog(agent=MagicMock(), parent=dialog)
dialog.login_dialog.login_status.connect(check_status)
qtbot.addWidget(dialog)
dialog.show()

assert dialog.client_id == "0123456489"
assert dialog.token_path.endswith("test_token.json")

completed = False

def handle_dialog() -> None:
nonlocal completed

qtbot.keyClicks(dialog.login_dialog.user_pwd, "password")
qtbot.wait(2000)
qtbot.mouseClick(dialog.login_dialog.button_login, QtCore.Qt.LeftButton)
completed = True

def dialog_completed() -> None:
nonlocal completed
assert completed is True

QtCore.QTimer.singleShot(500, functools.partial(handle_dialog))
qtbot.mouseClick(dialog.oncat_button, QtCore.Qt.LeftButton)

qtbot.waitUntil(dialog_completed, timeout=5000)


def test_login_client_id(qtbot: pytest.fixture) -> None:
client_id = "12cnfjejsfsdf3456789ab"
dialog = ONCatLogin(client_id=client_id)
dialog.login_dialog = ONCatLoginDialog(agent=MagicMock(), parent=dialog)
dialog.login_dialog.login_status.connect(check_status)
qtbot.addWidget(dialog)
dialog.show()

assert dialog.client_id == client_id
# token_12cnf.json
assert dialog.token_path.endswith(f"{client_id[0:8]}_token.json")
completed = False

def handle_dialog() -> None:
nonlocal completed

qtbot.keyClicks(dialog.login_dialog.user_pwd, "password")
qtbot.wait(2000)
qtbot.mouseClick(dialog.login_dialog.button_login, QtCore.Qt.LeftButton)
completed = True

def dialog_completed() -> None:
nonlocal completed
assert completed is True

QtCore.QTimer.singleShot(500, functools.partial(handle_dialog))
qtbot.mouseClick(dialog.oncat_button, QtCore.Qt.LeftButton)

qtbot.waitUntil(dialog_completed, timeout=5000)


def test_login_client_id_key(qtbot: pytest.fixture) -> None:
client_id = "12cnfjejsfsdf3456789ab"
key = "test"

dialog = ONCatLogin(client_id=client_id, key=key)
dialog.login_dialog = ONCatLoginDialog(agent=MagicMock(), parent=dialog)
dialog.login_dialog.login_status.connect(check_status)
qtbot.addWidget(dialog)
dialog.show()

# client id provided as parameter
assert dialog.client_id == client_id
# key used for filename only token_shiver.json
assert dialog.token_path.endswith(f"{key}_token.json")
completed = False

def handle_dialog() -> None:
Expand Down
Loading