019d694d2a
Closes #1059 Signed-off-by: Thomas Citharel <tcit@tcit.fr>
172 lines
4.3 KiB
Elixir
172 lines
4.3 KiB
Elixir
defmodule Mobilizon.Posts do
|
|
@moduledoc """
|
|
The Posts context.
|
|
"""
|
|
alias Mobilizon.Actors.Actor
|
|
alias Mobilizon.Events.Tag
|
|
alias Mobilizon.Posts.Post
|
|
alias Mobilizon.Service.Export.Cachable
|
|
alias Mobilizon.Storage.{Page, Repo}
|
|
|
|
import Ecto.Query
|
|
require Logger
|
|
|
|
@post_preloads [:author, :attributed_to, :picture, :media, :tags]
|
|
|
|
import EctoEnum
|
|
|
|
defenum(PostVisibility, :post_visibility, [
|
|
:public,
|
|
:unlisted,
|
|
:restricted,
|
|
:private
|
|
])
|
|
|
|
@spec list_public_local_posts(integer | nil, integer | nil) :: Page.t(Post.t())
|
|
def list_public_local_posts(page \\ nil, limit \\ nil) do
|
|
Post
|
|
|> filter_public()
|
|
|> filter_local()
|
|
|> preload_post_associations()
|
|
|> Page.build_page(page, limit)
|
|
end
|
|
|
|
@spec list_posts_for_stream :: Enum.t()
|
|
def list_posts_for_stream do
|
|
Post
|
|
|> filter_public()
|
|
|> Repo.stream()
|
|
end
|
|
|
|
@doc """
|
|
Returns the list of recent posts for a group
|
|
"""
|
|
@spec get_posts_for_group(Actor.t(), integer | nil, integer | nil) :: Page.t()
|
|
def get_posts_for_group(%Actor{id: group_id}, page \\ nil, limit \\ nil) do
|
|
group_id
|
|
|> do_get_posts_for_group()
|
|
|> Page.build_page(page, limit)
|
|
end
|
|
|
|
@spec get_public_posts_for_group(Actor.t(), integer | nil, integer | nil) :: Page.t()
|
|
def get_public_posts_for_group(%Actor{id: group_id}, page \\ nil, limit \\ nil) do
|
|
group_id
|
|
|> do_get_posts_for_group()
|
|
|> filter_public()
|
|
|> Page.build_page(page, limit)
|
|
end
|
|
|
|
@doc """
|
|
Get a post by it's ID
|
|
"""
|
|
@spec get_post(integer | String.t()) :: Post.t() | nil
|
|
def get_post(nil), do: nil
|
|
def get_post(id), do: Repo.get(Post, id)
|
|
|
|
@spec get_post_with_preloads(integer | String.t()) :: Post.t() | nil
|
|
def get_post_with_preloads(id) do
|
|
Post
|
|
|> Repo.get(id)
|
|
|> Repo.preload(@post_preloads)
|
|
end
|
|
|
|
@spec get_post_by_slug_with_preloads(String.t()) :: Post.t() | nil
|
|
def get_post_by_slug_with_preloads(slug) do
|
|
Post
|
|
|> Repo.get_by(slug: slug)
|
|
|> Repo.preload(@post_preloads)
|
|
end
|
|
|
|
@doc """
|
|
Get a post by it's URL
|
|
"""
|
|
@spec get_post_by_url(String.t()) :: Post.t() | nil
|
|
def get_post_by_url(url), do: Repo.get_by(Post, url: url)
|
|
|
|
@spec get_post_by_url_with_preloads(String.t()) :: Post.t() | nil
|
|
def get_post_by_url_with_preloads(url) do
|
|
Post
|
|
|> Repo.get_by(url: url)
|
|
|> Repo.preload(@post_preloads)
|
|
end
|
|
|
|
@doc """
|
|
Creates a post.
|
|
"""
|
|
@spec create_post(map) :: {:ok, Post.t()} | {:error, Ecto.Changeset.t()}
|
|
def create_post(attrs \\ %{}) do
|
|
with {:ok, %Post{} = post} <-
|
|
%Post{}
|
|
|> Post.changeset(attrs)
|
|
|> Repo.insert() do
|
|
{:ok, Repo.preload(post, @post_preloads)}
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Updates a post.
|
|
"""
|
|
@spec update_post(Post.t(), map) :: {:ok, Post.t()} | {:error, Ecto.Changeset.t()}
|
|
def update_post(%Post{} = post, attrs) do
|
|
Cachable.clear_all_caches(post)
|
|
|
|
post
|
|
|> Repo.preload([:tags, :media])
|
|
|> Post.changeset(attrs)
|
|
|> Repo.update()
|
|
end
|
|
|
|
@doc """
|
|
Deletes a post
|
|
"""
|
|
@spec delete_post(Post.t()) :: {:ok, Post.t()} | {:error, Ecto.Changeset.t()}
|
|
def delete_post(%Post{} = post) do
|
|
Cachable.clear_all_caches(post)
|
|
Repo.delete(post)
|
|
end
|
|
|
|
@doc """
|
|
Returns the list of tags for the post.
|
|
"""
|
|
@spec list_tags_for_post(integer | String.t()) :: [Tag.t()]
|
|
def list_tags_for_post(post_id) do
|
|
{:ok, uuid} = Ecto.UUID.dump(post_id)
|
|
|
|
uuid
|
|
|> tags_for_post_query()
|
|
|> Repo.all()
|
|
end
|
|
|
|
@spec tags_for_post_query(String.t()) :: Ecto.Query.t()
|
|
defp tags_for_post_query(post_id) do
|
|
from(
|
|
t in Tag,
|
|
join: p in "posts_tags",
|
|
on: t.id == p.tag_id,
|
|
where: p.post_id == ^post_id
|
|
)
|
|
end
|
|
|
|
@spec filter_public(Ecto.Queryable.t()) :: Ecto.Query.t()
|
|
defp filter_public(query) do
|
|
where(query, [p], p.visibility == ^:public and not p.draft)
|
|
end
|
|
|
|
@spec filter_local(Ecto.Queryable.t()) :: Ecto.Query.t()
|
|
defp filter_local(query) do
|
|
where(query, [q], q.local == true)
|
|
end
|
|
|
|
defp do_get_posts_for_group(group_id) do
|
|
Post
|
|
|> where(attributed_to_id: ^group_id)
|
|
|> order_by(desc: :inserted_at)
|
|
|> preload_post_associations()
|
|
end
|
|
|
|
@spec preload_post_associations(Ecto.Queryable.t(), list()) :: Ecto.Query.t()
|
|
defp preload_post_associations(query, associations \\ @post_preloads) do
|
|
preload(query, ^associations)
|
|
end
|
|
end
|