lib/openagents/notifications/notification.ex

58e6347eeb72 · 1 KB

defmodule OpenAgents.Notifications.Notification do
  @moduledoc """
  One durable delivery record addressed to one account.

  It is a pointer, not a copy. Nothing here renders without a second read of
  the issue through the recipient's own visibility, so a row that outlives the
  recipient's access to the repository reveals nothing.

  Seven kinds. `mention` and `issue_comment` announce something somebody wrote.
  `assigned`, `unassigned`, `labeled`, `unlabeled` and `state_changed` announce
  a change to the issue itself, derived from the difference between the issue
  before and after an update. The record still names no label and no state: the
  kind says which field moved, and reading the issue says what it moved to.
  """

  use Ecto.Schema
  import Ecto.Changeset

  alias OpenAgents.Accounts.User
  alias OpenAgents.Issues.Comment
  alias OpenAgents.Issues.Issue
  alias OpenAgents.Repositories.Repository

  @primary_key {:id, :binary_id, autogenerate: true}
  @foreign_key_type :binary_id

  @kinds ~w(mention issue_comment assigned unassigned labeled unlabeled state_changed)

  schema "notifications" do
    field :kind, :string
    field :actor_login, :string
    field :dedupe_key, :string
    field :read_at, :utc_datetime

    belongs_to :user, User
    belongs_to :repository, Repository
    belongs_to :issue, Issue, type: :id
    belongs_to :comment, Comment, type: :id

    timestamps(type: :utc_datetime)
  end

  def kinds, do: @kinds

  @doc false
  def changeset(notification, attrs) do
    notification
    |> cast(attrs, [:kind, :actor_login, :dedupe_key, :read_at])
    |> validate_required([:kind, :dedupe_key])
    |> validate_inclusion(:kind, @kinds)
    |> unique_constraint([:user_id, :dedupe_key])
    |> foreign_key_constraint(:user_id)
    |> foreign_key_constraint(:repository_id)
    |> foreign_key_constraint(:issue_id)
    |> foreign_key_constraint(:comment_id)
  end
end