From 8b9088797ae5d625ced966c54538923bcbf057ce Mon Sep 17 00:00:00 2001 From: Harshad Sharma Date: Mon, 13 May 2024 19:22:50 +0530 Subject: [PATCH] Add feature flag to disable registration in prod by default. --- config/config.exs | 5 + config/runtime.exs | 6 + lib/freedive/application.ex | 3 +- lib/freedive/features.ex | 45 ++++++++ .../live/user_registration_live.ex | 104 ++++++++++-------- .../live/user_registration_live_test.exs | 13 +++ 6 files changed, 132 insertions(+), 44 deletions(-) create mode 100644 lib/freedive/features.ex diff --git a/config/config.exs b/config/config.exs index 59eb359..de5dca8 100644 --- a/config/config.exs +++ b/config/config.exs @@ -11,6 +11,11 @@ config :freedive, ecto_repos: [Freedive.Repo], generators: [timestamp_type: :utc_datetime] +config :freedive, + features: [ + register_account: true + ] + # Configures the endpoint config :freedive, FreediveWeb.Endpoint, url: [host: "localhost"], diff --git a/config/runtime.exs b/config/runtime.exs index 2964b84..2ae8375 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -21,6 +21,12 @@ if System.get_env("PHX_SERVER") do end if config_env() == :prod do + # Account registration in production is disabled by default. + # To enable, set the REGISTER_ACCOUNT_ENABLE environment variable to "true". + if System.get_env("REGISTER_ACCOUNT_ENABLE") != "true" do + config :freedive, :features, register_account: false + end + database_path = System.get_env("DATABASE_PATH") || raise """ diff --git a/lib/freedive/application.ex b/lib/freedive/application.ex index d072ec9..d352fd0 100644 --- a/lib/freedive/application.ex +++ b/lib/freedive/application.ex @@ -25,7 +25,8 @@ defmodule Freedive.Application do # Start a worker by calling: Freedive.Worker.start_link(arg) # {Freedive.Worker, arg}, # Start to serve requests, typically the last entry - FreediveWeb.Endpoint + FreediveWeb.Endpoint, + Freedive.Features ] children = if minimal, do: app_minimal, else: app_minimal ++ app_features diff --git a/lib/freedive/features.ex b/lib/freedive/features.ex new file mode 100644 index 0000000..7aa05ef --- /dev/null +++ b/lib/freedive/features.ex @@ -0,0 +1,45 @@ +defmodule Freedive.Features do + use GenServer + require Logger + + def start_link(_args) do + GenServer.start_link(__MODULE__, nil, name: __MODULE__) + end + + def enable(feature) do + GenServer.cast(__MODULE__, {:enable, feature}) + end + + def disable(feature) do + GenServer.cast(__MODULE__, {:disable, feature}) + end + + def enabled?(feature) do + GenServer.call(__MODULE__, {:enabled?, feature}) + end + + def init(nil) do + state = feature_flags_from_config() + Logger.info("Feature flags: #{inspect(state)}") + {:ok, state} + end + + defp feature_flags_from_config() do + Application.get_env(:freedive, :features) + end + + def handle_cast({:enable, feature}, state) do + Logger.info("Enabling feature: #{feature}") + {:noreply, Keyword.put(state, feature, true)} + end + + def handle_cast({:disable, feature}, state) do + Logger.info("Disabling feature: #{feature}") + {:noreply, Keyword.put(state, feature, false)} + end + + def handle_call({:enabled?, feature}, _from, state) do + enabled = Keyword.get(state, feature, false) + {:reply, enabled, state} + end +end diff --git a/lib/freedive_web/live/user_registration_live.ex b/lib/freedive_web/live/user_registration_live.ex index ce9ca6c..809de50 100644 --- a/lib/freedive_web/live/user_registration_live.ex +++ b/lib/freedive_web/live/user_registration_live.ex @@ -3,43 +3,57 @@ defmodule FreediveWeb.UserRegistrationLive do alias Freedive.Accounts alias Freedive.Accounts.User + alias Freedive.Features def render(assigns) do - ~H""" -
- <.header class="text-center"> - Register for an account - <:subtitle> - Already registered? - <.link navigate={~p"/users/log_in"} class="font-semibold text-brand hover:underline"> - Log in - - to your account now. - - + if Features.enabled?(:register_account) do + ~H""" +
+ <.header class="text-center"> + Register for an account + <:subtitle> + Already registered? + <.link navigate={~p"/users/log_in"} class="font-semibold text-brand hover:underline"> + Log in + + to your account now. + + - <.simple_form - for={@form} - id="registration_form" - phx-submit="save" - phx-change="validate" - phx-trigger-action={@trigger_submit} - action={~p"/users/log_in?_action=registered"} - method="post" - > - <.error :if={@check_errors}> - Oops, something went wrong! Please check the errors below. - + <.simple_form + for={@form} + id="registration_form" + phx-submit="save" + phx-change="validate" + phx-trigger-action={@trigger_submit} + action={~p"/users/log_in?_action=registered"} + method="post" + > + <.error :if={@check_errors}> + Oops, something went wrong! Please check the errors below. + - <.input field={@form[:email]} type="email" label="Email" required /> - <.input field={@form[:password]} type="password" label="Password" required /> + <.input field={@form[:email]} type="email" label="Email" required /> + <.input field={@form[:password]} type="password" label="Password" required /> - <:actions> - <.button phx-disable-with="Creating account..." class="w-full">Create an account - - -
- """ + <:actions> + <.button phx-disable-with="Creating account..." class="w-full">Create an account + + +
+ """ + else + ~H""" + <.section> + <.title> + Sorry! + + <.subtitle> + Registration is closed. + + + """ + end end def mount(_params, _session, socket) do @@ -54,19 +68,23 @@ defmodule FreediveWeb.UserRegistrationLive do end def handle_event("save", %{"user" => user_params}, socket) do - case Accounts.register_user(user_params) do - {:ok, user} -> - {:ok, _} = - Accounts.deliver_user_confirmation_instructions( - user, - &url(~p"/users/confirm/#{&1}") - ) + if Features.enabled?(:register_account) do + case Accounts.register_user(user_params) do + {:ok, user} -> + {:ok, _} = + Accounts.deliver_user_confirmation_instructions( + user, + &url(~p"/users/confirm/#{&1}") + ) - changeset = Accounts.change_user_registration(user) - {:noreply, socket |> assign(trigger_submit: true) |> assign_form(changeset)} + changeset = Accounts.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)} + {:error, %Ecto.Changeset{} = changeset} -> + {:noreply, socket |> assign(check_errors: true) |> assign_form(changeset)} + end + else + {:noreply, socket} end end diff --git a/test/freedive_web/live/user_registration_live_test.exs b/test/freedive_web/live/user_registration_live_test.exs index 9986196..601f560 100644 --- a/test/freedive_web/live/user_registration_live_test.exs +++ b/test/freedive_web/live/user_registration_live_test.exs @@ -1,9 +1,22 @@ defmodule FreediveWeb.UserRegistrationLiveTest do use FreediveWeb.ConnCase + alias Freedive.Features import Phoenix.LiveViewTest import Freedive.AccountsFixtures + describe "Registration closed" do + test "shows registrations closed message", %{conn: conn} do + Features.disable(:register_account) + + {:ok, _lv, html} = live(conn, ~p"/users/register") + + assert html =~ "Registration is closed" + + Features.enable(:register_account) + end + end + describe "Registration page" do test "renders registration page", %{conn: conn} do {:ok, _lv, html} = live(conn, ~p"/users/register")