Storehouse.Plug.Presign (Storehouse v0.2.0)

Copy Markdown View Source

Signs uploads straight to the store for a frontend that is not a LiveView: a JSON endpoint in front of Storehouse.Batch.presign/2.

# lib/my_app_web/router.ex, behind your authentication
scope "/files" do
  pipe_through [:files, :require_user]  # the guide's, with its CSRF check

  forward "/presign", Storehouse.Plug.Presign,
    owner: &MyAppWeb.Files.owner/1,
    room: &MyAppWeb.Files.room/1,
    existing: &MyAppWeb.Files.existing/2,
    accept: Storehouse.Check.images(),
    max_bytes: 50_000_000

  forward "/register", Storehouse.Plug.Register, ...
end

A POST of

{"uploads": [{"name": "harbour.jpg", "type": "image/jpeg", "bytes": 35367, "checksum": "e3b0…"}]}

is answered 200 with one result per upload, in order:

{"uploads": [
  {"upload": {"key": "accounts/42/2026/10/…-harbour.jpg", "method": "PUT", "url": "https://…", "headers": {"content-type": "image/jpeg", …}}},
  {"existing": {"key": …, "url": …, …}},
  {"error": "storage_full"}
]}

The browser sends each file to its url with its method and exactly its headers, then gives the keys to Storehouse.Plug.Register. A body that is not that JSON gives 400, one that is not application/json 415 (a form of another site is never read), and a batch larger than :max_items 413, with {"error": code}.

Options

  • :owner - a function of the conn that gives the owner whose files these are (Storehouse.store/2's :owner), or nil.
  • :room - a function of the conn that gives the bytes the owner may still store, shared by the batch, or :infinity.
  • :existing - a function of the conn and a checksum that gives the file the app has already with it, or nil (:existing of Storehouse.presign_upload/4).
  • the other options of Storehouse.Batch.presign/2 (:accept, :max_bytes, :key, :cache, :expires_in, :adapter, :max_items), as they are.