diff --git a/lib/philomena/artist_links.ex b/lib/philomena/artist_links.ex index 14a17e42..e5567baf 100644 --- a/lib/philomena/artist_links.ex +++ b/lib/philomena/artist_links.ex @@ -9,8 +9,7 @@ defmodule Philomena.ArtistLinks do alias Philomena.ArtistLinks.ArtistLink alias Philomena.ArtistLinks.AutomaticVerifier - alias Philomena.Badges.Badge - alias Philomena.Badges.Award + alias Philomena.ArtistLinks.BadgeAwarder alias Philomena.Tags.Tag @doc """ @@ -77,32 +76,32 @@ defmodule Philomena.ArtistLinks do |> Repo.update() end - def verify_artist_link(%ArtistLink{} = artist_link, user) do - artist_link_changeset = - artist_link - |> ArtistLink.verify_changeset(user) + @doc """ + Transitions an artist_link to the verified state. + + ## Examples + + iex> verify_artist_link(artist_link, verifying_user) + {:ok, %ArtistLink{}} + + iex> verify_artist_link(artist_link, verifying_user) + :error + + """ + def verify_artist_link(%ArtistLink{} = artist_link, verifying_user) do + artist_link_changeset = ArtistLink.verify_changeset(artist_link, verifying_user) Multi.new() |> Multi.update(:artist_link, artist_link_changeset) - |> Multi.run(:add_award, fn repo, _changes -> - now = DateTime.utc_now() |> DateTime.truncate(:second) - - with badge when not is_nil(badge) <- repo.get_by(limit(Badge, 1), title: "Artist"), - nil <- repo.get_by(limit(Award, 1), badge_id: badge.id, user_id: artist_link.user_id) do - %Award{ - badge_id: badge.id, - user_id: artist_link.user_id, - awarded_by_id: user.id, - awarded_on: now - } - |> Award.changeset(%{}) - |> repo.insert() - else - _ -> - {:ok, nil} - end - end) + |> Multi.run(:add_award, fn _repo, _changes -> BadgeAwarder.award_badge(artist_link) end) |> Repo.transaction() + |> case do + {:ok, %{artist_link: artist_link}} -> + {:ok, artist_link} + + {:error, _operation, _value, _changes} -> + :error + end end def reject_artist_link(%ArtistLink{} = artist_link) do diff --git a/lib/philomena/artist_links/badge_awarder.ex b/lib/philomena/artist_links/badge_awarder.ex new file mode 100644 index 00000000..2e31b13f --- /dev/null +++ b/lib/philomena/artist_links/badge_awarder.ex @@ -0,0 +1,28 @@ +defmodule Philomena.ArtistLinks.BadgeAwarder do + @moduledoc """ + Handles awarding a badge to the user of an associated artist link. + """ + + alias Philomena.Badges + + @badge_title "Artist" + + @doc """ + Awards a badge to an artist with a verified link. + + If the badge with the title `"Artist"` does not exist, no award will be created. + If the user already has an award with that badge title, no award will be created. + + Returns `{:ok, award}`, `{:ok, nil}`, or `{:error, changeset}`. The return value is + suitable for use as the return value to an `Ecto.Multi.run/3` callback. + """ + def award_badge(artist_link) do + with badge when not is_nil(badge) <- Badges.get_badge_by_title(@badge_title), + award when is_nil(award) <- Badges.get_badge_award_for(badge, artist_link.user) do + Badges.create_badge_award(artist_link.user, artist_link.user) + else + _ -> + {:ok, nil} + end + end +end diff --git a/lib/philomena/badges.ex b/lib/philomena/badges.ex index d917f147..494dd752 100644 --- a/lib/philomena/badges.ex +++ b/lib/philomena/badges.ex @@ -38,6 +38,22 @@ defmodule Philomena.Badges do """ def get_badge!(id), do: Repo.get!(Badge, id) + @doc """ + Gets a single badge by its title. + + Returns nil if the Badge does not exist. + + ## Examples + + iex> get_badge_by_title("Artist") + %Badge{} + + iex> get_badge_by_title("Nonexistent") + nil + + """ + def get_badge_by_title(title), do: Repo.get_by(Badge, title: title) + @doc """ Creates a badge. @@ -162,6 +178,24 @@ defmodule Philomena.Badges do """ def get_badge_award!(id), do: Repo.get!(Award, id) + @doc """ + Gets a the badge_award with the given badge type belonging to the user. + + Raises nil if the Badge award does not exist. + + ## Examples + + iex> get_badge_award_for(badge, user) + %Award{} + + iex> get_badge_award_for(badge, user) + nil + + """ + def get_badge_award_for(badge, user) do + Repo.get_by(Award, badge_id: badge.id, user_id: user.id) + end + @doc """ Creates a badge_award. diff --git a/lib/philomena_web/controllers/admin/artist_link/verification_controller.ex b/lib/philomena_web/controllers/admin/artist_link/verification_controller.ex index a1a2f86a..3694f812 100644 --- a/lib/philomena_web/controllers/admin/artist_link/verification_controller.ex +++ b/lib/philomena_web/controllers/admin/artist_link/verification_controller.ex @@ -13,12 +13,12 @@ defmodule PhilomenaWeb.Admin.ArtistLink.VerificationController do preload: [:user] def create(conn, _params) do - {:ok, result} = + {:ok, artist_link} = ArtistLinks.verify_artist_link(conn.assigns.artist_link, conn.assigns.current_user) conn |> put_flash(:info, "Artist link successfully verified.") - |> moderation_log(details: &log_details/2, data: result.artist_link) + |> moderation_log(details: &log_details/2, data: artist_link) |> redirect(to: ~p"/admin/artist_links") end