require 'json' require 'solrizer' module Ddr module SolrDocumentBehavior extend ActiveSupport::Concern included do alias_method :pid, :id end class NotFound < Error; end module ClassMethods def find(id) query = Ddr::Index::Query.new { id id } if doc = query.docs.first return doc end raise NotFound, "SolrDocument not found for \"#{id}\"." end def find_by_permanent_id(ark) if ark.blank? raise ArgumentError, "ARK argument must be present." end query = Ddr::Index::Query.new do q *:* where permanent_id: ark end if doc = query.docs.first return doc end raise NotFound, "SolrDocument not found for permanent id \"#{ark}\"." end end def inspect "#<#{self.class.name} id=#{id.inspect}>" end def method_missing(name, *args, &block) if args.empty? && !block begin field = Ddr::Index::Fields.get(name) rescue NameError # pass else # Preserves the default behavior of the deprecated method # Blacklight::Solr::Document#get, which this procedure # effectively replaces. val = self[field] return val.is_a?(Array) ? val.join(", ") : val end end super end def resource @resource ||= Valkyrie::MetadataAdapter.find(:index_solr).query_service.find_by(id: id) end def object_create_date parse_date(self[Ddr::Index::Fields::RESOURCE_CREATE_DATE]) end def object_modified_date parse_date(self[Ddr::Index::Fields::RESOURCE_MODIFIED_DATE]) end def last_fixity_check_on get_date(Ddr::Index::Fields::LAST_FIXITY_CHECK_ON) end def last_virus_check_on get_date(Ddr::Index::Fields::LAST_VIRUS_CHECK_ON) end def has_admin_policy? admin_policy_id.present? end def admin_policy if has_admin_policy? self.class.find(admin_policy_id.gsub(/^id-/,'')) end end def has_children? resource.children.present? end def title_display title end def identifier # We want the multivalued version here self[Solrizer.solr_name(:identifier, :stored_searchable, type: :text)] end def source self[Solrizer.solr_name(:source, :stored_searchable, type: :text)] end def has_thumbnail? resource.has_thumbnail? end def has_content? resource.has_content? end def has_intermediate_file? resource.has_intermediate_file? end def has_extracted_text? resource.has_extracted_text? end def content_mime_type resource.content_type end # For duck-typing with Ddr::HasContent alias_method :content_type, :content_mime_type def content_human_size resource.content_human_size end def targets @targets ||= query_service.find_inverse_references_by(resource: resource, property: 'for_collection_id') end def targets_count @targets_count = targets.count end def has_target? targets_count > 0 end def tableized_name resource_model.tableize end def rights_statement @rights_statement ||= RightsStatement.call(self) end def roles @roles ||= resource.roles end def resource_roles resource.resource_roles end def inherited_roles resource.inherited_roles end def structure JSON.parse(fetch(Ddr::Index::Fields::STRUCTURE)) rescue nil end def effective_permissions(agents) Ddr::Auth::EffectivePermissions.call(self, agents) end def research_help research_help_contact = self[Ddr::Index::Fields::RESEARCH_HELP_CONTACT] || inherited_research_help_contact Ddr::Contact.call(research_help_contact) if research_help_contact end def parent_id is_part_of || is_member_of_collection end def has_parent? parent_id.present? end def parent if has_parent? self.class.find(parent_id) end end def multires_image_file_paths if structure structure_docs.map { |doc| doc.multires_image_file_path }.compact else [] end end def finding_aid resource.finding_aid end def intermediate_type if has_intermediate_file? resource.intermediate_type end end def intermediate_path if has_intermediate_file? resource.intermediate_path end end def intermediate_extension if has_intermediate_file? extensions = Ddr.preferred_file_extensions if extensions.include? intermediate_type extensions[intermediate_type] else intermediate_extension_default end end end def captionable? resource.captionable? end def captioned? resource.captioned? end def caption_type if captioned? resource.caption_type end end def caption_extension if captioned? extensions = Ddr.preferred_file_extensions if extensions.include? caption_type extensions[caption_type] else caption_extension_default end end end def caption_path if captioned? resource.caption_path end end def streamable? resource.streamable? end def streamable_media_extension if streamable? extensions = Ddr.preferred_file_extensions if extensions.include? streamable_media_type extensions[streamable_media_type] else streamable_media_extension_default end end end def streamable_media_type if streamable? resource.streamable_media_type end end def streamable_media_path if streamable? resource.streamable_media_path end end def thumbnail_path if has_thumbnail? resource.thumbnail_path end end def rights resource.rights end def children resource.children end def embargo resource.embargo end def embargoed? resource.embargoed? end private def query_service @query_service ||= Valkyrie::MetadataAdapter.find(:index_solr).query_service end def get_date(field) parse_date(self[field]) end def get_json(field) JSON.parse Array(self[field]).first end def parse_date(date) Time.parse(date).localtime if date end def inherited_research_help_contact if doc = admin_policy doc.research_help_contact end end def structure_docs structure_repo_ids.map { |repo_id| self.class.find(repo_id) }.compact end # For simplicity, initial implementation returns repo ID's only from top-level # (i.e., not nested) contents. This is done since we have not clarified what # an _ordered_ list of repo ID's should look like if structure contains nested # contents. def structure_repo_ids default_struct_map['contents'].map { |content| content['contents'].map { |content| content['repo_id'] } }.flatten end def default_struct_map structure['default'] || structure.values.first end def intermediate_extension_default resource.intermediate_file.default_file_extension end def caption_extension_default resource.caption.default_file_extension end def streamable_media_extension_default resource.streamable_media.default_file_extension end end end