defmodule ActiveStorage do @moduledoc """ The ActiveStorage context. """ import Ecto.Query, warn: false alias Chaskiq.Repo alias ActiveStorage.{Attachment, Blob} def verifier do Chaskiq.Verifier end def graphql_resolver( _a, %{ input: %{ byte_size: _byte_size, checksum: _checksum, content_type: _content_type, filename: _filename } = input }, %{context: %{current_user: _current_user}} ) do direct_upload_response = %{direct_upload: create_direct_upload(input)} {:ok, direct_upload_response} end def create_direct_upload(%{ byte_size: byte_size, checksum: checksum, content_type: content_type, filename: filename }) do service = "amazon" {:ok, blob} = ActiveStorage.create_storage_blob(%{ byte_size: byte_size, checksum: checksum, content_type: content_type, filename: filename, metadata: %{}, service_name: service }) _service = blob |> ActiveStorage.Blob.service() ActiveStorage.Service.S3Service.create_direct_upload(blob, %{ byte_size: byte_size, checksum: checksum, content_type: content_type, filename: filename }) end # def url(blob) do # service(blob).url(blob) # end def url(blob) do ActiveStorage.Service.url(blob) end def service_url(blob) do signed_blob_id = Chaskiq.Verifier.sign(blob.id) "/active_storage/blobs/redirect/#{signed_blob_id}" end @doc """ Returns the list of storage_blob. ## Examples iex> list_storage_blob() [%Blob{}, ...] """ def list_storage_blob do Repo.all(Blob) end @doc """ Gets a single storage_blob. Raises `Ecto.NoResultsError` if the Storage blob does not exist. ## Examples iex> get_storage_blob!(123) %Blob{} iex> get_storage_blob!(456) ** (Ecto.NoResultsError) """ def get_storage_blob!(id), do: Repo.get!(Blob, id) @doc """ Creates a storage_blob. ## Examples iex> create_storage_blob(%{field: value}) {:ok, %Blob{}} iex> create_storage_blob(%{field: bad_value}) {:error, %Ecto.Changeset{}} """ def create_storage_blob(attrs \\ %{}) do %Blob{} |> Blob.changeset(attrs) |> Repo.insert() end @doc """ Updates a storage_blob. ## Examples iex> update_storage_blob(storage_blob, %{field: new_value}) {:ok, %Blob{}} iex> update_storage_blob(storage_blob, %{field: bad_value}) {:error, %Ecto.Changeset{}} """ def update_storage_blob(%Blob{} = storage_blob, attrs) do storage_blob |> Blob.changeset(attrs) |> Repo.update() end @doc """ Deletes a storage_blob. ## Examples iex> delete_storage_blob(storage_blob) {:ok, %Blob{}} iex> delete_storage_blob(storage_blob) {:error, %Ecto.Changeset{}} """ def delete_storage_blob(%Blob{} = storage_blob) do Repo.delete(storage_blob) end @doc """ Returns an `%Ecto.Changeset{}` for tracking storage_blob changes. ## Examples iex> change_storage_blob(storage_blob) %Ecto.Changeset{data: %Blob{}} """ def change_storage_blob(%Blob{} = storage_blob, attrs \\ %{}) do Blob.changeset(storage_blob, attrs) end @doc """ Gets a record's attachment. Returns `nil` if attachment doesn't exist. ## Examples iex> get_attachment(user, "avatar") %ActiveStorage.Attachment{} """ def get_attachment(record, attachment_name) do attachment_query(record, attachment_name) |> repo().one() end def get_attachments(record, attachment_name) do attachment_query(record, attachment_name) |> repo().all() end @doc """ Checks if attachment(s) exists (works for `has_one_attached` and `has_many_attached`). ## Examples iex> attached?(user, "avatar") true """ def attached?(record, attachment_name) do attachment_query(record, attachment_name) |> repo().exists?() end defp attachment_query(%mod{id: record_id}, attachment_name) do record_type = mod.record_type() from(a in Attachment, where: a.name == ^attachment_name and a.record_type == ^record_type and a.record_id == ^record_id) |> preload(:blob) end defp repo do Application.fetch_env!(:active_storage, :repo) end # Downloads the blob to a tempfile on disk. Yields the tempfile. # # The tempfile's name is prefixed with +ActiveStorage-+ and the blob's ID. Its extension matches that of the blob. # # By default, the tempfile is created in Dir.tmpdir. Pass +tmpdir:+ to create it in a different directory: # # blob.open(tmpdir: "/path/to/tmp") do |file| # # ... # end # # The tempfile is automatically closed and unlinked after the given block is executed. # # Raises ActiveStorage::IntegrityError if the downloaded data does not match the blob's checksum. # def open(tmpdir: nil, &block) do # service.open( # key, # checksum: checksum, # verify: !composed, # name: [ "ActiveStorage-#{id}-", filename.extension_with_delimiter ], # tmpdir: tmpdir, # &block # ) # end # def mirror_later # :nodoc: # ActiveStorage::MirrorJob.perform_later(key, checksum: checksum) if service.respond_to?(:mirror) # end def variable_content_types, do: [ "image/png", "image/gif", "image/jpg", "image/jpeg", "image/pjpeg", "image/tiff", "image/bmp", "image/vnd.adobe.photoshop", "image/vnd.microsoft.icon", "image/webp" ] def web_image_content_types, do: [ "image/png", "image/jpeg", "image/jpg", "image/gif" ] def content_types_to_serve_as_binary, do: [ "text/html", "text/javascript", "image/svg+xml", "application/postscript", "application/x-shockwave-flash", "text/xml", "application/xml", "application/xhtml+xml", "application/mathml+xml", "text/cache-manifest" ] def content_types_allowed_inline, do: [ "image/png", "image/gif", "image/jpg", "image/jpeg", "image/tiff", "image/bmp", "image/vnd.adobe.photoshop", "image/vnd.microsoft.icon", "application/pdf" ] def previewers, do: [ ActiveStorage.Previewer.PopplerPDFPreviewer, ActiveStorage.Previewer.MuPDFPreviewer, ActiveStorage.Previewer.VideoPreviewer ] def analyzers, do: [ActiveStorage.Analyzer.ImageAnalyzer, ActiveStorage.Analyzer.VideoAnalyzer] # def paths, do: ActiveSupport :: OrderedOptions.new() # def queues, do: ActiveSupport :: InheritableOptions.new() end