Skip to content
Merged
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
43 changes: 37 additions & 6 deletions mavis/test/pages/log_in.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,28 @@
from playwright.sync_api import Page, expect

from mavis.test.annotations import step
from mavis.test.models import Team, User
from mavis.test.models import Organisation, Team, User
from mavis.test.utils import get_current_datetime


class LogInPage:
"""
Page object for login functionality with audit logging.

Usage with organisation tracking:
# Automatic org code extraction from team (recommended):
log_in_page.log_in_and_choose_team_if_necessary(user, team)

# Manual org code setting:
log_in_page.set_organisation(onboarding.organisation) # or
log_in_page.set_organisation_code("ABC123")
log_in_page.log_in(user)
"""

def __init__(self, page: Page) -> None:
self.page = page
self.current_user = None # Track current logged in user
self.current_org_code = None # Track current organisation code

self.username_input = page.get_by_role("textbox", name="Email address")
self.password_input = page.get_by_role("textbox", name="Password")
Expand All @@ -24,20 +38,32 @@ def __init__(self, page: Page) -> None:
self.select_a_team_heading = page.get_by_text("Select a team")
self.start_page_link = page.get_by_role("link", name="Start now")

def _write_audit_log(self, event_type: str, user: User) -> None:
def _write_audit_log(
self, event_type: str, user: User, org_code: str | None = None
) -> None:
"""Helper method to write audit log entries."""
audit_log_path = Path("logs") / "login.log"
audit_log_path.parent.mkdir(parents=True, exist_ok=True)

timestamp = get_current_datetime().strftime("%Y-%m-%d %H:%M:%S")
user_role = getattr(user, "role", "unknown")
org_code_str = org_code or "unknown"

with audit_log_path.open("a") as file:
log_message = (
f"{timestamp} | {event_type} | {user.username} | {user_role}\n"
f"{timestamp} | {event_type} | {user.username} | "
f"{user_role} | {org_code_str}\n"
)
file.write(log_message)

def set_organisation_code(self, org_code: str) -> None:
"""Set the organisation code for audit logging."""
self.current_org_code = org_code

def set_organisation(self, organisation: Organisation) -> None:
"""Set the organisation for audit logging using Organisation object."""
self.current_org_code = organisation.ods_code

@step("Go to log in page")
def navigate(self) -> None:
self.page.goto("/users/sign-in")
Expand All @@ -48,7 +74,7 @@ def log_in(self, user: User) -> None:
self.current_user = user

# Write to login audit log
self._write_audit_log("LOGIN_ATTEMPT", user)
self._write_audit_log("LOGIN_ATTEMPT", user, self.current_org_code)

self.username_input.fill(user.username)
self.password_input.fill(user.password)
Expand All @@ -59,7 +85,9 @@ def log_out(self) -> None:
if self.log_out_button.is_visible():
# Write logout to audit log
if self.current_user:
self._write_audit_log("LOGOUT", self.current_user)
self._write_audit_log(
"LOGOUT", self.current_user, self.current_org_code
)
self.current_user = None # Clear current user

self.log_out_button.click()
Expand All @@ -69,13 +97,16 @@ def log_out(self) -> None:
def log_out_via_reporting_component(self) -> None:
# Write logout to audit log
if self.current_user:
self._write_audit_log("LOGOUT", self.current_user)
self._write_audit_log("LOGOUT", self.current_user, self.current_org_code)
self.current_user = None # Clear current user

self.log_out_link.click()

@step("Log in as {1} and choose team {2}")
def log_in_and_choose_team_if_necessary(self, user: User, team: Team) -> None:
# Set organisation code from team's workgroup (which contains ods_code)
self.current_org_code = team.workgroup

self.log_in(user)
if self.select_a_team_heading.is_visible():
self.page.get_by_role("radio", name=team.name).check()
Expand Down
Loading