Support client version <= 0.9.7 in new upload endpoint
This commit is contained in:
parent
f34b9707f3
commit
515d486309
@ -20,8 +20,11 @@ defmodule Asciinema.Asciicasts do
|
||||
Repo.one!(q)
|
||||
end
|
||||
|
||||
def create_asciicast(user, %Plug.Upload{path: path, filename: filename} = upload) do
|
||||
def create_asciicast(user, params, user_agent \\ nil)
|
||||
|
||||
def create_asciicast(user, %Plug.Upload{path: path, filename: filename} = upload, user_agent) do
|
||||
asciicast = %Asciicast{user_id: user.id,
|
||||
user_agent: user_agent,
|
||||
file: filename,
|
||||
private: user.asciicasts_private_by_default}
|
||||
|
||||
@ -31,8 +34,8 @@ defmodule Asciinema.Asciicasts do
|
||||
{:ok, attrs} <- extract_attrs(attrs),
|
||||
changeset = Asciicast.create_changeset(asciicast, attrs),
|
||||
{:ok, %Asciicast{} = asciicast} <- Repo.insert(changeset) do
|
||||
put_file(asciicast, upload)
|
||||
# TODO: generate snapshot and poster
|
||||
save_file(asciicast, :file, upload)
|
||||
generate_poster(asciicast)
|
||||
{:ok, asciicast}
|
||||
else
|
||||
{:error, :invalid} ->
|
||||
@ -45,6 +48,30 @@ defmodule Asciinema.Asciicasts do
|
||||
result
|
||||
end
|
||||
|
||||
def create_asciicast(user, %{"meta" => attrs,
|
||||
"stdout" => %Plug.Upload{filename: d_filename} = data,
|
||||
"stdout_timing" => %Plug.Upload{filename: t_filename} = timing}, _user_agent) do
|
||||
attrs = Map.put(attrs, "version", 0)
|
||||
asciicast = %Asciicast{user_id: user.id,
|
||||
stdout_data: d_filename,
|
||||
stdout_timing: t_filename,
|
||||
private: user.asciicasts_private_by_default}
|
||||
|
||||
changeset = Asciicast.create_changeset(asciicast, attrs)
|
||||
{_, result} = Repo.transaction(fn ->
|
||||
with {:ok, %Asciicast{} = asciicast} <- Repo.insert(changeset) do
|
||||
save_file(asciicast, :stdout_data, data)
|
||||
save_file(asciicast, :stdout_timing, timing)
|
||||
generate_poster(asciicast)
|
||||
{:ok, asciicast}
|
||||
else
|
||||
otherwise -> otherwise
|
||||
end
|
||||
end)
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
defp extract_attrs(%{"version" => 1} = attrs) do
|
||||
attrs = %{version: attrs["version"],
|
||||
duration: attrs["duration"],
|
||||
@ -60,8 +87,12 @@ defmodule Asciinema.Asciicasts do
|
||||
{:error, :unknown_format}
|
||||
end
|
||||
|
||||
defp put_file(asciicast, %{path: tmp_file_path, content_type: content_type}) do
|
||||
file_store_path = Asciicast.json_store_path(asciicast)
|
||||
defp save_file(asciicast, type, %{path: tmp_file_path, content_type: content_type}) do
|
||||
file_store_path = Asciicast.file_store_path(asciicast, type)
|
||||
:ok = FileStore.put_file(file_store_path, tmp_file_path, content_type)
|
||||
end
|
||||
|
||||
defp generate_poster(_asciicast) do
|
||||
# TODO
|
||||
end
|
||||
end
|
||||
|
@ -21,4 +21,12 @@ defmodule Asciinema.Auth do
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
|
||||
def put_basic_auth(conn, nil, nil) do
|
||||
conn
|
||||
end
|
||||
def put_basic_auth(conn, username, password) do
|
||||
auth = Base.encode64("#{username}:#{password}")
|
||||
Conn.put_req_header(conn, "authorization", "Basic " <> auth)
|
||||
end
|
||||
end
|
||||
|
@ -3,14 +3,48 @@ defmodule Asciinema.AsciicastsTest do
|
||||
alias Asciinema.Asciicasts
|
||||
|
||||
describe "create_asciicast/2" do
|
||||
test "json file, v0 format, <= v0.9.7 client" do
|
||||
user = fixture(:user)
|
||||
params = %{"meta" => %{"command" => "/bin/bash",
|
||||
"duration" => 11.146430015564,
|
||||
"shell" => "/bin/zsh",
|
||||
"terminal_columns" => 96,
|
||||
"terminal_lines" => 26,
|
||||
"terminal_type" => "screen-256color",
|
||||
"title" => "bashing :)",
|
||||
"uname" => "Linux 3.9.9-302.fc19.x86_64 #1 SMP Sat Jul 6 13:41:07 UTC 2013 x86_64"},
|
||||
"stdout" => fixture(:upload, %{path: "0.9.7/stdout",
|
||||
content_type: "application/octet-stream"}),
|
||||
"stdout_timing" => fixture(:upload, %{path: "0.9.7/stdout.time",
|
||||
content_type: "application/octet-stream"})}
|
||||
|
||||
{:ok, asciicast} = Asciicasts.create_asciicast(user, params, "a/user/agent")
|
||||
|
||||
assert asciicast.version == 0
|
||||
assert asciicast.file == nil
|
||||
assert asciicast.stdout_data == "stdout"
|
||||
assert asciicast.stdout_timing == "stdout.time"
|
||||
assert asciicast.command == "/bin/bash"
|
||||
assert asciicast.duration == 11.146430015564
|
||||
assert asciicast.shell == "/bin/zsh"
|
||||
assert asciicast.terminal_type == "screen-256color"
|
||||
assert asciicast.terminal_columns == 96
|
||||
assert asciicast.terminal_lines == 26
|
||||
assert asciicast.title == "bashing :)"
|
||||
assert asciicast.uname == "Linux 3.9.9-302.fc19.x86_64 #1 SMP Sat Jul 6 13:41:07 UTC 2013 x86_64"
|
||||
assert asciicast.user_agent == nil
|
||||
end
|
||||
|
||||
test "json file, v1 format" do
|
||||
user = fixture(:user)
|
||||
upload = fixture(:upload, %{path: "1/asciicast.json"})
|
||||
|
||||
{:ok, asciicast} = Asciicasts.create_asciicast(user, upload)
|
||||
{:ok, asciicast} = Asciicasts.create_asciicast(user, upload, "a/user/agent")
|
||||
|
||||
assert asciicast.version == 1
|
||||
assert asciicast.file == "asciicast.json"
|
||||
assert asciicast.stdout_data == nil
|
||||
assert asciicast.stdout_timing == nil
|
||||
assert asciicast.command == "/bin/bash"
|
||||
assert asciicast.duration == 11.146430015564
|
||||
assert asciicast.shell == "/bin/zsh"
|
||||
@ -19,7 +53,7 @@ defmodule Asciinema.AsciicastsTest do
|
||||
assert asciicast.terminal_lines == 26
|
||||
assert asciicast.title == "bashing :)"
|
||||
assert asciicast.uname == nil
|
||||
# TODO assert asciicast.user_agent == "asciinema/1.0.0 gc/go1.3 jola-amd64"
|
||||
assert asciicast.user_agent == "a/user/agent"
|
||||
end
|
||||
|
||||
test "json file, v1 format (missing required data)" do
|
||||
|
@ -17,6 +17,20 @@ defmodule Asciinema.Api.AsciicastControllerTest do
|
||||
@asciicast_url ~r|^http://localhost:4001/a/[a-zA-Z0-9]{25}|
|
||||
|
||||
describe ".create" do
|
||||
@tag token: nil
|
||||
test "separate files (pre-v1 params), v0.9.7 client", %{conn: conn} do
|
||||
asciicast = %{"meta" => fixture(:upload, %{path: "0.9.7/meta.json",
|
||||
content_type: "application/json"}),
|
||||
"stdout" => fixture(:upload, %{path: "0.9.7/stdout",
|
||||
content_type: "application/octet-stream"}),
|
||||
"stdout_timing" => fixture(:upload, %{path: "0.9.7/stdout.time",
|
||||
content_type: "application/octet-stream"})}
|
||||
|
||||
conn = post conn, api_asciicast_path(conn, :create), %{"asciicast" => asciicast}
|
||||
assert text_response(conn, 201) =~ @asciicast_url
|
||||
assert List.first(get_resp_header(conn, "location")) =~ @asciicast_url
|
||||
end
|
||||
|
||||
test "json file, v1 format", %{conn: conn} do
|
||||
upload = fixture(:upload, %{path: "1/asciicast.json"})
|
||||
conn = post conn, api_asciicast_path(conn, :create), %{"asciicast" => upload}
|
||||
|
@ -1,14 +1,25 @@
|
||||
defmodule Asciinema.Api.AsciicastController do
|
||||
use Asciinema.Web, :controller
|
||||
import Asciinema.Auth, only: [get_basic_auth: 1]
|
||||
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
|
||||
user = conn.assigns.current_user
|
||||
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
|
||||
|
||||
case Asciicasts.create_asciicast(user, upload) do
|
||||
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
|
||||
@ -30,6 +41,36 @@ defmodule Asciinema.Api.AsciicastController do
|
||||
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
|
||||
|
@ -24,6 +24,7 @@ defmodule Asciinema.Asciicast do
|
||||
field :command, :string
|
||||
field :shell, :string
|
||||
field :uname, :string
|
||||
field :user_agent, :string
|
||||
|
||||
timestamps(inserted_at: :created_at)
|
||||
|
||||
@ -55,11 +56,27 @@ defmodule Asciinema.Asciicast do
|
||||
put_change(changeset, :secret_token, Crypto.random_token(25))
|
||||
end
|
||||
|
||||
def json_store_path(%__MODULE__{id: id, file: file}) when is_binary(file) do
|
||||
"asciicast/file/#{id}/#{file}"
|
||||
def json_store_path(%Asciicast{file: v} = asciicast) when is_binary(v) do
|
||||
file_store_path(asciicast, :file)
|
||||
end
|
||||
def json_store_path(%__MODULE__{id: id, stdout_frames: stdout_frames}) when is_binary(stdout_frames) do
|
||||
"asciicast/stdout_frames/#{id}/#{stdout_frames}"
|
||||
def json_store_path(%Asciicast{stdout_frames: v} = asciicast) when is_binary(v) do
|
||||
file_store_path(asciicast, :stdout_frames)
|
||||
end
|
||||
|
||||
def file_store_path(%Asciicast{id: id, file: fname}, :file) do
|
||||
file_store_path(:file, id, fname)
|
||||
end
|
||||
def file_store_path(%Asciicast{id: id, stdout_frames: fname}, :stdout_frames) do
|
||||
file_store_path(:stdout_frames, id, fname)
|
||||
end
|
||||
def file_store_path(%Asciicast{id: id, stdout_data: fname}, :stdout_data) do
|
||||
file_store_path(:stdout_data, id, fname)
|
||||
end
|
||||
def file_store_path(%Asciicast{id: id, stdout_timing: fname}, :stdout_timing) do
|
||||
file_store_path(:stdout_timing, id, fname)
|
||||
end
|
||||
def file_store_path(type, id, fname) when is_binary(fname) do
|
||||
"asciicast/#{type}/#{id}/#{fname}"
|
||||
end
|
||||
|
||||
def snapshot_at(%Asciicast{snapshot_at: snapshot_at, duration: duration}) do
|
||||
|
Loading…
Reference in New Issue
Block a user