asciinema.org/web/controllers/api/asciicast_controller.ex

86 lines
2.7 KiB
Elixir

defmodule Asciinema.Api.AsciicastController do
use Asciinema.Web, :controller
import Asciinema.Auth, only: [get_basic_auth: 1, put_basic_auth: 3]
alias Asciinema.{Asciicasts, Users, User}
plug :parse_v0_params
plug :authenticate
def create(conn, %{"asciicast" => %Plug.Upload{} = upload}) do
do_create(conn, upload)
end
def create(conn, %{"asciicast" => %{"meta" => %{},
"stdout" => %Plug.Upload{},
"stdout_timing" => %Plug.Upload{}} = asciicast_params}) do
do_create(conn, asciicast_params)
end
defp do_create(conn, params) do
user = conn.assigns.current_user
user_agent = conn |> get_req_header("user-agent") |> List.first
case Asciicasts.create_asciicast(user, params, user_agent) do
{:ok, asciicast} ->
url = asciicast_url(conn, :show, asciicast)
conn
|> put_status(:created)
|> put_resp_header("location", url)
|> text(url)
{:error, :parse_error} ->
conn
|> put_status(:bad_request)
|> text("This doesn't look like a valid asciicast file")
{:error, :unknown_format} ->
conn
|> put_status(:unsupported_media_type)
|> text("Format not supported")
{:error, %Ecto.Changeset{} = changeset} ->
conn
|> put_status(:unprocessable_entity)
|> render("error.json", changeset: changeset)
end
end
defp parse_v0_params(%Plug.Conn{params: %{"asciicast" => %{"meta" => %Plug.Upload{path: meta_path}}}} = conn, _) do
with {:ok, json} <- File.read(meta_path),
{:ok, attrs} <- Poison.decode(json),
{:ok, meta} <- extract_v0_attrs(attrs) do
conn
|> put_param(["asciicast", "meta"], meta)
|> put_basic_auth(attrs["username"], attrs["user_token"])
else
{:error, :invalid} ->
send_resp(conn, 400, "")
end
end
defp parse_v0_params(conn, _), do: conn
defp put_param(%Plug.Conn{params: params} = conn, path, value) do
params = put_in(params, path, value)
%{conn | params: params}
end
defp extract_v0_attrs(attrs) do
attrs = Map.merge(
Map.take(attrs, ["command", "duration", "shell", "title", "uname"]),
%{"terminal_columns" => get_in(attrs, ["term", "columns"]),
"terminal_lines" => get_in(attrs, ["term", "lines"]),
"terminal_type" => get_in(attrs, ["term", "type"])}
)
{:ok, attrs}
end
defp authenticate(conn, _opts) do
with {username, api_token} <- get_basic_auth(conn),
%User{} = user <- Users.get_user_with_api_token(username, api_token) do
assign(conn, :current_user, user)
else
_otherwise ->
conn
|> send_resp(401, "Invalid or revoked recorder token")
|> halt()
end
end
end