Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions lib/admin/accounts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,26 @@ defmodule Admin.Accounts do
|> update_user_and_delete_all_tokens()
end

def change_user_name(user, attrs \\ %{}) do
User.name_changeset(user, attrs)
end

def update_user_name(user, attrs \\ %{}) do
user
|> User.name_changeset(attrs)
|> Repo.update()
end

def change_user_language(user, attrs \\ %{}) do
User.language_changeset(user, attrs)
end

def update_user_language(user, attrs \\ %{}) do
user
|> User.language_changeset(attrs)
|> Repo.update()
end

## Session

@doc """
Expand Down
15 changes: 15 additions & 0 deletions lib/admin/accounts/user.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ defmodule Admin.Accounts.User do
# when we unify the access control for all users and use user roles to define who is an admin or not.
schema "admins" do
field :email, :string
field :name, :string
field :language, :string
field :password, :string, virtual: true, redact: true
field :hashed_password, :string, redact: true
field :confirmed_at, :utc_datetime
Expand Down Expand Up @@ -138,4 +140,17 @@ defmodule Admin.Accounts.User do
Bcrypt.no_user_verify()
false
end

def name_changeset(user, attrs) do
user
|> cast(attrs, [:name])
|> validate_required([:name])
end

def language_changeset(user, attrs) do
user
|> cast(attrs, [:language])
|> validate_required([:language])
|> validate_inclusion(:language, Admin.Languages.all_values())
end
end
57 changes: 57 additions & 0 deletions lib/admin/languages.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
defmodule Admin.Languages do
@moduledoc """
This module handles the currently supported languages.

It allows to get a language list suitable for displaying a select input with some options disabled.
"""
@languages [
%{value: "en", key: "English"},
%{value: "fr", key: "French"},
%{value: "es", key: "Spanish"},
%{value: "de", key: "German"},
%{value: "it", key: "Italian"}
Comment on lines +8 to +12
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Order by sth? value or key

]

def all do
@languages
end

def all_options do
@languages |> Enum.map(&Keyword.new(&1))
end

def all_values do
@languages |> Enum.map(& &1.value)
end

@doc """
Returns a list of languages excluding the ones with the given codes.

## Examples
iex> Admin.Languages.excluding(["en", "fr"])
[%{value: "es", key: "Spanish"}, %{value: "de", key: "German"}, %{value: "it", key: "Italian"}]
"""
def excluding(language_codes) when is_list(language_codes) do
@languages |> Enum.reject(&(&1.value in language_codes))
end

@doc """
Returns a list of keyword lists with languages with the disabled languages. Can be used in select options.

## Examples
iex> Admin.Languages.disabling(["en", "fr"])
[
[value: "en", key: "English", disabled: true],
[value: "fr", key: "French", disabled: true],
[value: "es", key: "Spanish", disabled: false],
[value: "de", key: "German", disabled: false],
[value: "it", key: "Italian", disabled: false]
]
"""
def disabling(language_codes) when is_list(language_codes) do
@languages
|> Enum.map(fn %{value: value, key: key} ->
Keyword.new(value: value, key: key, disabled: value in language_codes)
end)
end
end
2 changes: 1 addition & 1 deletion lib/admin_web/controllers/admin_html/dashboard.html.heex
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Layouts.admin flash={@flash} current_scope={@current_scope}>
<.header>
Welcome, {@current_scope.user.email}
Welcome, {@current_scope.user.name || @current_scope.user.email}
</.header>

<div class="stats shadow">
Expand Down
26 changes: 3 additions & 23 deletions lib/admin_web/controllers/user_html/show.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,10 @@
</.header>
<.list>
<:item title="ID">{@user.id}</:item>
<:item title="Name">{@user.email}</:item>
<:item title="Name">{@user.name}</:item>
<:item title="Email">{@user.email}</:item>
<:item title="Language">{@user.language}</:item>
<:item title="Inserted at">{@user.created_at}</:item>
<:item title="Confirmed at">{@user.confirmed_at || "Not confirmed yet"}</:item>
</.list>

<%!-- <.header>
Removal Notices
<:subtitle>Records of publications that have been removed for this user.</:subtitle>
</.header>
<%= if Enum.empty?(@user.removal_notices) do %>
<p class="italic text-secondary">No removal notices for user yet</p>
<% else %>
<.table id="removal-notices" rows={@user.removal_notices}>
<:col :let={notice} label="Name">{notice.publication_name}</:col>
<:col :let={notice} label="Removed on">
<div class="flex flex-col">
<.relative_date date={notice.created_at} />
<span class="text-xs text-secondary">
{notice.created_at}
</span>
</div>
</:col>
<:col :let={notice} label="By">{notice.creator.email}</:col>
<:col :let={notice} label="Reason">{notice.reason}</:col>
</.table>
<% end %> --%>
</Layouts.admin>
25 changes: 19 additions & 6 deletions lib/admin_web/live/user_live/listing.ex
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,26 @@ defmodule AdminWeb.UserLive.Listing do
class="flex flex-row justify-between"
>
<div class="">
<.link navigate={~p"/users/#{user}"}><span>{user.email}</span></.link>
<div :if={user.id == @current_scope.user.id} class="badge badge-soft badge-info text-xs">
You
</div>
<div :if={user.confirmed_at} class="badge badge-soft badge-success text-xs">
<.icon name="hero-check-circle" class="size-4 shrink-0" /> Email
<.link navigate={~p"/users/#{user}"}>
<span>{user.name}</span>

<div class="flex flex-row gap-1">
<span>{user.email}</span>
<div
:if={user.id == @current_scope.user.id}
class="badge badge-soft badge-info text-xs"
>
You
</div>
<div :if={user.confirmed_at} class="badge badge-soft badge-success text-xs">
<.icon name="hero-check-circle" class="size-4 shrink-0" /> Email
</div>
</div>
</.link>
<div class="text-xs">
<span class="text-secondary">Language:</span> {user.language}
</div>

<div class="flex flex-row gap-2 text-xs">
<span class="text-secondary">{user.id}</span>
<AdminWeb.DateTimeComponents.relative_date date={user.created_at} />
Expand Down
107 changes: 107 additions & 0 deletions lib/admin_web/live/user_live/settings.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,27 @@ defmodule AdminWeb.UserLive.Settings do
</.header>
</div>

<.form
for={@name_form}
id="name_form"
phx-change="validate_name"
phx-submit="update_name"
>
<.input
field={@name_form[:name]}
type="text"
label="Name"
autocomplete="name"
required
/>

<.button variant="primary" phx-disable-with="Saving...">
Save Name
</.button>
</.form>

<div class="divider" />

<.form for={@email_form} id="email_form" phx-submit="update_email" phx-change="validate_email">
<.input
field={@email_form[:email]}
Expand All @@ -29,6 +50,27 @@ defmodule AdminWeb.UserLive.Settings do

<div class="divider" />

<.form
for={@language_form}
id="language_form"
phx-change="validate_language"
phx-submit="update_language"
>
<.input
field={@language_form[:language]}
type="select"
label="Language"
options={Admin.Languages.all_options()}
required
/>

<.button variant="primary" phx-disable-with="Saving...">
Save Language
</.button>
</.form>

<div class="divider" />

<.form
for={@password_form}
id="password_form"
Expand Down Expand Up @@ -84,12 +126,17 @@ defmodule AdminWeb.UserLive.Settings do
user = socket.assigns.current_scope.user
email_changeset = Accounts.change_user_email(user, %{}, validate_unique: false)
password_changeset = Accounts.change_user_password(user, %{}, hash_password: false)
name_changeset = Accounts.change_user_name(user, %{})
language_changeset = Accounts.change_user_language(user, %{})

socket =
socket
|> assign(:page_title, "Account Settings")
|> assign(:current_email, user.email)
|> assign(:email_form, to_form(email_changeset))
|> assign(:password_form, to_form(password_changeset))
|> assign(:name_form, to_form(name_changeset))
|> assign(:language_form, to_form(language_changeset))
|> assign(:trigger_submit, false)

{:ok, socket}
Expand Down Expand Up @@ -154,4 +201,64 @@ defmodule AdminWeb.UserLive.Settings do
{:noreply, assign(socket, password_form: to_form(changeset, action: :insert))}
end
end

def handle_event("validate_name", params, socket) do
%{"user" => user_params} = params

name_form =
socket.assigns.current_scope.user
|> Accounts.change_user_name(user_params)
|> Map.put(:action, :validate)
|> to_form()

{:noreply, assign(socket, name_form: name_form)}
end

def handle_event("update_name", params, socket) do
%{"user" => user_params} = params
user = socket.assigns.current_scope.user
true = Accounts.sudo_mode?(user)

case Accounts.update_user_name(
user,
user_params
) do
{:ok, _user} ->
info = "The user name has been updated."
{:noreply, socket |> put_flash(:info, info)}

%Ecto.Changeset{} = changeset ->
{:noreply, assign(socket, name_form: to_form(changeset, action: :insert))}
end
end

def handle_event("validate_language", params, socket) do
%{"user" => user_params} = params

language_form =
socket.assigns.current_scope.user
|> Accounts.change_user_language(user_params)
|> Map.put(:action, :validate)
|> to_form()

{:noreply, assign(socket, language_form: language_form)}
end

def handle_event("update_language", params, socket) do
%{"user" => user_params} = params
user = socket.assigns.current_scope.user
true = Accounts.sudo_mode?(user)

case Accounts.update_user_language(
user,
user_params
) do
{:ok, _user} ->
info = "The user language has been updated."
{:noreply, socket |> put_flash(:info, info)}

%Ecto.Changeset{} = changeset ->
{:noreply, assign(socket, name_form: to_form(changeset, action: :insert))}
end
end
end
10 changes: 10 additions & 0 deletions priv/repo/migrations/20251217123725_add_user_name_language.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
defmodule Admin.Repo.Migrations.AddUserNameLanguage do
use Ecto.Migration

def change do
alter table(:admins) do
add :name, :string
add :language, :string, default: "en"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it null: false?

end
end
end
Loading
Loading