uploads: refactor /uploads/:id page for multi-file uploads.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
class ApplicationController < ActionController::Base
|
||||
include Pundit
|
||||
helper_method :search_params
|
||||
helper_method :search_params, :permitted_attributes
|
||||
|
||||
self.responder = ApplicationResponder
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ class PostsController < ApplicationController
|
||||
|
||||
def create
|
||||
@upload_media_asset = UploadMediaAsset.find(params[:upload_media_asset_id])
|
||||
@post = authorize Post.new_from_upload(@upload_media_asset.upload, @upload_media_asset.media_asset, **permitted_attributes(Post).to_h.symbolize_keys)
|
||||
@post = authorize Post.new_from_upload(@upload_media_asset, **permitted_attributes(Post).to_h.symbolize_keys)
|
||||
@post.save_if_unique(:md5)
|
||||
|
||||
if @post.errors.none?
|
||||
|
||||
@@ -39,14 +39,8 @@ class UploadsController < ApplicationController
|
||||
|
||||
def show
|
||||
@upload = authorize Upload.find(params[:id])
|
||||
@upload_media_asset = @upload.upload_media_assets.first
|
||||
@media_asset = @upload_media_asset&.media_asset
|
||||
|
||||
@post = Post.new_from_upload(@upload, @media_asset, source: @upload.source, **permitted_attributes(Post).to_h.symbolize_keys)
|
||||
@post.tag_string = "#{@post.tag_string} #{@upload.source_strategy&.artists.to_a.map(&:tag).map(&:name).join(" ")}".strip
|
||||
@post.tag_string += " " if @post.tag_string.present?
|
||||
|
||||
if request.format.html? && @upload.is_completed? && @upload.media_assets.first&.post.present?
|
||||
if request.format.html? && @upload.media_asset_count == 1 && @upload.media_assets.first&.post.present?
|
||||
flash[:notice] = "Duplicate of post ##{@upload.media_assets.first.post.id}"
|
||||
redirect_to @upload.media_assets.first.post
|
||||
else
|
||||
|
||||
@@ -74,7 +74,10 @@ class Post < ApplicationRecord
|
||||
has_many :versions, -> { Rails.env.test? ? order("post_versions.updated_at ASC, post_versions.id ASC") : order("post_versions.updated_at ASC") }, class_name: "PostVersion", dependent: :destroy
|
||||
end
|
||||
|
||||
def self.new_from_upload(upload, media_asset, tag_string: nil, rating: nil, parent_id: nil, source: nil, artist_commentary_title: nil, artist_commentary_desc: nil, translated_commentary_title: nil, translated_commentary_desc: nil, is_pending: nil)
|
||||
def self.new_from_upload(upload_media_asset, tag_string: nil, rating: nil, parent_id: nil, source: nil, artist_commentary_title: nil, artist_commentary_desc: nil, translated_commentary_title: nil, translated_commentary_desc: nil, is_pending: nil, add_artist_tag: false)
|
||||
upload = upload_media_asset.upload
|
||||
media_asset = upload_media_asset.media_asset
|
||||
|
||||
# XXX depends on CurrentUser
|
||||
commentary = ArtistCommentary.new(
|
||||
original_title: artist_commentary_title,
|
||||
@@ -83,6 +86,11 @@ class Post < ApplicationRecord
|
||||
translated_description: translated_commentary_desc,
|
||||
)
|
||||
|
||||
if add_artist_tag
|
||||
tag_string = "#{tag_string} #{upload_media_asset.source_strategy&.artists.to_a.map(&:tag).map(&:name).join(" ")}".strip
|
||||
tag_string += " " if tag_string.present?
|
||||
end
|
||||
|
||||
post = Post.new(
|
||||
uploader: upload.uploader,
|
||||
uploader_ip_addr: upload.uploader_ip_addr,
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Upload < ApplicationRecord
|
||||
extend Memoist
|
||||
|
||||
attr_accessor :file
|
||||
|
||||
belongs_to :uploader, class_name: "User"
|
||||
@@ -45,6 +43,10 @@ class Upload < ApplicationRecord
|
||||
def is_errored?
|
||||
status == "error"
|
||||
end
|
||||
|
||||
def is_finished?
|
||||
is_completed? || is_errored?
|
||||
end
|
||||
end
|
||||
|
||||
concerning :ValidationMethods do
|
||||
@@ -65,11 +67,6 @@ class Upload < ApplicationRecord
|
||||
Addressable::URI.normalized_encode(url)
|
||||
end
|
||||
end
|
||||
|
||||
def source_strategy
|
||||
return nil if source.blank?
|
||||
Sources::Strategies.find(source, referer_url)
|
||||
end
|
||||
end
|
||||
|
||||
def self.search(params)
|
||||
@@ -116,6 +113,4 @@ class Upload < ApplicationRecord
|
||||
def self.available_includes
|
||||
[:uploader, :upload_media_assets, :media_assets]
|
||||
end
|
||||
|
||||
memoize :source_strategy
|
||||
end
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class UploadMediaAsset < ApplicationRecord
|
||||
extend Memoist
|
||||
|
||||
belongs_to :upload
|
||||
belongs_to :media_asset, optional: true
|
||||
|
||||
@@ -23,4 +25,15 @@ class UploadMediaAsset < ApplicationRecord
|
||||
q = search_attributes(params, :id, :created_at, :updated_at, :status, :source_url, :page_url, :error, :upload, :media_asset)
|
||||
q.apply_default_order(params)
|
||||
end
|
||||
|
||||
def finished?
|
||||
active? || failed?
|
||||
end
|
||||
|
||||
def source_strategy
|
||||
return nil if source_url.blank?
|
||||
Sources::Strategies.find(source_url, page_url)
|
||||
end
|
||||
|
||||
memoize :source_strategy
|
||||
end
|
||||
|
||||
9
app/views/upload_media_assets/show.html.erb
Normal file
9
app/views/upload_media_assets/show.html.erb
Normal file
@@ -0,0 +1,9 @@
|
||||
<div id="c-uploads">
|
||||
<div id="a-show">
|
||||
<h1>Upload</h1>
|
||||
|
||||
<%= render "uploads/single_asset_upload", upload_media_asset: @upload_media_asset %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= render "uploads/secondary_links" %>
|
||||
7
app/views/uploads/_multiple_asset_upload.html.erb
Normal file
7
app/views/uploads/_multiple_asset_upload.html.erb
Normal file
@@ -0,0 +1,7 @@
|
||||
<%= render(MediaAssetGalleryComponent.new) do |gallery| %>
|
||||
<% upload.upload_media_assets.order(id: :asc).each do |upload_media_asset| %>
|
||||
<% gallery.media_asset do %>
|
||||
<%= render "upload_media_assets/preview", upload_media_asset: upload_media_asset, size: gallery.size %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
95
app/views/uploads/_single_asset_upload.html.erb
Normal file
95
app/views/uploads/_single_asset_upload.html.erb
Normal file
@@ -0,0 +1,95 @@
|
||||
<% if CurrentUser.user.upload_limit.limited? %>
|
||||
<p>You have reached your upload limit. Please wait for your pending uploads to be approved before uploading more.</p>
|
||||
|
||||
<p id="upload-limit">Upload Limit: <%= render "users/upload_limit", user: CurrentUser.user %></p>
|
||||
<% elsif upload_media_asset.pending? %>
|
||||
<p>Preparing to upload <%= external_link_to upload_media_asset.source_url %>...</p>
|
||||
<% elsif upload_media_asset.processing? %>
|
||||
<p>Processing <%= external_link_to upload_media_asset.source_url %>...</p>
|
||||
<% elsif upload_media_asset.failed? %>
|
||||
<p>Error: <%= upload_media_asset.error %>.</p>
|
||||
<% else %>
|
||||
<% upload = upload_media_asset.upload %>
|
||||
<% media_asset = upload_media_asset.media_asset %>
|
||||
|
||||
<%= embed_wiki("help:upload_notice", id: "upload-guide-notice") %>
|
||||
|
||||
<% unless CurrentUser.can_upload_free? %>
|
||||
<p id="upload-limit">Upload Limit: <%= render "users/upload_limit", user: CurrentUser.user %></p>
|
||||
<% end %>
|
||||
|
||||
<div id="client-errors" class="error-messages ui-state-error ui-corner-all" style="display:none"></div>
|
||||
|
||||
<div id="upload-image">
|
||||
<%= render MediaAssetComponent.new(media_asset: media_asset) %>
|
||||
|
||||
<p>
|
||||
<strong>Size</strong>
|
||||
<%= link_to media_asset.variant(:original).file_url do %>
|
||||
<%= number_to_human_size(media_asset.file_size) %> .<%= media_asset.file_ext %>
|
||||
<% end %>
|
||||
(<%= media_asset.image_width %>x<%= media_asset.image_height %>)
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<%= render "uploads/related_posts", source: upload_media_asset.source_strategy %>
|
||||
|
||||
<% if upload_media_asset.source_strategy.present? %>
|
||||
<%= render_source_data(upload_media_asset.source_strategy) %>
|
||||
<% end %>
|
||||
|
||||
<% post = Post.new_from_upload(upload_media_asset, add_artist_tag: true, source: upload_media_asset.source_strategy.canonical_url, **permitted_attributes(Post).to_h.symbolize_keys) %>
|
||||
<%= edit_form_for(post, html: { id: "form" }) do |f| %>
|
||||
<%= hidden_field_tag :media_asset_id, media_asset.id %> <%# used by iqdb javascript %>
|
||||
<%= hidden_field_tag :upload_media_asset_id, upload_media_asset.id %>
|
||||
|
||||
<%= f.input :source, as: :string, input_html: { value: post.source } %>
|
||||
<%= f.input :rating, collection: [["Explicit", "e"], ["Questionable", "q"], ["Safe", "s"]], as: :radio_buttons, selected: post.rating %>
|
||||
<%= f.input :parent_id, label: "Parent ID", as: :string, input_html: { value: post.parent_id } %>
|
||||
|
||||
<div class="input upload_artist_commentary_container">
|
||||
<strong>Commentary</strong>
|
||||
<a href="#" id="toggle-artist-commentary">show »</a>
|
||||
|
||||
<div class="artist-commentary" style="display: none;">
|
||||
<%= f.input :artist_commentary_title, as: :string, label: "Original Title", input_html: { value: post&.artist_commentary&.original_title } %>
|
||||
<%= f.input :artist_commentary_desc, as: :text, label: "Original Description", input_html: { value: post&.artist_commentary&.original_description } %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input upload_commentary_translation_container" style="display: none;">
|
||||
<strong>Translation</strong>
|
||||
<a href="#" id="toggle-commentary-translation">show »</a>
|
||||
|
||||
<div class="commentary-translation" style="display: none;">
|
||||
<%= f.input :translated_commentary_title, as: :string, label: "Translated Title", input_html: { value: post&.artist_commentary&.translated_title } %>
|
||||
<%= f.input :translated_commentary_desc, as: :text, label: "Translated Description", input_html: { value: post&.artist_commentary&.translated_description } %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input fixed-width-container" id="tags-container">
|
||||
<div class="header">
|
||||
<%= f.label :tag_string, "Tags" %>
|
||||
|
||||
<span data-tag-counter data-for="#post_tag_string">
|
||||
<span class="tag-count"></span>
|
||||
<img>
|
||||
</span>
|
||||
<a href="javascript:void(0)">
|
||||
<%= external_link_icon(id: "open-edit-dialog", "data-shortcut": "shift+e") %>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<%= f.input :tag_string, label: false, hint: "Ctrl+Enter to submit", input_html: { "data-autocomplete": "tag-edit", "data-shortcut": "e", value: post.tag_string } %>
|
||||
<%= render "related_tags/buttons" %>
|
||||
</div>
|
||||
|
||||
<%= f.submit "Post" %>
|
||||
|
||||
<% if CurrentUser.can_upload_free? %>
|
||||
<%= f.input :is_pending, as: :boolean, label: "Upload for approval", wrapper_html: { class: "inline-block" }, input_html: { checked: post.is_pending? } %>
|
||||
<% end %>
|
||||
|
||||
<%= render "related_tags/container" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
@@ -2,104 +2,14 @@
|
||||
<div id="a-show">
|
||||
<h1>Upload</h1>
|
||||
|
||||
<% if @upload.is_pending? || @upload.is_processing? %>
|
||||
<% content_for(:html_header) do %>
|
||||
<meta http-equiv="refresh" content="1">
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% if @upload.is_errored? %>
|
||||
<p>Error: <%= @upload.error %>.</p>
|
||||
<% elsif @upload.is_pending? && @upload.source.present? %>
|
||||
<p>Preparing to upload <%= external_link_to @upload.source %>...</p>
|
||||
<% elsif @upload.is_processing? && @upload.source.present? %>
|
||||
<p>Processing <%= external_link_to @upload.source %>...</p>
|
||||
<% elsif !@upload.is_completed? %>
|
||||
<% elsif @upload.media_asset_count == 0 %>
|
||||
<p>Processing upload...</p>
|
||||
<% elsif CurrentUser.user.upload_limit.limited? %>
|
||||
<p>You have reached your upload limit. Please wait for your pending uploads to be approved before uploading more.</p>
|
||||
|
||||
<p id="upload-limit">Upload Limit: <%= render "users/upload_limit", user: CurrentUser.user %></p>
|
||||
<% else %>
|
||||
<%= embed_wiki("help:upload_notice", id: "upload-guide-notice") %>
|
||||
|
||||
<% unless CurrentUser.can_upload_free? %>
|
||||
<p id="upload-limit">Upload Limit: <%= render "users/upload_limit", user: CurrentUser.user %></p>
|
||||
<% end %>
|
||||
|
||||
<div id="client-errors" class="error-messages ui-state-error ui-corner-all" style="display:none"></div>
|
||||
|
||||
<div id="upload-image">
|
||||
<%= render MediaAssetComponent.new(media_asset: @media_asset) %>
|
||||
|
||||
<p>
|
||||
<strong>Size</strong>
|
||||
<%= link_to @media_asset.variant(:original).file_url do %>
|
||||
<%= number_to_human_size(@media_asset.file_size) %> .<%= @media_asset.file_ext %>
|
||||
<% end %>
|
||||
(<%= @media_asset.image_width %>x<%= @media_asset.image_height %>)
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<%= render "uploads/related_posts", source: @upload.source_strategy %>
|
||||
|
||||
<% if @upload.source_strategy.present? %>
|
||||
<%= render_source_data(@upload.source_strategy) %>
|
||||
<% end %>
|
||||
|
||||
<%= edit_form_for(@post, html: { id: "form" }) do |f| %>
|
||||
<%= hidden_field_tag :media_asset_id, @media_asset.id %> <%# used by iqdb javascript %>
|
||||
<%= hidden_field_tag :upload_media_asset_id, @upload_media_asset.id %>
|
||||
|
||||
<%= f.input :source, as: :string, input_html: { value: @upload.source_strategy&.canonical_url } %>
|
||||
<%= f.input :rating, collection: [["Explicit", "e"], ["Questionable", "q"], ["Safe", "s"]], as: :radio_buttons, selected: @post.rating %>
|
||||
<%= f.input :parent_id, label: "Parent ID", as: :string, input_html: { value: @post.parent_id } %>
|
||||
|
||||
<div class="input upload_artist_commentary_container">
|
||||
<strong>Commentary</strong>
|
||||
<a href="#" id="toggle-artist-commentary">show »</a>
|
||||
|
||||
<div class="artist-commentary" style="display: none;">
|
||||
<%= f.input :artist_commentary_title, as: :string, label: "Original Title", input_html: { value: @post&.artist_commentary&.original_title } %>
|
||||
<%= f.input :artist_commentary_desc, as: :text, label: "Original Description", input_html: { value: @post&.artist_commentary&.original_description } %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input upload_commentary_translation_container" style="display: none;">
|
||||
<strong>Translation</strong>
|
||||
<a href="#" id="toggle-commentary-translation">show »</a>
|
||||
|
||||
<div class="commentary-translation" style="display: none;">
|
||||
<%= f.input :translated_commentary_title, as: :string, label: "Translated Title", input_html: { value: @post&.artist_commentary&.translated_title } %>
|
||||
<%= f.input :translated_commentary_desc, as: :text, label: "Translated Description", input_html: { value: @post&.artist_commentary&.translated_description } %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input fixed-width-container" id="tags-container">
|
||||
<div class="header">
|
||||
<%= f.label :tag_string, "Tags" %>
|
||||
|
||||
<span data-tag-counter data-for="#post_tag_string">
|
||||
<span class="tag-count"></span>
|
||||
<img>
|
||||
</span>
|
||||
<a href="javascript:void(0)">
|
||||
<%= external_link_icon(id: "open-edit-dialog", "data-shortcut": "shift+e") %>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<%= f.input :tag_string, label: false, hint: "Ctrl+Enter to submit", input_html: { "data-autocomplete": "tag-edit", "data-shortcut": "e", value: @post.tag_string } %>
|
||||
<%= render "related_tags/buttons" %>
|
||||
</div>
|
||||
|
||||
<%= f.submit "Post" %>
|
||||
|
||||
<% if CurrentUser.can_upload_free? %>
|
||||
<%= f.input :is_pending, as: :boolean, label: "Upload for approval", wrapper_html: { class: "inline-block" }, input_html: { checked: @post.is_pending? } %>
|
||||
<% end %>
|
||||
|
||||
<%= render "related_tags/container" %>
|
||||
<% end %>
|
||||
<% elsif @upload.media_asset_count > 1 %>
|
||||
<%= render "multiple_asset_upload", upload: @upload %>
|
||||
<% elsif @upload.media_asset_count == 1 %>
|
||||
<%= render "single_asset_upload", upload_media_asset: @upload.upload_media_assets.first %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -9,16 +9,18 @@ FactoryBot.define do
|
||||
|
||||
factory(:completed_source_upload) do
|
||||
status { "completed" }
|
||||
upload_media_assets { [build(:upload_media_asset)] }
|
||||
media_asset_count { 1 }
|
||||
upload_media_assets { [build(:upload_media_asset, source_url: "https://example.com/file.jpg", status: "active")] }
|
||||
end
|
||||
|
||||
factory(:completed_file_upload) do
|
||||
status { "completed" }
|
||||
source { nil }
|
||||
media_asset_count { 1 }
|
||||
file { Rack::Test::UploadedFile.new("#{Rails.root}/test/files/test.jpg") }
|
||||
|
||||
upload_media_assets do
|
||||
[build(:upload_media_asset, media_asset: build(:media_asset, file: "test/files/test.jpg"))]
|
||||
[build(:upload_media_asset, media_asset: build(:media_asset, file: "test/files/test.jpg"), source_url: "file://test.jpg", status: "active")]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,5 +2,6 @@ FactoryBot.define do
|
||||
factory(:upload_media_asset) do
|
||||
upload
|
||||
media_asset
|
||||
source_url { FFaker::Internet.http_url }
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user