diff --git a/app/components/path_template_preview.rb b/app/components/path_template_preview.rb index f8eefb707..6b615c0a9 100644 --- a/app/components/path_template_preview.rb +++ b/app/components/path_template_preview.rb @@ -27,7 +27,7 @@ class Components::PathTemplatePreview < Components::Base tr do td(style: "word-break: break-all") { path } td { find_or_new_from_path_component(Creator, parsed[:creator])&.name || "❌" } - td { find_or_new_from_path_component(Collection, parsed[:collection])&.name || "❌" } + td { parsed[:collections] ? Array(find_or_new_from_path_component(Collection, parsed[:collections])).map(&:name).join(", ") : "❌" } td { parsed[:tags]&.map do |it| Tag tag: ActsAsTaggableOn::Tag.new(name: it), link: false @@ -46,11 +46,15 @@ class Components::PathTemplatePreview < Components::Base def find_or_new_from_path_component(klass, path_component) return unless path_component - klass.find_by(slug: path_component) || - klass.find_by( - name: to_human_name(path_component) - ) || - klass.new(name: to_human_name(path_component)) + if path_component.is_a? Array + path_component.map { |it| find_or_new_from_path_component(klass, it) } + else + klass.find_by(slug: path_component) || + klass.find_by( + name: to_human_name(path_component) + ) || + klass.new(name: to_human_name(path_component)) + end end def to_human_name(str) diff --git a/app/jobs/scan/model/parse_metadata_job.rb b/app/jobs/scan/model/parse_metadata_job.rb index e2c937589..ddb55a48f 100644 --- a/app/jobs/scan/model/parse_metadata_job.rb +++ b/app/jobs/scan/model/parse_metadata_job.rb @@ -90,7 +90,7 @@ class Scan::Model::ParseMetadataJob < ApplicationJob components = PathParserService.new(library.path_template, path).call { creator: find_or_create_from_path_component(Creator, components[:creator]), - collections: [find_or_create_from_path_component(Collection, components[:collection])].compact, + collections: Array(find_or_create_from_path_component(Collection, components[:collections])), name: to_human_name(components[:model_name]) }.compact_blank end @@ -170,10 +170,14 @@ class Scan::Model::ParseMetadataJob < ApplicationJob def find_or_create_from_path_component(klass, path_component) return unless path_component - klass.find_by(slug: path_component) || - klass.create_with(slug: path_component.parameterize).find_or_create_by( - name: to_human_name(path_component) - ) + if path_component.is_a? Array + path_component.map { |it| find_or_create_from_path_component(klass, it) } + else + klass.find_by(slug: path_component) || + klass.create_with(slug: path_component.parameterize).find_or_create_by( + name: to_human_name(path_component) + ) + end end def to_human_name(str) diff --git a/app/services/path_parser_service.rb b/app/services/path_parser_service.rb index af6fed163..475f95409 100644 --- a/app/services/path_parser_service.rb +++ b/app/services/path_parser_service.rb @@ -8,9 +8,10 @@ class PathParserService components = @path.match(path_parse_pattern)&.named_captures&.symbolize_keys return {} if components.nil? components.merge({ - tags: components[:tags]&.split("/")&.compact_blank, + tags: components[:tags]&.split(File::SEPARATOR)&.compact_blank, + collections: components[:collection] ? [components.delete(:collection)] : components[:collections]&.split("/")&.compact_blank, model_id: nil # discard ID, never gonna use it in parsing - }).compact + }).compact_blank end private @@ -22,15 +23,17 @@ class PathParserService when "{tags}" "(?[[:print:]]*)" when "{creator}" - "(?[[:print:]&&[^/]]*?)" + "(?[[:print:]&&[^#{File::SEPARATOR}]]*?)" when "{collection}" - "(?[[:print:]&&[^/]]*?)" + "(?[[:print:]&&[^#{File::SEPARATOR}]]*?)" + when "{collections}" + "(?[[:print:]]*)" when "{modelName}" - "(?[[:print:]&&[^/]]*?)" + "(?[[:print:]&&[^#{File::SEPARATOR}]]*?)" when "{modelId}" "(?#[[:digit:]]+)?" else - "[[:print:]&&[^/]]*" + "[[:print:]&&[^#{File::SEPARATOR}]]*" end } + "$") end diff --git a/app/validators/path_template_validator.rb b/app/validators/path_template_validator.rb index ca25ac1b2..8405bdd20 100644 --- a/app/validators/path_template_validator.rb +++ b/app/validators/path_template_validator.rb @@ -3,6 +3,7 @@ class PathTemplateValidator < ActiveModel::EachValidator "tags", "creator", "collection", + "collections", "modelName", "modelId" ] diff --git a/app/views/libraries/_path_template_help.html.erb b/app/views/libraries/_path_template_help.html.erb index 98152f252..a3660a2bf 100644 --- a/app/views/libraries/_path_template_help.html.erb +++ b/app/views/libraries/_path_template_help.html.erb @@ -9,7 +9,7 @@ {creator}: <%= t ".tokens.creator" %>
  • - {collection}: <%= t ".tokens.collection" %> + {collections}: <%= t ".tokens.collections" %>
  • {modelName}: <%= t ".tokens.model_name" %> diff --git a/spec/services/path_parser_service_spec.rb b/spec/services/path_parser_service_spec.rb index bbd67f58f..505039742 100644 --- a/spec/services/path_parser_service_spec.rb +++ b/spec/services/path_parser_service_spec.rb @@ -7,10 +7,12 @@ RSpec.describe PathParserService do "{tags}" => %r{^/?.*?(?[[:print:]]*)$}, "{creator}" => %r{^/?.*?(?[[:print:]&&[^/]]*?)$}, "{collection}" => %r{^/?.*?(?[[:print:]&&[^/]]*?)$}, + "{collections}" => %r{^/?.*?(?[[:print:]]*)$}, "{tags}/{creator}" => %r{^/?.*?(?[[:print:]]*)/(?[[:print:]&&[^/]]*?)$}, "{tags}/{creator}/{modelName}{modelId}" => %r{^/?.*?(?[[:print:]]*)/(?[[:print:]&&[^/]]*?)/(?[[:print:]&&[^/]]*?)(?#[[:digit:]]+)?$}, "@{creator}{modelId}" => %r{^/?.*?@(?[[:print:]&&[^/]]*?)(?#[[:digit:]]+)?$}, - "{creator}/{collection}/{tags}/{modelName}{modelId}" => %r{^/?.*?(?[[:print:]&&[^/]]*?)/(?[[:print:]&&[^/]]*?)/(?[[:print:]]*)/(?[[:print:]&&[^/]]*?)(?#[[:digit:]]+)?$} + "{creator}/{collection}/{tags}/{modelName}{modelId}" => %r{^/?.*?(?[[:print:]&&[^/]]*?)/(?[[:print:]&&[^/]]*?)/(?[[:print:]]*)/(?[[:print:]&&[^/]]*?)(?#[[:digit:]]+)?$}, + "{collections}/{creator}" => %r{^/?.*?(?[[:print:]]*)/(?[[:print:]&&[^/]]*?)$} }.each_pair do |tag, regexp| it "correctly converts #{tag} into a regexp matcher" do service = described_class.new(tag, path) @@ -28,7 +30,7 @@ RSpec.describe PathParserService do model_name: "prefix - name" }, "{collection}/{modelName}{modelId}" => { - collection: "bottom", + collections: ["bottom"], model_name: "prefix - name" }, "{tags}/{creator}/{modelName}{modelId}" => { @@ -42,8 +44,13 @@ RSpec.describe PathParserService do "{tags}/{creator}/{collection} - {modelName}{modelId}" => { tags: ["top", "middle"], creator: "bottom", - collection: "prefix", + collections: ["prefix"], model_name: "name" + }, + "{collections}/{creator}/{modelName}{modelId}" => { + collections: ["top", "middle"], + creator: "bottom", + model_name: "prefix - name" } }.each_pair do |tag, values| it "correctly matches components of #{tag}" do