diff --git a/lib/microwaveprop/accounts/user.ex b/lib/microwaveprop/accounts/user.ex index 36e1fabe..bd6c2212 100644 --- a/lib/microwaveprop/accounts/user.ex +++ b/lib/microwaveprop/accounts/user.ex @@ -4,6 +4,8 @@ defmodule Microwaveprop.Accounts.User do import Ecto.Changeset + @admin_email "graham@mcintire.me" + @primary_key {:id, :binary_id, autogenerate: true} @foreign_key_type :binary_id schema "users" do @@ -13,11 +15,18 @@ defmodule Microwaveprop.Accounts.User do field :password, :string, virtual: true, redact: true field :hashed_password, :string, redact: true field :confirmed_at, :utc_datetime + field :is_admin, :boolean, default: false field :authenticated_at, :utc_datetime, virtual: true timestamps(type: :utc_datetime) end + @doc """ + Returns the email address that is automatically granted admin + privileges on registration. + """ + def admin_email, do: @admin_email + @doc """ A user changeset for registering a new user. @@ -40,6 +49,14 @@ defmodule Microwaveprop.Accounts.User do |> validate_email(opts) |> validate_confirmation(:password, message: "does not match password") |> validate_password(opts) + |> maybe_grant_admin() + end + + defp maybe_grant_admin(changeset) do + case get_field(changeset, :email) do + nil -> changeset + email -> if String.downcase(email) == @admin_email, do: put_change(changeset, :is_admin, true), else: changeset + end end defp validate_callsign(changeset, opts) do diff --git a/priv/repo/migrations/20260408163732_add_is_admin_to_users.exs b/priv/repo/migrations/20260408163732_add_is_admin_to_users.exs new file mode 100644 index 00000000..5e19a62a --- /dev/null +++ b/priv/repo/migrations/20260408163732_add_is_admin_to_users.exs @@ -0,0 +1,17 @@ +defmodule Microwaveprop.Repo.Migrations.AddIsAdminToUsers do + use Ecto.Migration + + def up do + alter table(:users) do + add :is_admin, :boolean, null: false, default: false + end + + execute "UPDATE users SET is_admin = true WHERE email = 'graham@mcintire.me'" + end + + def down do + alter table(:users) do + remove :is_admin + end + end +end diff --git a/test/microwaveprop/accounts_test.exs b/test/microwaveprop/accounts_test.exs index 530f956c..7e659175 100644 --- a/test/microwaveprop/accounts_test.exs +++ b/test/microwaveprop/accounts_test.exs @@ -133,6 +133,25 @@ defmodule Microwaveprop.AccountsTest do assert is_binary(user.hashed_password) assert is_nil(user.password) assert is_nil(user.confirmed_at) + refute user.is_admin + end + + test "grants is_admin to the configured admin email" do + {:ok, user} = + Accounts.register_user(valid_user_attributes(email: User.admin_email())) + + assert user.is_admin + end + + test "grants is_admin regardless of email case" do + upper = String.upcase(User.admin_email()) + {:ok, user} = Accounts.register_user(valid_user_attributes(email: upper)) + assert user.is_admin + end + + test "does not grant is_admin to other emails" do + {:ok, user} = Accounts.register_user(valid_user_attributes()) + refute user.is_admin end end