Packages

phoenix_kit

1.7.21
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 users registration.ex
Raw

lib/phoenix_kit_web/users/registration.ex

defmodule PhoenixKitWeb.Users.Registration do
@moduledoc """
LiveView for user registration.
Provides a registration form for new users to create an account.
Supports referral codes and respects the allow_registration setting.
Tracks anonymous visitor sessions during registration.
"""
use PhoenixKitWeb, :live_view
alias PhoenixKit.Admin.Presence
alias PhoenixKit.Config
alias PhoenixKit.Modules.Referrals
alias PhoenixKit.Settings
alias PhoenixKit.Users.Auth
alias PhoenixKit.Users.Auth.User
alias PhoenixKit.Utils.IpAddress
alias PhoenixKit.Utils.Routes
def mount(_params, session, socket) do
# Check if registration is allowed
allow_registration = Settings.get_boolean_setting("allow_registration", true)
if allow_registration do
# Track anonymous visitor session
if connected?(socket) do
session_id = session["live_socket_id"] || generate_session_id()
Presence.track_anonymous(session_id, %{
connected_at: DateTime.utc_now(),
ip_address: IpAddress.extract_from_socket(socket),
user_agent: get_connect_info(socket, :user_agent),
current_page: Routes.path("/users/register")
})
end
# Get project title from settings
project_title = Settings.get_setting("project_title", "PhoenixKit")
# Get referral codes configuration
referral_codes_config = Referrals.get_config()
# Get Magic Link registration setting
magic_link_registration_enabled =
Settings.get_boolean_setting("magic_link_registration_enabled", true)
# Get username field visibility setting
show_username = Settings.get_setting("registration_show_username", "true") != "false"
changeset = Auth.change_user_registration(%User{})
# Extract and store IP address during mount for later use
ip_address = IpAddress.extract_from_socket(socket)
socket =
socket
|> assign(trigger_submit: false, check_errors: false)
|> assign(project_title: project_title)
|> assign(referral_codes_enabled: referral_codes_config.enabled)
|> assign(referral_codes_required: referral_codes_config.required)
|> assign(referral_code: nil)
|> assign(referral_code_error: nil)
|> assign(user_ip_address: ip_address)
|> assign(magic_link_registration_enabled: magic_link_registration_enabled)
|> assign(show_username: show_username)
|> assign_form(changeset)
{:ok, socket, temporary_assigns: [form: nil]}
else
socket =
socket
|> put_flash(
:error,
"User registration is currently disabled. Please contact an administrator."
)
|> redirect(to: Routes.path("/users/log-in"))
{:ok, socket}
end
end
def handle_event("save", %{"user" => user_params} = params, socket) do
referral_code = params["referral_code"]
# Validate referral code if system is enabled
case validate_referral_code(referral_code, socket) do
{:ok, validated_code} ->
# Check if geolocation tracking is enabled
track_geolocation = Settings.get_boolean_setting("track_registration_geolocation", false)
ip_address = socket.assigns.user_ip_address
# Use appropriate registration function based on geolocation setting
registration_result =
if track_geolocation do
Auth.register_user_with_geolocation(user_params, ip_address)
else
Auth.register_user(user_params, ip_address)
end
case registration_result do
{:ok, user} ->
# Record referral code usage if provided and valid
if validated_code do
Referrals.use_code(validated_code.code, user.id)
end
case Auth.deliver_user_confirmation_instructions(
user,
&Routes.url("/users/confirm/#{&1}")
) do
{:ok, _} ->
# Email sent successfully
:ok
{:error, error} ->
# Log error but don't fail registration
require Logger
Logger.error("Failed to send confirmation email: #{inspect(error)}")
:ok
end
changeset = Auth.change_user_registration(user)
{:noreply, socket |> assign(trigger_submit: true) |> assign_form(changeset)}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, socket |> assign(check_errors: true) |> assign_form(changeset)}
end
{:error, error_message} ->
socket =
socket
|> assign(referral_code: referral_code)
|> assign(referral_code_error: error_message)
|> assign(check_errors: true)
{:noreply, socket}
end
end
def handle_event("validate", %{"user" => user_params} = params, socket) do
referral_code = params["referral_code"]
# Validate referral code and update error state
case validate_referral_code(referral_code, socket) do
{:ok, _} ->
socket =
socket
|> assign(referral_code: referral_code)
|> assign(referral_code_error: nil)
changeset = Auth.change_user_registration(%User{}, user_params)
{:noreply, assign_form(socket, Map.put(changeset, :action, :validate))}
{:error, error_message} ->
socket =
socket
|> assign(referral_code: referral_code)
|> assign(referral_code_error: error_message)
changeset = Auth.change_user_registration(%User{}, user_params)
{:noreply, assign_form(socket, Map.put(changeset, :action, :validate))}
end
end
defp assign_form(socket, %Ecto.Changeset{} = changeset) do
form = to_form(changeset, as: "user")
if changeset.valid? do
assign(socket, form: form, check_errors: false)
else
assign(socket, form: form)
end
end
defp validate_referral_code(referral_code, socket) do
cond do
# If referral codes are disabled, always allow registration
not socket.assigns.referral_codes_enabled ->
{:ok, nil}
# If referral codes are required but none provided
socket.assigns.referral_codes_required and
(is_nil(referral_code) or String.trim(referral_code) == "") ->
{:error, "Referral code is required"}
# If referral code is provided, validate it
referral_code && String.trim(referral_code) != "" ->
validate_referral_code_value(String.trim(referral_code))
# If referral codes are optional and none provided
true ->
{:ok, nil}
end
end
defp validate_referral_code_value(code_string) do
case Referrals.get_code_by_string(code_string) do
nil ->
{:error, "Invalid referral code"}
code ->
cond do
not code.status ->
{:error, "This referral code is no longer active"}
Referrals.expired?(code) ->
{:error, "This referral code has expired"}
Referrals.usage_limit_reached?(code) ->
{:error, "This referral code has reached its usage limit"}
true ->
{:ok, code}
end
end
end
defp show_dev_notice? do
Config.mailer_local?()
end
defp generate_session_id do
:crypto.strong_rand_bytes(16) |> Base.encode64()
end
end