Packages

phoenix_kit

1.7.49
1.7.208 1.7.207 1.7.206 1.7.205 1.7.204 1.7.203 1.7.202 1.7.201 1.7.200 1.7.199 1.7.198 1.7.197 1.7.196 1.7.194 1.7.193 1.7.192 1.7.191 1.7.190 1.7.189 1.7.187 1.7.186 1.7.185 1.7.184 1.7.183 1.7.182 1.7.181 1.7.180 1.7.179 1.7.178 1.7.177 1.7.176 1.7.175 1.7.174 1.7.173 1.7.172 1.7.171 1.7.170 1.7.169 1.7.168 1.7.167 1.7.166 1.7.165 1.7.164 1.7.162 1.7.161 1.7.160 1.7.159 1.7.157 1.7.156 1.7.155 1.7.154 1.7.153 1.7.152 1.7.151 1.7.150 1.7.149 1.7.146 1.7.145 1.7.144 1.7.143 1.7.138 1.7.133 1.7.132 1.7.131 1.7.130 1.7.128 1.7.126 1.7.125 1.7.121 1.7.120 1.7.119 1.7.118 1.7.117 1.7.116 1.7.115 1.7.114 1.7.113 1.7.112 1.7.111 1.7.110 1.7.109 1.7.108 1.7.107 1.7.106 1.7.105 1.7.104 1.7.103 1.7.102 1.7.101 1.7.100 1.7.99 1.7.98 1.7.97 1.7.96 1.7.95 1.7.94 1.7.93 1.7.92 1.7.91 1.7.90 1.7.89 1.7.88 1.7.87 1.7.86 1.7.85 1.7.84 1.7.83 1.7.82 1.7.81 1.7.80 1.7.79 1.7.78 1.7.77 1.7.76 1.7.75 1.7.74 1.7.71 1.7.70 1.7.69 1.7.66 1.7.65 1.7.64 1.7.63 1.7.62 1.7.61 1.7.59 1.7.58 1.7.57 1.7.56 1.7.55 1.7.54 1.7.53 1.7.52 1.7.51 1.7.49 1.7.44 1.7.43 1.7.42 1.7.41 1.7.39 1.7.38 1.7.37 1.7.36 1.7.34 1.7.33 1.7.31 1.7.30 1.7.29 1.7.28 1.7.27 1.7.26 1.7.25 1.7.24 1.7.23 1.7.22 1.7.21 1.7.20 1.7.19 1.7.18 1.7.17 1.7.16 1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 1.7.9 1.7.8 1.7.7 1.7.6 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 1.7.0 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.2 1.3.1 1.3.0 1.2.10 1.2.9 1.2.8 1.2.7 1.2.5 1.2.4 1.2.2 1.2.1 1.2.0 1.1.0 1.0.0

A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more

Current section

Files

Jump to
phoenix_kit lib phoenix_kit_web live users sessions.ex
Raw

lib/phoenix_kit_web/live/users/sessions.ex

defmodule PhoenixKitWeb.Live.Users.Sessions do
@moduledoc """
Live component for managing active user sessions in the PhoenixKit admin panel.
This module provides functionality to:
- View all active sessions across the system
- See session details including user info, creation time, and age
- Revoke individual sessions
- Revoke all sessions for a specific user
- View session statistics
Only accessible to users with Owner or Admin roles.
"""
use PhoenixKitWeb, :live_view
use Gettext, backend: PhoenixKitWeb.Gettext
alias PhoenixKit.Admin.Events
alias PhoenixKit.Settings
alias PhoenixKit.Users.{Auth, Sessions}
alias PhoenixKit.Utils.Date, as: UtilsDate
@per_page 20
def mount(params, _session, socket) do
# Set locale for LiveView process
locale =
params["locale"] || socket.assigns[:current_locale]
# Subscribe to session events for real-time updates
if connected?(socket) do
Events.subscribe_to_sessions()
end
# Get project title from settings
project_title = Settings.get_project_title()
socket =
socket
|> assign(:page, 1)
|> assign(:per_page, @per_page)
|> assign(:search_query, "")
|> assign(:filter_user_status, "all")
|> assign(:page_title, "Sessions")
|> assign(:project_title, project_title)
|> assign(:current_locale, locale)
|> assign(:show_revoke_modal, false)
|> assign(:selected_session, nil)
|> assign(:revoke_type, nil)
|> load_sessions()
|> load_stats()
{:ok, socket}
end
def handle_params(_params, _url, socket) do
{:noreply, socket}
end
def handle_event("search", %{"search" => search_query}, socket) do
socket =
socket
|> assign(:search_query, search_query)
|> assign(:page, 1)
|> load_sessions()
{:noreply, socket}
end
def handle_event("filter_by_user_status", %{"status" => status}, socket) do
socket =
socket
|> assign(:filter_user_status, status)
|> assign(:page, 1)
|> load_sessions()
{:noreply, socket}
end
def handle_event("change_page", %{"page" => page}, socket) do
page = String.to_integer(page)
socket =
socket
|> assign(:page, page)
|> load_sessions()
{:noreply, socket}
end
def handle_event("show_revoke_session", %{"token_id" => token_id}, socket) do
session_info = Sessions.get_session_info(token_id)
socket =
socket
|> assign(:selected_session, session_info)
|> assign(:revoke_type, :single)
|> assign(:show_revoke_modal, true)
{:noreply, socket}
end
def handle_event("show_revoke_user_sessions", %{"user_id" => user_id}, socket) do
user = Auth.get_user!(user_id)
user_sessions = Sessions.list_user_sessions(user)
socket =
socket
|> assign(:selected_user, user)
|> assign(:user_sessions_count, length(user_sessions))
|> assign(:revoke_type, :user_all)
|> assign(:show_revoke_modal, true)
{:noreply, socket}
end
def handle_event("hide_revoke_modal", _params, socket) do
socket =
socket
|> assign(:show_revoke_modal, false)
|> assign(:selected_session, nil)
|> assign(:selected_user, nil)
|> assign(:revoke_type, nil)
{:noreply, socket}
end
def handle_event("confirm_revoke_session", _params, socket) do
case socket.assigns.revoke_type do
:single ->
handle_single_session_revoke(socket)
:user_all ->
handle_user_sessions_revoke(socket)
_ ->
{:noreply, put_flash(socket, :error, "Invalid revoke operation")}
end
end
def handle_event("refresh_sessions", _params, socket) do
socket =
socket
|> load_sessions()
|> load_stats()
|> put_flash(:info, "Sessions refreshed successfully")
{:noreply, socket}
end
defp handle_single_session_revoke(socket) do
session = socket.assigns.selected_session
case Sessions.revoke_session(session.token_id) do
:ok ->
socket =
socket
|> put_flash(:info, "Session revoked successfully")
|> assign(:show_revoke_modal, false)
|> assign(:selected_session, nil)
|> assign(:revoke_type, nil)
|> load_sessions()
|> load_stats()
{:noreply, socket}
{:error, :not_found} ->
socket =
socket
|> put_flash(:error, "Session not found or already expired")
|> assign(:show_revoke_modal, false)
|> load_sessions()
{:noreply, socket}
end
end
defp handle_user_sessions_revoke(socket) do
user = socket.assigns.selected_user
revoked_count = Sessions.revoke_user_sessions(user)
socket =
socket
|> put_flash(:info, "#{revoked_count} session(s) revoked for user #{user.email}")
|> assign(:show_revoke_modal, false)
|> assign(:selected_user, nil)
|> assign(:revoke_type, nil)
|> load_sessions()
|> load_stats()
{:noreply, socket}
end
defp load_sessions(socket) do
sessions = Sessions.list_active_sessions()
# Apply filtering
filtered_sessions =
sessions
|> filter_by_search(socket.assigns.search_query)
|> filter_by_user_status(socket.assigns.filter_user_status)
# Apply pagination
total_count = length(filtered_sessions)
total_pages = div(total_count + @per_page - 1, @per_page)
page = max(1, min(socket.assigns.page, total_pages))
offset = (page - 1) * @per_page
paginated_sessions =
filtered_sessions
|> Enum.drop(offset)
|> Enum.take(@per_page)
socket
|> assign(:sessions, paginated_sessions)
|> assign(:total_count, total_count)
|> assign(:total_pages, total_pages)
|> assign(:page, page)
end
defp load_stats(socket) do
stats = Sessions.get_session_stats()
socket
|> assign(:stats, stats)
end
defp filter_by_search(sessions, ""), do: sessions
defp filter_by_search(sessions, query) do
query_lower = String.downcase(query)
Enum.filter(sessions, fn session ->
String.contains?(String.downcase(session.user_email), query_lower) ||
String.contains?(String.downcase(session.token_preview), query_lower)
end)
end
defp filter_by_user_status(sessions, "all"), do: sessions
defp filter_by_user_status(sessions, "active") do
Enum.filter(sessions, & &1.user_is_active)
end
defp filter_by_user_status(sessions, "inactive") do
Enum.filter(sessions, &(!&1.user_is_active))
end
defp filter_by_user_status(sessions, "confirmed") do
Enum.filter(sessions, &(!is_nil(&1.user_confirmed_at)))
end
defp filter_by_user_status(sessions, "pending") do
Enum.filter(sessions, &is_nil(&1.user_confirmed_at))
end
## Live Event Handlers for Sessions
def handle_info({:session_created, _user, _token_info}, socket) do
socket =
socket
|> load_sessions()
|> load_stats()
{:noreply, socket}
end
def handle_info({:session_revoked, _token_id}, socket) do
socket =
socket
|> load_sessions()
|> load_stats()
{:noreply, socket}
end
def handle_info({:user_sessions_revoked, _user_id, _count}, socket) do
socket =
socket
|> load_sessions()
|> load_stats()
{:noreply, socket}
end
def handle_info({:sessions_stats_updated, stats}, socket) do
socket =
socket
|> assign(:stats, stats)
{:noreply, socket}
end
end