-
-
Save wojtekmach/8310bf1d8725715a2801f334caa0c339 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Mix.install([ | |
| {:phoenix_playground, "~> 0.1.4"}, | |
| {:req_s3, "~> 0.2.0"} | |
| ]) | |
| # Based on https://hexdocs.pm/phoenix_live_view/uploads-external.html#direct-to-s3 | |
| defmodule DemoLive do | |
| use Phoenix.LiveView | |
| @impl true | |
| def mount(_params, _session, socket) do | |
| {:ok, | |
| socket | |
| |> allow_upload( | |
| :photo, | |
| accept: ~w[.png .jpeg .jpg], | |
| max_entries: 1, | |
| auto_upload: true, | |
| external: &presign_upload/2 | |
| )} | |
| end | |
| @impl true | |
| def render(assigns) do | |
| ~H""" | |
| <form id="upload-form" phx-change="validate"> | |
| <.live_file_input upload={@uploads.photo} /> | |
| </form> | |
| <div phx-drop-target={@uploads.photo.ref} style="width: 20em; height: 10em; padding: 1em; border: 1px dashed"> | |
| <%= for entry <- @uploads.photo.entries do %> | |
| <div> | |
| <.live_img_preview entry={entry} height="100" /> | |
| <div><%= entry.progress %>%</div> | |
| <%= if entry.done? do %> | |
| <.link href={presign_url(entry)}>Uploaded</.link> | |
| <% end %> | |
| </div> | |
| <% end %> | |
| </div> | |
| <script type="text/javascript"> | |
| window.uploaders.S3 = function(entries, onViewError) { | |
| entries.forEach(entry => { | |
| let formData = new FormData() | |
| let {url, fields} = entry.meta | |
| Object.entries(fields).forEach(([key, val]) => formData.append(key, val)) | |
| formData.append("file", entry.file) | |
| let xhr = new XMLHttpRequest() | |
| onViewError(() => xhr.abort()) | |
| xhr.onload = () => xhr.status === 204 ? entry.progress(100) : entry.error() | |
| xhr.onerror = () => entry.error() | |
| xhr.upload.addEventListener("progress", (event) => { | |
| if (event.lengthComputable) { | |
| let percent = Math.round((event.loaded / event.total) * 100) | |
| if (percent < 100) { entry.progress(percent) } | |
| } | |
| }) | |
| xhr.open("POST", url, true) | |
| xhr.send(formData) | |
| }) | |
| } | |
| </script> | |
| <style type="text/css"> | |
| body { padding: 1em; } | |
| </style> | |
| """ | |
| end | |
| @impl true | |
| def handle_event("validate", _params, socket) do | |
| {:noreply, socket} | |
| end | |
| defp presign_upload(entry, socket) do | |
| s3_options = s3_options(entry) | |
| form = ReqS3.presign_form(s3_options ++ [content_type: entry.client_type]) | |
| meta = %{ | |
| uploader: "S3", | |
| key: s3_options[:key], | |
| url: form.url, | |
| fields: Map.new(form.fields) | |
| } | |
| {:ok, meta, socket} | |
| end | |
| defp presign_url(entry) do | |
| ReqS3.presign_url(s3_options(entry)) | |
| end | |
| defp s3_options(entry) do | |
| [ | |
| access_key_id: System.fetch_env!("AWS_ACCESS_KEY_ID"), | |
| secret_access_key: System.fetch_env!("AWS_SECRET_ACCESS_KEY"), | |
| region: System.get_env("AWS_REGION", "us-east-1"), | |
| bucket: System.fetch_env!("BUCKET_NAME"), | |
| key: "uploads/#{entry.client_name}" | |
| ] | |
| end | |
| end | |
| PhoenixPlayground.start(live: DemoLive) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment