Packages
phoenix_kit
1.4.7
1.7.208
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
Files
Jump to
Current section
Files
lib/phoenix_kit_web/live/modules/publishing/publishing.ex
defmodule PhoenixKitWeb.Live.Modules.Publishing do
@moduledoc """
Publishing module for managing structured content types and entries.
This keeps content in the filesystem while providing an admin-friendly UI
for creating timestamped markdown entries (blogs, news, etc).
"""
alias PhoenixKitWeb.Live.Modules.Publishing.Storage
alias PhoenixKit.Settings
# Delegate language info function to Storage
defdelegate get_language_info(language_code), to: Storage
@enabled_key "publishing_enabled"
@types_key "publishing_types"
@type publishing_type :: map()
@doc """
Returns true when the publishing module is enabled.
"""
@spec enabled?() :: boolean()
def enabled?, do: Settings.get_boolean_setting(@enabled_key, false)
@doc """
Enables the publishing module.
"""
@spec enable_system() :: {:ok, any()} | {:error, any()}
def enable_system, do: Settings.update_boolean_setting(@enabled_key, true)
@doc """
Disables the publishing module.
"""
@spec disable_system() :: {:ok, any()} | {:error, any()}
def disable_system, do: Settings.update_boolean_setting(@enabled_key, false)
@doc """
Returns all configured publishing types.
"""
@spec list_types() :: [publishing_type()]
def list_types do
case Settings.get_json_setting(@types_key, %{"types" => []}) do
%{"types" => types} when is_list(types) -> types
list when is_list(list) -> list
_ -> []
end
end
@doc """
Adds a new publishing type.
"""
@spec add_type(String.t()) :: {:ok, publishing_type()} | {:error, atom()}
def add_type(name) when is_binary(name) do
trimmed = String.trim(name)
cond do
trimmed == "" ->
{:error, :invalid_name}
true ->
types = list_types()
slug = slugify(trimmed)
if Enum.any?(types, &(&1["slug"] == slug)) do
{:error, :already_exists}
else
type = %{"name" => trimmed, "slug" => slug}
updated = types ++ [type]
payload = %{"types" => updated}
with {:ok, _} <- Settings.update_json_setting(@types_key, payload),
:ok <- Storage.ensure_type_root(slug) do
{:ok, type}
end
end
end
end
@doc """
Removes a publishing type by slug.
"""
@spec remove_type(String.t()) :: {:ok, any()} | {:error, any()}
def remove_type(slug) when is_binary(slug) do
updated =
list_types()
|> Enum.reject(&(&1["slug"] == slug))
Settings.update_json_setting(@types_key, %{"types" => updated})
end
@doc """
Looks up a type name from its slug.
"""
@spec type_name(String.t()) :: String.t() | nil
def type_name(slug) do
Enum.find_value(list_types(), fn type ->
if type["slug"] == slug, do: type["name"]
end)
end
@doc """
Lists entries for a given type slug.
Accepts optional preferred_language to show titles in user's language.
"""
@spec list_entries(String.t(), String.t() | nil) :: [Storage.entry()]
def list_entries(type_slug, preferred_language \\ nil),
do: Storage.list_entries(type_slug, preferred_language)
@doc """
Creates a new entry for the given type using the current timestamp.
"""
@spec create_entry(String.t()) :: {:ok, Storage.entry()} | {:error, any()}
def create_entry(type_slug), do: Storage.create_entry(type_slug)
@doc """
Reads an existing entry.
"""
@spec read_entry(String.t(), String.t()) :: {:ok, Storage.entry()} | {:error, any()}
def read_entry(type_slug, relative_path), do: Storage.read_entry(type_slug, relative_path)
@doc """
Updates an entry and moves the file if the publication timestamp changes.
"""
@spec update_entry(String.t(), Storage.entry(), map()) ::
{:ok, Storage.entry()} | {:error, any()}
def update_entry(type_slug, entry, params),
do: Storage.update_entry(type_slug, entry, params)
@doc """
Adds a new language file to an existing entry.
"""
@spec add_language_to_entry(String.t(), String.t(), String.t()) ::
{:ok, Storage.entry()} | {:error, any()}
def add_language_to_entry(type_slug, entry_path, language_code),
do: Storage.add_language_to_entry(type_slug, entry_path, language_code)
@doc """
Generates a slug from a user-provided type name.
"""
@spec slugify(String.t()) :: String.t()
def slugify(name) when is_binary(name) do
name
|> String.downcase()
|> String.replace(~r/[^a-z0-9]+/u, "-")
|> String.trim("-")
|> case do
"" -> "type"
slug -> slug
end
end
end