mobilizon.chapril.org-mobil.../lib/mobilizon/posts/posts.ex

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