From 8286517841b699d37917d7ccfb9da58c816be02f Mon Sep 17 00:00:00 2001 From: GuilhermePSF Date: Sat, 26 Jul 2025 22:39:00 +0100 Subject: [PATCH 1/5] feat: create schema for user preferences --- lib/atlas/accounts/user_preferences.ex | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 lib/atlas/accounts/user_preferences.ex diff --git a/lib/atlas/accounts/user_preferences.ex b/lib/atlas/accounts/user_preferences.ex new file mode 100644 index 0000000..2d9616e --- /dev/null +++ b/lib/atlas/accounts/user_preferences.ex @@ -0,0 +1,30 @@ +defmodule Atlas.Accounts.UserPreference do + @moduledoc """ + Schema for storing a user's preference. + """ + + use Ecto.Schema + import Ecto.Changeset + + @primary_key {:id, :binary_id, autogenerate: true} + @foreign_key_type :binary_id + + @languages ~w(pt-PT en-US) + + schema "user_preferences" do + field :language, :string + + belongs_to :user, Atlas.Accounts.User + + timestamps() + end + + def changeset(user_preference, attrs) do + user_preference + |> cast(attrs, [:user_id, :language]) + |> validate_required([:user_id, :language]) + |> validate_inclusion(:language, @languages) + |> assoc_constraint(:user) + |> unique_constraint(:user_id) + end +end From a76acbfc328fc406936713ae8af615098e7c4da0 Mon Sep 17 00:00:00 2001 From: GuilhermePSF Date: Sat, 26 Jul 2025 22:39:36 +0100 Subject: [PATCH 2/5] feat: create migration --- .../20250726211654_create_user_preferences.exs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 priv/repo/migrations/20250726211654_create_user_preferences.exs diff --git a/priv/repo/migrations/20250726211654_create_user_preferences.exs b/priv/repo/migrations/20250726211654_create_user_preferences.exs new file mode 100644 index 0000000..33c17e1 --- /dev/null +++ b/priv/repo/migrations/20250726211654_create_user_preferences.exs @@ -0,0 +1,18 @@ +defmodule Atlas.Repo.Migrations.CreateUserPreferences do + use Ecto.Migration + + def change do + create table(:user_preferences) do + add :user_id, references(:users, type: :uuid, on_delete: :delete_all), null: false + add :language, :string, null: false + + timestamps() + end + + create unique_index(:user_preferences, [:user_id]) + + create constraint(:user_preferences, :language_must_be_valid, + check: "language IN ('pt-PT', 'en-US')" + ) + end +end From 06f60ebe518883dc1ba3765dbe556b4fa96863b4 Mon Sep 17 00:00:00 2001 From: GuilhermePSF Date: Sat, 26 Jul 2025 22:41:07 +0100 Subject: [PATCH 3/5] feat: extend helpers --- lib/atlas/accounts.ex | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/lib/atlas/accounts.ex b/lib/atlas/accounts.ex index 38a05f2..f0f94ac 100644 --- a/lib/atlas/accounts.ex +++ b/lib/atlas/accounts.ex @@ -5,7 +5,7 @@ defmodule Atlas.Accounts do use Atlas.Context - alias Atlas.Accounts.{User, UserNotifier, UserSession, UserToken} + alias Atlas.Accounts.{User, UserNotifier, UserPreference, UserSession, UserToken} ## Database getters @@ -488,4 +488,43 @@ defmodule Atlas.Accounts do Guardian.DB.revoke_all(user_session.id) Repo.delete(user_session) end + + ## User Preference + + @doc """ + Gets the language preference for a given user. + + ## Examples + + iex> get_user_preference(1) + %UserPreference{} + + iex> get_user_preference(999) + nil + """ + def get_user_preference(user_id) do + Repo.get_by(UserPreference, user_id: user_id) + end + + @doc """ + Sets the language preference for a given user. + + If the preference exists, it replaces it. + + ## Examples + + iex> set_user_language(1, "pt-PT") + {:ok, %UserPreference{}} + + iex> set_user_language(1, "invalid") + {:error, %Ecto.Changeset{}} + """ + def set_user_language(user_id, language) do + %UserPreference{} + |> UserPreference.changeset(%{user_id: user_id, language: language}) + |> Repo.insert( + on_conflict: :replace_all, + conflict_target: :user_id + ) + end end From fa8779e80024482e1d6d2887cc402ce7dd123a10 Mon Sep 17 00:00:00 2001 From: GuilhermePSF Date: Sat, 26 Jul 2025 22:49:36 +0100 Subject: [PATCH 4/5] feat: update set user language to only update language on conflict and add default language --- lib/atlas/accounts.ex | 4 ++-- .../migrations/20250726211654_create_user_preferences.exs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/atlas/accounts.ex b/lib/atlas/accounts.ex index f0f94ac..3083fb0 100644 --- a/lib/atlas/accounts.ex +++ b/lib/atlas/accounts.ex @@ -509,7 +509,7 @@ defmodule Atlas.Accounts do @doc """ Sets the language preference for a given user. - If the preference exists, it replaces it. + If the preference exists, it updates only the language field. ## Examples @@ -523,7 +523,7 @@ defmodule Atlas.Accounts do %UserPreference{} |> UserPreference.changeset(%{user_id: user_id, language: language}) |> Repo.insert( - on_conflict: :replace_all, + on_conflict: [set: [language: language]], conflict_target: :user_id ) end diff --git a/priv/repo/migrations/20250726211654_create_user_preferences.exs b/priv/repo/migrations/20250726211654_create_user_preferences.exs index 33c17e1..ff7a4c4 100644 --- a/priv/repo/migrations/20250726211654_create_user_preferences.exs +++ b/priv/repo/migrations/20250726211654_create_user_preferences.exs @@ -12,7 +12,7 @@ defmodule Atlas.Repo.Migrations.CreateUserPreferences do create unique_index(:user_preferences, [:user_id]) create constraint(:user_preferences, :language_must_be_valid, - check: "language IN ('pt-PT', 'en-US')" - ) + check: "language IN ('pt-PT', 'en-US')" + ) end end From 3f6a073e541e02f8745b6d41e03953d40d523a61 Mon Sep 17 00:00:00 2001 From: GuilhermePSF Date: Sat, 26 Jul 2025 22:55:22 +0100 Subject: [PATCH 5/5] feat: readd function to get user language by id --- lib/atlas/accounts.ex | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/lib/atlas/accounts.ex b/lib/atlas/accounts.ex index 3083fb0..9f28781 100644 --- a/lib/atlas/accounts.ex +++ b/lib/atlas/accounts.ex @@ -506,6 +506,28 @@ defmodule Atlas.Accounts do Repo.get_by(UserPreference, user_id: user_id) end + @doc """ + Gets the language string for a given user. + + Returns `nil` if no preference is set. + + ## Examples + + iex> get_user_language(1) + "pt-PT" + + iex> get_user_language(999) + nil + """ + def get_user_language(user_id) do + Repo.one( + from up in UserPreference, + where: up.user_id == ^user_id, + select: up.language, + limit: 1 + ) + end + @doc """ Sets the language preference for a given user.