defmodule WhoNeedHelp.Release do @moduledoc """ Used for executing DB release tasks when run in production without Mix installed. """ @app :who_need_help import Ecto.Query def migrate do load_app() for repo <- repos() do {:ok, _, _} = Ecto.Migrator.with_repo(repo, fn repo -> Ecto.Migrator.run(repo, :up, all: true) WhoNeedHelp.Catalog.seed_defaults() end) end end def rollback(repo, version) do load_app() {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version)) end def bootstrap_admin(email) when is_binary(email) do WhoNeedHelp.Repo.transact(fn -> WhoNeedHelp.Repo.query!( "SELECT pg_advisory_xact_lock(hashtext($1))", ["who_need_help.bootstrap_admin"] ) admin_count = WhoNeedHelp.Repo.aggregate( from(user in WhoNeedHelp.Accounts.User, where: user.role == :admin), :count ) cond do admin_count > 0 -> {:error, :admin_already_exists} user = WhoNeedHelp.Repo.get_by(WhoNeedHelp.Accounts.User, email: email) -> with {:ok, user} <- user |> WhoNeedHelp.Accounts.User.role_changeset(%{role: :admin}) |> WhoNeedHelp.Repo.update(), {:ok, _audit} <- WhoNeedHelp.Trust.audit(nil, "user.admin_bootstrapped", "user", user.id) do {:ok, %{id: user.id, email: user.email, role: user.role}} end true -> {:error, :user_not_found} end end) end def await_migrations do load_app() Enum.each(repos(), &await_repo/1) end defp await_repo(repo) do {:ok, ready?, _} = Ecto.Migrator.with_repo(repo, fn started_repo -> case Ecto.Migrator.migrations(started_repo) do [] -> false migrations -> Enum.all?(migrations, fn {status, _version, _name} -> status == :up end) end end) unless ready? do Process.sleep(1_000) await_repo(repo) end end defp repos do Application.fetch_env!(@app, :ecto_repos) end defp load_app do # Many platforms require SSL when connecting to the database Application.ensure_all_started(:ssl) Application.ensure_loaded(@app) end end