This allows to correctly proxy or redirect requests to the backend, while allowing to migrate backends without breaking any URL.
* `{url, url :: String.t}` to bypass `get_file/2` and use the `url` directly in the activity.
* `{:error, String.t}` error information if the file failed to be saved to the backend.
+ * `:wait_callback` will wait for an http post request at `/api/pleroma/upload_callback/:upload_path` and call the uploader's `http_callback/3` method.
"""
+ @type file_spec :: {:file | :url, String.t()}
@callback put_file(Pleroma.Upload.t()) ::
- :ok | {:ok, {:file | :url, String.t()}} | {:error, String.t()}
+ :ok | {:ok, file_spec()} | {:error, String.t()} | :wait_callback
+
+ @callback http_callback(Plug.Conn.t(), Map.t()) ::
+ {:ok, Plug.Conn.t()}
+ | {:ok, Plug.Conn.t(), file_spec()}
+ | {:error, Plug.Conn.t(), String.t()}
+ @optional_callbacks http_callback: 2
+
+ @spec put_file(module(), Pleroma.Upload.t()) :: {:ok, file_spec()} | {:error, String.t()}
- @spec put_file(module(), Pleroma.Upload.t()) ::
- {:ok, {:file | :url, String.t()}} | {:error, String.t()}
def put_file(uploader, upload) do
case uploader.put_file(upload) do
:ok -> {:ok, {:file, upload.path}}
- other -> other
+ :wait_callback -> handle_callback(uploader, upload)
+ {:ok, _} = ok -> ok
+ {:error, _} = error -> error
+ end
+ end
+
+ defp handle_callback(uploader, upload) do
+ :global.register_name({__MODULE__, upload.path}, self())
+
+ receive do
+ {__MODULE__, pid, conn, params} ->
+ case uploader.http_callback(conn, params) do
+ {:ok, conn, ok} ->
+ send(pid, {__MODULE__, conn})
+ {:ok, ok}
+
+ {:error, conn, error} ->
+ send(pid, {__MODULE__, conn})
+ {:error, error}
+ end
+ after
+ 30_000 -> {:error, "Uploader callback timeout"}
end
end
end
get("/captcha", UtilController, :captcha)
end
+ scope "/api/pleroma", Pleroma.Web do
+ pipe_through(:pleroma_api)
+ post("/uploader_callback/:upload_path", UploaderController, :callback)
+ end
+
scope "/api/pleroma/admin", Pleroma.Web.AdminAPI do
pipe_through(:admin_api)
delete("/user", AdminAPIController, :user_delete)
--- /dev/null
+defmodule Pleroma.Web.UploaderController do
+ use Pleroma.Web, :controller
+
+ alias Pleroma.Uploaders.Uploader
+
+ def callback(conn, params = %{"upload_path" => upload_path}) do
+ process_callback(conn, :global.whereis_name({Uploader, upload_path}), params)
+ end
+
+ def callbacks(conn, _) do
+ send_resp(conn, 400, "bad request")
+ end
+
+ defp process_callback(conn, pid, params) when is_pid(pid) do
+ send(pid, {Uploader, self(), conn, params})
+
+ receive do
+ {Uploader, conn} -> conn
+ end
+ end
+
+ defp process_callback(conn, _, _) do
+ send_resp(conn, 400, "bad request")
+ end
+end