Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions app/controllers/alchemy/admin/attachments_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,11 @@ def search_filter_params
params[:q] ||= ActionController::Parameters.new

if params[:only].present?
params[:q][:by_file_type] ||= Array(params[:only]).map do |extension|
Marcel::MimeType.for(extension:)
end
params[:q][:by_file_type] ||= Attachment.file_types(from_extensions: params[:only])
end

if params[:except].present?
params[:q][:by_file_type] ||= Attachment.file_types - params[:except].map do |extension|
Marcel::MimeType.for(extension:)
end
params[:q][:by_file_type] ||= Attachment.file_types - Attachment.file_types(from_extensions: params[:except])
end

params.except(*COMMON_SEARCH_FILTER_EXCLUDES + [:attachment]).permit(
Expand All @@ -108,9 +104,7 @@ def search_filter_params

def permitted_ransack_search_fields
super + [
{by_file_type: []},
:not_file_type,
{not_file_type: []}
{by_file_type: []}
]
end

Expand Down
44 changes: 35 additions & 9 deletions app/controllers/alchemy/admin/pictures_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,15 @@ class PicturesController < Alchemy::Admin::ResourcesController
@picture = Picture.find(params[:id])
end

add_alchemy_filter :by_file_format, type: :select, options: ->(query) do
Alchemy::Picture.file_formats(query.result)
add_alchemy_filter :by_file_format, type: :select, options: ->(_query, params) do
case params&.to_h
in {except:}
Alchemy::Picture.file_formats - Alchemy::Picture.file_formats(from_extensions: except)
in {only:}
Alchemy::Picture.file_formats(from_extensions: only)
else
Alchemy::Picture.file_formats
end
end
add_alchemy_filter :recent, type: :checkbox
add_alchemy_filter :last_upload, type: :checkbox
Expand Down Expand Up @@ -64,7 +71,6 @@ def url

def create
@picture = Picture.new(picture_params)
@picture.name = @picture.humanized_name
if @picture.save
render successful_uploader_response(file: @picture)
else
Expand Down Expand Up @@ -183,12 +189,32 @@ def redirect_to_index
end

def search_filter_params
@_search_filter_params ||= params.except(*COMMON_SEARCH_FILTER_EXCLUDES + [:picture_ids]).permit(
*common_search_filter_includes + [
:size,
:form_field_id
]
)
@_search_filter_params ||= begin
params[:q] ||= ActionController::Parameters.new

if params[:only].present?
params[:q][:by_file_format] ||= Picture.file_formats(from_extensions: params[:only])
end

if params[:except].present?
params[:q][:by_file_format] ||= Picture.file_formats - Picture.file_formats(from_extensions: params[:except])
end

params.except(*COMMON_SEARCH_FILTER_EXCLUDES + [:picture_ids]).permit(
*common_search_filter_includes + [
:size,
:form_field_id,
{only: []},
{except: []}
]
)
end
end

def permitted_ransack_search_fields
super + [
{by_file_format: []}
]
end

def picture_params
Expand Down
19 changes: 5 additions & 14 deletions app/models/alchemy/attachment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class Attachment < BaseRecord
include Alchemy::TouchElements
include Alchemy::RelatableResource

before_save :set_name, if: -> { Alchemy.storage_adapter.set_attachment_name?(self) }

include Alchemy.storage_adapter.attachment_class_methods

stampable stamper_class_name: Alchemy.config.user_class_name
Expand All @@ -33,10 +35,6 @@ class Attachment < BaseRecord
Alchemy.storage_adapter.by_file_type_scope(file_type)
end

scope :not_file_type, ->(*file_type) do
Alchemy.storage_adapter.not_file_type_scope(file_type)
end

scope :recent, -> { where("#{table_name}.created_at > ?", Time.current - 24.hours).order(:created_at) }
scope :without_tag, -> { left_outer_joins(:taggings).where(gutentag_taggings: {id: nil}) }

Expand Down Expand Up @@ -75,20 +73,15 @@ def ransackable_associations(_auth_object = nil)
end

def file_types(scope = all, from_extensions: nil)
if from_extensions.present?
scope = by_file_type(
Array(from_extensions).map { |extension| Marcel::MimeType.for(extension:) }
)
end
Alchemy.storage_adapter.file_formats(name, scope:)
Alchemy.storage_adapter.file_formats(name, scope:, from_extensions:)
end

def allowed_filetypes
Alchemy.config.uploader.allowed_filetypes.alchemy_attachments
end

def ransackable_scopes(_auth_object = nil)
%i[by_file_type not_file_type recent last_upload without_tag deletable]
%i[by_file_type recent last_upload without_tag deletable]
end
end

Expand All @@ -97,8 +90,6 @@ def ransackable_scopes(_auth_object = nil)
validate :file_type_allowed,
unless: -> { self.class.allowed_filetypes.include?("*") }

before_save :set_name, if: -> { Alchemy.storage_adapter.set_attachment_name?(self) }

scope :with_file_type, ->(file_type) { where(file_mime_type: file_type) }

# Instance methods
Expand Down Expand Up @@ -179,7 +170,7 @@ def file_type_allowed
end

def set_name
self.name ||= convert_to_humanized_name(file_name, extension)
self.name ||= Alchemy.storage_adapter.file_basename(self).humanize
end
end
end
2 changes: 2 additions & 0 deletions app/models/alchemy/ingredients/picture.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ class Picture < Alchemy::Ingredient
allow_settings %i[
crop
css_classes
except
fixed_ratio
linkable
only
size
sizes
srcset
Expand Down
23 changes: 12 additions & 11 deletions app/models/alchemy/picture.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ def self.preprocessor_class=(klass)
@_preprocessor_class = klass
end

before_create :set_name, if: :image_file_name

include Alchemy.storage_adapter.picture_class_methods

# We need to define this method here to have it available in the validations below.
Expand All @@ -80,7 +82,8 @@ def allowed_filetypes
scope :named, ->(name) { where("#{table_name}.name LIKE ?", "%#{name}%") }
scope :recent, -> { where("#{table_name}.created_at > ?", Time.current - 24.hours).order(:created_at) }
scope :without_tag, -> { left_outer_joins(:taggings).where(gutentag_taggings: {id: nil}) }
scope :by_file_format, ->(file_format) do

scope :by_file_format, ->(*file_format) do
Alchemy.storage_adapter.by_file_format_scope(file_format)
end

Expand Down Expand Up @@ -128,8 +131,8 @@ def ransackable_scopes(_auth_object = nil)
[:by_file_format, :recent, :last_upload, :without_tag, :deletable]
end

def file_formats(scope = all)
Alchemy.storage_adapter.file_formats(name, scope:)
def file_formats(scope = all, from_extensions: nil)
Alchemy.storage_adapter.file_formats(name, scope:, from_extensions:)
end
end

Expand Down Expand Up @@ -195,14 +198,6 @@ def urlname
end
end

# Returns a humanized, readable name from image filename.
#
def humanized_name
return "" if image_file_name.blank?

convert_to_humanized_name(image_file_name, image_file_extension)
end

# Returns the format the image should be rendered with
#
# Only returns a format differing from original if an +image_output_format+
Expand Down Expand Up @@ -287,6 +282,12 @@ def image_file_dimensions

private

# Returns a humanized, readable name from image filename.
#
def set_name
self.name ||= Alchemy.storage_adapter.image_file_basename(self).humanize
end

def image_file_type_allowed
unless image_file_extension&.in?(self.class.allowed_filetypes)
errors.add(:image_file, Alchemy.t("not a valid image"))
Expand Down
2 changes: 2 additions & 0 deletions app/models/alchemy/storage_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ class UnknownAdapterError < StandardError; end
:by_file_format_scope,
:by_file_type_scope,
:not_file_type_scope,
:file_basename,
:file_extension,
:file_formats,
:file_mime_type,
:file_name,
:file_size,
:has_convertible_format?,
:image_file_basename,
:image_file_extension,
:image_file_format,
:image_file_height,
Expand Down
26 changes: 25 additions & 1 deletion app/models/alchemy/storage_adapter/active_storage.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,17 @@ def picture_url_class
PictureUrl
end

def file_formats(class_name, scope:)
def file_formats(class_name, scope:, from_extensions: nil)
if from_extensions.present?
mime_types = Array(from_extensions).map { |extension| Marcel::MimeType.for(extension:) }
case class_name
when "Alchemy::Picture"
scope = scope.by_file_format(mime_types)
when "Alchemy::Attachment"
scope = scope.by_file_type(mime_types)
end
end

attachment_scope = case class_name
when "Alchemy::Attachment" then scope.with_attached_file
when "Alchemy::Picture" then scope.with_attached_image_file
Expand Down Expand Up @@ -96,6 +106,13 @@ def not_file_type_scope(file_type)
Attachment.with_attached_file.joins(:file_blob).where.not(active_storage_blobs: {content_type: file_type})
end

# @param [Alchemy::Attachment]
# @return [String]
def file_basename(attachment)
filename = attachment.file&.filename.to_s
File.basename(filename, File.extname(filename))
end

# @param [Alchemy::Attachment]
# @return [String]
def file_name(attachment)
Expand Down Expand Up @@ -126,6 +143,13 @@ def has_convertible_format?(picture)
picture.image_file&.variable?
end

# @param [Alchemy::Picture]
# @return [String]
def image_file_basename(picture)
filename = picture.image_file&.filename.to_s
File.basename(filename, File.extname(filename))
end

# @param [Alchemy::Picture]
# @return [String]
def image_file_name(picture)
Expand Down
24 changes: 23 additions & 1 deletion app/models/alchemy/storage_adapter/dragonfly.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,17 @@ def picture_url_class
@_picture_url_class ||= PictureUrl
end

def file_formats(class_name, scope:)
def file_formats(class_name, scope:, from_extensions: nil)
if from_extensions.present?
extensions = Array(from_extensions)
case class_name
when "Alchemy::Picture"
scope = scope.by_file_format(extensions.map(&:to_s))
when "Alchemy::Attachment"
scope = scope.by_file_type(extensions.map { |extension| Marcel::MimeType.for(extension:) })
end
end

mime_type_column = case class_name
when "Alchemy::Attachment" then :file_mime_type
when "Alchemy::Picture" then :image_file_format
Expand Down Expand Up @@ -127,6 +137,12 @@ def file_name(attachment)
attachment.read_attribute(:file_name)
end

# @param [Alchemy::Attachment]
# @return [String]
def file_basename(attachment)
attachment.file&.basename&.to_s
end

# @param [Alchemy::Attachment]
# @return [Integer]
def file_size(attachment)
Expand All @@ -152,6 +168,12 @@ def has_convertible_format?(picture)
image_file_extension(picture).in?(CONVERTIBLE_FILE_FORMATS)
end

# @param [Alchemy::Picture]
# @return [String]
def image_file_basename(picture)
picture.image_file&.basename&.to_s
end

# @param [Alchemy::Picture]
# @return [String]
def image_file_name(picture)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
<%= content_tag "sl-tooltip", content: picture_editor.picture ? Alchemy.t(:swap_image) : Alchemy.t(:insert_image) do %>
<%= link_to_dialog render_icon("image-add"),
alchemy.admin_pictures_path(
form_field_id: picture_editor.form_field_id(:picture_id)
form_field_id: picture_editor.form_field_id(:picture_id),
only: Array(picture_editor.settings[:only]),
except: Array(picture_editor.settings[:except])
),
{
title: Alchemy.t(:choose_image),
Expand Down
6 changes: 0 additions & 6 deletions lib/alchemy/name_conversions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,6 @@ def convert_to_urlname(name)
.parameterize
end

# Converts a filename and suffix into a human readable name.
#
def convert_to_humanized_name(name, suffix)
name.gsub(/\.#{::Regexp.quote(suffix)}$/i, "").tr("_", " ").strip
end

# Sanitizes a given filename by removing directory traversal attempts and HTML entities.
def sanitized_filename(file_name)
file_name = File.basename(file_name)
Expand Down
16 changes: 16 additions & 0 deletions spec/components/alchemy/ingredients/picture_editor_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,22 @@
end
end

context "with settings `only`" do
let(:settings) { {only: "jpeg"} }

it "renders a link to open the picture library overlay with only jpegs" do
is_expected.to have_selector("a[href*='only%5B%5D=jpeg']")
end
end

context "with settings `except`" do
let(:settings) { {except: "gif"} }

it "renders a link to open the picture library overlay without gifs" do
is_expected.to have_selector("a[href*='except%5B%5D=gif']")
end
end

describe "#ingredient_label" do
context "with another column given" do
it "has for attribute set to ingredient form field id for that column" do
Expand Down
Loading
Loading