mirror of
https://github.com/algora-io/tv.git
synced 2025-03-17 20:17:45 +02:00
280 lines
5.5 KiB
Elixir
280 lines
5.5 KiB
Elixir
defmodule Algora.Ads do
|
|
@moduledoc """
|
|
The Ads context.
|
|
"""
|
|
|
|
import Ecto.Query, warn: false
|
|
alias Algora.Repo
|
|
|
|
alias Algora.Ads.{Ad, Visit, Impression, Events, ContentMetrics, Appearance, ProductReview}
|
|
|
|
@pubsub Algora.PubSub
|
|
|
|
def display_duration, do: :timer.minutes(2)
|
|
def rotation_interval, do: :timer.minutes(30)
|
|
|
|
def unsubscribe_to_ads() do
|
|
Phoenix.PubSub.unsubscribe(@pubsub, topic())
|
|
end
|
|
|
|
def subscribe_to_ads() do
|
|
Phoenix.PubSub.subscribe(@pubsub, topic())
|
|
end
|
|
|
|
defp topic(), do: "ads"
|
|
|
|
defp broadcast!(topic, msg) do
|
|
Phoenix.PubSub.broadcast!(@pubsub, topic, {__MODULE__, msg})
|
|
end
|
|
|
|
def broadcast_ad_created!(ad) do
|
|
broadcast!(topic(), %Events.AdCreated{ad: ad})
|
|
end
|
|
|
|
def broadcast_ad_updated!(ad) do
|
|
broadcast!(topic(), %Events.AdUpdated{ad: ad})
|
|
end
|
|
|
|
def broadcast_ad_deleted!(ad) do
|
|
broadcast!(topic(), %Events.AdDeleted{ad: ad})
|
|
end
|
|
|
|
@doc """
|
|
Returns the list of ads.
|
|
|
|
## Examples
|
|
|
|
iex> list_ads()
|
|
[%Ad{}, ...]
|
|
|
|
"""
|
|
|
|
def list_ads do
|
|
Ad
|
|
|> order_by(asc: :id)
|
|
|> Repo.all()
|
|
end
|
|
|
|
def list_active_ads do
|
|
Ad
|
|
|> where(verified: true, status: :active)
|
|
|> order_by(asc: :id)
|
|
|> Repo.all()
|
|
end
|
|
|
|
@doc """
|
|
Gets a single ad.
|
|
|
|
Raises `Ecto.NoResultsError` if the Ad does not exist.
|
|
|
|
## Examples
|
|
|
|
iex> get_ad!(123)
|
|
%Ad{}
|
|
|
|
iex> get_ad!(456)
|
|
** (Ecto.NoResultsError)
|
|
|
|
"""
|
|
def get_ad!(id), do: Repo.get!(Ad, id)
|
|
|
|
def get_ad_by_slug!(slug) do
|
|
Repo.get_by!(Ad, slug: slug)
|
|
end
|
|
|
|
@doc """
|
|
Creates a ad.
|
|
|
|
## Examples
|
|
|
|
iex> create_ad(%{field: value})
|
|
{:ok, %Ad{}}
|
|
|
|
iex> create_ad(%{field: bad_value})
|
|
{:error, %Ecto.Changeset{}}
|
|
|
|
"""
|
|
def create_ad(attrs \\ %{}) do
|
|
%Ad{status: :active, verified: true}
|
|
|> Ad.changeset(attrs)
|
|
|> Repo.insert()
|
|
end
|
|
|
|
@doc """
|
|
Updates a ad.
|
|
|
|
## Examples
|
|
|
|
iex> update_ad(ad, %{field: new_value})
|
|
{:ok, %Ad{}}
|
|
|
|
iex> update_ad(ad, %{field: bad_value})
|
|
{:error, %Ecto.Changeset{}}
|
|
|
|
"""
|
|
def update_ad(%Ad{} = ad, attrs) do
|
|
ad
|
|
|> Ad.changeset(attrs)
|
|
|> Repo.update()
|
|
end
|
|
|
|
@doc """
|
|
Deletes a ad.
|
|
|
|
## Examples
|
|
|
|
iex> delete_ad(ad)
|
|
{:ok, %Ad{}}
|
|
|
|
iex> delete_ad(ad)
|
|
{:error, %Ecto.Changeset{}}
|
|
|
|
"""
|
|
def delete_ad(%Ad{} = ad) do
|
|
Repo.delete(ad)
|
|
end
|
|
|
|
@doc """
|
|
Returns an `%Ecto.Changeset{}` for tracking ad changes.
|
|
|
|
## Examples
|
|
|
|
iex> change_ad(ad)
|
|
%Ecto.Changeset{data: %Ad{}}
|
|
|
|
"""
|
|
def change_ad(%Ad{} = ad, attrs \\ %{}) do
|
|
Ad.changeset(ad, attrs)
|
|
end
|
|
|
|
def track_visit(attrs \\ %{}) do
|
|
%Visit{}
|
|
|> Visit.changeset(attrs)
|
|
|> Repo.insert()
|
|
end
|
|
|
|
def track_impressions(attrs \\ %{}) do
|
|
%Impression{}
|
|
|> Impression.changeset(attrs)
|
|
|> Repo.insert()
|
|
end
|
|
|
|
def get_current_index(ads) do
|
|
:os.system_time(:millisecond)
|
|
|> div(rotation_interval())
|
|
|> rem(length(ads))
|
|
end
|
|
|
|
def rotate_ads(ads, index \\ nil) do
|
|
index = index || get_current_index(ads)
|
|
Enum.concat(Enum.drop(ads, index), Enum.take(ads, index))
|
|
end
|
|
|
|
def next_slot(time \\ DateTime.utc_now()) do
|
|
time
|
|
|> DateTime.truncate(:millisecond)
|
|
|> DateTime.add(ms_until_next_slot(time), :millisecond)
|
|
end
|
|
|
|
def time_until_next_slot(time \\ DateTime.utc_now()) do
|
|
DateTime.diff(next_slot(time), time, :millisecond)
|
|
end
|
|
|
|
defp ms_until_next_slot(time) do
|
|
rotation_interval() - rem(DateTime.to_unix(time, :millisecond), rotation_interval())
|
|
end
|
|
|
|
def list_content_metrics do
|
|
Repo.all(ContentMetrics)
|
|
|> Repo.preload(video: [:appearances, :product_reviews])
|
|
end
|
|
|
|
def create_content_metrics(attrs \\ %{}) do
|
|
%ContentMetrics{}
|
|
|> ContentMetrics.changeset(attrs)
|
|
|> Repo.insert()
|
|
end
|
|
|
|
def change_content_metrics(%ContentMetrics{} = content_metrics, attrs \\ %{}) do
|
|
ContentMetrics.changeset(content_metrics, attrs)
|
|
end
|
|
|
|
@doc """
|
|
Gets a single content_metrics.
|
|
|
|
Raises `Ecto.NoResultsError` if the ContentMetrics does not exist.
|
|
|
|
## Examples
|
|
|
|
iex> get_content_metrics!(123)
|
|
%ContentMetrics{}
|
|
|
|
iex> get_content_metrics!(456)
|
|
** (Ecto.NoResultsError)
|
|
|
|
"""
|
|
def get_content_metrics!(id) do
|
|
Repo.get!(ContentMetrics, id)
|
|
end
|
|
|
|
@doc """
|
|
Updates a content_metrics.
|
|
|
|
## Examples
|
|
|
|
iex> update_content_metrics(content_metrics, %{field: new_value})
|
|
{:ok, %ContentMetrics{}}
|
|
|
|
iex> update_content_metrics(content_metrics, %{field: bad_value})
|
|
{:error, %Ecto.Changeset{}}
|
|
|
|
"""
|
|
def update_content_metrics(%ContentMetrics{} = content_metrics, attrs) do
|
|
content_metrics
|
|
|> ContentMetrics.changeset(attrs)
|
|
|> Repo.update()
|
|
end
|
|
|
|
def create_appearance(attrs \\ %{}) do
|
|
%Appearance{}
|
|
|> Appearance.changeset(attrs)
|
|
|> Repo.insert()
|
|
end
|
|
|
|
def change_appearance(%Appearance{} = appearance, attrs \\ %{}) do
|
|
Appearance.changeset(appearance, attrs)
|
|
end
|
|
|
|
def create_product_review(attrs \\ %{}) do
|
|
%ProductReview{}
|
|
|> ProductReview.changeset(attrs)
|
|
|> Repo.insert()
|
|
end
|
|
|
|
def change_product_review(%ProductReview{} = product_review, attrs \\ %{}) do
|
|
ProductReview.changeset(product_review, attrs)
|
|
end
|
|
|
|
def list_appearances(ad) do
|
|
Appearance
|
|
|> where(ad_id: ^ad.id)
|
|
|> preload(video: :user)
|
|
|> Repo.all()
|
|
end
|
|
|
|
def list_product_reviews(ad) do
|
|
ProductReview
|
|
|> where(ad_id: ^ad.id)
|
|
|> preload(video: [:user, :content_metrics])
|
|
|> Repo.all()
|
|
end
|
|
|
|
def list_content_metrics(appearances) do
|
|
video_ids = Enum.map(appearances, & &1.video_id)
|
|
|
|
ContentMetrics
|
|
|> where([cm], cm.video_id in ^video_ids)
|
|
|> Repo.all()
|
|
end
|
|
end
|