From a4059e71aa6799294b4106b63578b00dfb428635 Mon Sep 17 00:00:00 2001
From: Mark <16909269+Archmonger@users.noreply.github.com>
Date: Tue, 6 Jun 2023 10:05:34 -0700
Subject: [PATCH 1/5] Docs and readme tweaks (#146)
---
CHANGELOG.md | 2 +-
README.md | 29 ++++++++++++++++++-----
docs/src/changelog/index.md | 2 --
docs/src/contribute/code.md | 4 +---
docs/src/contribute/docs.md | 4 +---
docs/src/contribute/running-tests.md | 4 +---
docs/src/features/components.md | 4 +---
docs/src/features/decorators.md | 4 +---
docs/src/features/hooks.md | 6 ++---
docs/src/features/settings.md | 4 +---
docs/src/features/template-tag.md | 4 +---
docs/src/features/utils.md | 4 +---
docs/src/get-started/choose-django-app.md | 4 +---
docs/src/get-started/create-component.md | 4 +---
docs/src/get-started/installation.md | 4 +---
docs/src/get-started/learn-more.md | 2 +-
docs/src/get-started/register-view.md | 4 +---
docs/src/get-started/run-webserver.md | 4 +---
docs/src/get-started/use-template-tag.md | 4 +---
docs/src/stylesheets/extra.css | 19 +++++++++++----
mkdocs.yml | 5 ++--
21 files changed, 58 insertions(+), 63 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 55a8c0f5..4587311e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -203,7 +203,7 @@ Using the following categories, list your changes in this order:
### Added
-- Django-specific hooks! `use_websocket`, `use_scope`, and `use_location` are now available within the `django_idom.hooks` module.
+- Django specific hooks! `use_websocket`, `use_scope`, and `use_location` are now available within the `django_idom.hooks` module.
- Documentation has been placed into a formal docs webpage.
- Logging for when a component fails to import, or if no components were found within Django.
diff --git a/README.md b/README.md
index 90ec4754..f2d0f592 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,23 @@
-[](https://github.com/reactive-python/reactpy-django/actions?query=workflow%3ATest) [](https://pypi.python.org/pypi/reactpy-django) [](https://github.com/reactive-python/reactpy-django/blob/main/LICENSE) [](https://reactive-python.github.io/reactpy-django/)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -86,10 +102,11 @@ Additionally, you can pass in `args` and `kwargs` into your component function.
Follow the links below to find out more about this project.
-- [Try it Now](https://mybinder.org/v2/gh/reactive-python/reactpy-jupyter/main?urlpath=lab/tree/notebooks/introduction.ipynb) - check out ReactPy in a Jupyter Notebook.
-- [Documentation](https://reactive-python.github.io/reactpy-django) - learn how to install, run, and use ReactPy.
-- [Community Forum](https://github.com/reactive-python/reactpy/discussions) - ask questions, share ideas, and show off projects.
-- [Contributor Guide](https://reactive-python.github.io/reactpy-django/contribute/code/) - see how you can help develop this project.
-- [Code of Conduct](https://github.com/reactive-python/reactpy-django/blob/main/CODE_OF_CONDUCT.md) - standards for interacting with this community.
+- [Try ReactPy (Jupyter Notebook)](https://mybinder.org/v2/gh/reactive-python/reactpy-jupyter/main?urlpath=lab/tree/notebooks/introduction.ipynb)
+- [Documentation](https://reactive-python.github.io/reactpy-django)
+- [GitHub Discussions](https://github.com/reactive-python/reactpy-django/discussions)
+- [Discord](https://discord.gg/uNb5P4hA9X)
+- [Contributor Guide](https://reactive-python.github.io/reactpy-django/contribute/code/)
+- [Code of Conduct](https://github.com/reactive-python/reactpy-django/blob/main/CODE_OF_CONDUCT.md)
diff --git a/docs/src/changelog/index.md b/docs/src/changelog/index.md
index 20120d5e..9c2bef97 100644
--- a/docs/src/changelog/index.md
+++ b/docs/src/changelog/index.md
@@ -7,6 +7,4 @@ hide:
{% include-markdown "../../../CHANGELOG.md" start="" end="" %}
----
-
{% include-markdown "../../../CHANGELOG.md" start="" %}
diff --git a/docs/src/contribute/code.md b/docs/src/contribute/code.md
index 05cf0ca6..07824927 100644
--- a/docs/src/contribute/code.md
+++ b/docs/src/contribute/code.md
@@ -1,6 +1,6 @@
## Overview
-!!! summary
+!!! summary "Overview"
You will need to set up a Python environment to develop ReactPy-Django.
@@ -8,8 +8,6 @@
Everything within the `reactpy-django` repository must be specific to Django integration. Check out the [ReactPy Core documentation](https://reactpy.dev/docs/about/contributor-guide.html) to contribute general features such as: components, hooks, events, and more.
----
-
## Modifying Code
If you plan to make code changes to this repository, you will need to install the following dependencies first:
diff --git a/docs/src/contribute/docs.md b/docs/src/contribute/docs.md
index 549ac780..d5a02be7 100644
--- a/docs/src/contribute/docs.md
+++ b/docs/src/contribute/docs.md
@@ -1,11 +1,9 @@
## Overview
-!!! summary
+!!! summary "Overview"
You will need to set up a Python environment to preview docs changes.
----
-
## Modifying Docs
If you plan to make changes to this documentation, you will need to install the following dependencies first:
diff --git a/docs/src/contribute/running-tests.md b/docs/src/contribute/running-tests.md
index 6034253f..b714c5cd 100644
--- a/docs/src/contribute/running-tests.md
+++ b/docs/src/contribute/running-tests.md
@@ -1,11 +1,9 @@
## Overview
-!!! summary
+!!! summary "Overview"
You will need to set up a Python environment to run out test suite.
----
-
## Running Tests
This repository uses [Nox](https://nox.thea.codes/en/stable/) to run tests. For a full test of available scripts run `nox -l`.
diff --git a/docs/src/features/components.md b/docs/src/features/components.md
index bf33af2e..d7926803 100644
--- a/docs/src/features/components.md
+++ b/docs/src/features/components.md
@@ -1,11 +1,9 @@
## Overview
-!!! summary
+!!! summary "Overview"
Prefabricated components can be used within your `components.py` to help simplify development.
----
-
## View To Component
Convert any Django view into a ReactPy component by using this decorator. Compatible with [Function Based Views](https://docs.djangoproject.com/en/dev/topics/http/views/) and [Class Based Views](https://docs.djangoproject.com/en/dev/topics/class-based-views/). Views can be sync or async.
diff --git a/docs/src/features/decorators.md b/docs/src/features/decorators.md
index ed2b8d09..95779fae 100644
--- a/docs/src/features/decorators.md
+++ b/docs/src/features/decorators.md
@@ -1,11 +1,9 @@
## Overview
-!!! summary
+!!! summary "Overview"
Decorator utilities can be used within your `components.py` to help simplify development.
----
-
## Auth Required
You can limit access to a component to users with a specific `auth_attribute` by using this decorator (with or without parentheses).
diff --git a/docs/src/features/hooks.md b/docs/src/features/hooks.md
index dd53ac61..5916776a 100644
--- a/docs/src/features/hooks.md
+++ b/docs/src/features/hooks.md
@@ -1,17 +1,15 @@
## Overview
-!!! summary
+!!! summary "Overview"
Prefabricated hooks can be used within your `components.py` to help simplify development.
??? tip "Looking for standard React hooks?"
- Standard hooks are contained within [`reactive-python/reactpy`](https://github.com/reactive-python/reactpy). Since `reactpy` is installed alongside `reactpy-django`, you can import them at any time.
+ The `reactpy-django` package only contains django specific hooks. Standard hooks can be found within [`reactive-python/reactpy`](https://github.com/reactive-python/reactpy). Since `reactpy` is installed alongside `reactpy-django`, you can import them at any time.
Check out the [ReactPy Core docs](https://reactpy.dev/docs/reference/hooks-api.html#basic-hooks) to see what hooks are available!
----
-
## Use Query
The `use_query` hook is used fetch Django ORM queries.
diff --git a/docs/src/features/settings.md b/docs/src/features/settings.md
index 1454f6aa..3abd6575 100644
--- a/docs/src/features/settings.md
+++ b/docs/src/features/settings.md
@@ -1,11 +1,9 @@
## Overview
-!!! summary
+!!! summary "Overview"
Your **Django project's** `settings.py` can modify the behavior of ReactPy.
----
-
## Primary Configuration
These are ReactPy-Django's default settings values. You can modify these values in your **Django project's** `settings.py` to change the behavior of ReactPy.
diff --git a/docs/src/features/template-tag.md b/docs/src/features/template-tag.md
index 266b75ec..9d4ca18c 100644
--- a/docs/src/features/template-tag.md
+++ b/docs/src/features/template-tag.md
@@ -1,11 +1,9 @@
## Overview
-!!! summary
+!!! summary "Overview"
Template tags can be used within your Django templates such as `my-template.html` to import ReactPy features.
----
-
## Component
The `component` template tag can be used to insert any number of ReactPy components onto your page.
diff --git a/docs/src/features/utils.md b/docs/src/features/utils.md
index 73c5248d..9cec1aa4 100644
--- a/docs/src/features/utils.md
+++ b/docs/src/features/utils.md
@@ -1,11 +1,9 @@
## Overview
-!!! summary
+!!! summary "Overview"
Utility functions that you can use when needed.
----
-
## Django Query Postprocessor
This is the default postprocessor for the `use_query` hook.
diff --git a/docs/src/get-started/choose-django-app.md b/docs/src/get-started/choose-django-app.md
index 5f83fc2a..61dcfdba 100644
--- a/docs/src/get-started/choose-django-app.md
+++ b/docs/src/get-started/choose-django-app.md
@@ -1,11 +1,9 @@
## Overview
-!!! summary
+!!! summary "Overview"
Set up a **Django Project** with at least one app.
----
-
## Choose a Django App
If you have reached this point, you should have already [installed ReactPy-Django](../get-started/installation.md) through the previous steps.
diff --git a/docs/src/get-started/create-component.md b/docs/src/get-started/create-component.md
index e0516002..032906e7 100644
--- a/docs/src/get-started/create-component.md
+++ b/docs/src/get-started/create-component.md
@@ -1,11 +1,9 @@
## Overview
-!!! summary
+!!! summary "Overview"
Create a component function using our decorator.
----
-
## Create a Component
{% include-markdown "../../../README.md" start="" end="" %}
diff --git a/docs/src/get-started/installation.md b/docs/src/get-started/installation.md
index a27a3dc7..21e26201 100644
--- a/docs/src/get-started/installation.md
+++ b/docs/src/get-started/installation.md
@@ -1,11 +1,9 @@
## Overview
-!!! summary
+!!! summary "Overview"
ReactPy-Django can be installed from PyPI to an existing **Django project** with minimal configuration.
----
-
## Step 0: Create a Django Project
These docs assumes you have already created [a **Django project**](https://docs.djangoproject.com/en/dev/intro/tutorial01/), which involves creating and installing at least one **Django app**. If not, check out this [9 minute YouTube tutorial](https://www.youtube.com/watch?v=ZsJRXS_vrw0) created by _IDG TECHtalk_.
diff --git a/docs/src/get-started/learn-more.md b/docs/src/get-started/learn-more.md
index f2cb52ae..8b58400d 100644
--- a/docs/src/get-started/learn-more.md
+++ b/docs/src/get-started/learn-more.md
@@ -8,4 +8,4 @@ Additionally, the vast majority of tutorials/guides you find for ReactJS can be
=== "Learn More"
- [ReactPy-Django Advanced Usage](../features/components.md){ .md-button .md-button--primary} [ReactPy Core Documentation](https://reactpy.dev/docs/guides/creating-interfaces/index.html){ .md-button .md-button--primary } [Ask Questions](https://github.com/reactive-python/reactpy/discussions){ .md-button .md-button--primary }
+ [ReactPy-Django Advanced Usage](../features/components.md){ .md-button .md-button--primary} [ReactPy Core Documentation](https://reactpy.dev/docs/guides/creating-interfaces/index.html){ .md-button .md-button--primary } [Ask Questions on Discord](https://discord.gg/uNb5P4hA9X){ .md-button .md-button--primary }
diff --git a/docs/src/get-started/register-view.md b/docs/src/get-started/register-view.md
index 1c97d089..7f21bd66 100644
--- a/docs/src/get-started/register-view.md
+++ b/docs/src/get-started/register-view.md
@@ -1,11 +1,9 @@
## Overview
-!!! summary
+!!! summary "Overview"
Select your template containing an ReactPy component, and render it using a Django view.
----
-
## Register a View
We will assume you have [created a Django View](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view) before, but here's a simple example below.
diff --git a/docs/src/get-started/run-webserver.md b/docs/src/get-started/run-webserver.md
index 1c532558..5a1d27dd 100644
--- a/docs/src/get-started/run-webserver.md
+++ b/docs/src/get-started/run-webserver.md
@@ -1,11 +1,9 @@
## Overview
-!!! summary
+!!! summary "Overview"
Run a webserver to display your Django view.
----
-
## Run the Webserver
To test your new Django view, run the following command to start up a development webserver.
diff --git a/docs/src/get-started/use-template-tag.md b/docs/src/get-started/use-template-tag.md
index 6fd9017c..e108e407 100644
--- a/docs/src/get-started/use-template-tag.md
+++ b/docs/src/get-started/use-template-tag.md
@@ -1,11 +1,9 @@
## Overview
-!!! summary
+!!! summary "Overview"
Decide where the component will be displayed by using our template tag.
----
-
## Use the Template Tag
{% include-markdown "../../../README.md" start="" end="" %}
diff --git a/docs/src/stylesheets/extra.css b/docs/src/stylesheets/extra.css
index 72e8bd26..1599d525 100644
--- a/docs/src/stylesheets/extra.css
+++ b/docs/src/stylesheets/extra.css
@@ -31,11 +31,6 @@
border-color: transparent !important;
}
-[data-md-color-scheme="slate"] .md-typeset .admonition.summary,
-[data-md-color-scheme="slate"] .md-typeset details.summary {
- background: #353a45;
-}
-
[data-md-color-scheme="slate"] .md-typeset details > .admonition-title:after,
[data-md-color-scheme="slate"] .md-typeset details > summary:after {
color: var(--md-admonition-fg-color) !important;
@@ -45,6 +40,8 @@
[data-md-color-scheme="slate"] .md-typeset .admonition.summary,
[data-md-color-scheme="slate"] .md-typeset details.summary {
background: #353a45;
+ padding: 0.8rem 1.4rem;
+ border-radius: 0.8rem;
}
[data-md-color-scheme="slate"] .md-typeset details.summary > .admonition-title,
@@ -54,7 +51,19 @@
[data-md-color-scheme="slate"] .md-typeset .summary .admonition-title,
[data-md-color-scheme="slate"] .md-typeset .summary summary {
+ font-size: 1rem;
background: transparent;
+ padding-left: 0.6rem;
+ padding-bottom: 0;
+}
+
+[data-md-color-scheme="slate"] .md-typeset .summary .admonition-title:before {
+ display: none;
+}
+
+[data-md-color-scheme="slate"] .md-typeset .admonition,
+[data-md-color-scheme="slate"] .md-typeset details {
+ border-color: #ffffff17 !important;
}
/* Move the sidebars to the edges of the page */
diff --git a/mkdocs.yml b/mkdocs.yml
index bca3df26..fa7b5f90 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -21,7 +21,8 @@ nav:
- Code: contribute/code.md
- Docs: contribute/docs.md
- Running Tests: contribute/running-tests.md
- - Community: https://github.com/reactive-python/reactpy/discussions
+ - GitHub Discussions: https://github.com/reactive-python/reactpy-django/discussions
+ - Discord: https://discord.gg/uNb5P4hA9X
- Changelog: changelog/index.md
theme:
@@ -96,7 +97,7 @@ watch:
site_name: ReactPy-Django Docs
site_author: Archmonger
site_description: React for Django developers.
-copyright: Copyright © 2022 Reactive Python
+copyright: Copyright © 2023 Reactive Python
repo_url: https://github.com/reactive-python/reactpy-django
site_url: https://reactive-python.github.io/reactpy-django
repo_name: reactive-python/reactpy-django
From f2d54e15075109301df0ffc4bd8b267c7f1bfebf Mon Sep 17 00:00:00 2001
From: Mark <16909269+Archmonger@users.noreply.github.com>
Date: Wed, 7 Jun 2023 13:19:01 -0700
Subject: [PATCH 2/5] Add warning if poor performance is detected (#145)
---
CHANGELOG.md | 4 +++-
src/reactpy_django/utils.py | 10 ++++++++++
src/reactpy_django/websocket/consumer.py | 2 +-
3 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4587311e..06f30dff 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -34,7 +34,9 @@ Using the following categories, list your changes in this order:
## [Unreleased]
-- Nothing (yet)
+### Added
+
+- Added warning if poor system/cache/database performance is detected.
## [3.1.0] - 2023-05-06
diff --git a/src/reactpy_django/utils.py b/src/reactpy_django/utils.py
index 86425552..c44429ee 100644
--- a/src/reactpy_django/utils.py
+++ b/src/reactpy_django/utils.py
@@ -316,6 +316,7 @@ def db_cleanup(immediate: bool = False):
from .config import REACTPY_CACHE, REACTPY_DATABASE, REACTPY_RECONNECT_MAX
from .models import ComponentSession
+ clean_started_at = datetime.now()
cache_key: str = create_cache_key("last_cleaned")
now_str: str = datetime.strftime(timezone.now(), DATE_FORMAT)
cleaned_at_str: str = caches[REACTPY_CACHE].get(cache_key)
@@ -340,3 +341,12 @@ def db_cleanup(immediate: bool = False):
last_accessed__lte=expires_by
).delete()
caches[REACTPY_CACHE].set(cache_key, now_str, timeout=None)
+
+ # Check if cleaning took abnormally long
+ clean_duration = datetime.now() - clean_started_at
+ if clean_duration.total_seconds() > 1:
+ _logger.warning(
+ "ReactPy has taken %s seconds to clean up expired component sessions. "
+ "This may indicate a performance issue with your system, cache, or database.",
+ clean_duration.total_seconds(),
+ )
diff --git a/src/reactpy_django/websocket/consumer.py b/src/reactpy_django/websocket/consumer.py
index 3679f00a..aab994d3 100644
--- a/src/reactpy_django/websocket/consumer.py
+++ b/src/reactpy_django/websocket/consumer.py
@@ -77,7 +77,7 @@ async def _run_dispatch_loop(self):
carrier=ComponentWebsocket(self.close, self.disconnect, dotted_path),
)
now = timezone.now()
- component_args: Sequence[Any] = tuple()
+ component_args: Sequence[Any] = ()
component_kwargs: MutableMapping[str, Any] = {}
# Verify the component has already been registered
From f3e73aa03a654bff4921fa4e6bbb84a438854aa6 Mon Sep 17 00:00:00 2001
From: Ryan Morshead
Date: Fri, 16 Jun 2023 09:34:47 -0700
Subject: [PATCH 3/5] Update pull_request_template.md
---
.github/pull_request_template.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 95ad9c16..f237e91d 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1,3 +1,5 @@
+*By submitting this pull request you agree that all contributions to this project are made under the MIT license.*
+
## Description
A summary of the changes.
From a884af32ce60d53f9d55f3d55f1958ec275842d6 Mon Sep 17 00:00:00 2001
From: Mark Bakhit <16909269+Archmonger@users.noreply.github.com>
Date: Fri, 23 Jun 2023 15:20:31 -0700
Subject: [PATCH 4/5] Add `REACTPY_AUTH_BACKEND` setting (#151)
- Added `REACTPY_AUTH_BACKEND` setting to allow for custom authentication backends.
- Refactor the websocket consumer so that using `SessionMiddlewareStack` and/or `AuthMiddlewareStack` is now optional.
- Make Django a mandatory project dependency, since we need Django 4.1+
---
CHANGELOG.md | 6 +++++
docs/python/configure-asgi-middleware.py | 26 ++++++++++++++++++
docs/python/configure-asgi.py | 6 +----
docs/python/settings.py | 7 +++++
docs/src/features/decorators.md | 2 +-
docs/src/get-started/installation.md | 24 ++++++++++++++---
requirements/pkg-deps.txt | 1 +
requirements/test-env.txt | 1 -
src/reactpy_django/config.py | 5 ++++
src/reactpy_django/websocket/consumer.py | 34 +++++++++++++++++++-----
tests/test_app/settings.py | 4 +++
11 files changed, 99 insertions(+), 17 deletions(-)
create mode 100644 docs/python/configure-asgi-middleware.py
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 06f30dff..be5f1982 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -37,6 +37,12 @@ Using the following categories, list your changes in this order:
### Added
- Added warning if poor system/cache/database performance is detected.
+- Added `REACTPY_AUTH_BACKEND` setting to allow for custom authentication backends.
+
+### Changed
+
+- Using `SessionMiddlewareStack` is now optional.
+- Using `AuthMiddlewareStack` is now optional.
## [3.1.0] - 2023-05-06
diff --git a/docs/python/configure-asgi-middleware.py b/docs/python/configure-asgi-middleware.py
new file mode 100644
index 00000000..0ee33a8a
--- /dev/null
+++ b/docs/python/configure-asgi-middleware.py
@@ -0,0 +1,26 @@
+# Broken load order, only used for linting
+from channels.routing import ProtocolTypeRouter, URLRouter
+
+from reactpy_django import REACTPY_WEBSOCKET_PATH
+
+
+django_asgi_app = ""
+
+
+# start
+from channels.auth import AuthMiddlewareStack # noqa: E402
+from channels.sessions import SessionMiddlewareStack # noqa: E402
+
+
+application = ProtocolTypeRouter(
+ {
+ "http": django_asgi_app,
+ "websocket": SessionMiddlewareStack(
+ AuthMiddlewareStack(
+ URLRouter(
+ [REACTPY_WEBSOCKET_PATH],
+ )
+ )
+ ),
+ }
+)
diff --git a/docs/python/configure-asgi.py b/docs/python/configure-asgi.py
index 88b37b1e..6ae7cf8a 100644
--- a/docs/python/configure-asgi.py
+++ b/docs/python/configure-asgi.py
@@ -10,9 +10,7 @@
django_asgi_app = get_asgi_application()
-from channels.auth import AuthMiddlewareStack # noqa: E402
from channels.routing import ProtocolTypeRouter, URLRouter # noqa: E402
-from channels.sessions import SessionMiddlewareStack # noqa: E402
from reactpy_django import REACTPY_WEBSOCKET_PATH # noqa: E402
@@ -20,8 +18,6 @@
application = ProtocolTypeRouter(
{
"http": django_asgi_app,
- "websocket": SessionMiddlewareStack(
- AuthMiddlewareStack(URLRouter([REACTPY_WEBSOCKET_PATH]))
- ),
+ "websocket": URLRouter([REACTPY_WEBSOCKET_PATH]),
}
)
diff --git a/docs/python/settings.py b/docs/python/settings.py
index c3c2b0d9..9633da43 100644
--- a/docs/python/settings.py
+++ b/docs/python/settings.py
@@ -13,3 +13,10 @@
# Dotted path to the default `reactpy_django.hooks.use_query` postprocessor function, or `None`
REACTPY_DEFAULT_QUERY_POSTPROCESSOR = "reactpy_django.utils.django_query_postprocessor"
+
+# Dotted path to the Django authentication backend to use for ReactPy components
+# This is only needed if:
+# 1. You are using `AuthMiddlewareStack` and...
+# 2. You are using Django's `AUTHENTICATION_BACKENDS` settings and...
+# 3. Your Django user model does not define a `backend` attribute
+REACTPY_AUTH_BACKEND = None
diff --git a/docs/src/features/decorators.md b/docs/src/features/decorators.md
index 95779fae..45548799 100644
--- a/docs/src/features/decorators.md
+++ b/docs/src/features/decorators.md
@@ -8,7 +8,7 @@
You can limit access to a component to users with a specific `auth_attribute` by using this decorator (with or without parentheses).
-By default, this decorator checks if the user is logged in, and his/her account has not been deactivated.
+By default, this decorator checks if the user is logged in and not deactivated (`is_active`).
This decorator is commonly used to selectively render a component only if a user [`is_staff`](https://docs.djangoproject.com/en/dev/ref/contrib/auth/#django.contrib.auth.models.User.is_staff) or [`is_superuser`](https://docs.djangoproject.com/en/dev/ref/contrib/auth/#django.contrib.auth.models.User.is_superuser).
diff --git a/docs/src/get-started/installation.md b/docs/src/get-started/installation.md
index 21e26201..7aa2ea65 100644
--- a/docs/src/get-started/installation.md
+++ b/docs/src/get-started/installation.md
@@ -28,9 +28,11 @@ In your settings you will need to add `reactpy_django` to [`INSTALLED_APPS`](htt
ReactPy-Django requires ASGI Websockets from [Django Channels](https://github.com/django/channels).
- If you have not enabled ASGI on your **Django project** yet, you will need to install `channels[daphne]`, add `daphne` to `INSTALLED_APPS`, then set your `ASGI_APPLICATION` variable.
+ If you have not enabled ASGI on your **Django project** yet, you will need to
- Read the [Django Channels Docs](https://channels.readthedocs.io/en/stable/installation.html) for more info.
+ 1. Install `channels[daphne]`
+ 2. Add `daphne` to `INSTALLED_APPS`
+ 3. Set your `ASGI_APPLICATION` variable.
=== "settings.py"
@@ -38,11 +40,13 @@ In your settings you will need to add `reactpy_django` to [`INSTALLED_APPS`](htt
{% include "../../python/configure-channels.py" %}
```
+ Consider reading the [Django Channels Docs](https://channels.readthedocs.io/en/stable/installation.html) for more info.
+
??? note "Configure ReactPy settings (Optional)"
Below are a handful of values you can change within `settings.py` to modify the behavior of ReactPy.
- ```python
+ ```python linenums="0"
{% include "../../python/settings.py" %}
```
@@ -66,6 +70,20 @@ Register ReactPy's Websocket using `REACTPY_WEBSOCKET_PATH`.
{% include "../../python/configure-asgi.py" %}
```
+??? note "Add `AuthMiddlewareStack` and `SessionMiddlewareStack` (Optional)"
+
+ There are many situations where you need to access the Django `User` or `Session` objects within ReactPy components. For example, if you want to:
+
+ 1. Access the `User` that is currently logged in
+ 2. Login or logout the current `User`
+ 3. Access Django's `Sesssion` object
+
+ In these situations will need to ensure you are using `AuthMiddlewareStack` and/or `SessionMiddlewareStack`.
+
+ ```python linenums="0"
+ {% include "../../python/configure-asgi-middleware.py" start="# start" %}
+ ```
+
??? question "Where is my `asgi.py`?"
If you do not have an `asgi.py`, follow the [`channels` installation guide](https://channels.readthedocs.io/en/stable/installation.html).
diff --git a/requirements/pkg-deps.txt b/requirements/pkg-deps.txt
index 16b18367..75758695 100644
--- a/requirements/pkg-deps.txt
+++ b/requirements/pkg-deps.txt
@@ -1,4 +1,5 @@
channels >=4.0.0
+django >=4.1.0
reactpy >=1.0.0, <1.1.0
aiofile >=3.0
dill >=0.3.5
diff --git a/requirements/test-env.txt b/requirements/test-env.txt
index f7552f1d..cd40cf23 100644
--- a/requirements/test-env.txt
+++ b/requirements/test-env.txt
@@ -1,4 +1,3 @@
-django
playwright
twisted
channels[daphne]>=4.0.0
diff --git a/src/reactpy_django/config.py b/src/reactpy_django/config.py
index 33950b1e..960aa58f 100644
--- a/src/reactpy_django/config.py
+++ b/src/reactpy_django/config.py
@@ -50,3 +50,8 @@
)
)
)
+REACTPY_AUTH_BACKEND: str | None = getattr(
+ settings,
+ "REACTPY_AUTH_BACKEND",
+ None,
+)
diff --git a/src/reactpy_django/websocket/consumer.py b/src/reactpy_django/websocket/consumer.py
index aab994d3..de8ec423 100644
--- a/src/reactpy_django/websocket/consumer.py
+++ b/src/reactpy_django/websocket/consumer.py
@@ -27,25 +27,43 @@ class ReactpyAsyncWebsocketConsumer(AsyncJsonWebsocketConsumer):
"""Communicates with the browser to perform actions on-demand."""
async def connect(self) -> None:
- from django.contrib.auth.models import AbstractBaseUser
-
+ """The browser has connected."""
await super().connect()
- user: AbstractBaseUser = self.scope.get("user")
+ # Authenticate the user, if possible
+ from reactpy_django.config import REACTPY_AUTH_BACKEND
+
+ user: Any = self.scope.get("user")
if user and user.is_authenticated:
try:
- await login(self.scope, user)
- await database_sync_to_async(self.scope["session"].save)()
+ await login(self.scope, user, backend=REACTPY_AUTH_BACKEND)
except Exception:
_logger.exception("ReactPy websocket authentication has failed!")
elif user is None:
- _logger.warning("ReactPy websocket is missing AuthMiddlewareStack!")
+ _logger.debug(
+ "ReactPy websocket is missing AuthMiddlewareStack! "
+ "Users will not be accessible within `use_scope` or `use_websocket`!"
+ )
+
+ # Save the session, if possible
+ if self.scope.get("session"):
+ try:
+ await database_sync_to_async(self.scope["session"].save)()
+ except Exception:
+ _logger.exception("ReactPy has failed to save scope['session']!")
+ else:
+ _logger.debug(
+ "ReactPy websocket is missing SessionMiddlewareStack! "
+ "Sessions will not be accessible within `use_scope` or `use_websocket`!"
+ )
+ # Start allowing component renders
self._reactpy_dispatcher_future = asyncio.ensure_future(
self._run_dispatch_loop()
)
async def disconnect(self, code: int) -> None:
+ """The browser has disconnected."""
if self._reactpy_dispatcher_future.done():
await self._reactpy_dispatcher_future
else:
@@ -53,9 +71,11 @@ async def disconnect(self, code: int) -> None:
await super().disconnect(code)
async def receive_json(self, content: Any, **_) -> None:
+ """Receive a message from the browser. Typically messages are event signals."""
await self._reactpy_recv_queue.put(content)
async def _run_dispatch_loop(self):
+ """Runs the main loop that performs component rendering tasks."""
from reactpy_django import models
from reactpy_django.config import (
REACTPY_DATABASE,
@@ -130,7 +150,7 @@ async def _run_dispatch_loop(self):
)
return
- # Begin serving the ReactPy component
+ # Start the ReactPy component rendering loop
try:
await serve_layout(
Layout(ConnectionContext(component_instance, value=connection)),
diff --git a/tests/test_app/settings.py b/tests/test_app/settings.py
index aa2c5196..15d6d1a1 100644
--- a/tests/test_app/settings.py
+++ b/tests/test_app/settings.py
@@ -170,3 +170,7 @@
},
},
}
+
+
+# ReactPy Django Settings
+REACTPY_AUTH_BACKEND = "django.contrib.auth.backends.ModelBackend"
From 112f280dd3cff85039e78c082b823db068aad44d Mon Sep 17 00:00:00 2001
From: Mark Bakhit <16909269+Archmonger@users.noreply.github.com>
Date: Fri, 23 Jun 2023 15:39:05 -0700
Subject: [PATCH 5/5] v3.2.0 (#149)
---
CHANGELOG.md | 9 +++++++--
src/reactpy_django/__init__.py | 2 +-
src/reactpy_django/utils.py | 9 +++++++--
3 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index be5f1982..dcda688d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -34,9 +34,13 @@ Using the following categories, list your changes in this order:
## [Unreleased]
+- Nothing (yet)
+
+## [3.2.0] - 2023-06-08
+
### Added
-- Added warning if poor system/cache/database performance is detected.
+- Added warning if poor system/cache/database performance is detected while in `DEBUG` mode.
- Added `REACTPY_AUTH_BACKEND` setting to allow for custom authentication backends.
### Changed
@@ -285,7 +289,8 @@ Using the following categories, list your changes in this order:
- Support for IDOM within the Django
-[unreleased]: https://github.com/reactive-python/reactpy-django/compare/3.1.0...HEAD
+[unreleased]: https://github.com/reactive-python/reactpy-django/compare/3.2.0...HEAD
+[3.2.0]: https://github.com/reactive-python/reactpy-django/compare/3.1.0...3.2.0
[3.1.0]: https://github.com/reactive-python/reactpy-django/compare/3.0.1...3.1.0
[3.0.1]: https://github.com/reactive-python/reactpy-django/compare/3.0.0-reactpy...3.0.1
[3.0.0-reactpy]: https://github.com/reactive-python/reactpy-django/compare/3.0.0...3.0.0-reactpy
diff --git a/src/reactpy_django/__init__.py b/src/reactpy_django/__init__.py
index 195626aa..0d8bb188 100644
--- a/src/reactpy_django/__init__.py
+++ b/src/reactpy_django/__init__.py
@@ -2,7 +2,7 @@
from reactpy_django.websocket.paths import REACTPY_WEBSOCKET_PATH
-__version__ = "3.1.0"
+__version__ = "3.2.0"
__all__ = [
"REACTPY_WEBSOCKET_PATH",
"hooks",
diff --git a/src/reactpy_django/utils.py b/src/reactpy_django/utils.py
index c44429ee..da973a60 100644
--- a/src/reactpy_django/utils.py
+++ b/src/reactpy_django/utils.py
@@ -313,7 +313,12 @@ def create_cache_key(*args):
def db_cleanup(immediate: bool = False):
"""Deletes expired component sessions from the database.
This function may be expanded in the future to include additional cleanup tasks."""
- from .config import REACTPY_CACHE, REACTPY_DATABASE, REACTPY_RECONNECT_MAX
+ from .config import (
+ REACTPY_CACHE,
+ REACTPY_DATABASE,
+ REACTPY_DEBUG_MODE,
+ REACTPY_RECONNECT_MAX,
+ )
from .models import ComponentSession
clean_started_at = datetime.now()
@@ -344,7 +349,7 @@ def db_cleanup(immediate: bool = False):
# Check if cleaning took abnormally long
clean_duration = datetime.now() - clean_started_at
- if clean_duration.total_seconds() > 1:
+ if REACTPY_DEBUG_MODE and clean_duration.total_seconds() > 1:
_logger.warning(
"ReactPy has taken %s seconds to clean up expired component sessions. "
"This may indicate a performance issue with your system, cache, or database.",