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)
|
Repo.one!(q)
|
||||||
end
|
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,
|
asciicast = %Asciicast{user_id: user.id,
|
||||||
|
user_agent: user_agent,
|
||||||
file: filename,
|
file: filename,
|
||||||
private: user.asciicasts_private_by_default}
|
private: user.asciicasts_private_by_default}
|
||||||
|
|
||||||
@ -31,8 +34,8 @@ defmodule Asciinema.Asciicasts do
|
|||||||
{:ok, attrs} <- extract_attrs(attrs),
|
{:ok, attrs} <- extract_attrs(attrs),
|
||||||
changeset = Asciicast.create_changeset(asciicast, attrs),
|
changeset = Asciicast.create_changeset(asciicast, attrs),
|
||||||
{:ok, %Asciicast{} = asciicast} <- Repo.insert(changeset) do
|
{:ok, %Asciicast{} = asciicast} <- Repo.insert(changeset) do
|
||||||
put_file(asciicast, upload)
|
save_file(asciicast, :file, upload)
|
||||||
# TODO: generate snapshot and poster
|
generate_poster(asciicast)
|
||||||
{:ok, asciicast}
|
{:ok, asciicast}
|
||||||
else
|
else
|
||||||
{:error, :invalid} ->
|
{:error, :invalid} ->
|
||||||
@ -45,6 +48,30 @@ defmodule Asciinema.Asciicasts do
|
|||||||
result
|
result
|
||||||
end
|
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
|
defp extract_attrs(%{"version" => 1} = attrs) do
|
||||||
attrs = %{version: attrs["version"],
|
attrs = %{version: attrs["version"],
|
||||||
duration: attrs["duration"],
|
duration: attrs["duration"],
|
||||||
@ -60,8 +87,12 @@ defmodule Asciinema.Asciicasts do
|
|||||||
{:error, :unknown_format}
|
{:error, :unknown_format}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp put_file(asciicast, %{path: tmp_file_path, content_type: content_type}) do
|
defp save_file(asciicast, type, %{path: tmp_file_path, content_type: content_type}) do
|
||||||
file_store_path = Asciicast.json_store_path(asciicast)
|
file_store_path = Asciicast.file_store_path(asciicast, type)
|
||||||
:ok = FileStore.put_file(file_store_path, tmp_file_path, content_type)
|
:ok = FileStore.put_file(file_store_path, tmp_file_path, content_type)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp generate_poster(_asciicast) do
|
||||||
|
# TODO
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -21,4 +21,12 @@ defmodule Asciinema.Auth do
|
|||||||
_ -> nil
|
_ -> nil
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
@ -3,14 +3,48 @@ defmodule Asciinema.AsciicastsTest do
|
|||||||
alias Asciinema.Asciicasts
|
alias Asciinema.Asciicasts
|
||||||
|
|
||||||
describe "create_asciicast/2" do
|
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
|
test "json file, v1 format" do
|
||||||
user = fixture(:user)
|
user = fixture(:user)
|
||||||
upload = fixture(:upload, %{path: "1/asciicast.json"})
|
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.version == 1
|
||||||
assert asciicast.file == "asciicast.json"
|
assert asciicast.file == "asciicast.json"
|
||||||
|
assert asciicast.stdout_data == nil
|
||||||
|
assert asciicast.stdout_timing == nil
|
||||||
assert asciicast.command == "/bin/bash"
|
assert asciicast.command == "/bin/bash"
|
||||||
assert asciicast.duration == 11.146430015564
|
assert asciicast.duration == 11.146430015564
|
||||||
assert asciicast.shell == "/bin/zsh"
|
assert asciicast.shell == "/bin/zsh"
|
||||||
@ -19,7 +53,7 @@ defmodule Asciinema.AsciicastsTest do
|
|||||||
assert asciicast.terminal_lines == 26
|
assert asciicast.terminal_lines == 26
|
||||||
assert asciicast.title == "bashing :)"
|
assert asciicast.title == "bashing :)"
|
||||||
assert asciicast.uname == nil
|
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
|
end
|
||||||
|
|
||||||
test "json file, v1 format (missing required data)" do
|
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}|
|
@asciicast_url ~r|^http://localhost:4001/a/[a-zA-Z0-9]{25}|
|
||||||
|
|
||||||
describe ".create" do
|
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
|
test "json file, v1 format", %{conn: conn} do
|
||||||
upload = fixture(:upload, %{path: "1/asciicast.json"})
|
upload = fixture(:upload, %{path: "1/asciicast.json"})
|
||||||
conn = post conn, api_asciicast_path(conn, :create), %{"asciicast" => upload}
|
conn = post conn, api_asciicast_path(conn, :create), %{"asciicast" => upload}
|
||||||
|
@ -1,14 +1,25 @@
|
|||||||
defmodule Asciinema.Api.AsciicastController do
|
defmodule Asciinema.Api.AsciicastController do
|
||||||
use Asciinema.Web, :controller
|
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}
|
alias Asciinema.{Asciicasts, Users, User}
|
||||||
|
|
||||||
|
plug :parse_v0_params
|
||||||
plug :authenticate
|
plug :authenticate
|
||||||
|
|
||||||
def create(conn, %{"asciicast" => %Plug.Upload{} = upload}) do
|
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} ->
|
{:ok, asciicast} ->
|
||||||
url = asciicast_url(conn, :show, asciicast)
|
url = asciicast_url(conn, :show, asciicast)
|
||||||
conn
|
conn
|
||||||
@ -30,6 +41,36 @@ defmodule Asciinema.Api.AsciicastController do
|
|||||||
end
|
end
|
||||||
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
|
defp authenticate(conn, _opts) do
|
||||||
with {username, api_token} <- get_basic_auth(conn),
|
with {username, api_token} <- get_basic_auth(conn),
|
||||||
%User{} = user <- Users.get_user_with_api_token(username, api_token) do
|
%User{} = user <- Users.get_user_with_api_token(username, api_token) do
|
||||||
|
@ -24,6 +24,7 @@ defmodule Asciinema.Asciicast do
|
|||||||
field :command, :string
|
field :command, :string
|
||||||
field :shell, :string
|
field :shell, :string
|
||||||
field :uname, :string
|
field :uname, :string
|
||||||
|
field :user_agent, :string
|
||||||
|
|
||||||
timestamps(inserted_at: :created_at)
|
timestamps(inserted_at: :created_at)
|
||||||
|
|
||||||
@ -55,11 +56,27 @@ defmodule Asciinema.Asciicast do
|
|||||||
put_change(changeset, :secret_token, Crypto.random_token(25))
|
put_change(changeset, :secret_token, Crypto.random_token(25))
|
||||||
end
|
end
|
||||||
|
|
||||||
def json_store_path(%__MODULE__{id: id, file: file}) when is_binary(file) do
|
def json_store_path(%Asciicast{file: v} = asciicast) when is_binary(v) do
|
||||||
"asciicast/file/#{id}/#{file}"
|
file_store_path(asciicast, :file)
|
||||||
end
|
end
|
||||||
def json_store_path(%__MODULE__{id: id, stdout_frames: stdout_frames}) when is_binary(stdout_frames) do
|
def json_store_path(%Asciicast{stdout_frames: v} = asciicast) when is_binary(v) do
|
||||||
"asciicast/stdout_frames/#{id}/#{stdout_frames}"
|
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
|
end
|
||||||
|
|
||||||
def snapshot_at(%Asciicast{snapshot_at: snapshot_at, duration: duration}) do
|
def snapshot_at(%Asciicast{snapshot_at: snapshot_at, duration: duration}) do
|
||||||
|
Loading…
Reference in New Issue
Block a user