Skip to content

Commit a39549c

Browse files
committed
authenticated decorator prototype
1 parent 9f0fa65 commit a39549c

File tree

6 files changed

+76
-16
lines changed

6 files changed

+76
-16
lines changed

CHANGELOG.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
99
<!--attr-end-->
1010

1111
<!--
12-
Types of changes are to be listed in this order
12+
Using the following categories, list your changes in this order:
1313
- "Added" for new features.
1414
- "Changed" for changes in existing functionality.
1515
- "Deprecated" for soon-to-be removed features.
@@ -22,7 +22,9 @@ Types of changes are to be listed in this order
2222

2323
## [Unreleased]
2424

25-
- Nothing (yet)
25+
### Added
26+
27+
- `authenticated` decorator to prevent your components from rendered to unauthenticated users.
2628

2729
## [1.1.0] - 2022-07-01
2830

src/django_idom/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
from . import components, hooks
2-
from .websocket.consumer import IdomWebsocket
3-
from .websocket.paths import IDOM_WEBSOCKET_PATH
1+
from django_idom import components, hooks
2+
from django_idom.types import AuthLevel, IdomWebsocket
3+
from django_idom.websocket.paths import IDOM_WEBSOCKET_PATH
44

55

66
__version__ = "1.1.0"
7-
__all__ = ["IDOM_WEBSOCKET_PATH", "IdomWebsocket", "hooks", "components"]
7+
__all__ = ["IDOM_WEBSOCKET_PATH", "AuthLevel", "IdomWebsocket", "hooks", "components"]

src/django_idom/decorators.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
from functools import wraps
2+
from typing import Callable, Union
3+
4+
from idom.core.types import ComponentType, VdomDict
5+
6+
from django_idom.hooks import use_websocket
7+
from django_idom.types import AuthLevel
8+
9+
10+
def authenticated(
11+
component: Union[Callable, None] = None,
12+
auth_level: str = AuthLevel.user,
13+
fallback: Union[ComponentType, VdomDict, None] = None,
14+
) -> ComponentType | VdomDict | Callable | None:
15+
"""If the user is authenticated, the decorated component will be rendered.
16+
Otherwise, the fallback component will be rendered.
17+
18+
This decorator can be used with or without paranthesis.
19+
20+
Args:
21+
auth_level: The user's auth level. This value can be
22+
- One of the predefined `django_idom.AuthLevel` values
23+
- A string for a custom user attribute to check (ex. `UserModel.is_<auth_level>`).
24+
fallback: The component to render if the user is not authenticated.
25+
"""
26+
27+
def decorator(component):
28+
@wraps(component)
29+
def _wrapped_func(*args, **kwargs):
30+
websocket = use_websocket()
31+
32+
if getattr(websocket.scope["user"], f"is_{auth_level}", False):
33+
return component(*args, **kwargs)
34+
35+
if callable(fallback):
36+
return fallback(*args, **kwargs)
37+
return fallback
38+
39+
return _wrapped_func
40+
41+
# Return when used as @authenticated
42+
if component is None:
43+
return decorator
44+
45+
# Return when used as @authenticated(...)
46+
return decorator(component)

src/django_idom/hooks.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,9 @@
1-
from dataclasses import dataclass
2-
from typing import Awaitable, Callable, Dict, Optional, Type, Union
1+
from typing import Dict, Type, Union
32

43
from idom.backend.types import Location
54
from idom.core.hooks import Context, create_context, use_context
65

7-
8-
@dataclass
9-
class IdomWebsocket:
10-
scope: dict
11-
close: Callable[[Optional[int]], Awaitable[None]]
12-
disconnect: Callable[[int], Awaitable[None]]
13-
view_id: str
6+
from django_idom.types import IdomWebsocket
147

158

169
WebsocketContext: Type[Context[Union[IdomWebsocket, None]]] = create_context(

src/django_idom/types.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from dataclasses import dataclass
2+
from typing import Awaitable, Callable, Optional
3+
4+
5+
@dataclass
6+
class IdomWebsocket:
7+
scope: dict
8+
close: Callable[[Optional[int]], Awaitable[None]]
9+
disconnect: Callable[[int], Awaitable[None]]
10+
view_id: str
11+
12+
13+
@dataclass
14+
class AuthLevel:
15+
user: str = "authenticated"
16+
active_user: str = "active"
17+
staff: str = "staff"
18+
superuser: str = "superuser"

src/django_idom/websocket/consumer.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
from idom.core.serve import serve_json_patch
1313

1414
from django_idom.config import IDOM_REGISTERED_COMPONENTS
15-
from django_idom.hooks import IdomWebsocket, WebsocketContext
15+
from django_idom.hooks import WebsocketContext
16+
from django_idom.types import IdomWebsocket
1617

1718

1819
_logger = logging.getLogger(__name__)

0 commit comments

Comments
 (0)