-
Notifications
You must be signed in to change notification settings - Fork 196
Bulk Uploading Edition Images [WHIT-1812][WHIT-2434] #10625
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,7 @@ | ||
| <li class="govuk-grid-row"> | ||
| <div class="govuk-grid-column-one-third"> | ||
| <% if image.image_data&.all_asset_variants_uploaded? %> | ||
| <img src="<%= image.url %>" alt="<%= preview_alt_text %>" class="app-view-edition-resource__preview"> | ||
| <% if image.image_data&.original_uploaded? && image.thumbnail %> | ||
| <img src="<%= image.thumbnail %>" alt="<%= preview_alt_text %>" class="app-view-edition-resource__preview"> | ||
| <% else %> | ||
| <span class="govuk-tag govuk-tag--green">Processing</span> | ||
| <% end %> | ||
|
|
@@ -10,11 +10,15 @@ | |
| <div class="govuk-grid-column-two-thirds"> | ||
| <p class="govuk-body"><strong>Caption: </strong><%= caption %></p> | ||
| <p class="govuk-body"><strong>Alt text: </strong><%= alt_text %></p> | ||
| <%= render "govuk_publishing_components/components/copy_to_clipboard", { | ||
| label: tag.strong("Markdown code:"), | ||
| copyable_content: image_markdown, | ||
| button_text: "Copy Markdown", | ||
| } %> | ||
| <% if image.image_data&.bitmap? && image.image_data&.requires_crop? %> | ||
| <span class="govuk-tag govuk-tag--red">Requires crop</span> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Out of interest, what would happen if the user constructed the markdown themselves and embedded it before cropping took place? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think an error would likely occur since there's logic which stops variants from being generated if the crop hasn't been provided. I'm wondering if I should perhaps remove that which although would generate unnecessary images would make edition validation significantly easier. |
||
| <% else %> | ||
| <%= render "govuk_publishing_components/components/copy_to_clipboard", { | ||
| label: tag.strong("Markdown code:"), | ||
| copyable_content: image_markdown, | ||
| button_text: "Copy Markdown", | ||
| } %> | ||
| <% end %> | ||
| </div> | ||
|
|
||
| <div class="app-view-edition-resource__actions govuk-grid-column-full govuk-button-group govuk-!-margin-top-4"> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -40,6 +40,6 @@ def find_image_index | |
| end | ||
|
|
||
| def can_be_custom_lead_image? | ||
| edition.can_have_custom_lead_image? && !image.svg? | ||
| edition.can_have_custom_lead_image? && !image.svg? && !image.image_data.requires_crop? | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @lauraghiorghisor-tw we'll need to add this to the lead image select block if this merges There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In that case please hold off on merging this PR until #10635 is done 🙏 I don't want to have to change the lead image setting (and do all the integration import testing) again if I can help it! |
||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,7 +16,21 @@ def destroy | |
| end | ||
|
|
||
| def update | ||
| if image.update(params.require(:image).permit(:caption, :alt_text)) | ||
| image.assign_attributes(image_params) | ||
|
|
||
| if image_data_params["crop_data"].present? | ||
| image_data = image.image_data | ||
| new_image_data = ImageData.new | ||
| new_image_data.to_replace_id = image_data.id | ||
| new_image_data.assign_attributes(image_data_params) | ||
| new_image_data.file.download! image_data.file.url | ||
| new_image_data.save! | ||
| image.image_data = new_image_data | ||
| end | ||
|
|
||
| image.image_data.validate_on_image = image | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oooofff, wish we didn't do this, I know it's existing code though. But yeah, we should really have a unique filename validation for images at the edition level, not set transitive attributes on the image data to walk back up the association chain. Grim. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is unfortunately how we handle files in the bulk uploader too, I'd much prefer if it the filename was stored separately from the uploaded file within the |
||
|
|
||
| if image.save | ||
| PublishingApiDocumentRepublishingWorker.perform_async(@edition.document_id) | ||
| redirect_to admin_edition_images_path(@edition), notice: "#{image.image_data.carrierwave_image} details updated" | ||
| else | ||
|
|
@@ -25,47 +39,59 @@ def update | |
| end | ||
|
|
||
| def create | ||
| @new_image = @edition.images.build | ||
| @new_image.build_image_data(image_params["image_data"]) | ||
|
|
||
| @new_image.image_data.validate_on_image = @new_image | ||
| # so that auth_bypass_id is discoverable by AssetManagerStorage | ||
| @new_image.image_data.images << @new_image | ||
| @images = images_params.map { |image| create_image(image) } | ||
|
|
||
| if @new_image.save | ||
| if @images.empty? | ||
| flash.now.alert = "No images selected. Choose a valid JPEG, PNG, SVG or GIF." | ||
| elsif @images.all?(&:valid?) | ||
| @images.each(&:save) | ||
| @edition.update_lead_image if @edition.can_have_custom_lead_image? | ||
| PublishingApiDocumentRepublishingWorker.perform_async(@edition.document_id) | ||
| redirect_to edit_admin_edition_image_path(@edition, @new_image.id), notice: "#{@new_image.filename} successfully uploaded" | ||
| elsif new_image_needs_cropping? | ||
| image_kind_config = @new_image.image_data.image_kind_config | ||
| @valid_width = image_kind_config.valid_width | ||
| @valid_height = image_kind_config.valid_height | ||
| @data_url = image_data_url | ||
| render :crop | ||
| flash.now.notice = "Images successfully uploaded" | ||
| else | ||
| @new_image.errors.delete(:"image_data.file", :too_large) | ||
| # Remove @new_image from @edition.images array, otherwise the view will render it in the 'Uploaded images' list | ||
| @edition.images.delete(@new_image) | ||
| render :index | ||
| # Remove images from @edition.images array, otherwise the view will render it in the 'Uploaded images' list | ||
| @images.each { |image| @edition.images.delete(image) } | ||
| end | ||
|
|
||
| render :index | ||
| end | ||
|
|
||
| def create_image(image) | ||
| new_image = @edition.images.build | ||
|
|
||
| new_image.build_image_data(image["image_data"]) | ||
|
|
||
| new_image.image_data.validate_on_image = new_image | ||
|
|
||
| # so that auth_bypass_id is discoverable by AssetManagerStorage | ||
| new_image.image_data.images << new_image | ||
|
|
||
| new_image | ||
| end | ||
|
|
||
| def edit | ||
| image = Image.find(params[:id]) | ||
| flash.now.notice = "The image is being processed. Try refreshing the page." unless image&.image_data&.all_asset_variants_uploaded? | ||
| flash.now.notice = "The image is being processed. Try refreshing the page." unless image&.image_data&.original_uploaded? | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def new_image_needs_cropping? | ||
| @new_image.errors.of_kind?(:"image_data.file", :too_large) && @new_image.errors.size == 1 | ||
| def image_url | ||
| return unless image&.image_data&.original_uploaded? | ||
|
|
||
| image_data = image.image_data | ||
| unless image_data.file.cached? | ||
| image_data.file.download! image_data.file.url | ||
| end | ||
| img_data = Base64.strict_encode64(image_data.file.read) | ||
|
|
||
| "data:#{image_data.file.content_type};base64,#{img_data}" | ||
| end | ||
| helper_method :image_url | ||
|
|
||
| def image_data_url | ||
| file = @new_image.image_data.file | ||
| image_data = Base64.strict_encode64(file.read) | ||
| "data:#{file.content_type};base64,#{image_data}" | ||
| def image_kind_config | ||
| image.image_data.image_kind_config | ||
| end | ||
| helper_method :image_kind_config | ||
|
|
||
| def image | ||
| @image ||= find_image | ||
|
|
@@ -92,7 +118,15 @@ def enforce_permissions! | |
| end | ||
| end | ||
|
|
||
| def images_params | ||
| params.fetch(:images, []).map { |image| image.permit(image_data: %i[file]) } | ||
| end | ||
|
|
||
| def image_data_params | ||
| params.fetch(:image, {}).fetch(:image_data, {}).permit(:file, :image_kind, crop_data: %i[x y width height]) | ||
| end | ||
|
|
||
| def image_params | ||
| params.fetch(:image, {}).permit(image_data: %i[file image_kind]) | ||
| params.fetch(:image, {}).except(:image_data).permit(:caption, :alt_text, image_data: %i[crop_data file image_kind]) | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,14 +10,34 @@ class Image < ApplicationRecord | |
|
|
||
| accepts_nested_attributes_for :image_data | ||
|
|
||
| delegate :filename, :content_type, :width, :height, :bitmap?, :svg?, to: :image_data | ||
| delegate :filename, :content_type, :width, :height, :bitmap?, :svg?, :can_be_cropped?, :requires_crop?, to: :image_data | ||
|
|
||
| default_scope -> { order(:id) } | ||
|
|
||
| def url(*args) | ||
| image_data.file_url(*args) | ||
| end | ||
|
|
||
| def embed_url | ||
| return unless image_data.respond_to?(:image_kind_config) | ||
|
|
||
| embed_version = image_data.image_kind_config.embed_version | ||
|
|
||
| return url if embed_version.blank? || !image_data.all_asset_variants_uploaded? | ||
|
|
||
| url(embed_version.to_sym) || url | ||
| end | ||
|
|
||
| def thumbnail | ||
| return image_data.file_url unless bitmap? && !requires_crop? | ||
|
|
||
| variant = image_data.assets.find { |asset| asset.variant != "original" }&.variant&.to_sym | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we be looking for something specific here rather than any variant that isn't the original? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is just to present to the user a cropped version of the uploaded image. It might be a specific variant hasn't yet uploaded on page load, so this is why I've implemented it like this. |
||
|
|
||
| return if variant.blank? | ||
|
|
||
| url(variant) | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def destroy_image_data_if_required | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.