From 84abf98b30d9b591c3b3e0ddc3bb34e96d8d1ef3 Mon Sep 17 00:00:00 2001 From: "byte[]" Date: Mon, 25 Nov 2019 23:51:17 -0500 Subject: [PATCH] uploading works --- config/config.exs | 3 +- lib/philomena/conversations/conversation.ex | 2 +- .../image_intensities/image_intensity.ex | 1 + lib/philomena/images.ex | 22 +++++- lib/philomena/images/image.ex | 9 ++- lib/philomena/processors.ex | 39 ++++++--- .../controllers/image_controller.ex | 29 +++++++ lib/philomena_web/router.ex | 2 +- .../templates/image/new.html.slime | 79 +++++++++++++++++++ 9 files changed, 168 insertions(+), 18 deletions(-) create mode 100644 lib/philomena_web/templates/image/new.html.slime diff --git a/config/config.exs b/config/config.exs index af16b711..f72ebe32 100644 --- a/config/config.exs +++ b/config/config.exs @@ -14,7 +14,8 @@ config :philomena, otp_secret_key: "Wn7O/8DD+qxL0X4X7bvT90wOkVGcA90bIHww4twR03Ci//zq7PnMw8ypqyyT/b/C", image_url_root: "/img", avatar_url_root: "/avatars", - badge_url_root: "/media" + badge_url_root: "/media", + image_file_root: "priv/static/system/images" config :philomena, :pow, user: Philomena.Users.User, diff --git a/lib/philomena/conversations/conversation.ex b/lib/philomena/conversations/conversation.ex index 62ddbed2..6e423ac2 100644 --- a/lib/philomena/conversations/conversation.ex +++ b/lib/philomena/conversations/conversation.ex @@ -62,7 +62,7 @@ defmodule Philomena.Conversations.Conversation do defp put_recipient(changeset) do recipient = changeset |> get_field(:recipient) - user = Repo.get_by(User, name: recipient) |> IO.inspect() + user = Repo.get_by(User, name: recipient) changeset |> put_change(:to, user) diff --git a/lib/philomena/image_intensities/image_intensity.ex b/lib/philomena/image_intensities/image_intensity.ex index 83720c63..89500c81 100644 --- a/lib/philomena/image_intensities/image_intensity.ex +++ b/lib/philomena/image_intensities/image_intensity.ex @@ -20,5 +20,6 @@ defmodule Philomena.ImageIntensities.ImageIntensity do image_intensity |> cast(attrs, [:nw, :ne, :sw, :se]) |> validate_required([:image_id, :nw, :ne, :sw, :se]) + |> unique_constraint(:image_id, name: :index_image_intensities_on_image_id) end end diff --git a/lib/philomena/images.ex b/lib/philomena/images.ex index dc29d8e3..56a99d35 100644 --- a/lib/philomena/images.ex +++ b/lib/philomena/images.ex @@ -13,6 +13,7 @@ defmodule Philomena.Images do alias Philomena.TagChanges.TagChange alias Philomena.Tags alias Philomena.Tags.Tag + alias Philomena.Processors @doc """ Gets a single image. @@ -44,10 +45,23 @@ defmodule Philomena.Images do {:error, %Ecto.Changeset{}} """ - def create_image(attrs \\ %{}) do - %Image{} - |> Image.changeset(attrs) - |> Repo.insert() + def create_image(attribution, attrs \\ %{}) do + tags = Tags.get_or_create_tags(attrs["tag_input"]) + + image = + %Image{} + |> Image.creation_changeset(attrs, attribution) + |> Image.tag_changeset(attrs, [], tags) + |> Processors.after_upload(attrs) + + Multi.new + |> Multi.insert(:image, image) + |> Multi.run(:after, fn _repo, %{image: image} -> + Processors.after_insert(image) + + {:ok, nil} + end) + |> Repo.transaction() end @doc """ diff --git a/lib/philomena/images/image.ex b/lib/philomena/images/image.ex index b76b98f1..d2c9224b 100644 --- a/lib/philomena/images/image.ex +++ b/lib/philomena/images/image.ex @@ -109,8 +109,11 @@ defmodule Philomena.Images.Image do end def creation_changeset(image, attrs, attribution) do + now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second) + image |> cast(attrs, [:source_url, :description]) + |> change(first_seen_at: now) |> change(attribution) end @@ -119,12 +122,14 @@ defmodule Philomena.Images.Image do |> cast(attrs, [ :image, :image_name, :image_width, :image_height, :image_size, :image_format, :image_mime_type, :image_aspect_ratio, - :image_orig_sha512_hash, :image_sha512_hash, :uploaded_image + :image_orig_sha512_hash, :image_sha512_hash, :uploaded_image, + :is_animated ]) |> validate_required([ :image, :image_width, :image_height, :image_size, :image_format, :image_mime_type, :image_aspect_ratio, - :image_orig_sha512_hash, :image_sha512_hash, :uploaded_image + :image_orig_sha512_hash, :image_sha512_hash, :uploaded_image, + :is_animated ]) |> validate_number(:image_size, greater_than: 0, less_than_or_equal_to: 26214400) |> validate_number(:image_width, greater_than: 0, less_than_or_equal_to: 32767) diff --git a/lib/philomena/processors.ex b/lib/philomena/processors.ex index ef14e75f..4e3e1753 100644 --- a/lib/philomena/processors.ex +++ b/lib/philomena/processors.ex @@ -32,10 +32,22 @@ defmodule Philomena.Processors do "video/webm" => Philomena.Processors.Webm } + @versions [ + thumb_tiny: {50, 50}, + thumb_small: {150, 150}, + thumb: {250, 250}, + small: {320, 240}, + medium: {800, 600}, + large: {1280, 1024}, + tall: {1024, 4096}, + full: nil + ] + def after_upload(image, params) do with upload when not is_nil(upload) <- params["image"], file <- upload.path, - mime <- @mimes[Mime.file(file)], + {:ok, mime} <- Mime.file(file), + mime <- @mimes[mime], analyzer when not is_nil(analyzer) <- @analyzers[mime], analysis <- analyzer.analyze(file), changes <- analysis_to_changes(analysis, file, upload.filename) @@ -50,7 +62,10 @@ defmodule Philomena.Processors do end def after_insert(image) do - File.cp!(image.uploaded_image, Path.join([image_file_root(), image.image])) + file = image_file(image) + dir = Path.dirname(file) + File.mkdir_p!(dir) + File.cp!(image.uploaded_image, file) ImageProcessor.cast(self(), image.id) end @@ -62,7 +77,7 @@ defmodule Philomena.Processors do analyzer = @analyzers[mime] analysis = analyzer.analyze(file) processor = @processors[mime] - process = processor.process(analysis, file) + process = processor.process(analysis, file, @versions) apply_edit_script(image, process) sha512 = Sha512.file(file) @@ -102,22 +117,27 @@ defmodule Philomena.Processors do defp apply_thumbnail(_image, thumb_dir, {:copy, new_file, destination}) do new_destination = Path.join([thumb_dir, destination]) + dir = Path.dirname(new_destination) - File.cp(new_file, new_destination) - File.chmod(new_destination, 0o755) + File.mkdir_p!(dir) + File.cp!(new_file, new_destination) + File.chmod!(new_destination, 0o755) end defp apply_thumbnail(image, thumb_dir, {:symlink_original, destination}) do - file = image_file(image) + file = Path.absname(image_file(image)) new_destination = Path.join([thumb_dir, destination]) + dir = Path.dirname(new_destination) - File.ln_s(file, new_destination) - File.chmod(new_destination, 0o755) + File.mkdir_p!(dir) + File.rm(new_destination) + File.ln_s!(file, new_destination) + File.chmod!(new_destination, 0o755) end defp analysis_to_changes(analysis, file, upload_name) do {width, height} = analysis.dimensions - %{size: size} = File.stat(file) + {:ok, %{size: size}} = File.stat(file) sha512 = Sha512.file(file) filename = build_filename(analysis.extension) @@ -132,6 +152,7 @@ defmodule Philomena.Processors do "image_aspect_ratio" => aspect_ratio(width, height), "image_orig_sha512_hash" => sha512, "image_sha512_hash" => sha512, + "is_animated" => analysis.animated?, "uploaded_image" => file } end diff --git a/lib/philomena_web/controllers/image_controller.ex b/lib/philomena_web/controllers/image_controller.ex index ecd1c8c6..05fa4620 100644 --- a/lib/philomena_web/controllers/image_controller.ex +++ b/lib/philomena_web/controllers/image_controller.ex @@ -9,6 +9,10 @@ defmodule PhilomenaWeb.ImageController do plug :load_and_authorize_resource, model: Image, only: :show, preload: [:tags, user: [awards: :badge]] + plug PhilomenaWeb.FilterBannedUsersPlug when action in [:new, :create] + plug PhilomenaWeb.UserAttributionPlug when action in [:create] + plug PhilomenaWeb.CaptchaPlug when action in [:create] + def index(conn, _params) do query = conn.assigns.compiled_filter @@ -77,4 +81,29 @@ defmodule PhilomenaWeb.ImageController do layout_class: "layout--wide" ) end + + def new(conn, _params) do + changeset = + %Image{} + |> Images.change_image() + + render(conn, "new.html", changeset: changeset) + end + + def create(conn, %{"image" => image_params}) do + attributes = conn.assigns.attributes + + case Images.create_image(attributes, image_params) do + {:ok, %{image: image}} -> + Images.reindex_image(image) + + conn + |> put_flash(:info, "Image created successfully.") + |> redirect(to: Routes.image_path(conn, :show, image)) + + {:error, :image, changeset, _} -> + conn + |> render("new.html", changeset: changeset) + end + end end diff --git a/lib/philomena_web/router.ex b/lib/philomena_web/router.ex index 904dfa7f..1900da79 100644 --- a/lib/philomena_web/router.ex +++ b/lib/philomena_web/router.ex @@ -83,7 +83,7 @@ defmodule PhilomenaWeb.Router do get "/", ActivityController, :index resources "/activity", ActivityController, only: [:index] - resources "/images", ImageController, only: [:index, :show] do + resources "/images", ImageController, only: [:index, :show, :new, :create] do resources "/comments", Image.CommentController, only: [:index, :show, :create] resources "/tags", Image.TagController, only: [:update], singleton: true resources "/sources", Image.SourceController, only: [:update], singleton: true diff --git a/lib/philomena_web/templates/image/new.html.slime b/lib/philomena_web/templates/image/new.html.slime new file mode 100644 index 00000000..528500b7 --- /dev/null +++ b/lib/philomena_web/templates/image/new.html.slime @@ -0,0 +1,79 @@ += form_for @changeset, Routes.image_path(@conn, :create), [multipart: true], fn f -> + + .dnp-warning + h4 + ' Read the + a> href="/pages/rules" site rules + ' and check our + a> href="/dnp" do-not-post list + p + ' Don't post content the artist doesn't want here (or shared in general), + strong including commercial content. + + = if !@conn.assigns.current_user do + p + strong<> Sorry, but due to spam, anonymous uploaders need to fill this out. + | If you're logged in, you can still post anonymously and won't have to deal with captchas! + + .field + = checkbox f, :captcha, class: "js-captcha", value: 0 + = label f, :captcha, "I am not a robot!" + + p + strong + ' Please check it isn't already here with + a href="/search/reverse" reverse search. + + / todo: extract this + h4 Select an image + .image-other + #js-image-upload-previews + p Upload a file from your computer + .field + = file_input f, :image, class: "input js-scraper" + = error_tag f, :image_size + = error_tag f, :image_width + = error_tag f, :image_height + = error_tag f, :image_name + = error_tag f, :image_mime_type + + .field-error-js.hidden.js-scraper + + h4 About this image + .field + = label f, :source_url, "The page you found this image on" + = url_input f, :source_url, class: "input input--wide js-image-input", placeholder: "Source URL" + + .field + label for="image[tag_input]" + ' Describe with + strong> 3+ + ' tags, including ratings and applicable artist tags + + = render PhilomenaWeb.TagView, "_tag_editor.html", f: f, name: :tag_input, type: :upload + + button.button.button--state-success.button--separate-left.button--bold id="tagsinput-save" type="button" title="This button saves the tags listed above to your browser, allowing you to retrieve them again by clicking the Load button" Save + button.button.button--state-warning.button--separate-left.button--bold id="tagsinput-load" type="button" title="This button loads any saved tags from your browser" Load + button.button.button--state-danger.button--separate-left.button--bold id="tagsinput-clear" type="button" title="This button will clear the list of tags above" Clear + + br + + .field + .block + .block__header.block__header--js-tabbed + = link "Description", to: "#", class: "selected", data: [click_tab: "write"] + = link "Preview", to: "#", data: [click_tab: "preview"] + + .block__tab.selected data-tab="write" + /= render partial: 'layouts/textile_toolbar' + = textarea f, :description, class: "input input--wide input--text js-preview-description js-image-input js-toolbar-input", placeholder: "Describe this image in plain words - this should generally be info about the image that doesn't belong in the tags or source." + .block__tab.hidden data-tab="preview" + | Loading preview... + + = if @conn.assigns.current_user do + .field + = label f, :anonymous, "Post anonymously" + = checkbox f, :anonymous, class: "checkbox" + + .actions + = submit "Upload", class: "button", autocomplete: "off", data: [disable_with: "Please wait..."] \ No newline at end of file