Created
October 10, 2016 12:46
-
-
Save radzserg/3abc7a6fdac6fb98af8607d1b5a0cdaf 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
| defmodule App.Image do | |
| use App.Web, :model | |
| alias App.Image | |
| alias App.Repo | |
| alias App.Helpers.FileHelper | |
| alias App.Helpers.ImageHelper | |
| schema "images" do | |
| field :type, :string | |
| field :path, :string | |
| field :mime, :string | |
| field :size, :integer | |
| field :width, :integer | |
| field :height, :integer | |
| belongs_to :parent, App.Parent | |
| timestamps() | |
| end | |
| @doc """ | |
| Builds a changeset based on the `struct` and `params`. | |
| """ | |
| def changeset(struct, params \\ %{}) do | |
| struct | |
| |> cast(params, [:type, :path, :mime, :size, :width, :height, :parent_id]) | |
| |> validate_required([:type, :path, :mime, :size]) | |
| end | |
| @doc """ | |
| Creates image from provided URL | |
| """ | |
| def create_from_url(url, type) do | |
| %HTTPoison.Response{body: body, headers: headers} = HTTPoison.get!(url) | |
| mime = fetch_header_value(headers, "Content-Type") | |
| size = fetch_header_value(headers, "Content-Length") | |
| path = build_path_from_url(url, type) | |
| save_image_from_content(body, path, mime, size, type) | |
| end | |
| @doc """ | |
| Return resized image from parent image | |
| """ | |
| def resized_image(image, width, height) do | |
| case Repo.get_by(Image, parent_id: image.id, width: width, height: height) do | |
| nil -> create_resized_image(image, width, height) | |
| image -> image | |
| end | |
| end | |
| @doc """ | |
| Create imge from local file | |
| """ | |
| def create_from_file(path, type, filename \\ nil) do | |
| mime = FileHelper.get_mime!(path) | |
| size = FileHelper.get_size!(path) | |
| dest_path = if filename do | |
| build_path_from_path(path, type, filename) | |
| else | |
| build_path_from_path(path, type) | |
| end | |
| save_image_from_file(path, dest_path, mime, size, type) | |
| end | |
| @doc """ | |
| Returns URL to the image | |
| """ | |
| def url(image) do | |
| upload_manager = App.Pact.get("upload_manager") | |
| upload_manager.url(image.path) | |
| end | |
| _ = """ | |
| Build path based on image type and base name | |
| """ | |
| defp build_path_from_url(image_url, type) do | |
| uri = URI.parse(image_url) | |
| basename = Path.basename(uri.path) | |
| hash = random_string(32) | |
| path = "#{type}/#{hash}/#{basename}" | |
| path | |
| end | |
| defp build_path_from_path(path, type, filename) do | |
| hash = random_string(32) | |
| path = "#{type}/#{hash}/#{filename}" | |
| path | |
| end | |
| defp build_path_from_path(path, type) do | |
| basename = Path.basename(path) | |
| hash = random_string(32) | |
| path = "#{type}/#{hash}/#{basename}" | |
| path | |
| end | |
| _ = """ | |
| Generates uniq string to build uniq path | |
| """ | |
| defp random_string(length) do | |
| :crypto.strong_rand_bytes(length) | |
| |> Base.url_encode64 | |
| |> binary_part(0, length) | |
| end | |
| _ = """ | |
| Fetch header from headers received with HTTPoison | |
| """ | |
| defp fetch_header_value(headers, needed_header) do | |
| needed_header = String.downcase(needed_header) | |
| header = Enum.find(headers, fn(header) -> | |
| {header, _value} = header | |
| String.downcase(header) == needed_header | |
| end) | |
| if header do | |
| {header, value} = header | |
| value | |
| else | |
| nil | |
| end | |
| end | |
| _ = """ | |
| Creates resized image from given image | |
| """ | |
| defp create_resized_image(image, width, height) do | |
| upload_manager = App.Pact.get("upload_manager") | |
| base_path = Application.get_env(:tendsup, App.Endpoint)[:root] | |
| local_path = "#{base_path}/runtime/resize_cache/" <> random_string(32) | |
| upload_manager.save_to_local_file!(image.path, local_path) | |
| ImageHelper.thumb(local_path, local_path, width, height) | |
| path = build_path_from_path(image.path, image.type) | |
| save_image_from_file(local_path, path, image.mime, image.size, image.type, image.id) | |
| end | |
| _ = """ | |
| Common private method used in create_from_url and create_from_path | |
| """ | |
| defp save_image_from_content(body, path, mime, size, type, parent_id \\ nil) do | |
| changeset = Image.changeset(%Image{}, %{path: path, mime: mime, | |
| size: size, type: type, parent_id: parent_id}) | |
| if changeset.valid? do | |
| upload_manager = App.Pact.get("upload_manager") | |
| case upload_manager.save_from_content!(body, path, %{content_type: mime}) do | |
| :ok -> | |
| case Repo.insert(changeset) do | |
| {:ok, image} -> {:ok, image} | |
| {:error, changeset} -> {:error, changeset} | |
| end | |
| {:error, reason} -> {:error, reason} | |
| end | |
| else | |
| {:error, changeset} | |
| end | |
| end | |
| defp save_image_from_file(file, path, mime, size, type, parent_id \\ nil) do | |
| changeset = Image.changeset(%Image{}, %{path: path, mime: mime, | |
| size: size, type: type, parent_id: parent_id}) | |
| if changeset.valid? do | |
| upload_manager = App.Pact.get("upload_manager") | |
| case upload_manager.save_from_file!(file, path, %{content_type: mime}) do | |
| :ok -> | |
| case Repo.insert(changeset) do | |
| {:ok, image} -> {:ok, image} | |
| {:error, changeset} -> {:error, changeset} | |
| end | |
| {:error, reason} -> {:error, reason} | |
| end | |
| else | |
| {:error, changeset} | |
| end | |
| end | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment