1from http.cookies import SimpleCookie
2from typing import TYPE_CHECKING, Any
3
4from plain.http.request import Request
5from plain.runtime import settings
6from plain.sessions import SessionStore
7from plain.sessions.requests import get_request_session, set_request_session
8
9from .requests import set_request_user
10from .sessions import get_user, login, logout
11
12if TYPE_CHECKING:
13 from plain.test.client import Client
14
15
16def login_client(client: Client, user: Any) -> None:
17 """Log a user into a test client."""
18 request = Request(method="GET", path="/")
19 if client.session:
20 session = client.session
21 else:
22 session = SessionStore()
23 set_request_session(request, session)
24 login(request, user)
25 session = get_request_session(request)
26 session.save()
27 assert session.session_key is not None
28 session_cookie = settings.SESSION_COOKIE_NAME
29 client.cookies[session_cookie] = session.session_key
30 cookie_data: dict[str, Any] = {
31 "max-age": None,
32 "path": "/",
33 "domain": settings.SESSION_COOKIE_DOMAIN,
34 "secure": settings.SESSION_COOKIE_SECURE or None,
35 "expires": None,
36 }
37 # Morsel.update() is typed for str-only values, but these cookie
38 # attributes are legitimately None (unset). Set them one at a time
39 # through __setitem__, which is typed for Any and keeps Morsel's own
40 # reserved-key validation (unlike bypassing update() with dict.update()).
41 morsel = client.cookies[session_cookie]
42 for key, value in cookie_data.items():
43 morsel[key] = value
44
45
46def logout_client(client: Client) -> None:
47 """Log out a user from a test client."""
48 request = Request(method="GET", path="/")
49 if client.session:
50 session = client.session
51 set_request_session(request, session)
52 user = get_user(request)
53 set_request_user(request, user)
54 else:
55 session = SessionStore()
56 set_request_session(request, session)
57 logout(request)
58 client.cookies = SimpleCookie()