livebook/lib/livebook_web/controllers/session_controller.ex
Jonatan Kłosko d93b5d8450
Set up image uploads for Markdown content (#132)
* Add cell image upload modal

* Add controller for serving the images and handle this on markdown side

* Use per-session images dir

* Add etag header to session image responses

* Adjust markdown image styling

* Properly manage session images dir

* Add tests

* Set maximum file size for image uploads

* Move images dir specifics to the Session module

* Move images when nonpersistent session becomes persistent

* Update lib/livebook_web/live/session_live.ex

Co-authored-by: José Valim <jose.valim@dashbit.co>

* Update lib/livebook_web/live/session_live.ex

Co-authored-by: José Valim <jose.valim@dashbit.co>

* Update lib/livebook_web/live/session_live/cell_upload_component.ex

Co-authored-by: José Valim <jose.valim@dashbit.co>

* Test that close gets rid of session temporary dir

Co-authored-by: José Valim <jose.valim@dashbit.co>
2021-04-04 18:55:51 +02:00

53 lines
1.3 KiB
Elixir

defmodule LivebookWeb.SessionController do
use LivebookWeb, :controller
alias Livebook.{SessionSupervisor, Session}
def show_image(conn, %{"id" => id, "image" => image}) do
with true <- SessionSupervisor.session_exists?(id),
%{images_dir: images_dir} <- Session.get_summary(id),
path <- Path.join(images_dir, image),
true <- File.exists?(path) do
serve_static(conn, path)
else
_ ->
send_resp(conn, 404, "Not found")
end
end
defp serve_static(conn, path) do
case put_cache_header(conn, path) do
{:stale, conn} ->
filename = Path.basename(path)
content_type = MIME.from_path(filename)
conn
|> put_resp_header("content-type", content_type)
|> send_file(200, path)
{:fresh, conn} ->
send_resp(conn, 304, "")
end
end
defp put_cache_header(conn, path) do
etag = etag_for_path(path)
conn =
conn
|> put_resp_header("cache-control", "public")
|> put_resp_header("etag", etag)
if etag in get_req_header(conn, "if-none-match") do
{:fresh, conn}
else
{:stale, conn}
end
end
defp etag_for_path(path) do
%{size: size, mtime: mtime} = File.stat!(path)
hash = {size, mtime} |> :erlang.phash2() |> Integer.to_string(16)
<<?", hash::binary, ?">>
end
end