defmodule Box do @moduledoc """ Unofficial Box SDK for Elixir. See the BoxOAuth2 module to get started. """ alias Tesla.Multipart @box_api_url "https://api.box.com/2.0" @box_upload_url "https://upload.box.com/api/2.0" @doc """ Folder items returns the entries in a folder. {:ok, folder} = Box.folder_from_path(auth.client, "/") {:ok, entries} = Box.folder_items(auth.client, folder.id, [:id, :name]) IO.inspect(entries) """ def folder_items(client, folder, fields \\ []) do with {:ok, response} <- Tesla.get(client, @box_api_url <> "/folders/#{folder}/items", query: [fields: Enum.join(fields, ",")] ) do case response do %{status: 200, body: %{entries: entries}} -> {:ok, entries} %{status: status, body: %{message: message}} -> {:error, status, message} %{status: status} -> {:error, status, to_string(status)} end end end @doc """ Folder from path returns the folder id for a path in Box. {:ok, folder} = Box.folder_from_path(auth.client, "/") """ def folder_from_path(_client, path) do if path == "/" or path == "." do {:ok, %{id: "0"}} else # TODO: fetch id for other paths raise "not implemented: folder_from_path #{path}" end end @doc """ File from path returns the file name and id for a path in Box. {:ok, file} = Box.file_from_path(auth.client, "file.ext") """ def file_from_path(client, path) do with {:ok, folder} <- folder_from_path(client, Path.dirname(path)), {:ok, files} <- folder_items(client, folder.id, [:id, :name]) do filename = Path.basename(path) case Enum.find(files, fn f -> f.type == "file" and f.name == filename end) do nil -> {:error, "file not found"} f -> {:ok, f} end end end @doc """ Create shared link for a file. {:ok, file} = Box.file_from_path(auth.client, "file.ext") {:ok, response.shared_link} = Box.create_shared_link(auth.client, file.id) IO.puts(response.shared_link.download_url) """ def create_shared_link(client, file_id) do # https://developer.box.com/reference#shared-link-object body = %{ shared_link: %{ access: "open", # TODO: password, unshared_at? permissions: %{ can_download: true } } } with {:ok, response} <- Tesla.put(client, @box_api_url <> "/files/#{file_id}", body) do case response do %{status: 200, body: body} -> {:ok, body} %{status: status, body: %{message: message}} -> {:error, status, message} %{status: status} -> {:error, status, to_string(status)} end end end @doc """ File info for a file id. {:ok, file} = Box.file_from_path(auth.client, "file.ext") {:ok, response} = Box.file_info(auth.client, file.id) IO.puts(response.shared_link.download_url) """ def file_info(client, file_id) do fields = [ :type, :id, :sequence_id, :etag, :name, :created_at, :modified_at, :description, :size, :path_collection, :created_by, :modified_by, :trashed_at, :purged_at, :content_created_at, :content_modified_at, :owned_by, :shared_link, :folder_upload_email, :parent, :item_status, :item_collection, :sync_state, :has_collaborations, :permissions, :tags, :sha1, :shared_link, :version_number, :comment_count, :lock, :extension, :is_package, :can_non_owners_invite ] with {:ok, response} <- Tesla.get(client, @box_api_url <> "/files/#{file_id}", query: [fields: Enum.join(fields, ",")] ) do {:ok, response.body} end end @doc """ Upload a local file to a folder on Box. {:ok, folder} = Box.folder_from_path(auth.client, "/") {:ok, _response} = Box.upload(auth.client, "path/to/file.ext", folder.id, "file.ext") """ def upload(client, path, folder_id, name) do attributes = Jason.encode!(%{ name: name, parent: %{id: folder_id} }) mp = Multipart.new() |> Multipart.add_field("attributes", attributes) |> Multipart.add_file(path) with {:ok, response} <- Tesla.post(client, @box_upload_url <> "/files/content", mp) do case response do %{status: 201, body: body} -> {:ok, body} %{status: status, body: %{message: message}} -> {:error, status, message} %{status: status} -> {:error, status, to_string(status)} end end end @doc """ Create folder in a parent folder. {:ok, folder} = Box.folder_from_path(auth.client, "/") {:ok, response} = Box.create_folder(auth.client, "folder", folder.id) """ def create_folder(client, name, folder_id) do body = %{ name: name, parent: %{id: folder_id} } with {:ok, response} <- Tesla.post(client, @box_api_url <> "/folders", body) do case response do %{status: 201, body: body} -> {:ok, body} %{status: status, body: %{message: message}} -> {:error, status, message} %{status: status} -> {:error, status, to_string(status)} end end end end