diff --git a/.dassie/app/forms/collection_resource_form.rb b/.dassie/app/forms/collection_resource_form.rb index f9b2bf5938..4a0585238e 100644 --- a/.dassie/app/forms/collection_resource_form.rb +++ b/.dassie/app/forms/collection_resource_form.rb @@ -3,6 +3,6 @@ # Generated via # `rails generate hyrax:collection_resource CollectionResource` class CollectionResourceForm < Hyrax::Forms::PcdmCollectionForm - include Hyrax::FormFields(:basic_metadata) - include Hyrax::FormFields(:collection_resource) + include Hyrax::FormFields(:basic_metadata) unless Hyrax.config.flexible? + include Hyrax::FormFields(:collection_resource) unless Hyrax.config.flexible? end diff --git a/.dassie/app/forms/generic_work_resource_form.rb b/.dassie/app/forms/generic_work_resource_form.rb index 8aa9348d01..86e350a475 100644 --- a/.dassie/app/forms/generic_work_resource_form.rb +++ b/.dassie/app/forms/generic_work_resource_form.rb @@ -6,8 +6,8 @@ # @see https://github.com/samvera/hyrax/wiki/Hyrax-Valkyrie-Usage-Guide#forms # @see https://github.com/samvera/valkyrie/wiki/ChangeSets-and-Dirty-Tracking class GenericWorkResourceForm < Hyrax::Forms::ResourceForm(GenericWorkResource) - include Hyrax::FormFields(:basic_metadata) - include Hyrax::FormFields(:generic_work_resource) + include Hyrax::FormFields(:basic_metadata) unless Hyrax.config.flexible? + include Hyrax::FormFields(:generic_work_resource) unless Hyrax.config.flexible? # Define custom form fields using the Valkyrie::ChangeSet interface # diff --git a/.dassie/app/forms/monograph_form.rb b/.dassie/app/forms/monograph_form.rb index b347c1eb4e..448b93aa83 100644 --- a/.dassie/app/forms/monograph_form.rb +++ b/.dassie/app/forms/monograph_form.rb @@ -6,8 +6,8 @@ # @see https://github.com/samvera/hyrax/wiki/Hyrax-Valkyrie-Usage-Guide#forms # @see https://github.com/samvera/valkyrie/wiki/ChangeSets-and-Dirty-Tracking class MonographForm < Hyrax::Forms::ResourceForm(Monograph) - include Hyrax::FormFields(:basic_metadata) - include Hyrax::FormFields(:monograph) + include Hyrax::FormFields(:basic_metadata) unless Hyrax.config.flexible? + include Hyrax::FormFields(:monograph) unless Hyrax.config.flexible? # Define custom form fields using the Valkyrie::ChangeSet interface # diff --git a/.dassie/app/indexers/collection_resource_indexer.rb b/.dassie/app/indexers/collection_resource_indexer.rb index c8dd88b84e..76a4ace871 100644 --- a/.dassie/app/indexers/collection_resource_indexer.rb +++ b/.dassie/app/indexers/collection_resource_indexer.rb @@ -3,6 +3,7 @@ # Generated via # `rails generate hyrax:collection_resource CollectionResource` class CollectionResourceIndexer < Hyrax::PcdmCollectionIndexer - include Hyrax::Indexer(:basic_metadata) - include Hyrax::Indexer(:collection_resource) + include Hyrax::Indexer(:basic_metadata) unless Hyrax.config.flexible? + include Hyrax::Indexer(:collection_resource) unless Hyrax.config.flexible? + include Hyrax::Indexer('CollectionResource') if Hyrax.config.flexible? end diff --git a/.dassie/app/indexers/generic_work_resource_indexer.rb b/.dassie/app/indexers/generic_work_resource_indexer.rb index 7598e2a597..6fb90b0083 100644 --- a/.dassie/app/indexers/generic_work_resource_indexer.rb +++ b/.dassie/app/indexers/generic_work_resource_indexer.rb @@ -3,8 +3,9 @@ # Generated via # `rails generate hyrax:work_resource GenericWorkResource` class GenericWorkResourceIndexer < Hyrax::ValkyrieWorkIndexer - include Hyrax::Indexer(:basic_metadata) - include Hyrax::Indexer(:generic_work_resource) + include Hyrax::Indexer(:basic_metadata) unless Hyrax.config.flexible? + include Hyrax::Indexer(:generic_work_resource) unless Hyrax.config.flexible? + include Hyrax::Indexer('GenericWorkResource') if Hyrax.config.flexible? # Uncomment this block if you want to add custom indexing behavior: # def to_solr diff --git a/.dassie/app/indexers/monograph_indexer.rb b/.dassie/app/indexers/monograph_indexer.rb index 73fac4e9a6..092a84a4ba 100644 --- a/.dassie/app/indexers/monograph_indexer.rb +++ b/.dassie/app/indexers/monograph_indexer.rb @@ -3,8 +3,9 @@ # Generated via # `rails generate hyrax:work_resource Monograph` class MonographIndexer < Hyrax::ValkyrieWorkIndexer - include Hyrax::Indexer(:basic_metadata) - include Hyrax::Indexer(:monograph) + include Hyrax::Indexer(:basic_metadata) unless Hyrax.config.flexible? + include Hyrax::Indexer(:monograph) unless Hyrax.config.flexible? + include Hyrax::Indexer('Monograph') if Hyrax.config.flexible? # Uncomment this block if you want to add custom indexing behavior: # def to_solr diff --git a/.dassie/app/models/collection_resource.rb b/.dassie/app/models/collection_resource.rb index f0d140bc3e..1fd97de0e8 100644 --- a/.dassie/app/models/collection_resource.rb +++ b/.dassie/app/models/collection_resource.rb @@ -30,8 +30,8 @@ class CollectionResource < Hyrax::PcdmCollection # * add Valkyrie attributes to this class # * update form and indexer to process the attributes # - include Hyrax::Schema(:basic_metadata) - include Hyrax::Schema(:collection_resource) + include Hyrax::Schema(:basic_metadata) unless Hyrax.config.flexible? + include Hyrax::Schema(:collection_resource) unless Hyrax.config.flexible? Hyrax::ValkyrieLazyMigration.migrating(self, from: ::Collection) if Hyrax.config.valkyrie_transition? end diff --git a/.dassie/app/models/generic_work_resource.rb b/.dassie/app/models/generic_work_resource.rb index 4f034bf821..809d7945e0 100644 --- a/.dassie/app/models/generic_work_resource.rb +++ b/.dassie/app/models/generic_work_resource.rb @@ -3,8 +3,8 @@ # Generated via # `rails generate hyrax:work_resource GenericWorkResource` class GenericWorkResource < Hyrax::Work - include Hyrax::Schema(:basic_metadata) - include Hyrax::Schema(:generic_work_resource) + include Hyrax::Schema(:basic_metadata) unless Hyrax.config.flexible? + include Hyrax::Schema(:generic_work_resource) unless Hyrax.config.flexible? Hyrax::ValkyrieLazyMigration.migrating(self, from: GenericWork) if Hyrax.config.valkyrie_transition? end diff --git a/.dassie/app/models/monograph.rb b/.dassie/app/models/monograph.rb index fc3e67b2a5..34f9b195a4 100644 --- a/.dassie/app/models/monograph.rb +++ b/.dassie/app/models/monograph.rb @@ -3,6 +3,6 @@ # Generated via # `rails generate hyrax:work_resource Monograph` class Monograph < Hyrax::Work - include Hyrax::Schema(:basic_metadata) - include Hyrax::Schema(:monograph) + include Hyrax::Schema(:basic_metadata) unless Hyrax.config.flexible? + include Hyrax::Schema(:monograph) unless Hyrax.config.flexible? end diff --git a/.dassie/config/metadata_profiles/m3_profile.yaml b/.dassie/config/metadata_profiles/m3_profile.yaml new file mode 100644 index 0000000000..f8771baf05 --- /dev/null +++ b/.dassie/config/metadata_profiles/m3_profile.yaml @@ -0,0 +1,1094 @@ +--- +m3_version: 1.0.beta2 +profile: + date_modified: '2024-06-01' + responsibility: https://samvera.org + responsibility_statement: Hyrax Initial Profile + type: Initial Profile + version: 1 +classes: + GenericWork: + display_label: Generic Work + GenericWorkResource: + display_label: Generic Work + Wings(Hyrax::Resource): + display_label: Wings Resource + Monograph: + display_label: Monograph + AdminSet: + diplay_label: AdminSet + AdminSetResource: + diplay_label: AdministrativeSet + Collection: + display_label: Collection + CollectionResource: + display_label: PcdmCollection + Hyrax::FileSet: + display_label: FileSet + Hyrax::PcdmCollection: + display_label: PcdmCollection +contexts: + flexible_context: + display_label: Flexible Metadata Example +mappings: + blacklight: + name: Additional Blacklight Solr Mappings + metatags: + name: Metatags + mods_oai_pmh: + name: MODS OAI PMH + qualified_dc_pmh: + name: Qualified DC OAI PMH + simple_dc_pmh: + name: Simple DC OAI PMH +properties: + title: + available_on: + class: + - AdminSet + - AdminSetResource + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 1 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + definition: + default: Enter a standardized title for display. If only one title is needed, + transcribe the title from the source itself. + display_label: + default: Title + index_documentation: displayable, searchable + indexing: + - title_sim + - title_tesim + form: + required: true + primary: true + multi_value: true + mappings: + metatags: twitter:title, og:title + mods_oai_pmh: mods:titleInfo/mods:title + qualified_dc_pmh: dcterms:title + simple_dc_pmh: dc:title + property_uri: http://purl.org/dc/terms/title + range: http://www.w3.org/2001/XMLSchema#string + requirement: required + sample_values: + - Pencil drawn portrait study of woman + date_modified: + available_on: + class: + - AdminSet + - AdminSetResource + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + display_label: + default: Date Modified + property_uri: http://purl.org/dc/terms/modified + range: http://www.w3.org/2001/XMLSchema#dateTime + sample_values: + - '2024-06-06 21:06:51 +0000' + view: + label: + de: 'Zuletzt geändert' + en: 'Last modified' + es: 'Última modificación' + fr: 'Dernière modification' + it: 'Ultima modifica' + pt-BR: 'Última modificação' + zh: '最新修改' + html_dl: true + date_uploaded: + available_on: + class: + - AdminSet + - AdminSetResource + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + display_label: + default: Date Uploaded + property_uri: http://purl.org/dc/terms/dateSubmitted + range: http://www.w3.org/2001/XMLSchema#dateTime + sample_values: + - '2024-06-06 21:06:51 +0000' + depositor: + available_on: + class: + - AdminSet + - AdminSetResource + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Depositor + index_documentation: searchable + indexing: + - depositor_tesim + property_uri: http://id.loc.gov/vocabulary/relators/dpt + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Julie Allinson + creator: + available_on: + class: + - AdminSet + - AdminSetResource + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 1 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Creator + index_documentation: displayable, searchable + indexing: + - creator_sim + - creator_tesim + form: + required: true + primary: true + property_uri: http://purl.org/dc/elements/1.1/creator + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Julie Allinson + view: + render_as: "faceted" + html_dl: true + license: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: License + index_documentation: displayable, searchable + indexing: + - license_sim + - license_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/license + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - http://creativecommons.org/licenses/by/3.0/us/ + view: + render_as: "external_link" + html_dl: true + abstract: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Abstract + index_documentation: displayable, searchable + indexing: + - abstract_sim + - abstract_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/abstract + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - This is an abstract. + view: + html_dl: true + access_right: + available_on: + class: + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Access Right + index_documentation: displayable, searchable + indexing: + - access_right_sim + - access_right_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/accessRights + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Open Access + view: + html_dl: true + alternative_title: + available_on: + class: + - AdminSet + - AdminSetResource + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Alternative Title + index_documentation: displayable, searchable + indexing: + - alternative_title_sim + - alternative_title_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/alternative + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Alternate Title Example + view: + label: + en: 'Alternative Title' + es: 'Título Alternativo' + html_dl: true + arkivo_checksum: + available_on: + class: + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Arkivo Checksum + form: + primary: false + property_uri: http://scholarsphere.psu.edu/ns#arkivoChecksum + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - c0855931b7f1aefedb91d31af76873c0 + based_near: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Location + index_documentation: displayable, searchable + indexing: + - based_near_sim + - based_near_tesim + form: + primary: false + property_uri: http://xmlns.com/foaf/0.1/based_near + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - San Diego, California, United States + view: + label: Based Near + render_term: 'based_near_label_tesim' + html_dl: true + bibliographic_citation: + available_on: + class: + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Bibliographic Citation + index_documentation: displayable, searchable + indexing: + - bibliographic_citation_sim + - bibliographic_citation_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/bibliographicCitation + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Doe, J. (2024). Example Citation. Journal of Examples, 12(3), 45-67. + view: + html_dl: true + contributor: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Contributor + index_documentation: displayable, searchable + indexing: + - contributor_tesim + - contributor_sim + form: + primary: false + property_uri: http://purl.org/dc/elements/1.1/contributor + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Julie Allinson + view: + render_as: "faceted" + html_dl: true + date_created: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#dateTime + sources: + - 'null' + display_label: + default: Date Created + index_documentation: displayable, searchable + indexing: + - date_created_sim + - date_created_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/created + range: http://www.w3.org/2001/XMLSchema#dateTime + sample_values: + - '2024-06-06 21:06:51 +0000' + view: + render_as: "linked" + search_field: 'date_created_tesim' + html_dl: true + description: + available_on: + class: + - AdminSet + - AdminSetResource + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Description + index_documentation: displayable, searchable + indexing: + - description_sim + - description_tesim + form: + primary: false + property_uri: http://purl.org/dc/elements/1.1/description + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - This is a description. + identifier: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Identifier + index_documentation: displayable, searchable + indexing: + - identifier_sim + - identifier_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/identifier + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - abc123 + view: + render_as: "linked" + search_field: 'identifier_tesim' + html_dl: true + import_url: + available_on: + class: + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Import URL + property_uri: http://scholarsphere.psu.edu/ns#importUrl + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - http://example.com/resource1 + keyword: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Keyword + index_documentation: displayable, searchable + indexing: + - keyword_sim + - keyword_tesim + form: + primary: false + property_uri: http://schema.org/keywords + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Metadata + - Repository + view: + render_as: "faceted" + html_dl: true + label: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Label + index_documentation: displayable, searchable + indexing: + - label_sim + - label_tesim + form: + primary: false + property_uri: info:fedora/fedora-system:def/model#downloadFilename + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - file_label.txt + language: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Language + index_documentation: displayable, searchable + indexing: + - language_sim + - language_tesim + form: + primary: false + property_uri: http://purl.org/dc/elements/1.1/language + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - English + - Spanish + view: + render_as: "faceted" + html_dl: true + publisher: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Publisher + index_documentation: displayable, searchable + indexing: + - publisher_sim + - publisher_tesim + form: + primary: false + property_uri: http://purl.org/dc/elements/1.1/publisher + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Scholastic + view: + render_as: "faceted" + html_dl: true + related_url: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Related URL + index_documentation: displayable, searchable + indexing: + - related_url_sim + - related_url_tesim + form: + primary: false + property_uri: http://www.w3.org/2000/01/rdf-schema#seeAlso + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - http://example.com/resource1 + view: + render_as: "external_link" + html_dl: true + relative_path: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Relative Path + property_uri: http://scholarsphere.psu.edu/ns#relativePath + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - "/path/to/resource" + resource_type: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Resource Type + index_documentation: displayable, searchable + indexing: + - resource_type_sim + - resource_type_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/type + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Article + - Conference Proceeding + view: + render_as: "faceted" + html_dl: true + rights_notes: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Rights Notes + index_documentation: displayable, searchable + indexing: + - rights_notes_sim + - rights_notes_tesim + form: + primary: false + property_uri: http://purl.org/dc/elements/1.1/rights + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Creative Commons license. + view: + html_dl: true + rights_statement: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Rights Statement + index_documentation: displayable, searchable + indexing: + - rights_statement_sim + - rights_statement_tesim + form: + primary: true + property_uri: http://www.europeana.eu/schemas/edm/rights + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - http://rightsstatements.org/vocab/InC/1.0/ + view: + html_dl: true + render_as: "rights_statement" + source: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Source + index_documentation: displayable, searchable + indexing: + - source_sim + - source_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/source + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Original Manuscript + - Digital Archive + view: + html_dl: true + subject: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Wings(Hyrax::Resource) + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Subject + index_documentation: displayable, searchable + indexing: + - subject_sim + - subject_tesim + form: + primary: false + property_uri: http://purl.org/dc/elements/1.1/subject + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Art + - Science + view: + render_as: "faceted" + html_dl: true + target_audience: + available_on: + class: + - CollectionResource + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Target Audience + form: + primary: true + multiple: true + property_uri: http://hyrax-example.com/target_audience + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Researchers + - Students + department: + available_on: + class: + - CollectionResource + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Department + form: + primary: true + property_uri: http://hyrax-example.com/department + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Mathematics + - History + course: + available_on: + class: + - CollectionResource + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Course + form: + primary: false + property_uri: http://hyrax-example.com/course + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Computer Science 50 + monograph_title: + available_on: + class: + - Monograph + cardinality: + minimum: 1 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Monograph Title + property_uri: http://hyrax-example.com/monograph_title + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Example Monograph Title + record_info: + available_on: + class: + - Monograph + cardinality: + minimum: 1 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Record Info + index_documentation: searchable + indexing: + - record_info_tesim + form: + required: true + primary: true + property_uri: http://hyrax-example.com/record_info + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Example Record Info + place_of_publication: + available_on: + class: + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Place of Publication + form: + required: false + primary: true + property_uri: http://hyrax-example.com/place_of_publication + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Example Place of Publication + genre: + available_on: + class: + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Genre + form: + primary: true + property_uri: http://hyrax-example.com/genre + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Fiction + - Non-Fiction + series_title: + available_on: + class: + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Series Title + form: + primary: false + property_uri: http://hyrax-example.com/series_title + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Example Series Title + table_of_contents: + available_on: + class: + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Table of Contents + form: + multiple: false + property_uri: http://hyrax-example.com/table_of_contents + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Example Table of Contents + date_of_issuance: + available_on: + class: + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Date of Issuance + property_uri: http://hyrax-example.com/date_of_issuance + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - '2024-06-06 21:06:51 +0000' diff --git a/.dassie/db/migrate/20240606205215_create_hyrax_flexible_schemas.rb b/.dassie/db/migrate/20240606205215_create_hyrax_flexible_schemas.rb new file mode 100644 index 0000000000..bdbac2bc49 --- /dev/null +++ b/.dassie/db/migrate/20240606205215_create_hyrax_flexible_schemas.rb @@ -0,0 +1,9 @@ +class CreateHyraxFlexibleSchemas < ActiveRecord::Migration[6.1] + def change + create_table :hyrax_flexible_schemas do |t| + t.text :profile + + t.timestamps + end + end +end diff --git a/.dassie/db/migrate/20240606205216_add_contexts_to_hyrax_flexible_schemas.rb b/.dassie/db/migrate/20240606205216_add_contexts_to_hyrax_flexible_schemas.rb new file mode 100644 index 0000000000..b283bfbc88 --- /dev/null +++ b/.dassie/db/migrate/20240606205216_add_contexts_to_hyrax_flexible_schemas.rb @@ -0,0 +1,5 @@ +class AddContextsToHyraxFlexibleSchemas < ActiveRecord::Migration[6.1] + def change + add_column :hyrax_flexible_schemas, :contexts, :text unless column_exists?(:hyrax_flexible_schemas, :contexts) + end +end diff --git a/.dassie/db/schema.rb b/.dassie/db/schema.rb index 1515b687c5..639068a227 100644 --- a/.dassie/db/schema.rb +++ b/.dassie/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2024_05_06_070809) do +ActiveRecord::Schema.define(version: 2024_06_06_205215) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -172,6 +172,12 @@ t.datetime "updated_at", null: false end + create_table "hyrax_flexible_schemas", force: :cascade do |t| + t.text "profile" + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + end + create_table "job_io_wrappers", force: :cascade do |t| t.bigint "user_id" t.bigint "uploaded_file_id" diff --git a/.koppie/app/forms/collection_resource_form.rb b/.koppie/app/forms/collection_resource_form.rb index f9b2bf5938..4a0585238e 100644 --- a/.koppie/app/forms/collection_resource_form.rb +++ b/.koppie/app/forms/collection_resource_form.rb @@ -3,6 +3,6 @@ # Generated via # `rails generate hyrax:collection_resource CollectionResource` class CollectionResourceForm < Hyrax::Forms::PcdmCollectionForm - include Hyrax::FormFields(:basic_metadata) - include Hyrax::FormFields(:collection_resource) + include Hyrax::FormFields(:basic_metadata) unless Hyrax.config.flexible? + include Hyrax::FormFields(:collection_resource) unless Hyrax.config.flexible? end diff --git a/.koppie/app/forms/generic_work_form.rb b/.koppie/app/forms/generic_work_form.rb index 7e541b0e5e..d0e3141c7c 100644 --- a/.koppie/app/forms/generic_work_form.rb +++ b/.koppie/app/forms/generic_work_form.rb @@ -6,8 +6,8 @@ # @see https://github.com/samvera/hyrax/wiki/Hyrax-Valkyrie-Usage-Guide#forms # @see https://github.com/samvera/valkyrie/wiki/ChangeSets-and-Dirty-Tracking class GenericWorkForm < Hyrax::Forms::ResourceForm(GenericWork) - include Hyrax::FormFields(:basic_metadata) - include Hyrax::FormFields(:generic_work) + include Hyrax::FormFields(:basic_metadata) unless Hyrax.config.flexible? + include Hyrax::FormFields(:generic_work) unless Hyrax.config.flexible? # Define custom form fields using the Valkyrie::ChangeSet interface # diff --git a/.koppie/app/forms/monograph_form.rb b/.koppie/app/forms/monograph_form.rb index b347c1eb4e..448b93aa83 100644 --- a/.koppie/app/forms/monograph_form.rb +++ b/.koppie/app/forms/monograph_form.rb @@ -6,8 +6,8 @@ # @see https://github.com/samvera/hyrax/wiki/Hyrax-Valkyrie-Usage-Guide#forms # @see https://github.com/samvera/valkyrie/wiki/ChangeSets-and-Dirty-Tracking class MonographForm < Hyrax::Forms::ResourceForm(Monograph) - include Hyrax::FormFields(:basic_metadata) - include Hyrax::FormFields(:monograph) + include Hyrax::FormFields(:basic_metadata) unless Hyrax.config.flexible? + include Hyrax::FormFields(:monograph) unless Hyrax.config.flexible? # Define custom form fields using the Valkyrie::ChangeSet interface # diff --git a/.koppie/app/indexers/collection_resource_indexer.rb b/.koppie/app/indexers/collection_resource_indexer.rb index c8dd88b84e..76a4ace871 100644 --- a/.koppie/app/indexers/collection_resource_indexer.rb +++ b/.koppie/app/indexers/collection_resource_indexer.rb @@ -3,6 +3,7 @@ # Generated via # `rails generate hyrax:collection_resource CollectionResource` class CollectionResourceIndexer < Hyrax::PcdmCollectionIndexer - include Hyrax::Indexer(:basic_metadata) - include Hyrax::Indexer(:collection_resource) + include Hyrax::Indexer(:basic_metadata) unless Hyrax.config.flexible? + include Hyrax::Indexer(:collection_resource) unless Hyrax.config.flexible? + include Hyrax::Indexer('CollectionResource') if Hyrax.config.flexible? end diff --git a/.koppie/app/indexers/generic_work_indexer.rb b/.koppie/app/indexers/generic_work_indexer.rb index c71c28b6b3..27345aecaf 100644 --- a/.koppie/app/indexers/generic_work_indexer.rb +++ b/.koppie/app/indexers/generic_work_indexer.rb @@ -3,8 +3,9 @@ # Generated via # `rails generate hyrax:work_resource GenericWork` class GenericWorkIndexer < Hyrax::ValkyrieWorkIndexer - include Hyrax::Indexer(:basic_metadata) - include Hyrax::Indexer(:generic_work) + include Hyrax::Indexer(:basic_metadata) unless Hyrax.config.flexible? + include Hyrax::Indexer(:generic_work) unless Hyrax.config.flexible? + include Hyrax::Indexer('GenericWork') if Hyrax.config.flexible? # Uncomment this block if you want to add custom indexing behavior: # def to_solr diff --git a/.koppie/app/indexers/monograph_indexer.rb b/.koppie/app/indexers/monograph_indexer.rb index 73fac4e9a6..092a84a4ba 100644 --- a/.koppie/app/indexers/monograph_indexer.rb +++ b/.koppie/app/indexers/monograph_indexer.rb @@ -3,8 +3,9 @@ # Generated via # `rails generate hyrax:work_resource Monograph` class MonographIndexer < Hyrax::ValkyrieWorkIndexer - include Hyrax::Indexer(:basic_metadata) - include Hyrax::Indexer(:monograph) + include Hyrax::Indexer(:basic_metadata) unless Hyrax.config.flexible? + include Hyrax::Indexer(:monograph) unless Hyrax.config.flexible? + include Hyrax::Indexer('Monograph') if Hyrax.config.flexible? # Uncomment this block if you want to add custom indexing behavior: # def to_solr diff --git a/.koppie/app/models/collection_resource.rb b/.koppie/app/models/collection_resource.rb index 8ba57bc859..435cdf595f 100644 --- a/.koppie/app/models/collection_resource.rb +++ b/.koppie/app/models/collection_resource.rb @@ -27,6 +27,6 @@ class CollectionResource < Hyrax::PcdmCollection # * add Valkyrie attributes to this class # * update form and indexer to process the attributes # - include Hyrax::Schema(:basic_metadata) - include Hyrax::Schema(:collection_resource) + include Hyrax::Schema(:basic_metadata) unless Hyrax.config.flexible? + include Hyrax::Schema(:collection_resource) unless Hyrax.config.flexible? end diff --git a/.koppie/app/models/generic_work.rb b/.koppie/app/models/generic_work.rb index d884387774..0f3debda26 100644 --- a/.koppie/app/models/generic_work.rb +++ b/.koppie/app/models/generic_work.rb @@ -3,6 +3,6 @@ # Generated via # `rails generate hyrax:work_resource GenericWork` class GenericWork < Hyrax::Work - include Hyrax::Schema(:basic_metadata) - include Hyrax::Schema(:generic_work) + include Hyrax::Schema(:basic_metadata) unless Hyrax.config.flexible? + include Hyrax::Schema(:generic_work) unless Hyrax.config.flexible? end diff --git a/.koppie/app/models/monograph.rb b/.koppie/app/models/monograph.rb index fc3e67b2a5..34f9b195a4 100644 --- a/.koppie/app/models/monograph.rb +++ b/.koppie/app/models/monograph.rb @@ -3,6 +3,6 @@ # Generated via # `rails generate hyrax:work_resource Monograph` class Monograph < Hyrax::Work - include Hyrax::Schema(:basic_metadata) - include Hyrax::Schema(:monograph) + include Hyrax::Schema(:basic_metadata) unless Hyrax.config.flexible? + include Hyrax::Schema(:monograph) unless Hyrax.config.flexible? end diff --git a/.koppie/config/metadata_profiles/m3_profile.yaml b/.koppie/config/metadata_profiles/m3_profile.yaml new file mode 100644 index 0000000000..bb005e59ef --- /dev/null +++ b/.koppie/config/metadata_profiles/m3_profile.yaml @@ -0,0 +1,1040 @@ +--- +m3_version: 1.0.beta2 +profile: + date_modified: '2024-06-01' + responsibility: https://samvera.org + responsibility_statement: Hyrax Initial Profile + type: Initial Profile + version: 1 +classes: + GenericWork: + display_label: Generic Work + Monograph: + display_label: Monograph + Hyrax::AdministrativeSet: + diplay_label: AdministrativeSet + CollectionResource: + display_label: PcdmCollection + Hyrax::FileSet: + display_label: FileSet + Hyrax::PcdmCollection: + display_label: PcdmCollection +contexts: + flexible_context: + display_label: Flexible Metadata Example +mappings: + blacklight: + name: Additional Blacklight Solr Mappings + metatags: + name: Metatags + mods_oai_pmh: + name: MODS OAI PMH + qualified_dc_pmh: + name: Qualified DC OAI PMH + simple_dc_pmh: + name: Simple DC OAI PMH +properties: + title: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 1 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + definition: + default: Enter a standardized title for display. If only one title is needed, + transcribe the title from the source itself. + display_label: + default: Title + index_documentation: displayable, searchable + indexing: + - title_sim + - title_tesim + form: + required: true + primary: true + multi_value: true + mappings: + metatags: twitter:title, og:title + mods_oai_pmh: mods:titleInfo/mods:title + qualified_dc_pmh: dcterms:title + simple_dc_pmh: dc:title + property_uri: http://purl.org/dc/terms/title + range: http://www.w3.org/2001/XMLSchema#string + requirement: required + sample_values: + - Pencil drawn portrait study of woman + date_modified: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + display_label: + default: Date Modified + property_uri: http://purl.org/dc/terms/modified + range: http://www.w3.org/2001/XMLSchema#dateTime + sample_values: + - '2024-06-06 21:06:51 +0000' + view: + label: + de: 'Zuletzt geändert' + en: 'Last modified' + es: 'Última modificación' + fr: 'Dernière modification' + it: 'Ultima modifica' + pt-BR: 'Última modificação' + zh: '最新修改' + html_dl: true + date_uploaded: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + display_label: + default: Date Uploaded + property_uri: http://purl.org/dc/terms/dateSubmitted + range: http://www.w3.org/2001/XMLSchema#dateTime + sample_values: + - '2024-06-06 21:06:51 +0000' + depositor: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Depositor + index_documentation: searchable + indexing: + - depositor_tesim + property_uri: http://id.loc.gov/vocabulary/relators/dpt + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Julie Allinson + creator: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 1 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Creator + index_documentation: displayable, searchable + indexing: + - creator_sim + - creator_tesim + form: + required: true + primary: true + property_uri: http://purl.org/dc/elements/1.1/creator + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Julie Allinson + view: + render_as: "faceted" + html_dl: true + license: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: License + index_documentation: displayable, searchable + indexing: + - license_sim + - license_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/license + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - http://creativecommons.org/licenses/by/3.0/us/ + view: + render_as: "external_link" + html_dl: true + abstract: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Abstract + index_documentation: displayable, searchable + indexing: + - abstract_sim + - abstract_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/abstract + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - This is an abstract. + view: + html_dl: true + access_right: + available_on: + class: + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Access Right + index_documentation: displayable, searchable + indexing: + - access_right_sim + - access_right_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/accessRights + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Open Access + view: + html_dl: true + alternative_title: + available_on: + class: + - Hyrax::AdministrativeSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Alternative Title + index_documentation: displayable, searchable + indexing: + - alternative_title_sim + - alternative_title_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/alternative + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Alternate Title Example + view: + label: + en: 'Alternative Title' + es: 'Título Alternativo' + html_dl: true + arkivo_checksum: + available_on: + class: + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Arkivo Checksum + form: + primary: false + property_uri: http://scholarsphere.psu.edu/ns#arkivoChecksum + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - c0855931b7f1aefedb91d31af76873c0 + based_near: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Location + index_documentation: displayable, searchable + indexing: + - based_near_sim + - based_near_tesim + form: + primary: false + property_uri: http://xmlns.com/foaf/0.1/based_near + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - San Diego, California, United States + view: + label: Based Near + render_term: 'based_near_label_tesim' + html_dl: true + bibliographic_citation: + available_on: + class: + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Bibliographic Citation + index_documentation: displayable, searchable + indexing: + - bibliographic_citation_sim + - bibliographic_citation_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/bibliographicCitation + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Doe, J. (2024). Example Citation. Journal of Examples, 12(3), 45-67. + view: + html_dl: true + contributor: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Contributor + index_documentation: displayable, searchable + indexing: + - contributor_tesim + - contributor_sim + form: + primary: false + property_uri: http://purl.org/dc/elements/1.1/contributor + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Julie Allinson + view: + render_as: "faceted" + html_dl: true + date_created: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#dateTime + sources: + - 'null' + display_label: + default: Date Created + index_documentation: displayable, searchable + indexing: + - date_created_sim + - date_created_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/created + range: http://www.w3.org/2001/XMLSchema#dateTime + sample_values: + - '2024-06-06 21:06:51 +0000' + view: + render_as: "linked" + search_field: 'date_created_tesim' + html_dl: true + description: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Description + index_documentation: displayable, searchable + indexing: + - description_sim + - description_tesim + form: + primary: false + property_uri: http://purl.org/dc/elements/1.1/description + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - This is a description. + identifier: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Identifier + index_documentation: displayable, searchable + indexing: + - identifier_sim + - identifier_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/identifier + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - abc123 + view: + render_as: "linked" + search_field: 'identifier_tesim' + html_dl: true + import_url: + available_on: + class: + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Import URL + property_uri: http://scholarsphere.psu.edu/ns#importUrl + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - http://example.com/resource1 + keyword: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Keyword + index_documentation: displayable, searchable + indexing: + - keyword_sim + - keyword_tesim + form: + primary: false + property_uri: http://schema.org/keywords + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Metadata + - Repository + view: + render_as: "faceted" + html_dl: true + label: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Label + index_documentation: displayable, searchable + indexing: + - label_sim + - label_tesim + form: + primary: false + property_uri: info:fedora/fedora-system:def/model#downloadFilename + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - file_label.txt + language: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Language + index_documentation: displayable, searchable + indexing: + - language_sim + - language_tesim + form: + primary: false + property_uri: http://purl.org/dc/elements/1.1/language + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - English + - Spanish + view: + render_as: "faceted" + html_dl: true + publisher: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Publisher + index_documentation: displayable, searchable + indexing: + - publisher_sim + - publisher_tesim + form: + primary: false + property_uri: http://purl.org/dc/elements/1.1/publisher + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Scholastic + view: + render_as: "faceted" + html_dl: true + related_url: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Related URL + index_documentation: displayable, searchable + indexing: + - related_url_sim + - related_url_tesim + form: + primary: false + property_uri: http://www.w3.org/2000/01/rdf-schema#seeAlso + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - http://example.com/resource1 + view: + render_as: "external_link" + html_dl: true + relative_path: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Relative Path + property_uri: http://scholarsphere.psu.edu/ns#relativePath + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - "/path/to/resource" + resource_type: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Resource Type + index_documentation: displayable, searchable + indexing: + - resource_type_sim + - resource_type_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/type + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Article + - Conference Proceeding + view: + render_as: "faceted" + html_dl: true + rights_notes: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Rights Notes + index_documentation: displayable, searchable + indexing: + - rights_notes_sim + - rights_notes_tesim + form: + primary: false + property_uri: http://purl.org/dc/elements/1.1/rights + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Creative Commons license. + view: + html_dl: true + rights_statement: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Rights Statement + index_documentation: displayable, searchable + indexing: + - rights_statement_sim + - rights_statement_tesim + form: + primary: true + property_uri: http://www.europeana.eu/schemas/edm/rights + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - http://rightsstatements.org/vocab/InC/1.0/ + view: + html_dl: true + render_as: "rights_statement" + source: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Source + index_documentation: displayable, searchable + indexing: + - source_sim + - source_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/source + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Original Manuscript + - Digital Archive + view: + html_dl: true + subject: + available_on: + class: + - Hyrax::FileSet + - CollectionResource + - GenericWork + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Subject + index_documentation: displayable, searchable + indexing: + - subject_sim + - subject_tesim + form: + primary: false + property_uri: http://purl.org/dc/elements/1.1/subject + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Art + - Science + view: + render_as: "faceted" + html_dl: true + target_audience: + available_on: + class: + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Target Audience + form: + multiple: true + property_uri: http://hyrax-example.com/target_audience + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Researchers + - Students + view: + html_dl: true + department: + available_on: + class: + - CollectionResource + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Department + form: + primary: true + property_uri: http://hyrax-example.com/department + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Mathematics + - History + view: + html_dl: true + course: + available_on: + class: + - CollectionResource + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Course + form: + primary: false + property_uri: http://hyrax-example.com/course + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Computer Science 50 + view: + html_dl: true + monograph_title: + available_on: + class: + - Monograph + cardinality: + minimum: 1 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Monograph Title + property_uri: http://hyrax-example.com/monograph_title + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Example Monograph Title + view: + html_dl: true + record_info: + available_on: + class: + - Monograph + cardinality: + minimum: 1 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Record Info + index_documentation: searchable + indexing: + - record_info_tesim + form: + required: true + primary: true + property_uri: http://hyrax-example.com/record_info + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Example Record Info + view: + html_dl: true + place_of_publication: + available_on: + class: + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Place of Publication + form: + required: false + primary: true + property_uri: http://hyrax-example.com/place_of_publication + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Example Place of Publication + view: + html_dl: true + genre: + available_on: + class: + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Genre + form: + primary: true + property_uri: http://hyrax-example.com/genre + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Fiction + - Non-Fiction + view: + html_dl: true + series_title: + available_on: + class: + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Series Title + form: + primary: false + property_uri: http://hyrax-example.com/series_title + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Example Series Title + view: + html_dl: true + table_of_contents: + available_on: + class: + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Table of Contents + form: + multiple: false + property_uri: http://hyrax-example.com/table_of_contents + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Example Table of Contents + view: + html_dl: true + date_of_issuance: + available_on: + class: + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Date of Issuance + property_uri: http://hyrax-example.com/date_of_issuance + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - '2024-06-06 21:06:51 +0000' + view: + html_dl: true diff --git a/.koppie/db/migrate/20240606205215_create_hyrax_flexible_schemas.rb b/.koppie/db/migrate/20240606205215_create_hyrax_flexible_schemas.rb new file mode 100644 index 0000000000..bdbac2bc49 --- /dev/null +++ b/.koppie/db/migrate/20240606205215_create_hyrax_flexible_schemas.rb @@ -0,0 +1,9 @@ +class CreateHyraxFlexibleSchemas < ActiveRecord::Migration[6.1] + def change + create_table :hyrax_flexible_schemas do |t| + t.text :profile + + t.timestamps + end + end +end diff --git a/.koppie/db/migrate/20240606205216_add_contexts_to_hyrax_flexible_schemas.rb b/.koppie/db/migrate/20240606205216_add_contexts_to_hyrax_flexible_schemas.rb new file mode 100644 index 0000000000..b283bfbc88 --- /dev/null +++ b/.koppie/db/migrate/20240606205216_add_contexts_to_hyrax_flexible_schemas.rb @@ -0,0 +1,5 @@ +class AddContextsToHyraxFlexibleSchemas < ActiveRecord::Migration[6.1] + def change + add_column :hyrax_flexible_schemas, :contexts, :text unless column_exists?(:hyrax_flexible_schemas, :contexts) + end +end diff --git a/.koppie/db/schema.rb b/.koppie/db/schema.rb index 90c60c8384..c4dfd4eafa 100644 --- a/.koppie/db/schema.rb +++ b/.koppie/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2023_08_03_165135) do +ActiveRecord::Schema.define(version: 2024_06_06_205215) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -164,6 +164,12 @@ t.datetime "updated_at", null: false end + create_table "hyrax_flexible_schemas", force: :cascade do |t| + t.text "profile" + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + end + create_table "job_io_wrappers", force: :cascade do |t| t.bigint "user_id" t.bigint "uploaded_file_id" diff --git a/app/controllers/concerns/hyrax/flexible_schema_behavior.rb b/app/controllers/concerns/hyrax/flexible_schema_behavior.rb new file mode 100644 index 0000000000..023c45a89d --- /dev/null +++ b/app/controllers/concerns/hyrax/flexible_schema_behavior.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Hyrax + module FlexibleSchemaBehavior + extend ActiveSupport::Concern + + included do + before_action :set_latest_schema_version, only: [:new, :edit] + end + + private + + def set_latest_schema_version + @latest_schema_version = Hyrax::FlexibleSchema.current_schema_id.to_f if Hyrax.config.flexible? + end + end +end diff --git a/app/controllers/concerns/hyrax/works_controller_behavior.rb b/app/controllers/concerns/hyrax/works_controller_behavior.rb index 107acf4cae..1073e76824 100644 --- a/app/controllers/concerns/hyrax/works_controller_behavior.rb +++ b/app/controllers/concerns/hyrax/works_controller_behavior.rb @@ -6,6 +6,7 @@ module WorksControllerBehavior extend ActiveSupport::Concern include Blacklight::Base include Blacklight::AccessControls::Catalog + include Hyrax::FlexibleSchemaBehavior if Hyrax.config.flexible? included do with_themed_layout :decide_layout @@ -59,6 +60,7 @@ def new # TODO: move these lines to the work form builder in Hyrax curation_concern.depositor = current_user.user_key curation_concern.admin_set_id = params[:admin_set_id] || admin_set_id_for_new + curation_concern.contexts = Hyrax.query_service.find_by(id: curation_concern.admin_set_id)&.contexts build_form end @@ -177,7 +179,8 @@ def admin_set_id_for_new Hyrax::AdminSetCreateService.find_or_create_default_admin_set.id.to_s end - def build_form + def build_form(contexts: []) + curation_concern.contexts = contexts unless contexts.blank? @form = work_form_service.build(curation_concern, current_ability, self) end @@ -189,7 +192,7 @@ def actor # @return [#errors] # rubocop:disable Metrics/MethodLength def create_valkyrie_work - form = build_form + form = build_form(contexts: params[hash_key_for_curation_concern]['contexts']) action = create_valkyrie_work_action.new(form: form, transactions: transactions, user: current_user, diff --git a/app/controllers/hyrax/dashboard/collections_controller.rb b/app/controllers/hyrax/dashboard/collections_controller.rb index e980130efa..72f927fb51 100644 --- a/app/controllers/hyrax/dashboard/collections_controller.rb +++ b/app/controllers/hyrax/dashboard/collections_controller.rb @@ -5,6 +5,7 @@ module Dashboard class CollectionsController < Hyrax::My::CollectionsController include Blacklight::AccessControls::Catalog include Blacklight::Base + include Hyrax::FlexibleSchemaBehavior if Hyrax.config.flexible? configure_blacklight do |config| config.search_builder_class = Hyrax::Dashboard::CollectionsSearchBuilder diff --git a/app/controllers/hyrax/dashboard_controller.rb b/app/controllers/hyrax/dashboard_controller.rb index 4e4bef4500..01c549c86d 100644 --- a/app/controllers/hyrax/dashboard_controller.rb +++ b/app/controllers/hyrax/dashboard_controller.rb @@ -15,7 +15,7 @@ class DashboardController < ApplicationController # @example Add a custom partial to the tasks sidebar block # Hyrax::DashboardController.sidebar_partials[:tasks] << "hyrax/dashboard/sidebar/custom_task" class_attribute :sidebar_partials - self.sidebar_partials = { activity: [], configuration: [], repository_content: [], tasks: [] } + self.sidebar_partials = { activity: [], configuration: ["hyrax/dashboard/sidebar/metadata"], repository_content: [], tasks: [] } def show if can? :read, :admin_dashboard diff --git a/app/controllers/hyrax/file_sets_controller.rb b/app/controllers/hyrax/file_sets_controller.rb index 4fb3a9ded8..84a99d4d1d 100644 --- a/app/controllers/hyrax/file_sets_controller.rb +++ b/app/controllers/hyrax/file_sets_controller.rb @@ -6,6 +6,7 @@ class FileSetsController < ApplicationController include Blacklight::Base include Blacklight::AccessControls::Catalog include Hyrax::Breadcrumbs + include Hyrax::FlexibleSchemaBehavior if Hyrax.config.flexible? before_action :authenticate_user!, except: [:show, :citation, :stats] load_and_authorize_resource class: Hyrax.config.file_set_class diff --git a/app/controllers/hyrax/metadata_profiles_controller.rb b/app/controllers/hyrax/metadata_profiles_controller.rb new file mode 100644 index 0000000000..3dbd305e9f --- /dev/null +++ b/app/controllers/hyrax/metadata_profiles_controller.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +module Hyrax + class MetadataProfilesController < ApplicationController + include Hyrax::ThemedLayoutController + require 'yaml' + + with_themed_layout 'dashboard' + + # GET /allinson_flex_profiles + def index + add_breadcrumbs + @metadata_profiles = Hyrax::FlexibleSchema.page(params[:profile_entries_page]) + end + + # rubocop:disable Metrics/MethodLength + def import + uploaded_io = params[:file] + if uploaded_io.blank? + redirect_to metadata_profiles_path, alert: 'Please select a file to upload' + return + end + + begin + @flexible_schema = Hyrax::FlexibleSchema.create(profile: YAML.safe_load_file(uploaded_io.path)) + + if @flexible_schema.persisted? + redirect_to metadata_profiles_path, notice: 'AllinsonFlexProfile was successfully created.' + else + redirect_to metadata_profiles_path, alert: @flexible_schema.errors.messages.to_s + end + rescue => e + redirect_to metadata_profiles_path, alert: e.message + nil + end + end + # rubocop:enable Metrics/MethodLength + + def export + @schema = Hyrax::FlexibleSchema.find(params[:metadata_profile_id]) + filename = "metadata-profile-v.#{@schema.version}.yml" + yaml_data = @schema.profile.to_hash.to_yaml(indentation: 2) + send_data yaml_data, filename: filename, type: "application/yaml" + end + + private + + def add_breadcrumbs + add_breadcrumb t(:'hyrax.controls.home'), main_app.root_path + add_breadcrumb t(:'hyrax.dashboard.breadcrumbs.admin'), hyrax.dashboard_path + add_breadcrumb t(:'hyrax.dashboard.metadata_profiles'), hyrax.metadata_profiles_path + end + end +end diff --git a/app/forms/concerns/hyrax/based_near_field_behavior.rb b/app/forms/concerns/hyrax/based_near_field_behavior.rb new file mode 100644 index 0000000000..208f1e84f9 --- /dev/null +++ b/app/forms/concerns/hyrax/based_near_field_behavior.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true +module Hyrax + module BasedNearFieldBehavior + # Provides compatibility with the behavior of the based_near (location) controlled vocabulary form field. + # The form expects a ControlledVocabularies::Location object as input and produces a hash like those + # used with accepts_nested_attributes_for. + def self.included(descendant) + descendant.property :based_near_attributes, virtual: true, populator: :based_near_populator, prepopulator: :based_near_prepopulator + end + + private + + def based_near_populator(fragment:, **_options) + return unless respond_to?(:based_near) + adds = [] + deletes = [] + fragment.each do |_, h| + uri = RDF::URI.parse(h["id"]).to_s + if h["_destroy"] == "true" + deletes << uri + else + adds << uri + end + end + self.based_near = ((model.based_near + adds) - deletes).uniq + end + + def based_near_prepopulator + return unless respond_to?(:based_near) + self.based_near = based_near&.map do |loc| + uri = RDF::URI.parse(loc) + if uri + Hyrax::ControlledVocabularies::Location.new(uri) + else + loc + end + end + based_near ||= [] + based_near << Hyrax::ControlledVocabularies::Location.new if based_near.empty? + end + end +end diff --git a/app/forms/concerns/hyrax/basic_metadata_form_fields_behavior.rb b/app/forms/concerns/hyrax/basic_metadata_form_fields_behavior.rb index 19ebcd02cb..a59405479f 100644 --- a/app/forms/concerns/hyrax/basic_metadata_form_fields_behavior.rb +++ b/app/forms/concerns/hyrax/basic_metadata_form_fields_behavior.rb @@ -1,39 +1,10 @@ # frozen_string_literal: true module Hyrax module BasicMetadataFormFieldsBehavior - # Provides compatibility with the behavior of the based_near (location) controlled vocabulary form field. - # The form expects a ControlledVocabularies::Location object as input and produces a hash like those - # used with accepts_nested_attributes_for. - def self.included(descendant) - descendant.property :based_near_attributes, virtual: true, populator: :based_near_populator, prepopulator: :based_near_prepopulator - end - - private - - def based_near_populator(fragment:, **_options) - adds = [] - deletes = [] - fragment.each do |_, h| - uri = RDF::URI.parse(h["id"]).to_s - if h["_destroy"] == "true" - deletes << uri - else - adds << uri - end - end - self.based_near = ((model.based_near + adds) - deletes).uniq - end + extend ActiveSupport::Concern - def based_near_prepopulator - self.based_near = based_near.map do |loc| - uri = RDF::URI.parse(loc) - if uri - Hyrax::ControlledVocabularies::Location.new(uri) - else - loc - end - end - based_near << Hyrax::ControlledVocabularies::Location.new if based_near.empty? + included do + include Hyrax::BasedNearFieldBehavior end end end diff --git a/app/forms/concerns/hyrax/flexible_form_behavior.rb b/app/forms/concerns/hyrax/flexible_form_behavior.rb new file mode 100644 index 0000000000..9e54cc3d48 --- /dev/null +++ b/app/forms/concerns/hyrax/flexible_form_behavior.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +module Hyrax + module FlexibleFormBehavior + extend ActiveSupport::Concern + + included do + include Hyrax::BasedNearFieldBehavior + property :contexts + end + + # OVERRIDE disposable 0.6.3 to make schema dynamic + def schema + Hyrax::Forms::ResourceForm::Definition::Each.new(singleton_class.schema_definitions) + end + + private + + # OVERRIDE valkyrie 3.0.1 to make schema dynamic + def field(field_name) + singleton_class.schema_definitions.fetch(field_name.to_s) + end + + def _form_field_definitions + singleton_class.schema_definitions + end + end +end diff --git a/app/forms/hyrax/forms/administrative_set_form.rb b/app/forms/hyrax/forms/administrative_set_form.rb index 2c96c1e960..50879a32de 100644 --- a/app/forms/hyrax/forms/administrative_set_form.rb +++ b/app/forms/hyrax/forms/administrative_set_form.rb @@ -22,7 +22,7 @@ class AdministrativeSetForm < Hyrax::Forms::ResourceForm property :title, required: true, primary: true property :description, primary: true - + property :contexts, primary: true if Hyrax.config.flexible? property :creator validates :title, presence: true diff --git a/app/forms/hyrax/forms/file_set_form.rb b/app/forms/hyrax/forms/file_set_form.rb index 529a90c77c..ee530f2fe2 100644 --- a/app/forms/hyrax/forms/file_set_form.rb +++ b/app/forms/hyrax/forms/file_set_form.rb @@ -5,12 +5,13 @@ module Forms ## # A form for +Hyrax::FileSet+s. class FileSetForm < Hyrax::Forms::ResourceForm - include Hyrax::FormFields(:core_metadata) + include Hyrax::FormFields(:core_metadata) unless Hyrax.config.flexible? # The fields in +:file_set_metadata+ were hardcoded into this form in a # previous version of Hyrax, but ideally in the future this metadata will # be configurable. - include Hyrax::FormFields(:file_set_metadata) + include Hyrax::FormFields(:file_set_metadata) unless Hyrax.config.flexible? + include Hyrax::FormFields('Hyrax::FileSet') if Hyrax.config.flexible? include Hyrax::DepositAgreementBehavior include Hyrax::ContainedInWorksBehavior diff --git a/app/forms/hyrax/forms/pcdm_collection_form.rb b/app/forms/hyrax/forms/pcdm_collection_form.rb index 43abbdc33e..322e9fd7fc 100644 --- a/app/forms/hyrax/forms/pcdm_collection_form.rb +++ b/app/forms/hyrax/forms/pcdm_collection_form.rb @@ -6,7 +6,7 @@ module Forms # @api public # @see https://github.com/samvera/valkyrie/wiki/ChangeSets-and-Dirty-Tracking class PcdmCollectionForm < Hyrax::Forms::ResourceForm # rubocop:disable Metrics/ClassLength - include Hyrax::FormFields(:core_metadata) + include Hyrax::FormFields(:core_metadata) unless Hyrax.config.flexible? BannerInfoPrepopulator = lambda do |**_options| self.banner_info ||= begin @@ -62,9 +62,12 @@ def required_fields # @return [Array] terms for display 'above-the-fold', or in the most # prominent form real estate def primary_terms - _form_field_definitions - .select { |_, definition| definition[:primary] } - .keys.map(&:to_sym) + terms = _form_field_definitions + .select { |_, definition| definition[:primary] } + .keys.map(&:to_sym) + + terms = [:schema_version] + terms if Hyrax.config.flexible? + terms end ## diff --git a/app/forms/hyrax/forms/pcdm_object_form.rb b/app/forms/hyrax/forms/pcdm_object_form.rb index 7965f07388..bc895a157e 100644 --- a/app/forms/hyrax/forms/pcdm_object_form.rb +++ b/app/forms/hyrax/forms/pcdm_object_form.rb @@ -9,7 +9,7 @@ module Forms # Although File Sets are technically also PCDM objects, they use a separate # form class: +Hyrax::Forms::FileSetForm+. class PcdmObjectForm < Hyrax::Forms::ResourceForm - include Hyrax::FormFields(:core_metadata) + include Hyrax::FormFields(:core_metadata) unless Hyrax.config.flexible? include Hyrax::ContainedInWorksBehavior include Hyrax::DepositAgreementBehavior diff --git a/app/forms/hyrax/forms/resource_batch_edit_form.rb b/app/forms/hyrax/forms/resource_batch_edit_form.rb index 0e6fae59af..f08cab01af 100644 --- a/app/forms/hyrax/forms/resource_batch_edit_form.rb +++ b/app/forms/hyrax/forms/resource_batch_edit_form.rb @@ -2,7 +2,7 @@ module Hyrax module Forms class ResourceBatchEditForm < Hyrax::Forms::ResourceForm - include Hyrax::FormFields(:basic_metadata) + include Hyrax::FormFields(:basic_metadata) unless Hyrax.config.flexible? include Hyrax::ContainedInWorksBehavior include Hyrax::DepositAgreementBehavior diff --git a/app/forms/hyrax/forms/resource_form.rb b/app/forms/hyrax/forms/resource_form.rb index 75fb70d5e4..8431b4aceb 100644 --- a/app/forms/hyrax/forms/resource_form.rb +++ b/app/forms/hyrax/forms/resource_form.rb @@ -7,6 +7,11 @@ module Forms # # This form wraps +Hyrax::ChangeSet+ in the +HydraEditor::Form+ interface. class ResourceForm < Hyrax::ChangeSet # rubocop:disable Metrics/ClassLength + # These do not get auto loaded when using a flexible schema and should instead + # be added to the individual Form classes for a work type or smart enough + # to be selective as to when they trigger + include FlexibleFormBehavior if Hyrax.config.flexible? + ## # @api private # @@ -47,7 +52,16 @@ class ResourceForm < Hyrax::ChangeSet # rubocop:disable Metrics/ClassLength # # Forms should be initialized with an explicit +resource:+ parameter to # match indexers. - def initialize(deprecated_resource = nil, resource: nil) + def initialize(deprecated_resource = nil, resource: nil) # rubocop:disable Metrics/MethodLength + if Hyrax.config.flexible? + singleton_class.schema_definitions = self.class.definitions + r = resource || deprecated_resource + Hyrax::Schema.default_schema_loader.form_definitions_for(schema: r.class.to_s, version: Hyrax::FlexibleSchema.current_schema_id, contexts: r.contexts).map do |field_name, options| + singleton_class.property field_name.to_sym, options.merge(display: options.fetch(:display, true), default: []) + singleton_class.validates field_name.to_sym, presence: true if options.fetch(:required, false) + end + end + if resource.nil? if !deprecated_resource.nil? Deprecation.warn "Initializing Valkyrie forms without an explicit resource parameter is deprecated. Pass the resource with `resource:` instead." @@ -56,9 +70,21 @@ def initialize(deprecated_resource = nil, resource: nil) super() end else + # make a new resource with all of the existing attributes + if Hyrax.config.flexible? + hash = resource.attributes.dup + hash[:schema_version] = Hyrax::FlexibleSchema.current_schema_id + resource = resource.class.new(hash) + # find any fields removed by the new schema + to_remove = self.singleton_class.definitions.select {|k, v| !resource.respond_to?(k) && v.instance_variable_get("@options")[:display]} + to_remove.keys.each do |removed_field| + self.singleton_class.definitions.delete(removed_field) + end + end + super(resource) end - end + end # rubocop:enable Metrics/MethodLength class << self ## @@ -87,7 +113,7 @@ def for(deprecated_resource = nil, resource: nil) ## # @return [Array] list of required field names as symbols def required_fields - definitions + schema_definitions .select { |_, definition| definition[:required] } .keys.map(&:to_sym) end @@ -98,14 +124,25 @@ def required_fields # @return [Array] list of required field names as symbols def required_fields=(fields) fields = fields.map(&:to_s) - raise(KeyError) unless fields.all? { |f| definitions.key?(f) } + raise(KeyError) unless fields.all? { |f| schema_definitions.key?(f) } - fields.each { |field| definitions[field].merge!(required: true) } + fields.each { |field| schema_definitions[field].merge!(required: true) } required_fields end - end + def schema_definitions + @definitions + end + + def schema_definitions=(values) + @definitions = values + end + + def expose_class + @expose_class = Class.new(Disposable::Expose).from(schema_definitions.values) + end + end ## # @param [#to_s] attr # @param [Object] value @@ -127,9 +164,12 @@ def model_class # rubocop:disable Rails/Delegate # @return [Array] terms for display 'above-the-fold', or in the most # prominent form real estate def primary_terms - _form_field_definitions - .select { |_, definition| definition[:primary] } - .keys.map(&:to_sym) + terms = _form_field_definitions + .select { |_, definition| definition[:primary] } + .keys.map(&:to_sym) + + terms = [:schema_version, :contexts] + terms if Hyrax.config.flexible? + terms end ## @@ -145,12 +185,6 @@ def secondary_terms def display_additional_fields? secondary_terms.any? end - - private - - def _form_field_definitions - self.class.definitions - end end end end diff --git a/app/helpers/hyrax/attributes_helper.rb b/app/helpers/hyrax/attributes_helper.rb new file mode 100644 index 0000000000..796cebf216 --- /dev/null +++ b/app/helpers/hyrax/attributes_helper.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +module Hyrax + module AttributesHelper + def view_options_for(presenter) + model_name = presenter.model.model_name.name + + if Hyrax.config.flexible? + Hyrax::Schema.default_schema_loader.view_definitions_for(schema: model_name, version: presenter.solr_document.schema_version, contexts: presenter.solr_document.contexts) + else + schema = model_name.constantize.schema || (model_name + 'Resource').safe_constantize.schema + Hyrax::Schema.default_schema_loader.view_definitions_for(schema:) + end + end + + def conform_field(field_name, options_hash) + options = HashWithIndifferentAccess.new(options_hash) + HashWithIndifferentAccess.new(options)['render_term'] || field_name + end + + # @param [String] field name + # @param [Hash] a nested hash of view options... {:label=>{"en"=>"Title", "es"=>"Título"}, :html_dl=>true} + def conform_options(field_name, options_hash) + options = HashWithIndifferentAccess.new(options_hash) + hash_of_locales = HashWithIndifferentAccess.new(options)['label'] || {} + current_locale = params['locale'] || I18n.locale.to_s + + unless hash_of_locales.present? + options[:label] = field_name.to_s.humanize + return options + end + + return options_hash if hash_of_locales.is_a?(String) || hash_of_locales.empty? + + # If the params locale is found in the hash of locales, use that value + if hash_of_locales[current_locale].present? + options[:label] = hash_of_locales[current_locale] + # If the params locale is not found, fall back to english + elsif hash_of_locales['en'] + options[:label] = hash_of_locales['en'] + # If the params locale is not found and english is not found, use the first value in the hash as a fallback + elsif hash_of_locales['en'].nil? && hash_of_locales[current_locale].nil? + options[:label] = hash_of_locales.values.first + end + + options + end + end +end diff --git a/app/helpers/hyrax/hyrax_helper_behavior.rb b/app/helpers/hyrax/hyrax_helper_behavior.rb index bd1d6030df..5cebfc809c 100644 --- a/app/helpers/hyrax/hyrax_helper_behavior.rb +++ b/app/helpers/hyrax/hyrax_helper_behavior.rb @@ -19,6 +19,7 @@ module HyraxHelperBehavior include Hyrax::WorkFormHelper include Hyrax::WorkflowsHelper include Hyrax::FacetsHelper + include Hyrax::AttributesHelper ## # @return [Array] the list of all user groups diff --git a/app/indexers/hyrax/indexers/administrative_set_indexer.rb b/app/indexers/hyrax/indexers/administrative_set_indexer.rb index 787cbe7e4e..5c69a8e589 100644 --- a/app/indexers/hyrax/indexers/administrative_set_indexer.rb +++ b/app/indexers/hyrax/indexers/administrative_set_indexer.rb @@ -7,7 +7,8 @@ module Indexers class AdministrativeSetIndexer < Hyrax::Indexers::ResourceIndexer include Hyrax::PermissionIndexer include Hyrax::VisibilityIndexer - include Hyrax::Indexer(:core_metadata) + include Hyrax::Indexer(:core_metadata) unless Hyrax.config.flexible? + include Hyrax::Indexer('Hyrax::AdministrativeSet') if Hyrax.config.flexible? def to_solr # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength super.tap do |solr_doc| diff --git a/app/indexers/hyrax/indexers/file_set_indexer.rb b/app/indexers/hyrax/indexers/file_set_indexer.rb index b684753025..5862e2d32a 100644 --- a/app/indexers/hyrax/indexers/file_set_indexer.rb +++ b/app/indexers/hyrax/indexers/file_set_indexer.rb @@ -8,8 +8,9 @@ class FileSetIndexer < Hyrax::Indexers::ResourceIndexer # rubocop:disable Metric include Hyrax::PermissionIndexer include Hyrax::VisibilityIndexer include Hyrax::ThumbnailIndexer - include Hyrax::Indexer(:core_metadata) - include Hyrax::Indexer(:file_set_metadata) + include Hyrax::Indexer(:core_metadata) unless Hyrax.config.flexible? + include Hyrax::Indexer(:file_set_metadata) unless Hyrax.config.flexible? + include Hyrax::Indexer('Hyrax::FileSet') if Hyrax.config.flexible? def to_solr # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity super.tap do |solr_doc| # rubocop:disable Metrics/BlockLength diff --git a/app/indexers/hyrax/indexers/pcdm_collection_indexer.rb b/app/indexers/hyrax/indexers/pcdm_collection_indexer.rb index a146bc4d13..deb9e52338 100644 --- a/app/indexers/hyrax/indexers/pcdm_collection_indexer.rb +++ b/app/indexers/hyrax/indexers/pcdm_collection_indexer.rb @@ -9,7 +9,8 @@ class PcdmCollectionIndexer < Hyrax::Indexers::ResourceIndexer include Hyrax::VisibilityIndexer include Hyrax::LocationIndexer include Hyrax::ThumbnailIndexer - include Hyrax::Indexer(:core_metadata) + include Hyrax::Indexer(:core_metadata) unless Hyrax.config.flexible? + include Hyrax::Indexer('Hyrax::PcdmCollection') if Hyrax.config.flexible? self.thumbnail_path_service = CollectionThumbnailPathService diff --git a/app/indexers/hyrax/indexers/pcdm_object_indexer.rb b/app/indexers/hyrax/indexers/pcdm_object_indexer.rb index 8451a7d59d..3dcfc209f9 100644 --- a/app/indexers/hyrax/indexers/pcdm_object_indexer.rb +++ b/app/indexers/hyrax/indexers/pcdm_object_indexer.rb @@ -9,7 +9,7 @@ class PcdmObjectIndexer < Hyrax::Indexers::ResourceIndexer include Hyrax::VisibilityIndexer include Hyrax::LocationIndexer include Hyrax::ThumbnailIndexer - include Hyrax::Indexer(:core_metadata) + include Hyrax::Indexer(:core_metadata) unless Hyrax.config.flexible? def to_solr # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength super.tap do |solr_doc| @@ -20,13 +20,13 @@ def to_solr # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Met solr_doc['admin_set_sim'] = admin_set_label solr_doc['admin_set_tesim'] = admin_set_label solr_doc["#{Hyrax.config.admin_set_predicate.qname.last}_ssim"] = [resource.admin_set_id.to_s] - solr_doc['member_of_collection_ids_ssim'] = resource.member_of_collection_ids.map(&:to_s) - solr_doc['member_ids_ssim'] = resource.member_ids.map(&:to_s) + solr_doc['member_of_collection_ids_ssim'] = resource.member_of_collection_ids&.map(&:to_s) + solr_doc['member_ids_ssim'] = resource.member_ids&.map(&:to_s) solr_doc['depositor_ssim'] = [resource.depositor] solr_doc['depositor_tesim'] = [resource.depositor] solr_doc['hasRelatedMediaFragment_ssim'] = [resource.representative_id.to_s] solr_doc['hasRelatedImage_ssim'] = [resource.thumbnail_id.to_s] - solr_doc['hasFormat_ssim'] = resource.rendering_ids.map(&:to_s) if resource.rendering_ids.present? + solr_doc['hasFormat_ssim'] = resource.rendering_ids&.map(&:to_s) if resource.rendering_ids.present? index_embargo(solr_doc) index_lease(solr_doc) end diff --git a/app/models/concerns/hyrax/ability.rb b/app/models/concerns/hyrax/ability.rb index 24ff6bb78f..65a4e11a31 100644 --- a/app/models/concerns/hyrax/ability.rb +++ b/app/models/concerns/hyrax/ability.rb @@ -55,6 +55,7 @@ module Ability include Hyrax::Ability::PermissionTemplateAbility include Hyrax::Ability::ResourceAbility include Hyrax::Ability::SolrDocumentAbility + include Hyrax::Ability::FlexibleMetadataAbility class_attribute :admin_group_name, :registered_group_name, :public_group_name self.admin_group_name = Hyrax.config.admin_user_group_name @@ -79,7 +80,8 @@ module Ability :permission_template_abilities, :resource_abilities, :solr_document_abilities, - :trophy_abilities] + :trophy_abilities, + :flexible_metadata_abilities] end # Samvera doesn't use download user/groups, so make it an alias to read diff --git a/app/models/concerns/hyrax/ability/flexible_metadata_ability.rb b/app/models/concerns/hyrax/ability/flexible_metadata_ability.rb new file mode 100644 index 0000000000..3c6eef3f21 --- /dev/null +++ b/app/models/concerns/hyrax/ability/flexible_metadata_ability.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true +module Hyrax + module Ability + module FlexibleMetadataAbility + def flexible_metadata_abilities + can :manage, Hyrax::FlexibleSchema if admin? && Hyrax.config.flexible? + end + end + end +end diff --git a/app/models/concerns/hyrax/flexibility.rb b/app/models/concerns/hyrax/flexibility.rb new file mode 100644 index 0000000000..7580097094 --- /dev/null +++ b/app/models/concerns/hyrax/flexibility.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +module Hyrax + module Flexibility + extend ActiveSupport::Concern + included do + attribute :schema_version, Valkyrie::Types::String + attribute :contexts, Valkyrie::Types::Set.of(Valkyrie::Types::String) + end + + class_methods do + def try(term) + # This logic is necessary to handle method :try on a class + # otherwise load(attributes) tries to use the term as a schema to load and errors + return nil unless self.respond_to?(term) + self.send(term) + end + + ## Override dry-struct 1.6.0 to enable redefining schemas on the fly + def attributes(new_schema) + keys = new_schema.keys.map { |k| k.to_s.chomp("?").to_sym } + schema_location = singleton_class? ? self.superclass : self + schema schema_location.schema.schema(new_schema) + + define_accessors(keys) + + @attribute_names = nil + + direct_descendants = descendants&.select { |d| d.superclass == self } + direct_descendants&.each do |d| + inherited_attrs = new_schema.reject { |k, _| d.has_attribute?(k.to_s.chomp("?").to_sym) } + d.attributes(inherited_attrs) + end + + new_schema.each_key do |key| + key = key.to_s.chomp('?') + next if instance_methods.include?("#{key}=".to_sym) + + class_eval(<<-RUBY) + def #{key}=(value) + set_value("#{key}".to_sym, value) + end + RUBY + end + + self + end + + ## Override dry-struct 1.6.0 to filter attributes after schema reload happens + def new(attributes = default_attributes, safe = false, &block) # rubocop:disable Style/OptionalBooleanParameter + if attributes.is_a?(Struct) + if equal?(attributes.class) + attributes + else + # This implicit coercion is arguable but makes sense overall + # in cases there you pass child struct to the base struct constructor + # User.new(super_user) + # + # We may deprecate this behavior in future forcing people to be explicit + new(attributes.to_h, safe, &block) + end + else + load(attributes, safe) + end + rescue Dry::Types::CoercionError => e + raise Dry::Error, "[#{self}.new] #{e}", e.backtrace + end + + ## Read the schema from the database and load the correct schemas for the instance in to the class + def load(attributes, safe = false) + attributes[:schema_version] ||= Hyrax::FlexibleSchema.order('id DESC').pick(:id) + struct = allocate + schema_version = attributes[:schema_version] + contexts = attributes[:contexts] || [] + struct.singleton_class.attributes(Hyrax::Schema(self, schema_version:, contexts:).attributes) + clean_attributes = safe ? struct.singleton_class.schema.call_safe(attributes) { |output = attributes| return yield output } : struct.singleton_class.schema.call_unsafe(attributes) + struct.__send__(:initialize, clean_attributes) + struct + end + end + + def contexts=(value) + val = Array.wrap(value).map { |v| v.split }.flatten + @attributes[:contexts] = val + end + + # Override set_value from valkyrie 3.1.1 to enable dynamic schema loading + def set_value(key, value) + @attributes[key.to_sym] = self.singleton_class.schema.key(key.to_sym).type.call(value) + end + + # Override inspect from dry-struct 1.6.0 to enable dynamic schema loading + def inspect + klass = self.singleton_class + attrs = klass.attribute_names.map { |key| " #{key}=#{@attributes[key].inspect}" }.join + "#<#{klass.name || klass.inspect}#{attrs}>" + end + end +end diff --git a/app/models/concerns/hyrax/solr_document_behavior.rb b/app/models/concerns/hyrax/solr_document_behavior.rb index 82a2d48184..337a0b924f 100644 --- a/app/models/concerns/hyrax/solr_document_behavior.rb +++ b/app/models/concerns/hyrax/solr_document_behavior.rb @@ -82,9 +82,12 @@ def valkyrie? # Method to return the model def hydra_model(classifier: nil) - model = first('has_model_ssim')&.safe_constantize - model = (first('has_model_ssim')&.+ 'Resource')&.safe_constantize if Hyrax.config.valkyrie_transition? - model || model_classifier(classifier).classifier(self).best_model + model_name = first('has_model_ssim') + valkyrie_model = "#{model_name}Resource".safe_constantize if Hyrax.config.valkyrie_transition + + valkyrie_model || + model_name&.safe_constantize || + model_classifier(classifier).classifier(self).best_model end def depositor(default = '') @@ -146,6 +149,14 @@ def extensions_and_mime_types JSON.parse(self['extensions_and_mime_types_ssm'].first).map(&:with_indifferent_access) if self['extensions_and_mime_types_ssm'] end + def schema_version + self['schema_version_ssi'] + end + + def contexts + self['contexts_ssim'] + end + private def model_classifier(classifier) diff --git a/app/models/hyrax/administrative_set.rb b/app/models/hyrax/administrative_set.rb index 0b82afa7e4..325976a548 100644 --- a/app/models/hyrax/administrative_set.rb +++ b/app/models/hyrax/administrative_set.rb @@ -25,7 +25,7 @@ module Hyrax # @see Valkyrie query adapter's #find_inverse_references_by # class AdministrativeSet < Hyrax::Resource - include Hyrax::Schema(:core_metadata) + include Hyrax::Schema(:core_metadata) unless Hyrax.config.flexible? attribute :alternative_title, Valkyrie::Types::Set.of(Valkyrie::Types::String) attribute :creator, Valkyrie::Types::Set.of(Valkyrie::Types::String) diff --git a/app/models/hyrax/file_set.rb b/app/models/hyrax/file_set.rb index 2a4dfc1cec..2033e8c475 100644 --- a/app/models/hyrax/file_set.rb +++ b/app/models/hyrax/file_set.rb @@ -49,8 +49,10 @@ module Hyrax # @see Hyrax::CustomQueries::Navigators::ParentWorkNavigator#find_parent_work # @see https://wiki.duraspace.org/display/samvera/Hydra%3A%3AWorks+Shared+Modeling class FileSet < Hyrax::Resource - include Hyrax::Schema(:core_metadata) - include Hyrax::Schema(:file_set_metadata) + include Hyrax::Schema(:core_metadata) unless Hyrax.config.flexible? + include Hyrax::Schema(:file_set_metadata) unless Hyrax.config.flexible? + # TODO why isn't this automatic? + include Hyrax::Schema('Hyrax::FileSet') if Hyrax.config.flexible? def self.model_name(name_class: Hyrax::Name) @_model_name ||= name_class.new(self, nil, 'FileSet') diff --git a/app/models/hyrax/flexible_schema.rb b/app/models/hyrax/flexible_schema.rb new file mode 100644 index 0000000000..e76df715a5 --- /dev/null +++ b/app/models/hyrax/flexible_schema.rb @@ -0,0 +1,123 @@ +# frozen_string_literal: true +class Hyrax::FlexibleSchema < ApplicationRecord + serialize :profile, coder: YAML + serialize :contexts, coder: YAML + + validate :validate_profile_classes + + before_save :update_contexts + + def self.current_version + order("created_at asc").last.profile + end + + def self.current_schema_id + order("created_at asc").last.id + end + + def self.create_default_schema + Hyrax::FlexibleSchema.first_or_create do |f| + f.profile = YAML.safe_load_file(Rails.root.join('config', 'metadata_profiles', 'm3_profile.yaml')) + end + end + + # Retrieve the properties for the model / work type + # This is a class method called by the model at class load + # meaning AdminSet is not available and we cannot get the + # contextual dynamic_schema + # Instead we use the default (contextless) dynamic_schema + # which will add all properties available for that class + # @return [Array] property#to_sym + def self.default_properties + self.current_version['properties'].symbolize_keys!.keys + rescue StandardError => e + [] + end + + def update_contexts + self.contexts = profile['contexts'] + end + + def title + "#{profile['profile']['responsibility_statement']} - version #{id}" + end + + def attributes_for(class_name) + class_names[class_name] + end + + def schema_version + profile['m3_version'] + end + + def context_select + contexts&.map { |k, v| [v&.[]('display_label'), k] } + end + + def metadata_profile_type + profile['profile']['type'] + end + + def version + id + end + + def profile_created_at + created_at.strftime("%b %d, %Y") + end + + private + + def validate_profile_classes + required_classes = [ + Hyrax.config.collection_model, + Hyrax.config.file_set_model, + Hyrax.config.admin_set_model + ] + + if profile['classes'].blank? + errors.add(:profile, "Must specify classes") + else + missing_classes = required_classes - profile['classes'].keys + unless missing_classes.empty? + missing_classes_list = missing_classes.join(', ') + errors.add(:profile, "Must include #{missing_classes_list}") + end + end + end + + def class_names + return @class_names if @class_names + @class_names = {} + profile['classes'].keys.each do |class_name| + @class_names[class_name] = {} + end + profile['properties'].each do |key, values| + values['available_on']['class'].each do |property_class| + # map some m3 items to what Hyrax expects + values = values_map(values) + @class_names[property_class][key] = values + end + end + @class_names + end + + def values_map(values) + values['type'] = lookup_type(values['range']) + values['form']&.transform_keys!('multi_value' => 'multiple') + values['predicate'] = values['property_uri'] + values['index_keys'] = values['indexing'] + values['multiple'] = values['multi_value'] + values['context'] = values['available_on']['context'] + values + end + + def lookup_type(range) + case range + when "http://www.w3.org/2001/XMLSchema#dateTime" + 'date_time' + else + range.split('#').last.underscore + end + end +end diff --git a/app/models/hyrax/pcdm_collection.rb b/app/models/hyrax/pcdm_collection.rb index efc479bee6..b1a8ceb895 100644 --- a/app/models/hyrax/pcdm_collection.rb +++ b/app/models/hyrax/pcdm_collection.rb @@ -40,7 +40,7 @@ module Hyrax # @see Hyrax::CustomQueries::Navigators::CollectionMembers#find_members_of # class PcdmCollection < Hyrax::Resource - include Hyrax::Schema(:core_metadata) + include Hyrax::Schema(:core_metadata) unless Hyrax.config.flexible? attribute :collection_type_gid, Valkyrie::Types::String attribute :member_ids, Valkyrie::Types::Array.of(Valkyrie::Types::ID).meta(ordered: true) diff --git a/app/models/hyrax/resource.rb b/app/models/hyrax/resource.rb index 176f900848..d2da326ff0 100644 --- a/app/models/hyrax/resource.rb +++ b/app/models/hyrax/resource.rb @@ -31,6 +31,7 @@ module Hyrax # implementations). # class Resource < Valkyrie::Resource + include Hyrax::Flexibility if Hyrax.config.flexible? include Hyrax::Naming include Hyrax::WithEvents diff --git a/app/models/hyrax/work.rb b/app/models/hyrax/work.rb index 6ad04b35a0..a148009fad 100644 --- a/app/models/hyrax/work.rb +++ b/app/models/hyrax/work.rb @@ -94,7 +94,7 @@ module Hyrax # @see https://wiki.lyrasis.org/display/samvera/Hydra::Works+Shared+Modeling # for a historical perspective. class Work < Hyrax::Resource - include Hyrax::Schema(:core_metadata) + include Hyrax::Schema(:core_metadata) unless Hyrax.config.flexible? attribute :admin_set_id, Valkyrie::Types::ID attribute :member_ids, Valkyrie::Types::Array.of(Valkyrie::Types::ID).meta(ordered: true) diff --git a/app/presenters/hyrax/collection_presenter.rb b/app/presenters/hyrax/collection_presenter.rb index bb8f931a73..49cac418c9 100644 --- a/app/presenters/hyrax/collection_presenter.rb +++ b/app/presenters/hyrax/collection_presenter.rb @@ -25,7 +25,7 @@ def initialize(solr_document, current_ability, request = nil) # CurationConcern methods delegate :stringify_keys, :human_readable_type, :collection?, :representative_id, - :to_s, to: :solr_document + :to_s, :schema_version, to: :solr_document delegate(*Hyrax::CollectionType.settings_attributes, to: :collection_type, prefix: :collection_type_is) alias nestable? collection_type_is_nestable? diff --git a/app/presenters/hyrax/flexible_schema_presenter_behavior.rb b/app/presenters/hyrax/flexible_schema_presenter_behavior.rb new file mode 100644 index 0000000000..b856f0af04 --- /dev/null +++ b/app/presenters/hyrax/flexible_schema_presenter_behavior.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Hyrax + module FlexibleSchemaPresenterBehavior + extend ActiveSupport::Concern + + included do + extend ClassMethods + end + + module ClassMethods + def delegated_properties + Hyrax::FlexibleSchema.default_properties + end + end + end +end diff --git a/app/presenters/hyrax/work_show_presenter.rb b/app/presenters/hyrax/work_show_presenter.rb index 2b420f79cb..69e755cd1b 100644 --- a/app/presenters/hyrax/work_show_presenter.rb +++ b/app/presenters/hyrax/work_show_presenter.rb @@ -3,6 +3,7 @@ module Hyrax class WorkShowPresenter include ModelProxy include PresentsAttributes + include Hyrax::FlexibleSchemaPresenterBehavior if Hyrax.config.flexible? ## # @!attribute [w] member_presenter_factory @@ -24,11 +25,47 @@ def initialize(solr_document, current_ability, request = nil) @solr_document = Hyrax::SolrDocument::OrderedMembers.decorate(solr_document) @current_ability = current_ability @request = request + define_dynamic_methods if Hyrax.config.flexible? + end + + def define_dynamic_methods + Hyrax::FlexibleSchema.default_properties.each do |prop| + method_name = prop.to_s + property_details = Hyrax::FlexibleSchema.current_version["properties"][method_name] + next unless property_details + + index_keys = property_details["indexing"] + next unless index_keys + + multi_value = property_details.dig("multi_value") + + unless self.class.method_defined?(method_name) && solr_document.respond_to?(method_name) + # Define the method on the SolrDocument class + Hyrax::SolrDocument::OrderedMembers.send(:define_method, method_name) do + index_keys.each do |index_key| + value = self[index_key] + return value unless value.blank? + end + multi_value ? [] : "" + end + + # Define the method on the Presenter class + self.class.send(:define_method, method_name) do + @solr_document.send(method_name) + end + end + end end + + # We cannot rely on the method missing to catch this delegation. Because # most all objects implicitly implicitly implement #to_s - delegate :to_s, to: :solr_document + delegate :to_s, to: :solr_document unless Hyrax.config.flexible? + + def schema_version + solr_document[:schema_version_ssi] + end def page_title "#{human_readable_type} | #{title.first} | ID: #{id} | #{I18n.t('hyrax.product_name')}" diff --git a/app/services/hyrax/m3_schema_loader.rb b/app/services/hyrax/m3_schema_loader.rb new file mode 100644 index 0000000000..34d2804830 --- /dev/null +++ b/app/services/hyrax/m3_schema_loader.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +module Hyrax + ## + # @api private + # + # Read m3 profiles from the database + # + # @see config/metadata_profiles/m3_profile.yaml for an example configuration + class M3SchemaLoader < Hyrax::SchemaLoader + def view_definitions_for(schema:, version: 1, contexts: nil) + definitions(schema, version, contexts).each_with_object({}) do |definition, hash| + next if definition.view_options.empty? + + hash[definition.name] = definition.view_options + end + end + + private + + ## + # @param [#to_s] schema_name + # @return [Enumerable] a map from attribute names to + # types + def attributes_for(schema:, version: 1, contexts: nil) + definitions(schema, version, contexts).each_with_object({}) do |definition, hash| + hash[definition.name] = definition.type.meta(definition.config) + end + end + + ## + # @param [Symbol] schema + # + # @return [Hash{Symbol => Hash{Symbol => Object}}] + def form_definitions_for(schema:, version: 1, contexts: nil) + definitions(schema, version, contexts).each_with_object({}) do |definition, hash| + next if definition.form_options.empty? + + hash[definition.name] = definition.form_options + end + end + + ## + # @param [Symbol] schema + # + # @return [{Symbol => Symbol}] a map from index keys to attribute names + def index_rules_for(schema:, version: 1, contexts: nil) + definitions(schema, version, contexts).each_with_object({}) do |definition, hash| + definition.index_keys.each do |key| + hash[key] = definition.name + end + end + end + + ## + # @api private + class AttributeDefinition + ## + # @!attr_reader :config + # @return [Hash] + # @!attr_reader :name + # @return [#to_sym] + attr_reader :config, :name + + ## + # @param [#to_sym] name + # @param [Hash] config + def initialize(name, config) + @config = config + @name = name.to_sym + end + + ## + # @return [Hash{Symbol => Object}] + def form_options + config.fetch('form', {})&.symbolize_keys || {} + end + + ## + # @return [Enumerable] + def index_keys + config.fetch('index_keys', [])&.map(&:to_sym) || [] + end + + ## + # @return [Hash{Symbol => Object}] + def view_options + config.fetch('view', {})&.symbolize_keys || {} + end + + ## + # @return [Dry::Types::Type] + def type + collection_type = if config['multiple'] + Valkyrie::Types::Array.constructor { |v| Array(v).select(&:present?) } + else + Identity + end + collection_type.of(type_for(config['type'])) + end + + ## + # @api private + # + # This class acts as a Valkyrie/Dry::Types collection with typed members, + # but instead of wrapping the given type with itself as the collection type + # (as in `Valkyrie::Types::Array.of(MyType)`), it returns the given type. + # + # @example + # Identity.of(Valkyrie::Types::String) # => Valkyrie::Types::String + # + class Identity + ## + # @param [Dry::Types::Type] + # @return [Dry::Types::Type] the type passed in + def self.of(type) + type + end + end + + private + + ## + # Maps a configuration string value to a `Valkyrie::Type`. + # + # @param [String] + # @return [Dry::Types::Type] + def type_for(type) + case type + when 'id' + Valkyrie::Types::ID + when 'uri' + Valkyrie::Types::URI + when 'date_time' + Valkyrie::Types::DateTime + else + begin + "Valkyrie::Types::#{type.capitalize}".constantize + rescue NameError + raise ArgumentError, "Unrecognized type: #{type}" + end + end + end + end + + class UndefinedSchemaError < ArgumentError; end + + private + + def definitions(_schema_name, _version, _contexts) + raise NotImplementedError, 'Implement #definitions in a child class' + end + end +end diff --git a/app/services/hyrax/simple_schema_loader.rb b/app/services/hyrax/simple_schema_loader.rb index f87969e942..3841e3b2a1 100644 --- a/app/services/hyrax/simple_schema_loader.rb +++ b/app/services/hyrax/simple_schema_loader.rb @@ -7,39 +7,11 @@ module Hyrax # This is a simple yaml config-driven schema loader # # @see config/metadata/basic_metadata.yaml for an example configuration - class SimpleSchemaLoader - ## - # @param [Symbol] schema - # - # @return [Hash] a map from attribute names to - # types - def attributes_for(schema:) - definitions(schema).each_with_object({}) do |definition, hash| - hash[definition.name] = definition.type.meta(definition.config) - end - end - - ## - # @param [Symbol] schema - # - # @return [Hash{Symbol => Hash{Symbol => Object}}] - def form_definitions_for(schema:) - definitions(schema).each_with_object({}) do |definition, hash| - next if definition.form_options.empty? - - hash[definition.name] = definition.form_options - end - end - - ## - # @param [Symbol] schema - # - # @return [{Symbol => Symbol}] a map from index keys to attribute names - def index_rules_for(schema:) - definitions(schema).each_with_object({}) do |definition, hash| - definition.index_keys.each do |key| - hash[key] = definition.name - end + class SimpleSchemaLoader < Hyrax::SchemaLoader + def view_definitions_for(schema:, version: 1, contexts: nil) + schema.each_with_object({}) do |property, metadata| + view_options = property.meta['view'] + metadata[property.name.to_s] = view_options unless view_options.nil? end end @@ -49,95 +21,12 @@ def permissive_schema_for_valkrie_adapter end end - ## - # @api private - class AttributeDefinition - ## - # @!attr_reader :config - # @return [Hash] - # @!attr_reader :name - # @return [#to_sym] - attr_reader :config, :name - - ## - # @param [#to_sym] name - # @param [Hash] config - def initialize(name, config) - @config = config - @name = name.to_sym - end - - ## - # @return [Hash{Symbol => Object}] - def form_options - config.fetch('form', {}).symbolize_keys - end - - ## - # @return [Enumerable] - def index_keys - config.fetch('index_keys', []).map(&:to_sym) - end - - ## - # @return [Dry::Types::Type] - def type - collection_type = if config['multiple'] - Valkyrie::Types::Array.constructor { |v| Array(v).select(&:present?) } - else - Identity - end - collection_type.of(type_for(config['type'])) - end - - ## - # @api private - # - # This class acts as a Valkyrie/Dry::Types collection with typed members, - # but instead of wrapping the given type with itself as the collection type - # (as in `Valkyrie::Types::Array.of(MyType)`), it returns the given type. - # - # @example - # Identity.of(Valkyrie::Types::String) # => Valkyrie::Types::String - # - class Identity - ## - # @param [Dry::Types::Type] - # @return [Dry::Types::Type] the type passed in - def self.of(type) - type - end - end - - private - - ## - # Maps a configuration string value to a `Valkyrie::Type`. - # - # @param [String] - # @return [Dry::Types::Type] - def type_for(type) - case type - when 'id' - Valkyrie::Types::ID - when 'uri' - Valkyrie::Types::URI - when 'date_time' - Valkyrie::Types::DateTime - else - "Valkyrie::Types::#{type.capitalize}".constantize - end - end - end - - class UndefinedSchemaError < ArgumentError; end - private ## # @param [#to_s] schema_name # @return [Enumerable diff --git a/app/views/hyrax/admin/admin_sets/_form_metadata.html.erb b/app/views/hyrax/admin/admin_sets/_form_metadata.html.erb index e7be1dcff7..741dd9eb74 100644 --- a/app/views/hyrax/admin/admin_sets/_form_metadata.html.erb +++ b/app/views/hyrax/admin/admin_sets/_form_metadata.html.erb @@ -1,2 +1,5 @@ <%= f.input :title %> <%= f.input :description, as: :text %> +<% if Hyrax.config.flexible? && Hyrax.config.admin_set_class.new.respond_to?(:contexts) %> + <%= f.input :contexts, collection: Hyrax::FlexibleSchema.last.context_select, input_html: { multiple: true } %> +<% end %> diff --git a/app/views/hyrax/base/_attribute_rows.html.erb b/app/views/hyrax/base/_attribute_rows.html.erb index 557e1eaa2c..ba28733857 100644 --- a/app/views/hyrax/base/_attribute_rows.html.erb +++ b/app/views/hyrax/base/_attribute_rows.html.erb @@ -1,21 +1,3 @@ -<%= presenter.attribute_to_html(:alternative_title, html_dl: true) %> -<%= presenter.attribute_to_html(:abstract, html_dl: true) %> -<%= presenter.attribute_to_html(:date_modified, label: t('hyrax.base.show.last_modified'), html_dl: true) %> -<%= presenter.attribute_to_html(:creator, render_as: :faceted, html_dl: true) %> -<%= presenter.attribute_to_html(:contributor, render_as: :faceted, html_dl: true) %> -<%= presenter.attribute_to_html(:subject, render_as: :faceted, html_dl: true) %> -<%= presenter.attribute_to_html(:publisher, render_as: :faceted, html_dl: true) %> -<%= presenter.attribute_to_html(:bibliographic_citation, html_dl: true) %> -<%= presenter.attribute_to_html(:language, render_as: :faceted, html_dl: true) %> -<%= presenter.attribute_to_html(:identifier, render_as: :linked, search_field: 'identifier_tesim', html_dl: true) %> -<%= presenter.attribute_to_html(:keyword, render_as: :faceted, html_dl: true) %> -<%= presenter.attribute_to_html(:date_created, render_as: :linked, search_field: 'date_created_tesim', html_dl: true) %> -<%= presenter.attribute_to_html(:based_near_label, html_dl: true) %> -<%= presenter.attribute_to_html(:related_url, render_as: :external_link, html_dl: true) %> -<%= presenter.attribute_to_html(:resource_type, render_as: :faceted, html_dl: true) %> -<%= presenter.attribute_to_html(:source, html_dl: true) %> -<%= presenter.attribute_to_html(:extent, html_dl: true) %> -<%= presenter.attribute_to_html(:rights_statement, render_as: :rights_statement, html_dl: true) %> -<%= presenter.attribute_to_html(:rights_notes, html_dl: true) %> -<%= presenter.attribute_to_html(:access_right, html_dl: true) %> -<%= presenter.attribute_to_html(:license, render_as: :license, html_dl: true) %> +<% view_options_for(presenter).each do |field, options| %> + <%= presenter.attribute_to_html(conform_field(field, options), conform_options(field, options)) %> +<% end %> diff --git a/app/views/hyrax/collections/_default_group.html.erb b/app/views/hyrax/collections/_default_group.html.erb index 0350b9ef19..833bc0aa50 100644 --- a/app/views/hyrax/collections/_default_group.html.erb +++ b/app/views/hyrax/collections/_default_group.html.erb @@ -5,6 +5,9 @@ <%= render_check_all %> <%= t("hyrax.dashboard.my.heading.title") %> + <% if Hyrax.config.flexible? %> + <%= t("hyrax.dashboard.my.heading.profile_version") %> + <% end %> "><%= t("hyrax.dashboard.my.heading.date_uploaded") %> <%= t("hyrax.dashboard.my.heading.visibility") %> <%= t("hyrax.dashboard.my.heading.action") %> diff --git a/app/views/hyrax/collections/_list_collections.html.erb b/app/views/hyrax/collections/_list_collections.html.erb index e58d774ac0..bb27fcad65 100644 --- a/app/views/hyrax/collections/_list_collections.html.erb +++ b/app/views/hyrax/collections/_list_collections.html.erb @@ -18,6 +18,9 @@ + <% if Hyrax.config.flexible? %> + <%= collection_presenter.schema_version.to_f if collection_presenter.schema_version %> + <% end %> <%= collection_presenter.collection_type_badge %> diff --git a/app/views/hyrax/dashboard/collections/_default_group.html.erb b/app/views/hyrax/dashboard/collections/_default_group.html.erb index 570a793caa..0eb25fbd04 100644 --- a/app/views/hyrax/dashboard/collections/_default_group.html.erb +++ b/app/views/hyrax/dashboard/collections/_default_group.html.erb @@ -12,6 +12,9 @@ <%= t("hyrax.dashboard.my.heading.title") %> + <% if Hyrax.config.flexible? %> + <%= t("hyrax.dashboard.my.heading.profile_version") %> + <% end %> <% if !current_ability.admin? %> <%= t("hyrax.dashboard.my.heading.access") %> <% end %> diff --git a/app/views/hyrax/dashboard/collections/_list_collections.html.erb b/app/views/hyrax/dashboard/collections/_list_collections.html.erb index 0a413437dc..c91779a221 100644 --- a/app/views/hyrax/dashboard/collections/_list_collections.html.erb +++ b/app/views/hyrax/dashboard/collections/_list_collections.html.erb @@ -55,6 +55,9 @@ + <% if Hyrax.config.flexible? %> + <%= collection_presenter.schema_version.to_f if collection_presenter.schema_version %> + <% end %> <% if !current_ability.admin? %> <%= collection_presenter.managed_access %> <% end %> diff --git a/app/views/hyrax/dashboard/sidebar/_metadata.html.erb b/app/views/hyrax/dashboard/sidebar/_metadata.html.erb new file mode 100644 index 0000000000..5e44ea4ded --- /dev/null +++ b/app/views/hyrax/dashboard/sidebar/_metadata.html.erb @@ -0,0 +1,11 @@ +<%# menu item to be inserted when using flexible metadata %> +<% if current_ability.can? :manage, Hyrax::FlexibleSchema %> + +<% end %> \ No newline at end of file diff --git a/app/views/hyrax/dashboard/works/_default_group.html.erb b/app/views/hyrax/dashboard/works/_default_group.html.erb index c906616a53..b3c7b4fb90 100644 --- a/app/views/hyrax/dashboard/works/_default_group.html.erb +++ b/app/views/hyrax/dashboard/works/_default_group.html.erb @@ -5,6 +5,9 @@ <%= render_check_all %> <%= t("hyrax.dashboard.my.heading.title") %> + <% if Hyrax.config.flexible? %> + <%= t("hyrax.dashboard.my.heading.profile_version") %> + <% end %> <%= t("hyrax.dashboard.my.heading.date_modified") %> <%= t("blacklight.search.fields.facet.suppressed_bsi") %> <%= t("hyrax.dashboard.my.heading.work.visibility") %> diff --git a/app/views/hyrax/dashboard/works/_list_works.html.erb b/app/views/hyrax/dashboard/works/_list_works.html.erb index 8e4f804394..e71318fa46 100644 --- a/app/views/hyrax/dashboard/works/_list_works.html.erb +++ b/app/views/hyrax/dashboard/works/_list_works.html.erb @@ -30,6 +30,9 @@ + <% if Hyrax.config.flexible? %> + <%= document.schema_version.to_f if document.schema_version %> + <% end %> <%= document.date_modified %> <%= presenter.workflow.state_label %> <%= render_visibility_link document %> diff --git a/app/views/hyrax/file_sets/_form.html.erb b/app/views/hyrax/file_sets/_form.html.erb index 999890e8ac..fac8ccfd01 100644 --- a/app/views/hyrax/file_sets/_form.html.erb +++ b/app/views/hyrax/file_sets/_form.html.erb @@ -1,4 +1,5 @@ <%= simple_form_for [main_app, curation_concern], html: { multipart: true, class: 'nav-safety' } do |f| %> + <%= render('shared/schema_version', f: f) if Hyrax.config.flexible? %>
<%= label_tag 'file_set[title][]', t('.title'), class: "string optional" %> diff --git a/app/views/hyrax/metadata_profiles/_import_modal.html.erb b/app/views/hyrax/metadata_profiles/_import_modal.html.erb new file mode 100644 index 0000000000..da4561dfab --- /dev/null +++ b/app/views/hyrax/metadata_profiles/_import_modal.html.erb @@ -0,0 +1,20 @@ + diff --git a/app/views/hyrax/metadata_profiles/index.html.erb b/app/views/hyrax/metadata_profiles/index.html.erb new file mode 100644 index 0000000000..28f72ff7f7 --- /dev/null +++ b/app/views/hyrax/metadata_profiles/index.html.erb @@ -0,0 +1,54 @@ +<% provide :page_title, t(:'hyrax.dashboard.metadata_profiles') %> + +<% provide :page_header do %> +

<%= t(:'hyrax.admin.sidebar.metadata_profiles') %>

+
+ +
+<% end %> + +
+
+ <% if @metadata_profiles.present? %> +
+ + + + + + + + + + + + <% @metadata_profiles.order("updated_at DESC").each do |hyrax_metadata_profile| %> + + + + + + + + + + <% end %> + +
Schema VersionProfile VersionProfile TypeCreated AtActions
<%= hyrax_metadata_profile.schema_version %><%= hyrax_metadata_profile.id.to_f %><%= hyrax_metadata_profile.metadata_profile_type %><%= hyrax_metadata_profile.created_at.strftime("%b %d, %Y") %><%= link_to raw(''), hyrax.metadata_profile_export_path(hyrax_metadata_profile), target: "_blank" %>
+ + <%= page_entries_info @metadata_profiles %>
+ <%= paginate(@metadata_profiles, param_name: :metadata_profile_entries_page) %> + +
+ <% else %> +

No Metadata Schema Profiles have been created.

+ <% end %> +
+
+ + + +<%= render 'import_modal' %> diff --git a/app/views/hyrax/my/collections/_default_group.html.erb b/app/views/hyrax/my/collections/_default_group.html.erb index 3f18ec0369..de761bdbe6 100644 --- a/app/views/hyrax/my/collections/_default_group.html.erb +++ b/app/views/hyrax/my/collections/_default_group.html.erb @@ -4,6 +4,9 @@ <%= render_check_all %> <%= t("hyrax.dashboard.my.heading.title") %> + <% if Hyrax.config.flexible? %> + <%= t("hyrax.dashboard.my.heading.profile_version") %> + <% end %> <%= t("hyrax.dashboard.my.heading.type") %> <%= t("hyrax.dashboard.my.heading.last_modified") %> <%= t("hyrax.dashboard.my.heading.items") %> diff --git a/app/views/hyrax/my/collections/_list_collections.html.erb b/app/views/hyrax/my/collections/_list_collections.html.erb index c536ce248b..ce4f8ce2ae 100644 --- a/app/views/hyrax/my/collections/_list_collections.html.erb +++ b/app/views/hyrax/my/collections/_list_collections.html.erb @@ -57,6 +57,9 @@ + <% if Hyrax.config.flexible? %> + <%= collection_presenter.schema_version.to_f if collection_presenter.schema_version %> + <% end %> <%= collection_presenter.collection_type_badge %> diff --git a/app/views/hyrax/my/works/_default_group.html.erb b/app/views/hyrax/my/works/_default_group.html.erb index 09415527da..020b09d8b3 100644 --- a/app/views/hyrax/my/works/_default_group.html.erb +++ b/app/views/hyrax/my/works/_default_group.html.erb @@ -5,6 +5,9 @@ <%= render_check_all %> <%= t("hyrax.dashboard.my.heading.title") %> + <% if Hyrax.config.flexible? %> + <%= t("hyrax.dashboard.my.heading.profile_version") %> + <% end %> <%= t("hyrax.dashboard.my.heading.last_modified") %> <%= t("hyrax.dashboard.my.heading.highlighted") %> <%= t("hyrax.dashboard.my.heading.work.visibility") %> diff --git a/app/views/hyrax/my/works/_list_works.html.erb b/app/views/hyrax/my/works/_list_works.html.erb index f69d8edd9a..9de582d84b 100644 --- a/app/views/hyrax/my/works/_list_works.html.erb +++ b/app/views/hyrax/my/works/_list_works.html.erb @@ -10,7 +10,7 @@ <%= link_to [main_app, document], class: 'mr-2' do %> <%= document_presenter(document)&.thumbnail&.thumbnail_tag( { class: 'd-none d-md-block file_listing_thumbnail', alt: "#{document.title_or_label} #{t('hyrax.homepage.admin_sets.thumbnail')}" }, - { suppress_link: true } + { suppress_link: true } ) %> <% end %> @@ -27,6 +27,9 @@ + <% if Hyrax.config.flexible? %> + <%= document.schema_version.to_f if document.schema_version %> + <% end %> <%= document.date_modified %> diff --git a/app/views/records/edit_fields/_contexts.html.erb b/app/views/records/edit_fields/_contexts.html.erb new file mode 100644 index 0000000000..c55b1ea33f --- /dev/null +++ b/app/views/records/edit_fields/_contexts.html.erb @@ -0,0 +1 @@ +<%= f.input key, as: :hidden %> diff --git a/app/views/records/edit_fields/_schema_version.html.erb b/app/views/records/edit_fields/_schema_version.html.erb new file mode 100644 index 0000000000..b51622b589 --- /dev/null +++ b/app/views/records/edit_fields/_schema_version.html.erb @@ -0,0 +1 @@ +<%= render('shared/schema_version', f: f) if Hyrax.config.flexible? %> diff --git a/app/views/shared/_schema_version.html.erb b/app/views/shared/_schema_version.html.erb new file mode 100644 index 0000000000..c9ec753291 --- /dev/null +++ b/app/views/shared/_schema_version.html.erb @@ -0,0 +1,38 @@ +<% schema_version = SolrDocument.find(f.object.id).schema_version if action_name == 'edit' %> +<% schema_version = Hyrax::FlexibleSchema.current_schema_id if action_name == 'new' %> +<% updating = (schema_version.to_f < @latest_schema_version.to_f) ? 'updating' : '' %> + +
+ <% if schema_version.present? %> +
+ Created On Version +

<%= schema_version.to_f %>

+
+ <% end %> +
+ Version After Save +

<%= @latest_schema_version %>

+
+
+ + diff --git a/config/locales/hyrax.de.yml b/config/locales/hyrax.de.yml index 85ce7e1d53..65e001df8b 100644 --- a/config/locales/hyrax.de.yml +++ b/config/locales/hyrax.de.yml @@ -55,6 +55,11 @@ de: new: Neue Sammlung Hinzufügen delete: Löschen edit: Bearbeiten + hyrax_metadata_profile: + hint: Durch das Importieren eines neuen Profils wird das vorhandene Profil überschrieben + import: Metadatenprofil importieren + import_metadata_profile: Importprofil + submit: Importieren less: Weniger more: Mehr refresh: Aktualisierung @@ -94,6 +99,7 @@ de: note: Benutzern, denen eine neue Rolle zugewiesen wurde, können die damit verbundenen Rollenrechte nur auf jene Arbeiten übertragen, die nach der Gewährung dieser Rolle deponiert wurden. permission_destroy_errors: admin_group: Die Gruppe der Administratoren des Repositoriums kann nicht entfernt werden + participants: Das Löschen der Teilnehmerrechte des Verwaltungssets ist fehlgeschlagen. permission_update_errors: error: Ungültige Update-Option für Admin-Set-Vorlage. no_date: Für die gewählte Release-Option ist ein Datum erforderlich. @@ -410,6 +416,7 @@ de: content_blocks: Inhaltsblöcke dashboard: Dashboard delete_all: Alles löschen + metadata_profiles: Metadatenprofile notifications: Benachrichtigungen pages: Seiten profile: Profil @@ -473,9 +480,17 @@ de: workflows: index: header: Rückmeldung + heading: + depositor: Einzahler + status: Status + submission_date: Abgabetermin + work: Arbeiten tabs: published: Veröffentlicht under_review: Unter Begutachtung + works_listing: Werkverzeichnis + works_published: "%{total_count} Werke veröffentlicht" + works_under_review: "%{total_count} Werke werden überprüft" api: accepted: default: Ihre Anfrage wurde zur Bearbeitung angenommen, aber die Verarbeitung ist nicht abgeschlossen. Siehe Job für mehr Info. @@ -542,13 +557,7 @@ de: add_folder: Ordner hinzufügen cancel_upload: Upload abbrechen dropzone: Dateien hier hinziehen. - local_upload_browse_everything_html: | -

Sie können eine oder mehre Dateien von Ihrem lokalen System oder einem Cloudanbieter hinzufügen, welche mit - dieser Arbeit verknüpft werden sollen.

-

Bitte beachten Sie, dass der Cloud-Anbieter möglicherweise nicht in der Lage ist Ihrer Anfrage - nachzukommen, wenn Sie eine große Anzahl von Dateien innerhalb einer kurzen Zeitspanne hochladen. - Wenn Sie irgendwelche Fehler beim Hochladen aus der Cloud erhalten, teilen Sie uns dies bitte über %{contact_href} mit.

-

Das Hochladen ist auf %{upload_file_limit} Dateien mit jeweils %{upload_size_limit} MB begrenzt.

+ local_upload_browse_everything_html: "

Sie können eine oder mehre Dateien von Ihrem lokalen System oder einem Cloudanbieter hinzufügen, welche mit\ndieser Arbeit verknüpft werden sollen.

\n

Bitte beachten Sie, dass der Cloud-Anbieter möglicherweise nicht in der Lage ist Ihrer Anfrage \nnachzukommen, wenn Sie eine große Anzahl von Dateien innerhalb einer kurzen Zeitspanne hochladen. \nWenn Sie irgendwelche Fehler beim Hochladen aus der Cloud erhalten, teilen Sie uns dies bitte über %{contact_href} mit.

\n

Das Hochladen ist auf %{upload_file_limit} Dateien mit jeweils %{upload_size_limit} MB begrenzt.

\n" local_upload_html: |

Sie können eine oder mehrere Dateien hinzufügen, die dieser Arbeit zugeordnet werden sollen.

Das Hochladen ist auf %{upload_file_limit} Dateien mit jeweils %{upload_size_limit} MB begrenzt.

@@ -589,6 +598,11 @@ de: help_html: Wählen Sie die Datei mit den Medien aus, die diese Arbeit darstellen. legend_html: Repräsentative Medien form_share: + access_options: + creator: Schöpfer + depositor: Einzahler + manager: Manager + viewer: Zuschauer access_type_to_grant: Zu gewährende Zugriffsart account_label_without_suffix: "%{account_label} (ohne den Teil %{suffix})" add_sharing: Hinzufügen von individuellen Freigaben @@ -603,8 +617,8 @@ de: help_html: Wählen Sie die Datei aus, die als Miniaturansicht für diese Arbeit verwendet werden soll. legend_html: Miniaturansicht form_visibility_component: + subtitle_html: "Wer sollte diesen Inhalt anzeigen oder herunterladen können?" visibility: Sichtbarkeit - subtitle_html: Wer sollte diesen Inhalt anzeigen oder herunterladen können? inspect_work: back_to: Zurück zu entity_id: Mandanten-ID @@ -857,6 +871,7 @@ de: form: permission_update_errors: error: Ungültige Update-Option für die Berechtigungsvorlage + sharing: Die Freigabeoptionen der Sammlung konnten nicht aktualisiert werden. permission_update_notices: participants: Die Freigabeoptionen der Sammlung wurden aktualisiert. sharing: Die Freigabeoptionen der Sammlung wurden aktualisiert. @@ -1002,6 +1017,7 @@ de: managed: collections: Verwaltete Sammlungen works: Verwaltete Arbeiten + metadata_profiles: Metadatenprofile my: action: add_to_collection: Zur Sammlung hinzufügen @@ -1495,6 +1511,7 @@ de: owner: edit: Zugriff bearbeiten read: Lesen/Download + read_only: Das Repository befindet sich zur Wartung im Nur-Lese-Modus. Derzeit können keine Einsendungen oder Änderungen vorgenommen werden. search: button: html: Suchen @@ -1712,6 +1729,8 @@ de: note_html: Nur Benutzer und / oder Gruppen, denen im Abschnitt „Freigeben“ einen bestimmten Zugriff gewährt wurde. text: Privat restricted_title_attr: Ändern Sie die Sichtbarkeit dieser Ressource + unknown: + text: Unbekannt work_button_row: attach_child: Unterarbeit anhängen workflow: diff --git a/config/locales/hyrax.en.yml b/config/locales/hyrax.en.yml index 709b0118ab..51345033ef 100644 --- a/config/locales/hyrax.en.yml +++ b/config/locales/hyrax.en.yml @@ -53,6 +53,11 @@ en: delete: Delete edit: Edit less: Less + hyrax_metadata_profile: + hint: Importing a new profile will overwrite the existing profile + import: Import Metadata Profile + import_metadata_profile: Import Profile + submit: Import more: More refresh: Refresh remove: Remove @@ -398,6 +403,7 @@ en: content_blocks: Content Blocks dashboard: Dashboard delete_all: Delete All + metadata_profiles: Metadata Profiles notifications: Notifications pages: Pages profile: Profile @@ -1004,6 +1010,7 @@ en: managed: collections: Managed Collections works: Managed Works + metadata_profiles: Metadata Profiles my: action: add_to_collection: Add to collection diff --git a/config/locales/hyrax.es.yml b/config/locales/hyrax.es.yml index 9799833dc0..5a633a1054 100644 --- a/config/locales/hyrax.es.yml +++ b/config/locales/hyrax.es.yml @@ -55,6 +55,11 @@ es: new: Añadir Nueva Colección delete: Borrar edit: Editar + hyrax_metadata_profile: + hint: Importar un nuevo perfil sobrescribirá el perfil existente + import: Importar perfil de metadatos + import_metadata_profile: Importar perfil + submit: Importar less: Menos more: Más refresh: Refrescar @@ -94,6 +99,7 @@ es: note: Los usuarios a los que se les otorgue un nuevo rol solo obtendrán el rol en los trabajos que se depositen después de que se haya otorgado ese rol. permission_destroy_errors: admin_group: No se puede eliminar el grupo de administradores del repositorio + participants: No se pudieron eliminar los derechos de participante del conjunto administrativo. permission_update_errors: error: Opción de actualización no válida para la plantilla de permiso. no_date: Se requiere una fecha para la opción de lanzamiento seleccionada. @@ -410,6 +416,7 @@ es: content_blocks: Bloques de Contenido dashboard: Tablero delete_all: Eliminar todos + metadata_profiles: Perfiles de metadatos notifications: Notificaciones pages: Páginas profile: Perfil @@ -473,9 +480,17 @@ es: workflows: index: header: Revise Envíos + heading: + depositor: Depositor + status: estado + submission_date: Día de entrega + work: Trabajar tabs: published: Publicados under_review: En Revisión + works_listing: Listado de obras + works_published: "%{total_count} obras publicadas" + works_under_review: "%{total_count} funciona en revisión" api: accepted: default: Su solicitud se ha aceptado para su procesamiento, pero el procesamiento no está completo. Ver tarea para más información. @@ -589,6 +604,11 @@ es: help_html: Seleccione el archivo con los medios que representa este trabajo. legend_html: Medios representativos form_share: + access_options: + creator: Creador + depositor: Depositor + manager: Gerente + viewer: Espectador access_type_to_grant: Tipo de acceso a otorgar account_label_without_suffix: "%{account_label} (sin la parte %{suffix})" add_sharing: Agregar Compartir @@ -603,8 +623,8 @@ es: help_html: Seleccione el archivo que se utilizará como miniatura para este trabajo. legend_html: Miniatura form_visibility_component: + subtitle_html: "¿Quién debería poder ver o descargar este contenido?" visibility: La visibilidad - subtitle_html: ¿Quién debería poder ver o descargar este contenido? inspect_work: back_to: De regreso entity_id: ID de entidad @@ -857,6 +877,7 @@ es: form: permission_update_errors: error: La opción de actualización no válida para la plantilla de permisos. + sharing: Las opciones para compartir de la colección no se pudieron actualizar. permission_update_notices: participants: Las opciones de uso compartido de la colección se han actualizado. sharing: Las opciones de uso compartido de la colección se han actualizado. @@ -909,7 +930,7 @@ es: creator: Creador depositor: Depositor manager: Gerente - viewer: Espectador + viewer: Espectador add_group: Añadir grupo add_sharing: Agregar Compartir add_user: Agregar usuario @@ -1002,6 +1023,7 @@ es: managed: collections: Colecciones administradas works: Trabajos administrados + metadata_profiles: Perfiles de metadatos my: action: add_to_collection: Añadir a la colección @@ -1497,6 +1519,7 @@ es: owner: edit: Editar acceso read: Ver descarga + read_only: El repositorio está en modo de solo lectura para mantenimiento. No se pueden realizar envíos ni modificaciones en este momento. search: button: html: Ir @@ -1714,6 +1737,8 @@ es: note_html: Sólo los usuarios y / o grupos a los que se les ha dado acceso específico en la sección "Compartir con". text: Privado restricted_title_attr: Cambiar la visibilidad de este recurso + unknown: + text: Desconocido work_button_row: attach_child: Adjuntar niño workflow: diff --git a/config/locales/hyrax.fr.yml b/config/locales/hyrax.fr.yml index 43341a938a..b87619cee5 100644 --- a/config/locales/hyrax.fr.yml +++ b/config/locales/hyrax.fr.yml @@ -55,6 +55,11 @@ fr: new: Ajouter une nouvelle collection delete: Effacer edit: modifier + hyrax_metadata_profile: + hint: L'importation d'un nouveau profil écrasera le profil existant + import: Importer un profil de métadonnées + import_metadata_profile: Profil d'importation + submit: Importer less: Moins more: Plus refresh: Rafraîchir @@ -94,6 +99,7 @@ fr: note: Les utilisateurs auxquels un nouveau rôle est attribué n'acquièrent un rôle que sur les œuvres déposées après l'attribution de ce rôle. permission_destroy_errors: admin_group: Le groupe des administrateurs du référentiel ne peut pas être supprimé + participants: Les droits de participant de l'ensemble d'administration n'ont pas pu être supprimés. permission_update_errors: error: Option de mise à jour non valide pour le modèle d'autorisation. no_date: Une date est requise pour l'option de publication sélectionnée. @@ -410,6 +416,7 @@ fr: content_blocks: Blocs de contenu dashboard: Tableau de bord delete_all: Supprimer tout + metadata_profiles: Profils de métadonnées notifications: Notifications pages: Pages profile: Profil @@ -473,9 +480,17 @@ fr: workflows: index: header: Soumissions de révision + heading: + depositor: Déposant + status: statut + submission_date: Date de soumission + work: Travail tabs: published: Publié under_review: À l'étude + works_listing: Liste des travaux + works_published: "%{total_count} œuvres publiées" + works_under_review: "%{total_count} travaux en cours d'examen" api: accepted: default: Votre demande a été acceptée pour traitement, mais le traitement n'est pas complet. Consultez le travail pour plus d'informations. @@ -590,6 +605,11 @@ fr: help_html: Sélectionnez le fichier avec le média qui représente ce travail. legend_html: Médias représentatifs form_share: + access_options: + creator: Créateur + depositor: Déposant + manager: Directeur + viewer: Téléspectateur access_type_to_grant: Type d'accès à accorder account_label_without_suffix: "%{account_label} (sans la partie %{suffix})" add_sharing: Ajouter un partage @@ -604,8 +624,8 @@ fr: help_html: Sélectionnez le fichier à utiliser comme vignette pour ce travail. legend_html: La vignette form_visibility_component: + subtitle_html: "Qui devrait être en mesure d’afficher ou de télécharger ce contenu?" visibility: Visibilité - subtitle_html: Qui devrait être en mesure d’afficher ou de télécharger ce contenu? inspect_work: back_to: Retour à entity_id: ID d'entité @@ -858,6 +878,7 @@ fr: form: permission_update_errors: error: Option de mise à jour non valide pour le modèle d'autorisation. + sharing: Les options de partage de la collection n'ont pas pu être mises à jour. permission_update_notices: participants: Les options de partage de la collection ont été mises à jour. sharing: Les options de partage de la collection ont été mises à jour. @@ -1003,6 +1024,7 @@ fr: managed: collections: Collections gérées works: Travaux gérés + metadata_profiles: Profils de métadonnées my: action: add_to_collection: Ajouter à la collection @@ -1496,6 +1518,7 @@ fr: owner: edit: Modifier l'accès read: Voir le téléchargement + read_only: Le référentiel est en mode lecture seule pour la maintenance. Aucune soumission ou modification ne peut être effectuée pour le moment. search: button: html: Aller @@ -1713,6 +1736,8 @@ fr: note_html: Seuls les utilisateurs et / ou les groupes ayant reçu un accès spécifique dans la section "Partager avec". text: Privé restricted_title_attr: Modifier la visibilité de cette ressource + unknown: + text: Inconnu work_button_row: attach_child: Attacher l'enfant workflow: diff --git a/config/locales/hyrax.it.yml b/config/locales/hyrax.it.yml index e6bb985c23..30737946bb 100644 --- a/config/locales/hyrax.it.yml +++ b/config/locales/hyrax.it.yml @@ -55,6 +55,11 @@ it: new: Aggiungi nuova collezione delete: Elimina edit: Modifica + hyrax_metadata_profile: + hint: L'importazione di un nuovo profilo sovrascriverà il profilo esistente + import: Importa profilo metadati + import_metadata_profile: Importa profilo + submit: Importare less: Di meno more: Di Più refresh: ricaricare @@ -94,6 +99,7 @@ it: note: Gli utenti che hanno assegnato un nuovo ruolo avranno solo il ruolo di opere che vengono depositate dopo che tale ruolo è stato concesso. permission_destroy_errors: admin_group: Impossibile rimuovere il gruppo amministratori di repository + participants: Impossibile eliminare i diritti del partecipante del set amministrativo. permission_update_errors: error: Opzione di aggiornamento non valida per il modello di autorizzazione. no_date: È necessaria una data per l'opzione di rilascio selezionata. @@ -410,6 +416,7 @@ it: content_blocks: Blocchi di contenuti dashboard: Pannello di controllo delete_all: Cancella tutto + metadata_profiles: Profili di metadati notifications: notifiche pages: pagine profile: Profilo @@ -473,9 +480,17 @@ it: workflows: index: header: Revisione degli inviti + heading: + depositor: Depositante + status: stato + submission_date: Data di presentazione + work: Lavoro tabs: published: Pubblicato under_review: In corso di revisione + works_listing: Elenco delle opere + works_published: "%{total_count} lavori pubblicati" + works_under_review: "%{total_count} lavori in fase di revisione" api: accepted: default: La tua richiesta è stata accettata per l'elaborazione, ma l'elaborazione non è completa. Vedere il lavoro per ulteriori informazioni. @@ -589,6 +604,11 @@ it: help_html: Seleziona il file con il supporto che rappresenta questo lavoro. legend_html: Media rappresentativo form_share: + access_options: + creator: Creatore + depositor: Depositante + manager: Manager + viewer: Spettatore access_type_to_grant: Tipo di accesso da concedere account_label_without_suffix: "%{account_label} (senza la parte %{suffix})" add_sharing: Aggiungi condivisione @@ -603,8 +623,8 @@ it: help_html: Seleziona il file da utilizzare come anteprima per questo lavoro. legend_html: Thumbnail form_visibility_component: + subtitle_html: "Chi dovrebbe essere in grado di visualizzare o scaricare questo contenuto?" visibility: Visibilità - subtitle_html: Chi dovrebbe essere in grado di visualizzare o scaricare questo contenuto? inspect_work: back_to: Torna a entity_id: ID entità @@ -857,6 +877,7 @@ it: form: permission_update_errors: error: Opzione di aggiornamento non valida per modello di autorizzazione. + sharing: Impossibile aggiornare le opzioni di condivisione della raccolta. permission_update_notices: participants: Le opzioni di condivisione della raccolta sono state aggiornate. sharing: Le opzioni di condivisione della raccolta sono state aggiornate. @@ -909,7 +930,7 @@ it: creator: Creatore depositor: Depositante manager: Gestore - viewer: Spettatore + viewer: Spettatore add_group: Aggiungere gruppo add_sharing: Aggiungi condivisione add_user: Aggiungi utente @@ -1002,6 +1023,7 @@ it: managed: collections: Collezioni gestite works: Lavori gestiti + metadata_profiles: Profili di metadati my: action: add_to_collection: Aggiungere alla collezione @@ -1495,6 +1517,7 @@ it: owner: edit: Accesso in modifica read: Visualizza / Scarica + read_only: Il repository è in modalità di sola lettura per manutenzione. Al momento non è possibile effettuare invii o modifiche. search: button: html: Partire @@ -1712,6 +1735,8 @@ it: note_html: Solo utenti e / o gruppi che hanno ricevuto l'accesso specifico nella sezione "Condividi con". text: Privato restricted_title_attr: Cambiare la visibilità di questa risorsa + unknown: + text: Sconosciuto work_button_row: attach_child: Allega bambino workflow: diff --git a/config/locales/hyrax.pt-BR.yml b/config/locales/hyrax.pt-BR.yml index abc297c192..043dd71723 100644 --- a/config/locales/hyrax.pt-BR.yml +++ b/config/locales/hyrax.pt-BR.yml @@ -55,6 +55,11 @@ pt-BR: new: Nova coleção delete: Excluir edit: Editar + hyrax_metadata_profile: + hint: A importação de um novo perfil substituirá o perfil existente + import: Importar perfil de metadados + import_metadata_profile: Perfil de importação + submit: Importar less: Menos more: Mais refresh: Atualizar @@ -94,6 +99,7 @@ pt-BR: note: Os usuários que receberam uma nova função só terão a função nas obras que são depositadas depois da concessão da função. permission_destroy_errors: admin_group: O grupo de administradores do repositório não pode ser removido + participants: Os direitos de participante do conjunto administrativo não foram excluídos. permission_update_errors: error: Opção de atualização inválida para o modelo de permissão. no_date: É necessária uma data para a opção de divulgação selecionada. @@ -410,6 +416,7 @@ pt-BR: content_blocks: Blocos de Conteúdo dashboard: Painel delete_all: Excluir tudo + metadata_profiles: Perfis de metadados notifications: Notificações pages: Páginas profile: Perfil @@ -473,9 +480,17 @@ pt-BR: workflows: index: header: Rever Submissões + heading: + depositor: Depositante + status: status + submission_date: Data de submissão + work: Trabalhar tabs: published: Publicados under_review: Sob revisão + works_listing: Listagem de obras + works_published: "%{total_count} trabalhos publicados" + works_under_review: "%{total_count} funciona em revisão" api: accepted: default: Seu pedido foi aceito para processamento, mas o processamento ainda não acabou. Veja o processo para mais informações. @@ -542,12 +557,7 @@ pt-BR: add_folder: Adicionar pasta cancel_upload: Cancelar upload dropzone: Largue os arquivos aqui. - local_upload_browse_everything_html: | -

Você pode associar um ou mais arquivos a esta obra. Associe arquivos de seu sistema local ou um provedor de nuvem.

-

Note que se você carregar uma grande quantidade de arquivos dentro de um curto período de tempo, - o fornecedor de nuvem pode não ser capaz de acomodar a sua solicitação. Se você tiver algum erro ao carregar - da nuvem, avise-nos através do %{contact_href}.

-

Os uploads são limitados a %{upload_file_limit} arquivos, %{upload_size_limit} MB cada.

+ local_upload_browse_everything_html: "

Você pode associar um ou mais arquivos a esta obra. Associe arquivos de seu sistema local ou um provedor de nuvem.

\n

Note que se você carregar uma grande quantidade de arquivos dentro de um curto período de tempo, \no fornecedor de nuvem pode não ser capaz de acomodar a sua solicitação. Se você tiver algum erro ao carregar \nda nuvem, avise-nos através do %{contact_href}.

\n

Os uploads são limitados a %{upload_file_limit} arquivos, %{upload_size_limit} MB cada.

\n" local_upload_html: |

Você pode acrescentar um ou mais arquivos para associar a esta obra.

Os uploads são limitados a %{upload_file_limit} arquivos, %{upload_size_limit} MB cada.

@@ -588,6 +598,11 @@ pt-BR: help_html: Selecione o arquivo com a mídia que representa esta obra. legend_html: Mídia representativa form_share: + access_options: + creator: O Criador + depositor: Depositante + manager: Gerente + viewer: Visualizador access_type_to_grant: Tipo de acesso a conceder account_label_without_suffix: "%{account_label} (sem a parte %{suffix})" add_sharing: Acrescentar compartilhamento @@ -602,8 +617,8 @@ pt-BR: help_html: Selecione o arquivo a ser usado como miniatura para esta obra. legend_html: Miniatura form_visibility_component: + subtitle_html: "Quem deve conseguir visualizar ou baixar este conteúdo?" visibility: Visibilidade - subtitle_html: Quem deve conseguir visualizar ou baixar este conteúdo? inspect_work: back_to: De volta a entity_id: ID da entidade @@ -856,6 +871,7 @@ pt-BR: form: permission_update_errors: error: Opção de atualização inválida para o modelo de permissão. + sharing: As opções de compartilhamento da coleção não foram atualizadas. permission_update_notices: participants: As opções de compartilhamento da coleção foram atualizadas. sharing: As opções de compartilhamento da coleção foram atualizadas. @@ -908,7 +924,7 @@ pt-BR: creator: O Criador depositor: Depositante manager: Gerente - viewer: Visualizador + viewer: Visualizador add_group: Acrescentar Grupo add_sharing: Acrescentar Compartilhamento add_user: Acrescentar Usuário @@ -1001,6 +1017,7 @@ pt-BR: managed: collections: Coleções Curateladas works: Obras Curateladas + metadata_profiles: Perfis de metadados my: action: add_to_collection: Acrescentar à coleção @@ -1494,6 +1511,7 @@ pt-BR: owner: edit: Editar acesso read: Visualizar download + read_only: O repositório está em modo somente leitura para manutenção. Nenhum envio ou edição pode ser feito neste momento. search: button: html: Ir @@ -1711,6 +1729,8 @@ pt-BR: note_html: Manter privado com a opção de compartilhar. text: Privado restricted_title_attr: Altere a permissão de acesso deste recurso + unknown: + text: Desconhecido work_button_row: attach_child: Anexar criança workflow: diff --git a/config/locales/hyrax.zh.yml b/config/locales/hyrax.zh.yml index 7ce7ce25fb..172454b638 100644 --- a/config/locales/hyrax.zh.yml +++ b/config/locales/hyrax.zh.yml @@ -55,6 +55,11 @@ zh: new: 添加新集合 delete: 删除 edit: 编辑 + hyrax_metadata_profile: + hint: 导入新配置文件将覆盖现有配置文件 + import: 导入元数据配置文件 + import_metadata_profile: 导入配置文件 + submit: 进口 less: 减 more: 更多 refresh: 刷新 @@ -94,6 +99,7 @@ zh: note: 授予新角色的用户只能在授予该角色后存储的作品获得角色。 permission_destroy_errors: admin_group: 无法删除存储库管理员组 + participants: 管理集的参与者权限删除失败。 permission_update_errors: error: 权限模板的更新选项无效。 no_date: 所选发布项需要一个日期。 @@ -410,6 +416,7 @@ zh: content_blocks: 内容块 dashboard: 仪表盘 delete_all: 删除所有 + metadata_profiles: 元数据配置文件 notifications: 通知 pages: 网页 profile: 个人资料 @@ -473,9 +480,17 @@ zh: workflows: index: header: 审查提交 + heading: + depositor: 储户 + status: 地位 + submission_date: 提交日期 + work: 工作 tabs: published: 已出版 under_review: 在审查中 + works_listing: 作品列表 + works_published: 已发布%{total_count} 部作品 + works_under_review: "%{total_count} 作品正在审核中" api: accepted: default: 您的请求已被接受,还在处理中,详细信息请见后台作业。 @@ -587,6 +602,11 @@ zh: help_html: 选择代表这项工作的媒体文件。 legend_html: 代表媒体 form_share: + access_options: + creator: 创建者 + depositor: 储户 + manager: 经理 + viewer: 查看器 access_type_to_grant: 要授予的访问类型 account_label_without_suffix: "%{account_label}(没有%{suffix}部分)" add_sharing: 添加共享 @@ -601,8 +621,8 @@ zh: help_html: 选择要用作此作品缩略图的文件。 legend_html: 缩略图 form_visibility_component: + subtitle_html: "谁应该能够查看或下载此内容?" visibility: 可见性 - subtitle_html: 谁应该能够查看或下载此内容? inspect_work: back_to: 回到 entity_id: 实体ID @@ -855,6 +875,7 @@ zh: form: permission_update_errors: error: 无效的权限模板更新选项。 + sharing: 该收藏集的共享选项更新失败。 permission_update_notices: participants: 收藏的分享选项已更新。 sharing: 收藏的分享选项已更新。 @@ -1000,6 +1021,7 @@ zh: managed: collections: 管理集合 works: 托管作品 + metadata_profiles: 元数据配置文件 my: action: add_to_collection: 添加到收藏 @@ -1493,6 +1515,7 @@ zh: owner: edit: 编辑权限 read: 查看/下载 + read_only: 由于维护原因,存储库处于只读模式。目前无法进行任何提交或编辑。 search: button: html: 转到 @@ -1710,6 +1733,8 @@ zh: note_html: 非公开保留分享权限。 text: 非公开 restricted_title_attr: 更改此资源的公开度 + unknown: + text: 未知 work_button_row: attach_child: 附上孩子 workflow: diff --git a/config/metadata/basic_metadata.yaml b/config/metadata/basic_metadata.yaml index ab355e5e0c..0c15953f3a 100644 --- a/config/metadata/basic_metadata.yaml +++ b/config/metadata/basic_metadata.yaml @@ -9,6 +9,8 @@ attributes: - "abstract_sim" - "abstract_tesim" predicate: http://purl.org/dc/terms/abstract + view: + html_dl: true access_right: type: string multiple: true @@ -18,6 +20,8 @@ attributes: - "access_right_sim" - "access_right_tesim" predicate: http://purl.org/dc/terms/accessRights + view: + html_dl: true alternative_title: type: string multiple: true @@ -27,6 +31,8 @@ attributes: - "alternative_title_sim" - "alternative_title_tesim" predicate: http://purl.org/dc/terms/alternative + view: + html_dl: true arkivo_checksum: type: string multiple: false @@ -42,6 +48,9 @@ attributes: - "based_near_sim" - "based_near_tesim" predicate: http://xmlns.com/foaf/0.1/based_near + view: + render_term: 'based_near_label' + html_dl: true bibliographic_citation: type: string multiple: true @@ -51,6 +60,8 @@ attributes: - "bibliographic_citation_sim" - "bibliographic_citation_tesim" predicate: http://purl.org/dc/terms/bibliographicCitation + view: + html_dl: true contributor: type: string multiple: true @@ -60,6 +71,9 @@ attributes: - "contributor_tesim" - "contributor_sim" predicate: http://purl.org/dc/elements/1.1/contributor + view: + render_as: "faceted" + html_dl: true creator: type: string multiple: true @@ -70,6 +84,9 @@ attributes: - "creator_sim" - "creator_tesim" predicate: http://purl.org/dc/elements/1.1/creator + view: + render_as: "faceted" + html_dl: true date_created: type: date_time multiple: true @@ -79,6 +96,23 @@ attributes: - "date_created_sim" - "date_created_tesim" predicate: http://purl.org/dc/terms/created + view: + render_as: "linked" + search_field: 'date_created_tesim' + html_dl: true + date_modified: + type: date_time + predicate: http://purl.org/dc/terms/modified + view: + label: + de: 'Zuletzt geändert' + en: 'Last modified' + es: 'Última modificación' + fr: 'Dernière modification' + it: 'Ultima modifica' + pt-BR: 'Última modificação' + zh: '最新修改' + html_dl: true description: type: string multiple: true @@ -97,6 +131,10 @@ attributes: - "identifier_sim" - "identifier_tesim" predicate: http://purl.org/dc/terms/identifier + view: + render_as: "linked" + search_field: 'identifier_tesim' + html_dl: true import_url: type: string predicate: http://scholarsphere.psu.edu/ns#importUrl @@ -109,6 +147,9 @@ attributes: form: primary: false predicate: http://schema.org/keywords + view: + render_as: "faceted" + html_dl: true publisher: type: string multiple: true @@ -118,6 +159,9 @@ attributes: - "publisher_sim" - "publisher_tesim" predicate: http://purl.org/dc/elements/1.1/publisher + view: + render_as: "faceted" + html_dl: true label: type: string form: @@ -135,6 +179,9 @@ attributes: - "language_sim" - "language_tesim" predicate: http://purl.org/dc/elements/1.1/language + view: + render_as: "faceted" + html_dl: true license: type: string multiple: true @@ -144,6 +191,9 @@ attributes: - "license_sim" - "license_tesim" predicate: http://purl.org/dc/terms/license + view: + render_as: "license" + html_dl: true relative_path: type: string predicate: http://scholarsphere.psu.edu/ns#relativePath @@ -156,6 +206,9 @@ attributes: - "related_url_sim" - "related_url_tesim" predicate: http://www.w3.org/2000/01/rdf-schema#seeAlso + view: + render_as: "external_link" + html_dl: true resource_type: type: string multiple: true @@ -165,6 +218,9 @@ attributes: - "resource_type_sim" - "resource_type_tesim" predicate: http://purl.org/dc/terms/type + view: + render_as: "faceted" + html_dl: true rights_notes: type: string multiple: true @@ -174,6 +230,8 @@ attributes: - "rights_notes_sim" - "rights_notes_tesim" predicate: http://purl.org/dc/elements/1.1/rights + view: + html_dl: true rights_statement: type: string multiple: true @@ -182,6 +240,9 @@ attributes: index_keys: - "rights_statement_sim" - "rights_statement_tesim" + view: + html_dl: true + render_as: "rights_statement" predicate: http://www.europeana.eu/schemas/edm/rights source: type: string @@ -192,6 +253,8 @@ attributes: - "source_sim" - "source_tesim" predicate: http://purl.org/dc/terms/source + view: + html_dl: true subject: type: string multiple: true @@ -201,3 +264,6 @@ attributes: form: primary: false predicate: http://purl.org/dc/elements/1.1/subject + view: + render_as: "faceted" + html_dl: true diff --git a/config/metadata_profiles/m3_profile.yaml b/config/metadata_profiles/m3_profile.yaml new file mode 100644 index 0000000000..3599c4dd39 --- /dev/null +++ b/config/metadata_profiles/m3_profile.yaml @@ -0,0 +1,836 @@ +--- +m3_version: 1.0.beta2 +profile: + date_modified: '2024-06-01' + responsibility: https://samvera.org + responsibility_statement: Hyrax Initial Profile + type: Initial Profile + version: 1 +classes: + Hyrax::Work: + display_label: Work + Hyrax::AdministrativeSet: + diplay_label: AdministrativeSet + Hyrax::PcdmCollection: + display_label: PcdmCollection + Hyrax::FileSet: + display_label: FileSet +contexts: + flexible_context: + display_label: Flexible Metadata Example + special_context: + display_label: Special Case Context +mappings: + blacklight: + name: Additional Blacklight Solr Mappings + metatags: + name: Metatags + mods_oai_pmh: + name: MODS OAI PMH + qualified_dc_pmh: + name: Qualified DC OAI PMH + simple_dc_pmh: + name: Simple DC OAI PMH +properties: + title: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 1 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + definition: + default: Enter a standardized title for display. If only one title is needed, + transcribe the title from the source itself. + display_label: + default: Title + index_documentation: displayable, searchable + indexing: + - title_sim + - title_tesim + form: + required: true + primary: true + multi_value: true + mappings: + metatags: twitter:title, og:title + mods_oai_pmh: mods:titleInfo/mods:title + qualified_dc_pmh: dcterms:title + simple_dc_pmh: dc:title + property_uri: http://purl.org/dc/terms/title + range: http://www.w3.org/2001/XMLSchema#string + requirement: required + sample_values: + - Pencil drawn portrait study of woman + date_modified: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + display_label: + default: Date Modified + property_uri: http://purl.org/dc/terms/modified + range: http://www.w3.org/2001/XMLSchema#dateTime + sample_values: + - '2024-06-06 21:06:51 +0000' + view: + label: + de: 'Zuletzt geändert' + en: 'Last modified' + es: 'Última modificación' + fr: 'Dernière modification' + it: 'Ultima modifica' + pt-BR: 'Última modificação' + zh: '最新修改' + html_dl: true + date_uploaded: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + display_label: + default: Date Uploaded + property_uri: http://purl.org/dc/terms/dateSubmitted + range: http://www.w3.org/2001/XMLSchema#dateTime + sample_values: + - '2024-06-06 21:06:51 +0000' + depositor: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Depositor + index_documentation: searchable + indexing: + - depositor_tesim + property_uri: http://id.loc.gov/vocabulary/relators/dpt + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Julie Allinson + creator: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 1 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Creator + index_documentation: displayable, searchable + indexing: + - creator_sim + - creator_tesim + form: + required: true + primary: true + property_uri: http://purl.org/dc/elements/1.1/creator + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Julie Allinson + view: + render_as: "faceted" + html_dl: true + license: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: License + index_documentation: displayable, searchable + indexing: + - license_sim + - license_tesim + form: + required: false + primary: false + property_uri: http://purl.org/dc/terms/license + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - http://creativecommons.org/licenses/by/3.0/us/ + view: + render_as: "external_link" + html_dl: true + abstract: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Abstract + index_documentation: displayable, searchable + indexing: + - abstract_sim + - abstract_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/abstract + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - This is an abstract. + view: + html_dl: true + access_right: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Access Right + index_documentation: displayable, searchable + indexing: + - access_right_sim + - access_right_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/accessRights + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Open Access + view: + html_dl: true + alternative_title: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Alternative Title + index_documentation: displayable, searchable + indexing: + - alternative_title_sim + - alternative_title_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/alternative + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Alternate Title Example + view: + label: + en: 'Alternative Title' + es: 'Título Alternativo' + html_dl: true + arkivo_checksum: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Arkivo Checksum + form: + primary: false + property_uri: http://scholarsphere.psu.edu/ns#arkivoChecksum + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - c0855931b7f1aefedb91d31af76873c0 + based_near: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Location + index_documentation: displayable, searchable + indexing: + - based_near_sim + - based_near_tesim + form: + primary: false + property_uri: http://xmlns.com/foaf/0.1/based_near + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - San Diego, California, United States + view: + label: Based Near + render_term: 'based_near_label_tesim' + html_dl: true + bibliographic_citation: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Bibliographic Citation + index_documentation: displayable, searchable + indexing: + - bibliographic_citation_sim + - bibliographic_citation_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/bibliographicCitation + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Doe, J. (2024). Example Citation. Journal of Examples, 12(3), 45-67. + view: + html_dl: true + contributor: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Contributor + index_documentation: displayable, searchable + indexing: + - contributor_tesim + - contributor_sim + form: + primary: false + property_uri: http://purl.org/dc/elements/1.1/contributor + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Julie Allinson + view: + render_as: "faceted" + html_dl: true + date_created: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#dateTime + sources: + - 'null' + display_label: + default: Date Created + index_documentation: displayable, searchable + indexing: + - date_created_sim + - date_created_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/created + range: http://www.w3.org/2001/XMLSchema#dateTime + sample_values: + - '2024-06-06 21:06:51 +0000' + view: + render_as: "linked" + search_field: 'date_created_tesim' + html_dl: true + description: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Description + index_documentation: displayable, searchable + indexing: + - description_sim + - description_tesim + form: + primary: false + property_uri: http://purl.org/dc/elements/1.1/description + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - This is a description. + identifier: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Identifier + index_documentation: displayable, searchable + indexing: + - identifier_sim + - identifier_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/identifier + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - abc123 + view: + render_as: "linked" + search_field: 'identifier_tesim' + html_dl: true + import_url: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Import URL + property_uri: http://scholarsphere.psu.edu/ns#importUrl + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - http://example.com/resource1 + keyword: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Keyword + index_documentation: displayable, searchable + indexing: + - keyword_sim + - keyword_tesim + form: + primary: false + property_uri: http://schema.org/keywords + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Metadata + - Repository + view: + render_as: "faceted" + html_dl: true + label: + available_on: + class: + - Hyrax::FileSet + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Label + index_documentation: displayable, searchable + indexing: + - label_sim + - label_tesim + form: + primary: false + property_uri: info:fedora/fedora-system:def/model#downloadFilename + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - file_label.txt + language: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Language + index_documentation: displayable, searchable + indexing: + - language_sim + - language_tesim + form: + primary: false + property_uri: http://purl.org/dc/elements/1.1/language + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - English + - Spanish + view: + render_as: "faceted" + html_dl: true + publisher: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Publisher + index_documentation: displayable, searchable + indexing: + - publisher_sim + - publisher_tesim + form: + primary: false + property_uri: http://purl.org/dc/elements/1.1/publisher + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Scholastic + view: + render_as: "faceted" + html_dl: true + related_url: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Related URL + index_documentation: displayable, searchable + indexing: + - related_url_sim + - related_url_tesim + form: + primary: false + property_uri: http://www.w3.org/2000/01/rdf-schema#seeAlso + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - http://example.com/resource1 + view: + render_as: "external_link" + html_dl: true + relative_path: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Relative Path + property_uri: http://scholarsphere.psu.edu/ns#relativePath + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - '/path/to/resource' + resource_type: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Resource Type + index_documentation: displayable, searchable + indexing: + - resource_type_sim + - resource_type_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/type + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Article + - Conference Proceeding + view: + render_as: "faceted" + html_dl: true + rights_notes: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Rights Notes + index_documentation: displayable, searchable + indexing: + - rights_notes_sim + - rights_notes_tesim + form: + primary: false + property_uri: http://purl.org/dc/elements/1.1/rights + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Creative Commons license. + view: + html_dl: true + rights_statement: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Rights Statement + index_documentation: displayable, searchable + indexing: + - rights_statement_sim + - rights_statement_tesim + form: + primary: true + property_uri: http://www.europeana.eu/schemas/edm/rights + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - http://rightsstatements.org/vocab/InC/1.0/ + view: + html_dl: true + render_as: "rights_statement" + source: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Source + index_documentation: displayable, searchable + indexing: + - source_sim + - source_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/source + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Original Manuscript + - Digital Archive + view: + html_dl: true + subject: + available_on: + class: + - Hyrax::AdministrativeSet + - Hyrax::FileSet + - Hyrax::PcdmCollection + - Hyrax::Work + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Subject + index_documentation: displayable, searchable + indexing: + - subject_sim + - subject_tesim + form: + primary: false + property_uri: http://purl.org/dc/elements/1.1/subject + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Art + - Science + view: + render_as: "faceted" + html_dl: true + dimensions: + available_on: + class: + - Hyrax::Work + context: + - special_context + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Dimensions + index_documentation: displayable, searchable + indexing: + - dimensions_sim + - dimensions_tesim + form: + primary: false + property_uri: http://purl.org/dc/terms/format + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - 50" x 20" + - 5 m x 10 m x 8 m + view: + render_as: "faceted" + html_dl: true diff --git a/config/routes.rb b/config/routes.rb index 69e6dbfecb..c030a0a054 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -272,4 +272,12 @@ %w[zotero mendeley].each do |action| get action, controller: 'static', action: action, as: action end + + if ENV.fetch('HYRAX_FLEXIBLE', false) + # Metadata profiles routes + resources :metadata_profiles, except: [:update, :show, :destroy] do + collection { post :import } + get 'export' + end + end end diff --git a/lib/generators/hyrax/collection_resource/collection_resource_generator.rb b/lib/generators/hyrax/collection_resource/collection_resource_generator.rb index 818c7a1f3d..3bc7965d44 100644 --- a/lib/generators/hyrax/collection_resource/collection_resource_generator.rb +++ b/lib/generators/hyrax/collection_resource/collection_resource_generator.rb @@ -69,7 +69,7 @@ def create_form template('collection_form.rb.erb', filepath) return unless include_basic_metadata? inject_into_file filepath, before: /include Hyrax::FormFields/ do - "include Hyrax::FormFields(:basic_metadata)\n " + "include Hyrax::FormFields(:basic_metadata) unless Hyrax.config.flexible?\n " end end @@ -84,7 +84,7 @@ def create_indexer template('collection_indexer.rb.erb', filepath) return unless include_basic_metadata? inject_into_file filepath, before: /include Hyrax::Indexer/ do - "include Hyrax::Indexer(:basic_metadata)\n " + "include Hyrax::Indexer(:basic_metadata) unless Hyrax.config.flexible?\n " end end diff --git a/lib/generators/hyrax/collection_resource/templates/collection_form.rb.erb b/lib/generators/hyrax/collection_resource/templates/collection_form.rb.erb index 6d3872ca4e..ab6ee6d281 100644 --- a/lib/generators/hyrax/collection_resource/templates/collection_form.rb.erb +++ b/lib/generators/hyrax/collection_resource/templates/collection_form.rb.erb @@ -3,5 +3,5 @@ # Generated via # `rails generate hyrax:collection_resource <%= class_name %>` class <%= class_name %>Form < Hyrax::Forms::PcdmCollectionForm - include Hyrax::FormFields(:<%= file_name %>) + include Hyrax::FormFields(:<%= file_name %>) unless Hyrax.config.flexible? end diff --git a/lib/generators/hyrax/collection_resource/templates/collection_indexer.rb.erb b/lib/generators/hyrax/collection_resource/templates/collection_indexer.rb.erb index 7a3309be0a..1715502ebd 100644 --- a/lib/generators/hyrax/collection_resource/templates/collection_indexer.rb.erb +++ b/lib/generators/hyrax/collection_resource/templates/collection_indexer.rb.erb @@ -3,5 +3,6 @@ # Generated via # `rails generate hyrax:collection_resource <%= class_name %>` class <%= class_name %>Indexer < Hyrax::Indexers::PcdmCollectionIndexer - include Hyrax::Indexer(:<%= file_name %>) + include Hyrax::Indexer(:<%= file_name %>) unless Hyrax.config.flexible? + include Hyrax::Indexer('<%= class_name %>') if Hyrax.config.flexible? end diff --git a/lib/generators/hyrax/templates/db/migrate/20240606205215_create_hyrax_flexible_schemas.rb.erb b/lib/generators/hyrax/templates/db/migrate/20240606205215_create_hyrax_flexible_schemas.rb.erb new file mode 100644 index 0000000000..2f78c686d3 --- /dev/null +++ b/lib/generators/hyrax/templates/db/migrate/20240606205215_create_hyrax_flexible_schemas.rb.erb @@ -0,0 +1,9 @@ +class CreateHyraxFlexibleSchemas < ActiveRecord::Migration<%= migration_version %> + def change + create_table :hyrax_flexible_schemas do |t| + t.text :profile + + t.timestamps + end + end +end diff --git a/lib/generators/hyrax/templates/db/migrate/20240606205216_add_contexts_to_hyrax_flexible_schemas.rb.erb b/lib/generators/hyrax/templates/db/migrate/20240606205216_add_contexts_to_hyrax_flexible_schemas.rb.erb new file mode 100644 index 0000000000..0218cce73a --- /dev/null +++ b/lib/generators/hyrax/templates/db/migrate/20240606205216_add_contexts_to_hyrax_flexible_schemas.rb.erb @@ -0,0 +1,5 @@ +class AddContextsToHyraxFlexibleSchemas < ActiveRecord::Migration<%= migration_version %> + def change + add_column :hyrax_flexible_schemas, :contexts, :text unless column_exists?(:hyrax_flexible_schemas, :contexts) + end +end diff --git a/lib/generators/hyrax/work_resource/templates/form.rb.erb b/lib/generators/hyrax/work_resource/templates/form.rb.erb index 309e2196f8..3e361ec5b6 100644 --- a/lib/generators/hyrax/work_resource/templates/form.rb.erb +++ b/lib/generators/hyrax/work_resource/templates/form.rb.erb @@ -6,8 +6,8 @@ # @see https://github.com/samvera/hyrax/wiki/Hyrax-Valkyrie-Usage-Guide#forms # @see https://github.com/samvera/valkyrie/wiki/ChangeSets-and-Dirty-Tracking class <%= class_name %>Form < Hyrax::Forms::PcdmObjectForm(<%= class_name %>) - include Hyrax::FormFields(:basic_metadata) - include Hyrax::FormFields(:<%= file_name %>) + include Hyrax::FormFields(:basic_metadata) unless Hyrax.config.flexible? + include Hyrax::FormFields(:<%= file_name %>) unless Hyrax.config.flexible? # Define custom form fields using the Valkyrie::ChangeSet interface # diff --git a/lib/generators/hyrax/work_resource/templates/indexer.rb.erb b/lib/generators/hyrax/work_resource/templates/indexer.rb.erb index 3ba45902f7..626cdac9d6 100644 --- a/lib/generators/hyrax/work_resource/templates/indexer.rb.erb +++ b/lib/generators/hyrax/work_resource/templates/indexer.rb.erb @@ -3,8 +3,9 @@ # Generated via # `rails generate hyrax:work_resource <%= class_name %>` class <%= class_name %>Indexer < Hyrax::Indexers::PcdmObjectIndexer(<%= class_name %>) - include Hyrax::Indexer(:basic_metadata) - include Hyrax::Indexer(:<%= file_name %>) + include Hyrax::Indexer(:basic_metadata) unless Hyrax.config.flexible? + include Hyrax::Indexer(:<%= file_name %>) unless Hyrax.config.flexible? + include Hyrax::Indexer('<%= class_name %>') if Hyrax.config.flexible? # Uncomment this block if you want to add custom indexing behavior: # def to_solr diff --git a/lib/hyrax/configuration.rb b/lib/hyrax/configuration.rb index 470873b192..53e304e474 100644 --- a/lib/hyrax/configuration.rb +++ b/lib/hyrax/configuration.rb @@ -305,6 +305,14 @@ def fixity_service @fixity_service ||= Hyrax::Fixity::ActiveFedoraFixityService end + # This value determines whether to use m3 flexible metadata schema or not + attr_writer :flexible + attr_reader :flexible + def flexible? + @flexible ||= + ActiveModel::Type::Boolean.new.cast(ENV.fetch('HYRAX_FLEXIBLE', false)) + end + # This value determines whether to use load the Freyja adapter in dassie attr_writer :valkyrie_transition attr_reader :valkyrie_transition diff --git a/lib/hyrax/form_fields.rb b/lib/hyrax/form_fields.rb index de81ced9e8..bc9de03547 100644 --- a/lib/hyrax/form_fields.rb +++ b/lib/hyrax/form_fields.rb @@ -16,7 +16,7 @@ def self.FormFields(schema_name, **options) # # @see .FormFields class FormFields < Module - attr_reader :name + attr_reader :name, :version, :contexts ## # @api private @@ -25,15 +25,17 @@ class FormFields < Module # @param [#form_definitions_for] definition_loader # # @note use Hyrax::FormFields(:my_schema) instead - def initialize(schema_name, definition_loader: SimpleSchemaLoader.new) + def initialize(schema_name, definition_loader: Hyrax::Schema.default_schema_loader, version: 1, contexts:) @name = schema_name + @contexts = contexts + @version = version @definition_loader = definition_loader end ## # @return [Hash{Symbol => Hash{Symbol => Object}}] def form_field_definitions - @definition_loader.form_definitions_for(schema: name) + @definition_loader.form_definitions_for(schema: name, version:, contexts:) end ## @@ -46,10 +48,13 @@ def inspect def included(descendant) super + return if Hyrax.config.flexible? + form_field_definitions.each do |field_name, options| descendant.property field_name.to_sym, options.merge(display: options.fetch(:display, true), default: []) descendant.validates field_name.to_sym, presence: true if options.fetch(:required, false) end + # Auto include any matching FormFieldBehaviors schema_name = name.to_s.camelcase behavior = "#{schema_name}FormFieldsBehavior".safe_constantize || diff --git a/lib/hyrax/indexer.rb b/lib/hyrax/indexer.rb index f47630e9e4..8743ebc7f7 100644 --- a/lib/hyrax/indexer.rb +++ b/lib/hyrax/indexer.rb @@ -19,7 +19,7 @@ module Hyrax # end # # @since 3.0.0 - def self.Indexer(schema_name, index_loader: SimpleSchemaLoader.new) + def self.Indexer(schema_name, index_loader: Hyrax::Schema.default_schema_loader) Indexer.new(index_loader.index_rules_for(schema: schema_name)) end @@ -33,8 +33,16 @@ class Indexer < Module def initialize(rules) define_method :to_solr do |*args| super(*args).tap do |document| - rules.each do |index_key, method| - document[index_key] = resource.try(method) + if Hyrax.config.flexible? + Hyrax::Schema.default_schema_loader.index_rules_for(schema: resource.class.to_s, version: resource.schema_version, contexts: resource.contexts).each do |index_key, method| + document[index_key] = resource.try(method) + end + document['schema_version_ssi'] = resource.schema_version + document['contexts_ssim'] = resource.contexts + else + rules.each do |index_key, method| + document[index_key] = resource.try(method) + end end end end diff --git a/lib/hyrax/schema.rb b/lib/hyrax/schema.rb index 0a96b2c5ad..b9325b2cfa 100644 --- a/lib/hyrax/schema.rb +++ b/lib/hyrax/schema.rb @@ -56,7 +56,13 @@ class Schema < Module ## # @!attribute [r] name # @return [Symbol] - attr_reader :name + attr_reader :name, :version, :contexts + + ## + # Pick the default schema loader based on whether flex is on or not + def self.default_schema_loader + Hyrax.config.flexible? ? M3SchemaLoader.new : SimpleSchemaLoader.new + end ## # @param [Symbol] schema_name @@ -64,15 +70,17 @@ class Schema < Module # @note use Hyrax::Schema(:my_schema) instead # # @api private - def initialize(schema_name, schema_loader: SimpleSchemaLoader.new) - @name = schema_name + def initialize(schema_name, schema_loader: Hyrax::Schema.default_schema_loader, schema_version: '1', contexts: []) + @name = schema_name.to_s + @version = schema_version @schema_loader = schema_loader + @contexts = contexts end ## # @return [Hash{Symbol => Dry::Types::Type}] def attributes - @schema_loader.attributes_for(schema: name) + @schema_loader.attributes_for(schema: name, version:, contexts:) end ## diff --git a/lib/hyrax/transactions/steps/save.rb b/lib/hyrax/transactions/steps/save.rb index cd5bf8bc45..dc8b83035f 100644 --- a/lib/hyrax/transactions/steps/save.rb +++ b/lib/hyrax/transactions/steps/save.rb @@ -79,7 +79,6 @@ def save_lease_or_embargo(unsaved) # @return [Array] def changed_collection_membership(change_set) return [] unless change_set.changed?(:member_of_collection_ids) - change_set.member_of_collection_ids - change_set.model.member_of_collection_ids end diff --git a/spec/fixtures/files/m3_profile.yaml b/spec/fixtures/files/m3_profile.yaml new file mode 100644 index 0000000000..e8d1dcb582 --- /dev/null +++ b/spec/fixtures/files/m3_profile.yaml @@ -0,0 +1,162 @@ +--- +m3_version: 1.0.beta2 +profile: + date_modified: '2024-06-01' + responsibility: https://samvera.org + responsibility_statement: Hyrax Initial Profile + type: + version: 1 +classes: + GenericWorkResource: + display_label: Generic Work + Monograph: + display_label: Monograph + AdminSet: + diplay_label: AdminSet + AdminSetResource: + diplay_label: AdministrativeSet + Collection: + display_label: Collection + CollectionResource: + display_label: PcdmCollection + Hyrax::FileSet: + display_label: FileSet +contexts: + flexible_context: + display_label: Flexible Metadata Example +mappings: + blacklight: + name: Additional Blacklight Solr Mappings + metatags: + name: Metatags + mods_oai_pmh: + name: MODS OAI PMH + qualified_dc_pmh: + name: Qualified DC OAI PMH + simple_dc_pmh: + name: Simple DC OAI PMH +properties: + title: + available_on: + class: + - AdminSetResource + - AdminSet + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Monograph + cardinality: + minimum: 0 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + definition: + default: Enter a standardized title for display. If only one + title is needed, transcribe the title from the source + itself. + display_label: + default: Title + index_documentation: displayable, searchable + indexing: + - 'title_sim' + - 'title_tesim' + form: + required: true + primary: true + multi_value: true + mappings: + metatags: twitter:title, og:title + mods_oai_pmh: mods:titleInfo/mods:title + qualified_dc_pmh: dcterms:title + simple_dc_pmh: dc:title + property_uri: http://purl.org/dc/terms/title + range: http://www.w3.org/2001/XMLSchema#string + requirement: required + sample_values: + - Pencil drawn portrait study of woman + date_modified: + available_on: + class: + - AdminSetResource + - AdminSet + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + display_label: + default: Date Modified + property_uri: http://purl.org/dc/terms/modified + range: http://www.w3.org/2001/XMLSchema#dateTime + sample_values: + - "2024-06-06 21:06:51 +0000" + date_uploaded: + available_on: + class: + - AdminSetResource + - AdminSet + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + display_label: + default: Date Uploaded + property_uri: http://purl.org/dc/terms/dateSubmitted + range: http://www.w3.org/2001/XMLSchema#dateTime + sample_values: + - "2024-06-06 21:06:51 +0000" + depositor: + available_on: + class: + - AdminSetResource + - AdminSet + - Hyrax::FileSet + - CollectionResource + - GenericWorkResource + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Depositor + index_documentation: searchable + indexing: + - 'depositor_tesim' + property_uri: http://id.loc.gov/vocabulary/relators/dpt + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Julie Allinson + creator: + available_on: + class: + - Hyrax::FileSet + cardinality: + minimum: 1 + multi_value: true + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Creator + index_documentation: searchable + indexing: + - 'creator_tesim' + property_uri: http://purl.org/dc/elements/1.1/creator + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Julie Allinson diff --git a/spec/forms/hyrax/forms/resource_form_spec.rb b/spec/forms/hyrax/forms/resource_form_spec.rb index 687d6921d6..15abaeb933 100644 --- a/spec/forms/hyrax/forms/resource_form_spec.rb +++ b/spec/forms/hyrax/forms/resource_form_spec.rb @@ -94,7 +94,7 @@ let(:form_class) do Class.new(Hyrax::Forms::ResourceForm(work.class)) do - include Hyrax::FormFields(:basic_metadata) + include Hyrax::FormFields(:basic_metadata) unless Hyrax.config.flexible? end end @@ -373,7 +373,7 @@ let(:form_class) do Class.new(Hyrax::Forms::ResourceForm(work.class)) do - include Hyrax::FormFields(:basic_metadata) + include Hyrax::FormFields(:basic_metadata) unless Hyrax.config.flexible? end end @@ -440,7 +440,7 @@ let(:form_class) do Class.new(Hyrax::Forms::ResourceForm(work.class)) do - include Hyrax::FormFields(:basic_metadata) + include Hyrax::FormFields(:basic_metadata) unless Hyrax.config.flexible? end end diff --git a/spec/hyrax/schema_spec.rb b/spec/hyrax/schema_spec.rb index 855cbbd0d8..ca1baf3977 100644 --- a/spec/hyrax/schema_spec.rb +++ b/spec/hyrax/schema_spec.rb @@ -12,7 +12,7 @@ class Resource < Hyrax::Resource; end Hyrax::Test::Schema::Resource end - after { Hyrax::Test.send(:remove_const, :Schema) } + after { Hyrax::Test.send(:remove_const, :Schema) if defined?(Hyrax::Test::Schema) } describe 'including' do it 'applies the specified schema' do @@ -96,4 +96,22 @@ class Resource < Hyrax::Resource; end expect(saved[:date_created].map { |t| DateTime.parse(t.to_s).strftime("%FT%R") }).to match_array(times_parsed) end end + + describe '.default_schema_loader' do + context 'when using flexible metadata' do + it 'returns an M3SchemaLoader' do + allow(Hyrax.config).to receive(:flexible?).and_return(true) + + expect(described_class.default_schema_loader).to be_a(Hyrax::M3SchemaLoader) + end + end + + context 'when not using flexible metadata' do + it 'returns a SimpleSchemaLoader' do + allow(Hyrax.config).to receive(:flexible?).and_return(false) + + expect(described_class.default_schema_loader).to be_a(Hyrax::SimpleSchemaLoader) + end + end + end end diff --git a/spec/models/concerns/hyrax/flexibility_spec.rb b/spec/models/concerns/hyrax/flexibility_spec.rb new file mode 100644 index 0000000000..85c2f49bfe --- /dev/null +++ b/spec/models/concerns/hyrax/flexibility_spec.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Hyrax::Flexibility' do + subject(:flexibility_class) { Hyrax::Test::Flexibility::TestWork } + let(:schema) { Hyrax::FlexibleSchema.create(profile: profile.deep_merge(test_work_profile)) } + let(:profile) { YAML.safe_load_file(Hyrax::Engine.root.join('spec', 'fixtures', 'files', 'm3_profile.yaml')) } + let(:test_work_profile) do + YAML.safe_load(<<-YAML) + classes: + Hyrax::Test::Flexibility::TestWork: + display_label: Test Work + properties: + title: + available_on: + class: + - Hyrax::Test::Flexibility::TestWork + YAML + end + + before do + allow(Hyrax.config).to receive(:flexible?).and_return(true) + allow(Hyrax::FlexibleSchema).to receive(:find).and_return(schema) + + module Hyrax::Test::Flexibility + class TestWork < Hyrax::Resource + include Hyrax::Flexibility if Hyrax.config.flexible? + end + end + end + + after do + Hyrax::Test::Flexibility.send(:remove_const, :TestWork) + allow(Hyrax.config).to receive(:flexible?).and_return(false) + end + + its(:included_modules) { is_expected.to include(Hyrax::Flexibility) } + + describe '#schema_version' do + let(:flexibility_instance) { flexibility_class.new } + + it 'responds to #schema_version' do + expect(flexibility_instance).to respond_to(:schema_version) + end + end + + describe '.attributes' do + let(:flexibility_instance) { flexibility_class.new } + + it 'defines the attribute setter methods' do + expect(flexibility_instance).to respond_to(:title=) + end + end + + describe '.new' do + context 'when attributes is a Struct' do + it 'creates a new instance with attributes converted to a hash' do + new_instance = flexibility_class.new(Struct.new(:title).new(['Test Title'])) + expect(new_instance.title).to eq(['Test Title']) + end + end + + context 'when attributes is a hash' do + it 'loads the attributes' do + instance = flexibility_class.new(title: ['Test Title']) + expect(instance.title).to eq(['Test Title']) + end + end + end +end diff --git a/spec/models/hyrax/flexible_schema_spec.rb b/spec/models/hyrax/flexible_schema_spec.rb new file mode 100644 index 0000000000..fefa70acd3 --- /dev/null +++ b/spec/models/hyrax/flexible_schema_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true +require 'rails_helper' + +RSpec.describe Hyrax::FlexibleSchema, type: :model do + let(:profile_file_path) { File.join(fixture_path, 'files', 'm3_profile.yaml') } + let(:profile_data) { YAML.load_file(profile_file_path) } + + subject { described_class.create(profile: profile_data) } + + describe '#title' do + it 'returns the correct title' do + responsibility_statement = profile_data['profile']['responsibility_statement'] + expect(subject.title).to eq("#{responsibility_statement} - version #{subject.id}") + end + end + + describe '#attributes_for' do + context 'when class_name exists' do + it 'returns the correct attributes for each class' do + profile_data['classes'].keys.each do |class_name| + attributes = subject.attributes_for(class_name) + expect(attributes).to be_a(Hash) + attributes.each do |_key, values| + expect(values).to include('type', 'predicate', 'index_keys', 'multiple') + end + end + end + end + + context 'when class_name does not exist' do + it 'returns nil' do + expect(subject.attributes_for('NonExistentClass')).to be_nil + end + end + end +end diff --git a/spec/services/hyrax/m3_schema_loader_spec.rb b/spec/services/hyrax/m3_schema_loader_spec.rb new file mode 100644 index 0000000000..1c626c5035 --- /dev/null +++ b/spec/services/hyrax/m3_schema_loader_spec.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Hyrax::M3SchemaLoader do + subject(:schema_loader) { described_class.new } + let(:profile) { YAML.safe_load_file(Hyrax::Engine.root.join('spec', 'fixtures', 'files', 'm3_profile.yaml')) } + let(:schema) do + Hyrax::FlexibleSchema.create( + profile: profile + ) + end + + before do + allow(Hyrax.config).to receive(:flexible?).and_return(true) + allow(Hyrax::FlexibleSchema).to receive(:find).and_return(schema) + end + + describe '#attributes_for' do + it 'provides an attributes hash' do + expect(schema_loader.attributes_for(schema: Monograph.to_s)) + .to include(title: Valkyrie::Types::Array.of(Valkyrie::Types::String), + depositor: Valkyrie::Types::String) + end + + it 'provides access to attribute metadata' do + expect(schema_loader.attributes_for(schema: Monograph.to_s)[:title].meta) + .to include({ "type" => "string", + "form" => { "multiple" => true, "primary" => true, "required" => true }, + "index_keys" => ["title_sim", "title_tesim"], + "multiple" => true, + "predicate" => "http://purl.org/dc/terms/title" }) + end + + context 'with generated resource' do + let(:sample_attribute) do + YAML.safe_load(<<-YAML) + properties: + sample_attribute: + available_on: + class: + - Monograph + cardinality: + minimum: 0 + maximum: 1 + multi_value: false + controlled_values: + format: http://www.w3.org/2001/XMLSchema#string + sources: + - 'null' + display_label: + default: Sample Attribute + property_uri: http://hyrax-example.com/sample_attribute + range: http://www.w3.org/2001/XMLSchema#string + sample_values: + - Example Sample Attribute + YAML + end + let(:schema) do + Hyrax::FlexibleSchema.create( + profile: profile.deep_merge(sample_attribute) + ) + end + + it 'provides an attributes hash' do + expect(schema_loader.attributes_for(schema: Monograph.to_s)) + .to include(sample_attribute: Valkyrie::Types::Array.of(Valkyrie::Types::String)) + end + end + + it 'raises an error for an undefined schema' do + expect { schema_loader.attributes_for(schema: :NOT_A_SCHEMA) } + .to raise_error described_class::UndefinedSchemaError + end + end + + describe '#index_rules_for' do + it 'provides index configuration' do + expect(schema_loader.index_rules_for(schema: Monograph.to_s)).to include(title_sim: :title, title_tesim: :title) + end + end + + describe '#form_definitions_for' do + it 'provides form configuration' do + expect(schema_loader.form_definitions_for(schema: Monograph.to_s)) + .to eq(title: { required: true, primary: true, multiple: true }) + end + end +end diff --git a/spec/services/hyrax/schema_loader_spec.rb b/spec/services/hyrax/schema_loader_spec.rb new file mode 100644 index 0000000000..139986d18b --- /dev/null +++ b/spec/services/hyrax/schema_loader_spec.rb @@ -0,0 +1,105 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Hyrax::SchemaLoader do + subject(:schema_loader) { described_class.new } + + describe '#definitions' do + it 'raises NotImplementedError' do + expect { schema_loader.send(:definitions, :some_schema, 1) } + .to raise_error(NotImplementedError, 'Implement #definitions in a child class') + end + end +end + +RSpec.describe Hyrax::SchemaLoader::AttributeDefinition do + subject(:attribute_definition) { described_class.new(name, config) } + + let(:name) { 'title' } + let(:config) do + { 'type' => 'string', + 'form' => { 'multiple' => true, 'primary' => true, 'required' => true }, + 'index_keys' => ['title_sim', 'title_tesim'], + 'multiple' => true, + 'predicate' => 'http://purl.org/dc/terms/title' } + end + + describe '#form_options' do + it 'returns form options as a symbolized hash' do + expect(attribute_definition.form_options).to eq(multiple: true, primary: true, required: true) + end + + context 'when form options are missing' do + let(:config) { { 'type' => 'string' } } + + it 'returns an empty hash' do + expect(attribute_definition.form_options).to eq({}) + end + end + end + + describe '#index_keys' do + it 'returns index keys as symbols' do + expect(attribute_definition.index_keys).to eq([:title_sim, :title_tesim]) + end + + context 'when index keys are missing' do + let(:config) { { 'type' => 'string' } } + + it 'returns an empty array' do + expect(attribute_definition.index_keys).to eq([]) + end + end + end + + describe '#type' do + context 'when multiple is true' do + it 'returns a Valkyrie array type' do + expect(attribute_definition.type).to be_a(Dry::Types::Constructor) + expect(attribute_definition.type.to_s).to include('Array') + expect(attribute_definition.type.member).to eq(Valkyrie::Types::String) + end + end + + context 'when multiple is false' do + let(:config) { { 'type' => 'string', 'multiple' => false } } + + it 'returns a Valkyrie string type' do + expect(attribute_definition.type).to eq(Valkyrie::Types::String) + end + end + + context 'when type is id' do + let(:config) { { 'type' => 'id' } } + + it 'returns a Valkyrie ID type' do + expect(attribute_definition.type).to eq(Valkyrie::Types::ID) + end + end + + context 'when type is uri' do + let(:config) { { 'type' => 'uri' } } + + it 'returns a Valkyrie URI type' do + expect(attribute_definition.type).to eq(Valkyrie::Types::URI) + end + end + + context 'when type is date_time' do + let(:config) { { 'type' => 'date_time' } } + + it 'returns a Valkyrie DateTime type' do + expect(attribute_definition.type).to eq(Valkyrie::Types::DateTime) + end + end + + context 'when type is not recognized' do + let(:config) { { 'type' => 'custom' } } + + it 'raises an ArgumentError' do + expect { attribute_definition.type }.to raise_error(ArgumentError, 'Unrecognized type: custom') + end + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a9ddfb9b0e..9be9ad0e07 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -5,6 +5,7 @@ # Analytics is turned off by default ENV['HYRAX_ANALYTICS'] = 'false' +ENV['HYRAX_FLEXIBLE'] = 'false' require "bundler/setup"