Packages

phoenix_kit

1.7.31
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
phoenix_kit lib modules publishing storage paths.ex
Raw

lib/modules/publishing/storage/paths.ex

defmodule PhoenixKit.Modules.Publishing.Storage.Paths do
@moduledoc """
Path management for publishing storage.
Handles root paths, group paths, legacy/new path resolution,
and path utilities for the filesystem storage system.
"""
@doc """
Returns the root path for reading content.
Prefers new "publishing" path, falls back to legacy "blogging" path.
For writing new content, use `write_root_path/0` instead.
"""
@spec root_path() :: String.t()
def root_path do
base_priv = get_parent_app_priv()
new_path = Path.join(base_priv, "publishing")
legacy_path = Path.join(base_priv, "blogging")
cond do
File.dir?(new_path) -> new_path
File.dir?(legacy_path) -> legacy_path
true -> new_path
end
end
@doc """
Returns the path for a specific publishing group, checking both new and legacy locations.
Returns the path where the group actually exists, or the new path if it doesn't exist yet.
"""
@spec group_path(String.t()) :: String.t()
def group_path(group_slug) do
base_priv = get_parent_app_priv()
new_group_path = Path.join([base_priv, "publishing", group_slug])
legacy_group_path = Path.join([base_priv, "blogging", group_slug])
cond do
File.dir?(new_group_path) -> new_group_path
File.dir?(legacy_group_path) -> legacy_group_path
true -> new_group_path
end
end
@doc """
Returns the write root path for creating new groups.
Always returns the new "publishing" path.
"""
@spec write_root_path() :: String.t()
def write_root_path do
base_priv = get_parent_app_priv()
path = Path.join(base_priv, "publishing")
File.mkdir_p!(path)
path
end
@doc """
Returns the new publishing root path.
"""
@spec new_root_path() :: String.t()
def new_root_path do
base_priv = get_parent_app_priv()
Path.join(base_priv, "publishing")
end
@doc """
Returns the legacy blogging root path.
"""
@spec legacy_root_path() :: String.t()
def legacy_root_path do
base_priv = get_parent_app_priv()
Path.join(base_priv, "blogging")
end
@doc """
Checks if a specific publishing group is stored in the legacy "blogging" directory.
"""
@spec legacy_group?(String.t()) :: boolean()
def legacy_group?(group_slug) do
legacy_path = Path.join(legacy_root_path(), group_slug)
new_path = Path.join(new_root_path(), group_slug)
File.dir?(legacy_path) and not File.dir?(new_path)
end
@doc """
Migrates a publishing group from the legacy "blogging" directory to the new "publishing" directory.
Returns {:ok, new_path} on success, {:error, reason} on failure.
"""
@spec migrate_group(String.t()) :: {:ok, String.t()} | {:error, term()}
def migrate_group(group_slug) do
legacy_path = Path.join(legacy_root_path(), group_slug)
new_path = Path.join(new_root_path(), group_slug)
cond do
File.dir?(new_path) ->
{:error, :already_migrated}
not File.dir?(legacy_path) ->
{:error, :not_found}
true ->
File.mkdir_p!(new_root_path())
case File.rename(legacy_path, new_path) do
:ok ->
cleanup_empty_legacy_root()
{:ok, new_path}
{:error, reason} ->
{:error, reason}
end
end
end
@doc """
Removes the legacy root directory if it's empty.
"""
@spec cleanup_empty_legacy_root() :: :ok
def cleanup_empty_legacy_root do
legacy_root = legacy_root_path()
if File.dir?(legacy_root) do
case File.ls(legacy_root) do
{:ok, []} -> File.rmdir(legacy_root)
_ -> :ok
end
end
:ok
end
@doc """
Returns whether there are any publishing groups still in the legacy location.
"""
@spec has_legacy_groups?() :: boolean()
def has_legacy_groups? do
legacy_root = legacy_root_path()
if File.dir?(legacy_root) do
case File.ls(legacy_root) do
{:ok, entries} -> Enum.any?(entries, &File.dir?(Path.join(legacy_root, &1)))
_ -> false
end
else
false
end
end
@doc """
Ensures the folder for a publishing group exists.
For new groups, creates in the new "publishing" directory.
For existing groups, uses their current location.
"""
@spec ensure_group_root(String.t()) :: :ok | {:error, term()}
def ensure_group_root(group_slug) do
group_path(group_slug)
|> File.mkdir_p()
end
@doc """
Returns the absolute path for a relative blogging path.
Handles per-blog legacy/new path resolution.
"""
@spec absolute_path(String.t()) :: String.t()
def absolute_path(relative_path) do
trimmed = String.trim_leading(relative_path, "/")
case String.split(trimmed, "/", parts: 2) do
[group_slug, rest] ->
Path.join(group_path(group_slug), rest)
[group_slug] ->
group_path(group_slug)
end
end
@doc """
Cleans up empty directories going up from a path.
Stops at the publishing/blogging root.
"""
@spec cleanup_empty_dirs(String.t()) :: :ok
def cleanup_empty_dirs(path) do
new_root = new_root_path()
legacy_root = legacy_root_path()
path
|> Path.dirname()
|> Stream.iterate(&Path.dirname/1)
|> Enum.take_while(fn dir ->
String.starts_with?(dir, new_root) or String.starts_with?(dir, legacy_root)
end)
|> Enum.each(fn dir ->
case File.ls(dir) do
{:ok, []} -> File.rmdir(dir)
_ -> :ok
end
end)
:ok
end
# Gets the parent application's priv directory
defp get_parent_app_priv do
parent_app =
case PhoenixKit.Config.get_parent_app() do
nil ->
raise """
PhoenixKit parent app not configured.
Cannot determine storage path for publishing module.
Please add the following to your config/config.exs:
config :phoenix_kit, parent_app_name: :your_app_name
"""
app ->
app
end
Application.app_dir(parent_app, "priv")
end
end