Source code for ogu_api.resources.session

from __future__ import annotations

from typing import Any, Mapping

import tls_client.response

from ._base import ResourceBase

__all__ = ['SessionResource']


[docs] class SessionResource(ResourceBase): """Login, logout, and the public landing page. Wraps ``/member.php?action=login`` (form + submit) and ``/member.php?action=logout``. The session cookie (``ogusid``) ends up on the client's cookie jar after a successful login. """
[docs] async def get_home(self) -> tls_client.response.Response: """Fetch the forum landing page (``/index.php``). Returns: Raw response. Useful for sanity-checking the session (``len(response.text)`` should be substantial when logged in). """ return await self._http.get('/index.php')
[docs] async def get_login_page(self) -> tls_client.response.Response: """Fetch the login form page (``/member.php?action=login``). Returns: Raw response. Pass ``response.text`` to :meth:`extract_login_hidden` to recover the CSRF / hidden fields when calling :meth:`login` manually. """ return await self._http.get('/member.php?action=login', allow_redirects = True)
[docs] async def login( self, username: str, password: str, two_factor: str = '', *, hidden: Mapping[str, Any] | None = None, ) -> tls_client.response.Response: """Submit the login form and capture the session cookie. When ``hidden`` is omitted, the SDK first GETs ``/member.php?action=login`` and extracts the hidden fields itself, so most callers just pass username + password. Args: username: Forum username. password: Forum password. two_factor: Current TOTP code. Empty string if 2FA is disabled. hidden: Pre-fetched hidden form fields. Skips the extra round-trip. Returns: Raw POST response. The ``ogusid`` session cookie is set on ``client.cookies`` automatically on success. Example: >>> await client.session.login('username', 'password') >>> await client.session.login('username', 'password', '123456') """ if hidden is None: page = await self.get_login_page() hidden = self.extract_login_hidden(page.text) return await self._http.post( '/member.php?action=login', data = { **hidden, 'username': username, 'password': password, '2facode': two_factor, }, allow_redirects = False, )
[docs] async def logout(self, logout_key: str | None = None) -> tls_client.response.Response: """End the current session. OGU's logout requires a ``logoutkey`` query parameter. When omitted, the SDK fetches the home page and extracts it from the logout link. Args: logout_key: Pre-fetched key. Skips the extra round-trip when provided. Returns: Raw GET response. The session cookies are invalidated server-side. """ if logout_key is None: home = await self.get_home() logout_key = self.extract_logout_key(home.text) or '' return await self._http.get( f'/member.php?action=logout&logoutkey={logout_key}', allow_redirects = False, )
[docs] @staticmethod def extract_login_hidden(page_html: str) -> dict[str, Any]: """Pull the hidden ``<input>`` fields off the login form. Args: page_html: HTML of ``/member.php?action=login``. Returns: ``{name: value}`` for every hidden input inside ``<form action="member.php">``. """ return ResourceBase._extract_hidden(page_html, form_selector = 'form[action="member.php"]')