legendary-doc-site/apps/content/lib/posts.ex

287 lines
5.9 KiB
Elixir
Raw Normal View History

2020-07-20 22:04:04 +00:00
defmodule Content.Posts do
@page_size 3
@moduledoc """
The Content context.
"""
import Ecto.Query, warn: false
alias Content.Repo
alias Content.Option
alias Content.Post
alias Ecto.Changeset
@preloads [:metas, :author, :categories, :tags, :comments, :post_format]
@doc """
Returns the lisdpt of posts for admin interface.
## Examples
iex> list_admin_posts()
[%Post{}, ...]
"""
def list_admin_posts(page, post_type \\ "post") do
post_type = post_type || "post"
Repo.all(
from p in Post,
where: p.post_type == ^post_type,
where: p.post_status in ["publish", "future", "draft", "pending", "private", "inherit"],
preload: ^@preloads,
order_by: [desc: p.post_date],
limit: @page_size,
offset: ^(@page_size * (String.to_integer(page) - 1))
)
end
@doc """
Returns the list of posts.
## Examples
iex> list_posts()
[%Post{}, ...]
"""
def list_posts(params \\ %{}) do
page = params |> Map.get("page", "1")
normal_posts =
params
|> post_scope_for_params()
|> limit(@page_size)
|> offset(^(@page_size * (String.to_integer(page) - 1)))
|> Repo.all()
sticky_posts_for_page(params) ++ normal_posts
end
def post_scope_for_params(params) do
post_type = params |> Map.get("post_type", "post")
category = params |> Map.get("category")
query =
post_scope()
|> where([p], p.post_type == ^post_type)
if category do
query |> join(:inner, [p], term in assoc(p, :categories), on: term.slug == ^category)
else
query
end
end
def post_scope do
from p in Post,
where: p.post_status == "publish",
preload: ^@preloads,
order_by: [desc: p.post_date]
end
def post_scope_with_drafts do
from p in Post,
preload: ^@preloads,
order_by: [desc: p.post_date]
end
def sticky_posts_for_page(%{"page" => "1"} = params) do
sticky_posts =
params
|> post_scope_for_params()
|> where([p], p.'ID' in ^sticky_ids())
|> Repo.all()
sticky_posts
|> Enum.map(fn post ->
post
|> Changeset.change(%{sticky: true})
|> Changeset.apply_changes()
end)
end
def sticky_posts_for_page(_), do: []
defp sticky_ids do
case Repo.one(from opt in Option, where: opt.option_name == "sticky_posts") do
nil ->
[]
option ->
option
|> Option.parse_option_value
|> Enum.map(&(elem(&1, 1)))
end
end
def last_page(params \\ %{}) do
post_count =
params
|> post_scope_for_params()
|> Repo.aggregate(:count, :ID)
post_count
|> (&(&1 / @page_size)).()
|> Float.ceil
|> trunc
end
def thumbs_for_posts(posts) do
post_to_thumbnail_id =
posts
|> Enum.map(fn post -> {post.'ID', (post |> Post.metas_map)["_thumbnail_id"]} end)
|> Enum.reject(&(elem(&1, 1) == nil))
thumbs =
Post
|> preload(:metas)
|> where([thumb], thumb.'ID' in ^Enum.map(post_to_thumbnail_id, &(elem(&1, 1))))
|> Repo.all()
|> Enum.map(fn thumb -> {thumb.'ID', thumb} end)
|> Map.new
post_to_thumbnail_id
|> Enum.map(fn {key, value} -> {key, thumbs[String.to_integer(value)]} end)
|> Map.new
end
@doc """
Gets a single posts.
Raises `Ecto.NoResultsError` if the Wp posts does not exist.
## Examples
iex> get_posts!(123)
%Post{}
iex> get_posts!(456)
** (Ecto.NoResultsError)
"""
def get_posts!(slug) do
id_filter = fn scope, id ->
case Integer.parse(id, 10) do
:error ->
scope |> where([p], p.post_name == ^id)
{int_id, _} ->
scope |> where([p], p.'ID' == ^int_id)
end
end
post_scope()
|> where([p], p.post_type != "nav_menu_item")
|> id_filter.(slug)
|> Repo.one!()
end
@doc """
Gets a single post that may or may not be in draft status.
Raises `Ecto.NoResultsError` if the Wp posts does not exist.
## Examples
iex> get_post_with_drafts!(123)
%Post{}
iex> get_post_with_drafts!(456)
** (Ecto.NoResultsError)
"""
def get_post_with_drafts!(slug) do
id_filter = fn scope, id ->
case Integer.parse(id, 10) do
:error ->
scope |> where([p], p.post_name == ^id)
{int_id, ""} ->
scope |> where([p], p.'ID' == ^int_id)
{_int_id, _} ->
scope |> where([p], p.post_name == ^id)
end
end
post_scope_with_drafts()
|> where([p], p.post_type != "nav_menu_item")
|> id_filter.(slug)
|> Repo.one!()
end
@doc """
Creates a posts.
## Examples
iex> create_posts(%{field: value})
{:ok, %Post{}}
iex> create_posts(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_posts(attrs \\ %{}) do
%Post{}
|> Post.changeset(attrs)
|> Repo.insert()
end
@doc """
Builds a post for preview, but does not save it.
"""
def preview_post(attrs \\ %{}) do
%Post{}
|> Repo.preload(@preloads)
|> Post.changeset(attrs)
|> Changeset.put_change(:post_name, "preview")
|> Changeset.apply_changes()
end
@doc """
Updates a posts.
## Examples
iex> update_posts(posts, %{field: new_value})
{:ok, %Post{}}
iex> update_posts(posts, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_posts(%Post{} = posts, attrs) do
posts
|> Post.changeset(attrs)
|> Repo.update()
end
@doc """
Deletes a Post.
## Examples
iex> delete_posts(posts)
{:ok, %Post{}}
iex> delete_posts(posts)
{:error, %Ecto.Changeset{}}
"""
def delete_posts(%Post{} = posts) do
Repo.delete(posts)
end
@doc """
Returns an `%Ecto.Changeset{}` for tracking posts changes.
## Examples
iex> change_posts(posts)
%Ecto.Changeset{source: %Post{}}
"""
def change_posts(%Post{} = posts) do
Post.changeset(posts, %{})
end
end