Extract ad restriction application to new module

This commit is contained in:
Liam 2024-06-22 12:06:48 -04:00
parent ad2b4b004c
commit 180aa23478
3 changed files with 110 additions and 43 deletions

View file

@ -7,53 +7,61 @@ defmodule Philomena.Adverts do
alias Philomena.Repo alias Philomena.Repo
alias Philomena.Adverts.Advert alias Philomena.Adverts.Advert
alias Philomena.Adverts.Restrictions
alias Philomena.Adverts.Uploader alias Philomena.Adverts.Uploader
@doc """
Gets an advert that is currently live.
Returns the advert, or nil if nothing was live.
iex> random_live()
nil
iex> random_live()
%Advert{}
"""
def random_live do def random_live do
random_live_for_tags([])
end
@doc """
Gets an advert that is currently live, matching any tagging restrictions
for the given image.
Returns the advert, or nil if nothing was live.
## Examples
iex> random_live(%Image{})
nil
iex> random_live(%Image{})
%Advert{}
"""
def random_live(image) do
image
|> Repo.preload(:tags)
|> Map.get(:tags)
|> Enum.map(& &1.name)
|> random_live_for_tags()
end
defp random_live_for_tags(tags) do
now = DateTime.utc_now() now = DateTime.utc_now()
restrictions = Restrictions.tags(tags)
Advert query =
|> where(live: true, restrictions: "none") from a in Advert,
|> where([a], a.start_date < ^now and a.finish_date > ^now) where: a.live == true,
|> order_by(asc: fragment("random()")) where: a.restrictions in ^restrictions,
|> limit(1) where: a.start_date < ^now and a.finish_date > ^now,
|> Repo.one() order_by: [asc: fragment("random()")],
end limit: 1
def random_live_for(image) do Repo.one(query)
image = Repo.preload(image, :tags)
now = DateTime.utc_now()
Advert
|> where(live: true)
|> where([a], a.restrictions in ^restrictions(image))
|> where([a], a.start_date < ^now and a.finish_date > ^now)
|> order_by(asc: fragment("random()"))
|> limit(1)
|> Repo.one()
end
defp sfw?(image) do
image_tags = MapSet.new(image.tags |> Enum.map(& &1.name))
sfw_tags = MapSet.new(["safe", "suggestive"])
intersect = MapSet.intersection(image_tags, sfw_tags)
MapSet.size(intersect) > 0
end
defp nsfw?(image) do
image_tags = MapSet.new(image.tags |> Enum.map(& &1.name))
nsfw_tags = MapSet.new(["questionable", "explicit"])
intersect = MapSet.intersection(image_tags, nsfw_tags)
MapSet.size(intersect) > 0
end
defp restrictions(image) do
restrictions = ["none"]
restrictions = if nsfw?(image), do: ["nsfw" | restrictions], else: restrictions
restrictions = if sfw?(image), do: ["sfw" | restrictions], else: restrictions
restrictions
end end
@doc """ @doc """
@ -102,7 +110,7 @@ defmodule Philomena.Adverts do
end end
@doc """ @doc """
Updates an advert. Updates an Advert without updating its image.
## Examples ## Examples
@ -119,6 +127,18 @@ defmodule Philomena.Adverts do
|> Repo.update() |> Repo.update()
end end
@doc """
Updates the image for an Advert.
## Examples
iex> update_advert_image(advert, %{image: new_value})
{:ok, %Advert{}}
iex> update_advert(advert, %{image: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_advert_image(%Advert{} = advert, attrs) do def update_advert_image(%Advert{} = advert, attrs) do
advert advert
|> Advert.changeset(attrs) |> Advert.changeset(attrs)

View file

@ -0,0 +1,47 @@
defmodule Philomena.Adverts.Restrictions do
@moduledoc """
Advert restriction application.
"""
@type restriction :: String.t()
@type restriction_list :: [restriction()]
@type tag_list :: [String.t()]
@nsfw_tags MapSet.new(["questionable", "explicit"])
@sfw_tags MapSet.new(["safe", "suggestive"])
@doc """
Calculates the restrictions available to a given tag list.
Returns a list containing `"none"`, and neither or one of `"sfw"`, `"nsfw"`.
## Examples
iex> tags([])
["none"]
iex> tags(["safe"])
["sfw", "none"]
iex> tags(["explicit"])
["nsfw", "none"]
"""
@spec tags(tag_list()) :: restriction_list()
def tags(tags) do
tags = MapSet.new(tags)
["none"]
|> apply_if(tags, @nsfw_tags, "nsfw")
|> apply_if(tags, @sfw_tags, "sfw")
end
@spec apply_if(restriction_list(), MapSet.t(), MapSet.t(), restriction()) :: restriction_list()
defp apply_if(restrictions, tags, test, new_restriction) do
if MapSet.disjoint?(tags, test) do
restrictions
else
[new_restriction | restrictions]
end
end
end

View file

@ -19,7 +19,7 @@ defmodule PhilomenaWeb.AdvertPlug do
do: Conn.assign(conn, :advert, record_impression(Adverts.random_live())) do: Conn.assign(conn, :advert, record_impression(Adverts.random_live()))
defp maybe_assign_ad(conn, image, true), defp maybe_assign_ad(conn, image, true),
do: Conn.assign(conn, :advert, record_impression(Adverts.random_live_for(image))) do: Conn.assign(conn, :advert, record_impression(Adverts.random_live(image)))
defp maybe_assign_ad(conn, _image, _false), defp maybe_assign_ad(conn, _image, _false),
do: Conn.assign(conn, :advert, nil) do: Conn.assign(conn, :advert, nil)