1
0
mirror of https://github.com/algora-io/tv.git synced 2025-03-17 20:17:45 +02:00
2024-08-22 23:48:46 +03:00

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