2020-07-09 17:24:28 +02:00
|
|
|
defmodule Mobilizon.Discussions.Discussion.TitleSlug do
|
|
|
|
@moduledoc """
|
|
|
|
Module to generate the slug for discussions
|
|
|
|
"""
|
|
|
|
use EctoAutoslugField.Slug, from: [:title, :id], to: :slug
|
|
|
|
|
2021-09-28 19:40:37 +02:00
|
|
|
@spec build_slug([String.t()], Ecto.Changeset.t()) :: String.t()
|
2020-07-09 17:24:28 +02:00
|
|
|
def build_slug([title, id], %Ecto.Changeset{valid?: true}) do
|
|
|
|
[title, ShortUUID.encode!(id)]
|
|
|
|
|> Enum.join("-")
|
|
|
|
|> Slugger.slugify()
|
|
|
|
end
|
|
|
|
|
|
|
|
def build_slug(_sources, %Ecto.Changeset{valid?: false}), do: ""
|
|
|
|
end
|
|
|
|
|
|
|
|
defmodule Mobilizon.Discussions.Discussion do
|
|
|
|
@moduledoc """
|
|
|
|
Represents a discussion
|
|
|
|
"""
|
|
|
|
|
|
|
|
use Ecto.Schema
|
|
|
|
|
|
|
|
import Ecto.Changeset
|
|
|
|
|
|
|
|
alias Mobilizon.Actors
|
|
|
|
alias Mobilizon.Actors.Actor
|
|
|
|
alias Mobilizon.Discussions.Comment
|
|
|
|
alias Mobilizon.Discussions.Discussion.TitleSlug
|
|
|
|
alias Mobilizon.Web.Endpoint
|
|
|
|
alias Mobilizon.Web.Router.Helpers, as: Routes
|
2021-03-24 15:47:03 +01:00
|
|
|
import Mobilizon.Web.Gettext, only: [dgettext: 2]
|
2020-07-09 17:24:28 +02:00
|
|
|
|
|
|
|
@type t :: %__MODULE__{
|
2021-09-28 19:40:37 +02:00
|
|
|
id: String.t(),
|
2020-07-09 17:24:28 +02:00
|
|
|
creator: Actor.t(),
|
|
|
|
actor: Actor.t(),
|
|
|
|
title: String.t(),
|
|
|
|
url: String.t(),
|
|
|
|
slug: String.t(),
|
|
|
|
last_comment: Comment.t(),
|
|
|
|
comments: list(Comment.t())
|
|
|
|
}
|
|
|
|
|
|
|
|
@required_attrs [:actor_id, :creator_id, :title, :last_comment_id, :url, :id]
|
|
|
|
@optional_attrs []
|
|
|
|
@attrs @required_attrs ++ @optional_attrs
|
|
|
|
|
|
|
|
@primary_key {:id, Ecto.UUID, autogenerate: true}
|
|
|
|
|
|
|
|
schema "discussions" do
|
|
|
|
field(:title, :string)
|
|
|
|
field(:slug, TitleSlug.Type)
|
|
|
|
field(:url, :string)
|
|
|
|
belongs_to(:creator, Actor)
|
|
|
|
belongs_to(:actor, Actor)
|
|
|
|
belongs_to(:last_comment, Comment)
|
|
|
|
has_many(:comments, Comment, foreign_key: :discussion_id)
|
|
|
|
|
|
|
|
timestamps(type: :utc_datetime)
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc false
|
2021-09-24 16:46:42 +02:00
|
|
|
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
|
2020-07-09 17:24:28 +02:00
|
|
|
def changeset(%__MODULE__{} = discussion, attrs) do
|
|
|
|
discussion
|
|
|
|
|> cast(attrs, @attrs)
|
|
|
|
|> maybe_generate_id()
|
2021-03-24 15:47:03 +01:00
|
|
|
|> validate_required([:title, :id], message: dgettext("errors", "can't be blank"))
|
2020-07-09 17:24:28 +02:00
|
|
|
|> TitleSlug.maybe_generate_slug()
|
|
|
|
|> TitleSlug.unique_constraint()
|
|
|
|
|> maybe_generate_url()
|
|
|
|
|> validate_required(@required_attrs)
|
|
|
|
end
|
|
|
|
|
|
|
|
defp maybe_generate_id(%Ecto.Changeset{} = changeset) do
|
|
|
|
case fetch_field(changeset, :id) do
|
|
|
|
res when res in [:error, {:data, nil}] ->
|
|
|
|
put_change(changeset, :id, Ecto.UUID.generate())
|
|
|
|
|
|
|
|
_ ->
|
|
|
|
changeset
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
@spec maybe_generate_url(Ecto.Changeset.t()) :: Ecto.Changeset.t()
|
|
|
|
defp maybe_generate_url(%Ecto.Changeset{} = changeset) do
|
|
|
|
with res when res in [:error, {:data, nil}] <- fetch_field(changeset, :url),
|
|
|
|
{changes, slug} when changes in [:changes, :data] <-
|
|
|
|
fetch_field(changeset, :slug),
|
|
|
|
{_changes, actor_id} <-
|
|
|
|
fetch_field(changeset, :actor_id),
|
|
|
|
%Actor{preferred_username: preferred_username} <-
|
|
|
|
Actors.get_actor(actor_id),
|
|
|
|
url <- generate_url(preferred_username, slug) do
|
|
|
|
put_change(changeset, :url, url)
|
|
|
|
else
|
|
|
|
_ -> changeset
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
@spec generate_url(String.t(), String.t()) :: String.t()
|
|
|
|
defp generate_url(preferred_username, slug),
|
|
|
|
do: Routes.page_url(Endpoint, :discussion, preferred_username, slug)
|
|
|
|
end
|