Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion lib/mix/tasks/phoenix_kit.status.ex
Original file line number Diff line number Diff line change
Expand Up @@ -532,11 +532,15 @@ defmodule Mix.Tasks.PhoenixKit.Status do

# Ensure repo is properly started for database operations.
# Since we use --no-start, the repo may not be running yet.
# We start repo with its application config so it gets the connection params.
defp ensure_repo_started(repo) do
if repo_available?(repo) do
:ok
else
case repo.start_link([]) do
parent_app = Mix.Project.config()[:app]
config = Application.get_env(parent_app, repo, [])

case repo.start_link(config) do
{:ok, _pid} -> :ok
{:error, {:already_started, _pid}} -> :ok
{:error, reason} -> {:error, "Failed to start #{inspect(repo)}: #{inspect(reason)}"}
Expand Down
54 changes: 28 additions & 26 deletions lib/modules/publishing/web/editor.ex
Original file line number Diff line number Diff line change
Expand Up @@ -527,33 +527,10 @@ defmodule PhoenixKit.Modules.Publishing.Web.Editor do
)

has_changes = Forms.dirty?(socket_with_slug.assigns.post, new_form, socket.assigns.content)

language = Helpers.editor_language(socket.assigns)
new_status = new_form["status"]

# Update both metadata.status and language_statuses for the current language
# This ensures the language switcher reflects the user's selection immediately
current_language_statuses = Map.get(socket.assigns.post, :language_statuses, %{})
updated_language_statuses = Map.put(current_language_statuses, language, new_status)

# Update post with current form values for accurate public URL
form_slug = new_form["slug"]
form_url_slug = new_form["url_slug"]

updated_post =
socket.assigns.post
|> Map.put(:metadata, Map.merge(socket.assigns.post.metadata, %{status: new_status}))
|> Map.put(:language_statuses, updated_language_statuses)
|> then(fn p ->
if form_slug && form_slug != "", do: Map.put(p, :slug, form_slug), else: p
end)
|> then(fn p ->
if form_url_slug && form_url_slug != "",
do: Map.put(p, :url_slug, form_url_slug),
else: p
end)

public_url = Helpers.build_public_url(updated_post, language)

{updated_post, public_url} =
update_post_from_form(socket.assigns.post, new_form, language)

socket =
socket_with_slug
Expand Down Expand Up @@ -1052,6 +1029,31 @@ defmodule PhoenixKit.Modules.Publishing.Web.Editor do
handle_event("attempt_cancel", %{}, socket)
end

# Update post struct with current form values for accurate public URL and status display
defp update_post_from_form(post, form, language) do
new_status = form["status"]
current_language_statuses = Map.get(post, :language_statuses, %{})
updated_language_statuses = Map.put(current_language_statuses, language, new_status)

form_slug = form["slug"]
form_url_slug = form["url_slug"]

updated_post =
post
|> Map.put(:metadata, Map.merge(post.metadata, %{status: new_status}))
|> Map.put(:language_statuses, updated_language_statuses)
|> then(fn p ->
if form_slug && form_slug != "", do: Map.put(p, :slug, form_slug), else: p
end)
|> then(fn p ->
if form_url_slug && form_url_slug != "",
do: Map.put(p, :url_slug, form_url_slug),
else: p
end)

{updated_post, Helpers.build_public_url(updated_post, language)}
end

# ============================================================================
# Handle Info - Autosave
# ============================================================================
Expand Down
39 changes: 38 additions & 1 deletion lib/modules/sitemap/sources/router_discovery.ex
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ defmodule PhoenixKit.Modules.Sitemap.Sources.RouterDiscovery do

UrlEntry.new(%{
loc: url,
lastmod: nil,
lastmod: module_lastmod(route),
changefreq: "weekly",
priority: 0.5,
title: title,
Expand All @@ -331,6 +331,43 @@ defmodule PhoenixKit.Modules.Sitemap.Sources.RouterDiscovery do
})
end

# Approximate lastmod from the beam file modification time of the route's LiveView module.
# Falls back to the plug module if no LiveView metadata is found.
defp module_lastmod(route) do
module = extract_liveview_module(route) || route.plug
beam_file_mtime(module)
rescue
_ -> nil
end

defp extract_liveview_module(route) do
case route.metadata do
%{phoenix_live_view: {module, _, _, _}} when is_atom(module) -> module
%{phoenix_live_view: {module, _, _}} when is_atom(module) -> module
_ -> nil
end
rescue
_ -> nil
end

defp beam_file_mtime(module) when is_atom(module) do
case :code.which(module) do
beam_path when is_list(beam_path) ->
case File.stat(List.to_string(beam_path)) do
{:ok, %{mtime: mtime}} ->
NaiveDateTime.from_erl!(mtime) |> DateTime.from_naive!("Etc/UTC")

_ ->
nil
end

_ ->
nil
end
end

defp beam_file_mtime(_), do: nil

defp build_url(path, nil) do
base = Settings.get_setting("site_url", "")
normalized_base = String.trim_trailing(base, "/")
Expand Down
4 changes: 2 additions & 2 deletions lib/modules/sitemap/sources/static.ex
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ defmodule PhoenixKit.Modules.Sitemap.Sources.Static do

UrlEntry.new(%{
loc: url,
lastmod: nil,
lastmod: Date.utc_today(),
changefreq: Map.get(config, "changefreq", "weekly"),
priority: Map.get(config, "priority", 0.5),
title: Map.get(config, "title", path),
Expand All @@ -224,7 +224,7 @@ defmodule PhoenixKit.Modules.Sitemap.Sources.Static do

UrlEntry.new(%{
loc: url,
lastmod: nil,
lastmod: Date.utc_today(),
changefreq: Map.get(config, "changefreq", "weekly"),
priority: Map.get(config, "priority", 0.5),
title: Map.get(config, "title", path),
Expand Down
46 changes: 35 additions & 11 deletions lib/phoenix_kit/migrations/postgres.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1097,22 +1097,46 @@ defmodule PhoenixKit.Migrations.Postgres do

defp ensure_repo_loaded?(_), do: false

# Ensure repo is properly started for database operations
# Note: For Mix tasks, the application should already be started
# Ensure repo is properly started for database operations.
# In --no-start context, Repo process may not be running yet.
defp ensure_repo_started(repo) do
# Try Mix.Ecto.ensure_repo if available
if Code.ensure_loaded?(Mix.Ecto) do
Mix.Ecto.ensure_repo(repo, [])
if Process.whereis(repo) != nil do
:ok
else
# Basic check if repo is available
if Code.ensure_loaded?(repo) && function_exported?(repo, :__adapter__, 0) do
:ok
else
{:error, "Repository #{inspect(repo)} is not available"}
end
start_repo_with_config(repo)
end
rescue
error -> {:error, "Failed to start repo: #{inspect(error)}"}
end

defp start_repo_with_config(repo) do
# Try Mix.Ecto.ensure_repo first (handles config resolution)
if Code.ensure_loaded?(Mix.Ecto) do
Mix.Ecto.ensure_repo(repo, [])

# ensure_repo loads but doesn't start — start the process
if Process.whereis(repo) == nil do
do_start_repo(repo)
else
:ok
end
else
do_start_repo(repo)
end
end

defp do_start_repo(repo) do
# Get config from parent app's application env
app =
if Code.ensure_loaded?(Mix) and function_exported?(Mix.Project, :config, 0),
do: Mix.Project.config()[:app]

config = if app, do: Application.get_env(app, repo, []), else: []

case repo.start_link(config) do
{:ok, _pid} -> :ok
{:error, {:already_started, _pid}} -> :ok
{:error, reason} -> {:error, "Failed to start #{inspect(repo)}: #{inspect(reason)}"}
end
end
end
Loading