defmodule LivebookWeb.UserHook do import Phoenix.Component import Phoenix.LiveView alias Livebook.Users.User def on_mount(:default, _params, %{"identity_data" => identity_data} = session, socket) do if connected?(socket) do Livebook.Users.subscribe(identity_data.id) end socket = socket |> assign_new(:current_user, fn -> build_current_user(session, socket) end) |> attach_hook(:current_user_subscription, :handle_info, &info/2) {:cont, socket} end defp info( {:user_change, %{id: id} = user}, %{assigns: %{current_user: %{id: id}}} = socket ) do {:halt, assign(socket, :current_user, user)} end defp info(_message, socket), do: {:cont, socket} # Builds `Livebook.Users.User` using information from # session and socket. # # Uses `user_data` from socket `connect_params` as initial # attributes if the socket is connected. Otherwise uses # `user_data` from session. defp build_current_user(session, socket) do identity_data = Map.new(session["identity_data"], fn {k, v} -> {Atom.to_string(k), v} end) connect_params = get_connect_params(socket) || %{} attrs = connect_params["user_data"] || session["user_data"] || %{} attrs = case Map.merge(attrs, identity_data) do %{"name" => nil, "email" => email} = attrs -> %{attrs | "name" => email} attrs -> attrs end user = User.new(attrs["id"]) case Livebook.Users.update_user(user, attrs) do {:ok, user} -> user {:error, _changeset} -> user end end end