Skip to content

Commit a85d2a3

Browse files
committed
2nd self review
1 parent 7e3f489 commit a85d2a3

File tree

3 files changed

+49
-24
lines changed

3 files changed

+49
-24
lines changed

src/reactpy_django/auth/components.py

+11-9
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
@component
2222
def root_manager(child: Any):
23+
"""This component is serves as the parent component for any ReactPy component tree,
24+
which allows for the management of the entire component tree."""
2325
scope = hooks.use_connection().scope
2426
_, set_rerender = hooks.use_state(uuid4)
2527

@@ -29,7 +31,7 @@ def setup_asgi_scope():
2931
any relevant actions."""
3032
scope["reactpy"]["rerender"] = rerender
3133

32-
async def rerender():
34+
def rerender():
3335
"""Event that can force a rerender of the entire component tree."""
3436
set_rerender(uuid4())
3537

@@ -44,7 +46,7 @@ def auth_manager():
4446
Used to force persistent authentication between Django's websocket and HTTP stack."""
4547
from reactpy_django import config
4648

47-
synchronize_requested, set_synchronize_requested = hooks.use_state(False)
49+
sync_needed, set_sync_needed = hooks.use_state(False)
4850
token = hooks.use_ref("")
4951
scope = hooks.use_connection().scope
5052

@@ -54,19 +56,19 @@ def setup_asgi_scope():
5456
any relevant actions."""
5557
scope["reactpy"]["synchronize_auth"] = synchronize_auth
5658

57-
@hooks.use_effect(dependencies=[synchronize_requested])
59+
@hooks.use_effect(dependencies=[sync_needed])
5860
async def synchronize_auth_watchdog():
59-
"""Detected if the client has taken too long to request a auth session synchronization.
61+
"""Detect if the client has taken too long to request a auth session synchronization.
6062
6163
This effect will automatically be cancelled if the session is successfully
6264
synchronized (via effect dependencies)."""
63-
if synchronize_requested:
65+
if sync_needed:
6466
await asyncio.sleep(config.REACTPY_AUTH_TOKEN_TIMEOUT + 0.1)
6567
await asyncio.to_thread(
6668
_logger.warning,
6769
f"Client did not switch authentication sessions within {config.REACTPY_AUTH_TOKEN_TIMEOUT} (REACTPY_AUTH_TOKEN_TIMEOUT) seconds.",
6870
)
69-
set_synchronize_requested(False)
71+
set_sync_needed(False)
7072

7173
async def synchronize_auth():
7274
"""Event that can command the client to switch HTTP auth sessions (to match the websocket session)."""
@@ -88,12 +90,12 @@ async def synchronize_auth():
8890
# Begin the process of synchronizing HTTP and websocket auth sessions
8991
obj = await AuthToken.objects.acreate(value=token.current, session_key=session.session_key)
9092
await obj.asave()
91-
set_synchronize_requested(True)
93+
set_sync_needed(True)
9294

9395
async def synchronize_auth_callback(status_code: int, response: str):
9496
"""This callback acts as a communication bridge, allowing the client to notify the server
9597
of the status of auth session switch."""
96-
set_synchronize_requested(False)
98+
set_sync_needed(False)
9799
if status_code >= 300 or status_code < 200:
98100
await asyncio.to_thread(
99101
_logger.error,
@@ -103,7 +105,7 @@ async def synchronize_auth_callback(status_code: int, response: str):
103105
# If needed, synchronize authenication sessions by configuring all relevant session cookies.
104106
# This is achieved by commanding the client to perform a HTTP request to our session manager endpoint,
105107
# which will set any required cookies.
106-
if synchronize_requested:
108+
if sync_needed:
107109
return HttpRequest(
108110
{
109111
"method": "GET",

src/reactpy_django/hooks.py

+14-15
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
Mutation,
3434
Query,
3535
SyncPostprocessor,
36+
UseAuthTuple,
3637
UserData,
3738
)
3839
from reactpy_django.utils import django_query_postprocessor, ensure_async, generate_obj_name, get_pk
@@ -417,37 +418,35 @@ def use_root_id() -> str:
417418
return scope["reactpy"]["id"]
418419

419420

420-
def use_auth():
421+
def use_rerender() -> Callable[[], None]:
422+
"""Provides a callable that can re-render the entire component tree without disconnecting the websocket."""
423+
scope = use_scope()
424+
return scope["reactpy"]["rerender"]
425+
426+
427+
def use_auth() -> UseAuthTuple:
421428
"""Provides the ability to login/logout a user using Django's authentication framework."""
422429
from reactpy_django import config
423430

424431
scope = use_scope()
432+
trigger_rerender = use_rerender()
425433

426-
async def login(user: AbstractUser, rerender: bool = True):
427-
"""Login a user.
428-
429-
Args:
430-
user: The user to login.
431-
rerender: If True, the root component will be re-rendered after the user is logged in."""
434+
async def login(user: AbstractUser, rerender: bool = True) -> None:
432435
await channels_auth.login(scope, user, backend=config.REACTPY_AUTH_BACKEND)
433436
session_save_method = getattr(scope["session"], "asave", scope["session"].save)
434437
await ensure_async(session_save_method)()
435438
await scope["reactpy"]["synchronize_auth"]()
436439

437440
if rerender:
438-
await scope["reactpy"]["rerender"]()
439-
440-
async def logout(rerender: bool = True):
441-
"""Logout the current user.
441+
trigger_rerender()
442442

443-
Args:
444-
rerender: If True, the root component will be re-rendered after the user is logged out."""
443+
async def logout(rerender: bool = True) -> None:
445444
await channels_auth.logout(scope)
446445

447446
if rerender:
448-
await scope["reactpy"]["rerender"]()
447+
trigger_rerender()
449448

450-
return login, logout
449+
return UseAuthTuple(login=login, logout=logout)
451450

452451

453452
async def _get_user_data(user: AbstractUser, default_data: None | dict, save_default_data: bool) -> dict | None:

src/reactpy_django/types.py

+24
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
if TYPE_CHECKING:
2020
from collections.abc import MutableMapping, Sequence
2121

22+
from django.contrib.auth.models import AbstractUser
2223
from django.forms import Form, ModelForm
2324

2425
from reactpy_django.websocket.consumer import ReactpyAsyncWebsocketConsumer
@@ -108,3 +109,26 @@ def __call__(
108109

109110
class ViewToIframeConstructor(Protocol):
110111
def __call__(self, *args: Any, key: Key | None = None, **kwargs: Any) -> ComponentType: ...
112+
113+
114+
class UseAuthLogin(Protocol):
115+
async def __call__(self, user: AbstractUser, rerender: bool = True) -> None: ...
116+
117+
118+
class UseAuthLogout(Protocol):
119+
async def __call__(self, rerender: bool = True) -> None: ...
120+
121+
122+
class UseAuthTuple(NamedTuple):
123+
login: UseAuthLogin
124+
"""Login a user.
125+
126+
Args:
127+
user: The user to login.
128+
rerender: If True, the root component will be re-rendered after the user is logged in."""
129+
130+
logout: UseAuthLogout
131+
"""Logout the current user.
132+
133+
Args:
134+
rerender: If True, the root component will be re-rendered after the user is logged out."""

0 commit comments

Comments
 (0)