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

Update cached user #580

Open
sezaru opened this issue Oct 30, 2020 · 2 comments
Open

Update cached user #580

sezaru opened this issue Oct 30, 2020 · 2 comments

Comments

@sezaru
Copy link

sezaru commented Oct 30, 2020

is there some way to update the cached user so the next API calls will contain that change?

Reading Update cached user credentials it seems like I have to read directly from the database the updated user anytime I want an updated user or update the cached one using Pow.Plug.create/2.

The problem with the first solution is that only a handful of my API queries change the user data, the rest only reads it, so it seems not very optimized to have to query the updated user from the database with all API "read" queries I have only because the cached user is outdated.

The second solution would fix this since it would allow me to update the cached user in my API "write" queries guaranteeing that when I read it again it would be the latest one.

The issue with that is that Pow.Plug.create/2 creates a new session, so if I use it to try to update the cached user I will receive a "not logged" error message the next time I try to run any API query.

So, is there some way to update the cached user without creating a new session?

@danschultzer
Copy link
Collaborator

danschultzer commented Nov 6, 2020

The easiest would be to run Pow.Plug.create/2 in a way that won't invalidate the current session:

defp update_cached_user(conn) do
  conn
  |> Plug.Conn.put_private(:plug_session, %{})
  |> Plug.Conn.put_private(:pow_session_metadata, Keyword.delete(conn.private[:pow_session_metadata] || [], :fingerprint))
  |> Pow.Plug.create(user)

  :ok
end

What the above does is that it'll create a new session, which updates the cached user. It won't invalidate the current session since we'll clear out the plug session data and reset the session fingerprint metadata.

You could also call Pow.Store.CredentialsCache or the cache backend to more directly update the cached user. Maybe there should be a update_user function there to just update the user cache, but I think it might make the cache module too aware of the backend storage (it could be the backend store is in the DB which means the user is always up-to-date).

@sezaru
Copy link
Author

sezaru commented Nov 11, 2020

Hmm, doesn't seem to be working here. I changed my function from:

  def update(conn, %{"u_a" => updated_at, "c" => config}) do
    user = Pow.Plug.current_user(conn)
    
    if is_date_valid?(user, updated_at) do
      with {:ok, user} <- Configuration.update(config, user.id) do
        config = Pow.Plug.fetch_config(conn)

        conn
        |> Pow.Plug.assign_current_user(user, config)
        |> json(%{u_a: user.configuration_updated_at})
      end
    else
      conn |> put_status(403) |> json(0)
    end
  end

to

  def update(conn, %{"u_a" => updated_at, "c" => config}) do
    user = Pow.Plug.current_user(conn)

    if is_date_valid?(user, updated_at) do
      with {:ok, user} <- Configuration.update(config, user.id) do
        config = Pow.Plug.fetch_config(conn)

        conn
        |> Plug.Conn.put_private(:plug_session, %{})
        |> Plug.Conn.put_private(:pow_session_metadata, Keyword.delete(conn.private[:pow_session_metadata] || [], :fingerprint))
        |> Pow.Plug.create(user)
        
        json(conn, %{u_a: user.configuration_updated_at})
      end
    else
      conn |> put_status(403) |> json(0)
    end
  end

But it still replaces the session.

I'm using the Postgres store to persist the session btw, and I can see the data stored there for this user being updated when I run this function.

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

No branches or pull requests

2 participants