defmodule Frenzy.Task.CreateItem do require Logger use Task alias Frenzy.Repo def start_link(feed, entry) do Task.start_link(__MODULE__, :run, [feed, entry]) end def run(feed, entry) do Logger.metadata(item_task_id: generate_task_id()) url = get_real_url(entry) Logger.debug("Creating item for #{url}") date = entry.date |> Timex.Timezone.convert(:utc) |> case do {:error, reason} -> Logger.debug("Couldn't convert date '#{entry.date}' to UTC: #{reason}") nil utc_date -> DateTime.truncate(utc_date, :second) end item_params = %{ guid: entry.guid, title: entry.title, url: url, date: date, creator: "", content: entry.content } feed = Repo.preload(feed, :pipeline) result = if feed.pipeline do feed.pipeline.stages |> Enum.reduce({:ok, item_params}, fn stage, {:ok, item_params} -> apply(String.to_existing_atom("Elixir." <> stage["module_name"]), :apply, [ stage["options"], item_params ]) _stage, :tombstone -> :tombstone _stage, {:error, _error} = error -> error end) else {:ok, item_params} end case result do {:err, error} -> Logger.error(error) {:ok, item_params} -> changeset = Ecto.build_assoc(feed, :items, item_params) case Repo.insert(changeset) do {:ok, item} -> item {:error, changeset} -> Logger.error("Error inserting item #{entry.guid}") Logger.error(changeset) end :tombstone -> changeset = Ecto.build_assoc(feed, :items, %{ guid: item_params.guid, tombstone: true }) case Repo.insert(changeset) do {:ok, item} -> item {:error, changeset} -> Logger.error("Error inserting tombstone for #{entry.guid}") Logger.error(changeset) end end end defp get_real_url(entry) do links = Enum.reject(entry.links, fn {_, rel} -> rel == "shorturl" end) case Enum.find(links, fn {_, rel} -> rel == "related" end) do nil -> case Enum.find(links, fn {_, rel} -> rel == "alternate" end) do nil -> [{href, _} | _] = links href {href, _} -> href end {href, _} -> href end end # from https://github.com/elixir-plug/plug/blob/v1.8.3/lib/plug/request_id.ex#L60 defp generate_task_id() do binary = << System.system_time(:nanosecond)::64, :erlang.phash2({node(), self()}, 16_777_216)::24, :erlang.unique_integer()::32 >> Base.url_encode64(binary) end end