Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UserModel related hooks, decorators, and settings #190

Merged
merged 65 commits into from
Jan 7, 2024

Conversation

Archmonger
Copy link
Contributor

@Archmonger Archmonger commented Sep 19, 2023

Description

  • New Django User related features!
    • reactpy_django.hooks.use_user can be used to access the current user.
    • reactpy_django.hooks.use_user_data provides a simplified interface for storing user key-value data.
    • reactpy_django.decorators.user_passes_test is inspired by Django's user_passes_test decorator, but works with ReactPy components.
    • settings.py:REACTPY_AUTO_RELOGIN will cause component WebSocket connections to automatically re-login users that are already authenticated. This is useful to continuously update last_login timestamps and refresh the Django login session.

Checklist:

Please update this checklist as you complete each item:

  • Tests have been developed for bug fixes or new functionality.
  • The changelog has been updated, if necessary.
  • Documentation has been updated, if necessary.
  • GitHub Issues closed by this PR have been linked.

By submitting this pull request you agree that all contributions comply with this project's open source license(s).

@Archmonger Archmonger changed the title UserModel related hooks and decorators UserModel related hooks, decorators, and settings Oct 15, 2023
@Archmonger
Copy link
Contributor Author

Archmonger commented Dec 13, 2023

@rmorshea I need your opinion on the use_user_data API. To save you some time, here's the short and sweet summary:

use_user_data allows you to store or retrieve data specific to the connection's User object. This user_data is persistently stored within the database and can be accessed like such:

from reactpy import component, html
from reactpy_django.hooks import use_user_data

@component
def my_component():
    # user_data properties: current, loading, error 
    # user_data callable attributes: refetch
    # set_user_data properties: loading, error
    # set_user_data callable attributes: __call__, reset
    user_data, set_user_data = use_user_data()

    # Here's an example that uses most of the API
    async def on_key_press(event):
        if event["key"] == "Enter":
            # User data is always a dict
            merged_data = user_data.current | {uuid4(): event["target"]["value"]}
            set_user_data(merged_data)

    return html.div(
        html.input({"placeholder": "Type some user data here...", "on_key_press": on_key_press}),
        html.div(f"Data: {user_data.current}"),
        html.div(f"Data Loading: {user_data.loading}"),
        html.div(f"Set Data Loading: {set_user_data.loading}"),
        html.div(f"Error(s): {user_data.error} {set_user_data.error}"),
    )

To get the conversation started, here's a few questions/concerns I have:

  1. Does it make sense that user_data.current returns a dict?
  2. Does splitting the interface into user_data, set_user_data feel right?
  3. Is the set_user_data interface clear and logical? The interface is identical to use_mutation.
  4. Is the user_data interface clear and logical? This interface is different than use_query interface in the fact that the data attribute was renamed to current (user_data.data looked weird to me).

@rmorshea
Copy link
Contributor

rmorshea commented Dec 17, 2023

I'll try and take a look in the next couple days.

@Archmonger
Copy link
Contributor Author

Would you have time to look at the interface proposed in the above comment this weekend?

This PR is fairly bulky and has a lot of Django-only jargon, so a PR review won't be needed.

@rmorshea
Copy link
Contributor

Sure. I'll make time today or tomorrow.

@rmorshea
Copy link
Contributor

rmorshea commented Dec 31, 2023

My take is that the marginal UX improvements made by creating special wrappers for the query and mutation objects may be outweighed by requiring the user to learn something new. It seems easier to explain to the user that use_user_data returns a tuple with a query and a mutation.

To address some of the usability concerns in a slightly simpler way, we could consider adding a __call__ method to mutations and returning a named tuple from use_user_data so usage would be

user_data = use_user_data()

# access data
user_data.query.data

def some_callback():
    new_user_data = user_data.query.data | {...}
    user_data.mutation(new_user_data)

@Archmonger
Copy link
Contributor Author

Agreed, will implement soon.

@Archmonger Archmonger mentioned this pull request Dec 31, 2023
4 tasks
@Archmonger Archmonger marked this pull request as ready for review January 7, 2024 02:59
@Archmonger Archmonger requested a review from a team as a code owner January 7, 2024 02:59
@Archmonger Archmonger merged commit b307b3e into reactive-python:main Jan 7, 2024
7 checks passed
@Archmonger Archmonger deleted the use-user-state-hook branch January 7, 2024 03:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

use_user_state hook
2 participants