diff --git a/lib/live_beats/accounts/user.ex b/lib/live_beats/accounts/user.ex index e6c007f..e65ba48 100644 --- a/lib/live_beats/accounts/user.ex +++ b/lib/live_beats/accounts/user.ex @@ -4,6 +4,8 @@ defmodule LiveBeats.Accounts.User do alias LiveBeats.Accounts.{User, Identity} + @max_songs 30 + schema "users" do field :email, :string field :name, :string @@ -14,6 +16,7 @@ defmodule LiveBeats.Accounts.User do field :active_profile_user_id, :id field :avatar_url, :string field :external_homepage_url, :string + field :songs_number, :integer has_many :identities, Identity @@ -59,6 +62,13 @@ defmodule LiveBeats.Accounts.User do |> validate_username() end + def songs_changeset(%User{} = user, params) do + user + |> cast(params, [:songs_number]) + |> validate_required([:songs_number]) + |> validate_number(:songs_number, less_than_or_equal_to: @max_songs) + end + defp validate_email(changeset) do changeset |> validate_required([:email]) diff --git a/lib/live_beats/media_library.ex b/lib/live_beats/media_library.ex index d38a68e..2a413d0 100644 --- a/lib/live_beats/media_library.ex +++ b/lib/live_beats/media_library.ex @@ -157,6 +157,16 @@ defmodule LiveBeats.MediaLibrary do Ecto.Multi.insert(acc, {:song, ref}, chset) end) + |> Ecto.Multi.update(:update_songs_number, fn acc -> + new_songs = acc |> Enum.filter(&match?({{:song, _ref}, _}, &1)) |> Enum.count() + user = Accounts.get_user!(user.id) + + user_params = %{ + songs_number: user.songs_number + new_songs + } + + Accounts.User.songs_changeset(user, user_params) + end) case LiveBeats.Repo.transaction(multi) do {:ok, results} -> @@ -169,8 +179,17 @@ defmodule LiveBeats.MediaLibrary do end) |> Enum.into(%{})} - {:error, _failed_op, _failed_val, _changes} -> - {:error, :invalid} + {:error, failed_op, failed_val, _changes} -> + reason = + case {failed_op, format_errors(failed_val)} do + {:update_songs_number, %{songs_number: _errors}} -> + {:songs_number, :songs_limit_exceeded} + + _ -> + {:form, :invalid} + end + + {:error, reason} end end @@ -338,4 +357,12 @@ defmodule LiveBeats.MediaLibrary do end defp topic(user_id) when is_integer(user_id), do: "profile:#{user_id}" + + defp format_errors(changeset) do + Changeset.traverse_errors(changeset, fn {message, opts} -> + Regex.replace(~r"%{(\w+)}", message, fn _, key -> + opts |> Keyword.get(String.to_existing_atom(key), key) |> to_string() + end) + end) + end end diff --git a/lib/live_beats_web/live/song_live/upload_form_component.ex b/lib/live_beats_web/live/song_live/upload_form_component.ex index b14bfe9..f4e1793 100644 --- a/lib/live_beats_web/live/song_live/upload_form_component.ex +++ b/lib/live_beats_web/live/song_live/upload_form_component.ex @@ -52,12 +52,16 @@ defmodule LiveBeatsWeb.SongLive.UploadFormComponent do case MediaLibrary.import_songs(current_user, changesets, &consume_entry(socket, &1, &2)) do {:ok, songs} -> {:noreply, - socket - |> put_flash(:info, "#{map_size(songs)} song(s) uploaded") - |> push_redirect(to: profile_path(current_user))} + socket + |> put_flash(:info, "#{map_size(songs)} song(s) uploaded") + |> push_redirect(to: profile_path(current_user))} - {:error, _reason} -> - {:noreply, socket} + {:error, error} -> + updated_socket = + socket + |> update(:error_messages, &Enum.take(&1 ++ [error], -10)) + + {:noreply, updated_socket} end end end @@ -148,6 +152,11 @@ defmodule LiveBeatsWeb.SongLive.UploadFormComponent do defp file_error(%{kind: :not_accepted} = assigns), do: ~H|not a valid MP3 file| defp file_error(%{kind: :too_many_files} = assigns), do: ~H|too many files| + defp file_error(%{kind: :songs_limit_exceeded} = assigns), + do: ~H|You exceeded the limit of songs per account| + + defp file_error(%{kind: :invalid} = assigns), do: ~H|Something went wrong| + defp file_error(%{kind: {msg, opts}} = assigns) when is_binary(msg) and is_list(opts) do ~H|<%= LiveBeatsWeb.ErrorHelpers.translate_error(@kind) %>| end @@ -190,7 +199,7 @@ defmodule LiveBeatsWeb.SongLive.UploadFormComponent do socket |> cancel_upload(:mp3, entry.ref) |> drop_changeset(entry.ref) - |> update(:error_messages, &(Enum.take(&1 ++ [{entry.client_name, reason}], -10))) + |> update(:error_messages, &Enum.take(&1 ++ [{entry.client_name, reason}], -10)) end defp get_entry!(socket, entry_ref) do diff --git a/priv/repo/migrations/20211117174157_add_songs_number_to_users.exs b/priv/repo/migrations/20211117174157_add_songs_number_to_users.exs new file mode 100644 index 0000000..e3fae99 --- /dev/null +++ b/priv/repo/migrations/20211117174157_add_songs_number_to_users.exs @@ -0,0 +1,20 @@ +defmodule LiveBeats.Repo.Migrations.AddSongsNumberToUsers do + use Ecto.Migration + + def up do + alter table(:users) do + add :songs_number, :integer, null: false, default: 0 + end + + execute(" + UPDATE users set songs_number = + (SELECT count (*) from songs + where songs.user_id = users.id)") + end + + def down do + alter table(:users) do + remove :songs_number + end + end +end