From 3f2569b93841028106a43cdd25c2c4090d0c601d Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Thu, 2 Dec 2021 02:49:09 -0500 Subject: [PATCH] Forem Creation: Logo Upload & Resizing (#15499) * wip - Got logo upload working * Now have the logo rendering in the header and in the admin image config section. * Small layout tweak for admin -> config -> images -> logo. * feat: create a logo uploader with some tests * feat: use the logoUploader instead of the ArticleImageUploader * feat: return early because svg's do not contain exif or gps data * chore: we can move the raise outside the transaction as the rest of the transaction won't execute if we raise an error * feat: add a size range * WIP: resize an image to a random number for now * hid the logo behind a feature flag and kept logo_svg as is in the site header. * Added the jpe file type to the logo uploader. * Skipped the resizing of an image if it's an SVG in the logo uploader. * Added content types to the content type logo uploader allow list. * Synced logo validation with frontend and backend. * Removed unnecessary ALLOWED_PARAMS elements. * feat: update the logo upoader and tests * chore: remove comments * chore: remove comments * feat: update the resizing for the images + add the correct content type * spec: test the versions * fix: update the Constant * feat: add the versions of the logo * feat: populate the settings correctly and consistently * feat: add an random string to the file name to avoid caching issues * feat: amend the logo layout * chore: remove comments * spec: update * feat: image type whitelist * feat: update the logo css and also just use resized_logo and remove mobile resize * feat: add a max-height * only add site-logo if the feature flag is off * Renamed IMAGE_TYPE_WHITELIST to IMAGE_TYPE_ALLOWLIST * Update app/controllers/admin/creator_settings_controller.rb Co-authored-by: Michael Kohl * Update app/uploaders/logo_uploader.rb Co-authored-by: Michael Kohl * Update app/uploaders/logo_uploader.rb Co-authored-by: Michael Kohl * Update app/uploaders/logo_uploader.rb Co-authored-by: Michael Kohl * Update spec/uploaders/logo_uploader_spec.rb Co-authored-by: Julianna Tetreault <32834804+juliannatetreault@users.noreply.github.com> * Update spec/uploaders/logo_uploader_spec.rb Co-authored-by: Julianna Tetreault <32834804+juliannatetreault@users.noreply.github.com> * chore: revert admin change * refactor: use a static value for directory * feat: freeze constants * feat: remove the logo requirement * chore: spacing * remove logo requirement Co-authored-by: Ridhwana Co-authored-by: Michael Kohl Co-authored-by: Julianna Tetreault <32834804+juliannatetreault@users.noreply.github.com> --- app/assets/stylesheets/base/main.scss | 1 + .../admin/creator_settings_controller.rb | 24 ++++- app/models/settings/general.rb | 3 + app/uploaders/base_uploader.rb | 3 + app/uploaders/logo_uploader.rb | 50 ++++++++++ .../admin/creator_settings/_form.html.erb | 7 +- app/views/admin/creator_settings/new.html.erb | 2 +- app/views/layouts/_logo.html.erb | 8 +- .../creatorSettings.spec.js | 5 - spec/uploaders/logo_uploader_spec.rb | 97 +++++++++++++++++++ 10 files changed, 182 insertions(+), 18 deletions(-) create mode 100644 app/uploaders/logo_uploader.rb create mode 100644 spec/uploaders/logo_uploader_spec.rb diff --git a/app/assets/stylesheets/base/main.scss b/app/assets/stylesheets/base/main.scss index 592f89a91..b8018e18f 100644 --- a/app/assets/stylesheets/base/main.scss +++ b/app/assets/stylesheets/base/main.scss @@ -64,6 +64,7 @@ a { // Logo .site-logo { max-width: var(--max-width, 125px); + max-height: 40px; font-size: var(--font-size, var(--fs-base)); font-weight: var(--font-weight, var(--fw-medium)); diff --git a/app/controllers/admin/creator_settings_controller.rb b/app/controllers/admin/creator_settings_controller.rb index 673daef0c..a6c3ca2f6 100644 --- a/app/controllers/admin/creator_settings_controller.rb +++ b/app/controllers/admin/creator_settings_controller.rb @@ -1,18 +1,28 @@ module Admin class CreatorSettingsController < Admin::ApplicationController - ALLOWED_PARAMS = %i[community_name logo_svg primary_brand_color_hex invite_only_mode public checked_code_of_conduct - checked_terms_and_conditions].freeze + ALLOWED_PARAMS = %i[checked_code_of_conduct checked_terms_and_conditions community_name + invite_only_mode logo primary_brand_color_hex public].freeze - def new; end + def new + @max_file_size = LogoUploader::MAX_FILE_SIZE + @logo_allowed_types = (LogoUploader::CONTENT_TYPE_ALLOWLIST + + LogoUploader::EXTENSION_ALLOWLIST.map { |extension| ".#{extension}" }).join(",") + end def create extra_authorization ActiveRecord::Base.transaction do ::Settings::Community.community_name = settings_params[:community_name] - ::Settings::General.logo_svg = settings_params[:logo_svg] ::Settings::UserExperience.primary_brand_color_hex = settings_params[:primary_brand_color_hex] ::Settings::Authentication.invite_only_mode = settings_params[:invite_only] ::Settings::UserExperience.public = settings_params[:public] + + if settings_params[:logo] + logo_uploader = upload_logo(settings_params[:logo]) + ::Settings::General.original_logo = logo_uploader.url + # An SVG will not be resized, hence we apply the OR statements below to populate SETTINGS consistently. + ::Settings::General.resized_logo = logo_uploader.resized_logo.url || logo_uploader.url + end end current_user.update!( saw_onboarding: true, @@ -34,5 +44,11 @@ module Admin def settings_params params.permit(ALLOWED_PARAMS) end + + def upload_logo(image) + LogoUploader.new.tap do |uploader| + uploader.store!(image) + end + end end end diff --git a/app/models/settings/general.rb b/app/models/settings/general.rb index 24860adc2..fa26d5083 100644 --- a/app/models/settings/general.rb +++ b/app/models/settings/general.rb @@ -37,6 +37,9 @@ module Settings setting :logo_svg, type: :string + setting :original_logo, type: :string + setting :resized_logo, type: :string + setting :enable_video_upload, type: :boolean, default: false # Mascot diff --git a/app/uploaders/base_uploader.rb b/app/uploaders/base_uploader.rb index 52e2e7674..cc762694b 100644 --- a/app/uploaders/base_uploader.rb +++ b/app/uploaders/base_uploader.rb @@ -26,6 +26,9 @@ class BaseUploader < CarrierWave::Uploader::Base # strip EXIF (and GPS) data def strip_exif + # svg's do not contain exif or gps data + return if file.content_type.include?("svg") + manipulate! do |image| image.strip unless image.frames.count > FRAME_STRIP_MAX image = yield(image) if block_given? diff --git a/app/uploaders/logo_uploader.rb b/app/uploaders/logo_uploader.rb new file mode 100644 index 000000000..754190a69 --- /dev/null +++ b/app/uploaders/logo_uploader.rb @@ -0,0 +1,50 @@ +class LogoUploader < BaseUploader + MAX_FILE_SIZE = 3.megabytes + STORE_DIRECTORY = "uploads/logos/".freeze + EXTENSION_ALLOWLIST = %w[svg png jpg jpeg jpe].freeze + IMAGE_TYPE_ALLOWLIST = %i[svg png jpg jpeg jpe].freeze + CONTENT_TYPE_ALLOWLIST = %w[image/svg+xml image/png image/jpg image/jpeg].freeze + + def store_dir + STORE_DIRECTORY + end + + def extension_allowlist + EXTENSION_ALLOWLIST + end + + def image_type_whitelist + # this is needed by CarrierWave::BombShelter + IMAGE_TYPE_ALLOWLIST + end + + def size_range + 1..MAX_FILE_SIZE + end + + def content_type_allowlist + CONTENT_TYPE_ALLOWLIST + end + + def filename + # random_string in the filename to avoid caching issues + "original_logo_#{random_string}.#{file.extension}" if original_filename + end + + version :resized_logo, if: :not_svg? do + process resize_to_limit: [nil, 80] + def full_filename(_for_file = file) + "resized_logo_#{random_string}.#{file.extension}" if original_filename + end + end + + private + + def random_string + SecureRandom.alphanumeric(20) + end + + def not_svg?(file) + file.content_type.exclude?("svg") + end +end diff --git a/app/views/admin/creator_settings/_form.html.erb b/app/views/admin/creator_settings/_form.html.erb index 75dac8b43..4a9fda539 100644 --- a/app/views/admin/creator_settings/_form.html.erb +++ b/app/views/admin/creator_settings/_form.html.erb @@ -8,17 +8,14 @@
- <%= label_tag :logo_svg, class: "crayons-field__label" do %> + <%= label_tag :logo, class: "crayons-field__label" do %> Logo

Ideally SVG, but PNG or JPEG will work, too.

<% end %>
- <%= file_field_tag :logo_svg, required: true, accept: ".svg,.png,.jpg,image/svg+xml,image/png,image/jpg", data: { "max-file-size-mb": "25", action: "change->creator-settings#previewLogo" }, aria: { describedby: "logo-subtitle" } %> + <%= file_field_tag :logo, accept: @logo_allowed_types.to_s, data: { "max-file-size-mb": @max_file_size.to_s, action: "change->creator-settings#previewLogo" }, aria: { describedby: "logo-subtitle" } %>
- <% if ::Settings::General.logo_svg.present? %> - <%= ::Settings::General.logo_svg.html_safe %> - <% end %>
diff --git a/app/views/admin/creator_settings/new.html.erb b/app/views/admin/creator_settings/new.html.erb index a1ab796a6..f83efba7f 100644 --- a/app/views/admin/creator_settings/new.html.erb +++ b/app/views/admin/creator_settings/new.html.erb @@ -12,7 +12,7 @@ <% end %> - <%= form_tag(admin_creator_settings_path, method: "post", class: "relative z-elevate p-4", "data-action": "submit->creator-settings#formValidations") do %> + <%= form_tag(admin_creator_settings_path, method: "post", multipart: true, class: "relative z-elevate p-4", "data-action": "submit->creator-settings#formValidations") do %> <% if defined?(resource) && resource&.errors&.any? %>