Skip to content

Commit

Permalink
Add dynamically generated metadata guide
Browse files Browse the repository at this point in the history
This also removes the previous static guide.
  • Loading branch information
little9 committed Oct 1, 2019
1 parent 06ac5e1 commit 0c53d93
Show file tree
Hide file tree
Showing 18 changed files with 306 additions and 61 deletions.
3 changes: 2 additions & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Metrics/AbcSize:
- lib/zizia/importer.rb
- lib/zizia/hyrax/hyrax_metadata_only_updater.rb
- 'app/importers/modular_importer.rb'
- 'app/lib/zizia/metadata_details.rb'

Metrics/BlockLength:
Exclude:
Expand Down Expand Up @@ -75,6 +76,6 @@ RSpec/MultipleExpectations:
- 'spec/integration/import_hyrax_csv.rb'
- 'spec/controllers/importer_documentation_controller_spec.rb'
- 'spec/integration/csv_import_detail_spec.rb'

- 'spec/controllers/**/*'
Style/StructInheritance:
Enabled: false
30 changes: 30 additions & 0 deletions app/config/usage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
# Metadata usage hints
# attribute: usage

arkivo_checksum: "-- system field - not directly editable --"
based_near: " A location that something is based near, for some broadly human notion of near."
contributor: "Identifies contributors to the material; can be used very broadly if exact contributions aren't known"
creator: "Identifies the primary Creator(s) of the material"
date_created: "The date the material was created"
date_modified: "-- system field - not directly editable --"
date_uploaded: "-- system field - not directly editable --"
depositor: "-- system field - not directly editable --"
description: "Free-text, summary description of the content, such as an abstract. Provides additional search terms in natural language; provides important summary information for non-textual resources such as images, audio, and video"
has_model: "-- system field - not directly editable --"
head: "-- system field - not directly editable --"
identifier: "An unambiguous reference to the resource within a given context."
keywords: "Uncontrolled keywords describing the material, often provided by content creators"
language: "The language of the source content being described: applies to textual or spoken word (linguistic) content"
license: "A legal document giving official permission to do something with the resource."
on_behalf_of: "-- system field - not directly editable --"
owner: "-- system field - not directly editable --"
proxy_depositor: "-- system field - not directly editable --"
publisher: "The name of the entity formally publishing the work"
related_url: "The resource O may provide additional information about S. It may be possible to retrieve representations of O from the Web, but this is not required. When such representations may be retrieved, no constraints are placed on the format of those representations."
resource_type: "The nature or genre of the resource."
rights_statement: "Standardized rights statement from rightsstatements.org that can be used to communicate the copyright and re-use status of digital objects to the end users [DESCRIPTIVE/USER FACING]"
source: "A related resource from which the described resource is derived."
state: "-- system field - not directly editable --"
tail: "-- system field - not directly editable --"
title: "The name of the resource being described. The title may either be transcribed from the resource itself, or it may need to be created."
11 changes: 0 additions & 11 deletions app/controllers/zizia/importer_documentation_controller.rb

This file was deleted.

20 changes: 20 additions & 0 deletions app/controllers/zizia/metadata_details_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true
module Zizia
class MetadataDetailsController < ApplicationController
def show
@details = MetadataDetails.instance.details(work_attributes:
WorkAttributes.instance)
respond_to do |format|
format.html
format.json { render json: @details.to_json }
format.any { redirect_to action: :show }
end
end

def profile
@csv = MetadataDetails.instance.to_csv(work_attributes:
WorkAttributes.instance)
send_data @csv, type: 'text/csv', filename: "metadata-profile-#{Date.current}.csv"
end
end
end
13 changes: 0 additions & 13 deletions app/helpers/importer_documentation_helper.rb

This file was deleted.

68 changes: 68 additions & 0 deletions app/lib/zizia/metadata_details.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# frozen_string_literal: true
require 'csv'

module Zizia
class MetadataDetails
include Singleton

def details(work_attributes:)
validators = work_attributes.validators
work_attributes.properties.sort.map do |p|
Hash[
attribute: p[0],
predicate: p[1].predicate.to_s,
multiple: p[1].try(:multiple?).to_s,
type: type_to_s(p[1].type),
validator: validator_to_string(validator: validators[p[0].to_sym][0]),
label: I18n.t("simple_form.labels.defaults.#{p[0]}"),
csv_header: csv_header(p[0]),
required_on_form: required_on_form_to_s(p[0]),
usage: MetadataUsage.instance.usage[p[0]]
]
end
end

def to_csv(work_attributes:)
attribute_list = details(work_attributes: work_attributes)
headers = extract_headers(attribute_list[0])
csv_string = CSV.generate do |csv|
csv << headers
attribute_list.each do |attribute|
csv << headers.map { |h| attribute[h] }
end
end
csv_string
end

private

def csv_header(field)
Zizia.config.metadata_mapper_class.csv_header(field) || "not configured"
end

def extract_headers(attribute_hash)
headers = attribute_hash.keys.sort
headers = [:attribute] + (headers - [:attribute]) # force :attribute to the beginning of the list
headers = (headers - [:usage]) + [:usage] # force :usage to the end of the list becuause it's so long
headers
end

def required_on_form_to_s(attribute)
Hyrax::Forms::WorkForm.required_fields.include?(attribute.to_sym).to_s
end

def type_to_s(type)
return 'Not specified' unless type.present?
type.to_s
end

def validator_to_string(validator:)
case validator
when ActiveModel::Validations::PresenceValidator
'required'
else
'No validation present in the model.'
end
end
end
end
22 changes: 22 additions & 0 deletions app/lib/zizia/metadata_usage.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

module Zizia
class MetadataUsage
include Singleton

def usage
YAML.load_file(config)
end

private

def default_location
File.join(File.dirname(__FILE__), '../../config/usage.yml')
end

def config
return default_location unless File.exist?(Rails.root.join("config", "usage.yml"))
Rails.root.join("config", "usage.yml")
end
end
end
31 changes: 31 additions & 0 deletions app/lib/zizia/work_attributes.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# frozen_string_literal: true

# A singleton class to get the list of attributes
# from a work.
#
# It is a Singleton so that there is only one of these
# initialized and uses the ||= operator so that when you
# read the attributes property it uses an already initialized
# work.
#
# This is to ensure that we can get a list of the attributes
# programmatically, but without using any unnecessary memory.
module Zizia
class WorkAttributes
include Singleton
attr_reader :attributes, :properties, :validators, :local_attributes

def initialize
work ||= klass.new
@local_attributes || work.local_attributes
@attributes ||= work.local_attributes
@properties ||= work.send(:properties)
@validators ||= work.send(:_validators)
end

# Override to choose a different Work class
def klass
Work
end
end
end
49 changes: 49 additions & 0 deletions app/views/zizia/metadata_details/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<% content_for :title, 'Importer Field Guide' %>
<div class="guide-container">
<a class="btn btn-primary" href="/importer_documentation/profile">Download as CSV</a>
<dl>
<% @details.each do |detail| %>
<h2>
<dt>
<%= detail[:attribute] %>
</dt>
</h2>
<dd>
<div>
<b>Predicate:</b>
<a href="<%= detail[:predicate] %>"><%= detail[:predicate] %></a>
</div>
<div>
<b>Type:</b>
<%= detail[:type] %>
</div>
<div>
<b>Validation:</b>
<%= detail[:validator] %>
</div>
<div>
<b>Multiple:</b>
<%= detail[:multiple] %>
</div>
<div>
<b>Edit Form Label:</b>
<%= detail[:label] %>
</div>
<div>
<b>Import header:</b>
<span class=<%= css_class(detail[:csv_header])%>>
<%= detail[:csv_header] %>
</span>
</div>
<div>
<b>Required on Edit Form:</b>
<%= detail[:required_on_form] %>
</div>
<div class=metadata_usage>
<b>Usage:</b>
<%= detail[:usage] %>
</div>
</dd>
<% end %>
</dl>
</div>
6 changes: 3 additions & 3 deletions config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# frozen_string_literal: true
Zizia::Engine.routes.draw do
get 'importer_documentation/guide'
get 'importer_documentation/csv'

post 'csv_imports/preview', as: 'preview_csv_import'
get 'csv_imports/preview', to: redirect('csv_imports/new')
resources :csv_imports, only: [:index, :show, :new, :create]

get 'importer_documentation/guide', to: 'metadata_details#show'
get 'importer_documentation/profile', to: 'metadata_details#profile'
end
1 change: 0 additions & 1 deletion lib/zizia/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
require 'rails/all'
require 'carrierwave'
require 'carrierwave/orm/activerecord'
require 'redcarpet'
require 'devise'
require 'hyrax'
require 'riiif'
Expand Down
4 changes: 4 additions & 0 deletions lib/zizia/hyrax/hyrax_basic_metadata_mapper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ def map_field(name)
Array(metadata[key]&.split(delimiter))
end

def self.csv_header(field)
CSV_HEADERS[field.to_sym]
end

protected

# Some fields should have single values instead
Expand Down
14 changes: 0 additions & 14 deletions spec/controllers/importer_documentation_controller_spec.rb

This file was deleted.

73 changes: 73 additions & 0 deletions spec/controllers/metadata_details_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe Zizia::MetadataDetailsController, type: :controller do
routes { Zizia::Engine.routes }

describe 'GET show' do
it 'has 200 code for show' do
get :show
expect(response.status).to eq(200)
end

it 'responds with html when no format is specified' do
get :show
expect(response.content_type).to eq "text/html"
end

it 'responds to json requests' do
get :show, format: :json
expect(response.content_type).to eq "application/json"
end

it 'has details' do
get :show
details = assigns(:details)
title = details.find { |h| h[:attribute] == 'title' }
expect(title[:predicate]).to eq('http://purl.org/dc/terms/title')
end

it 'has details in json' do
get :show, format: :json
details = JSON[response.body, symbolize_names: true]
title = details.find { |h| h[:attribute] == 'title' }
expect(title[:predicate]).to eq('http://purl.org/dc/terms/title')
end

it 'redirects unknown formats to html' do
get :show, format: :something_else
expect(response).to redirect_to action: :show
end
end

describe 'GET profile' do
it 'has a downloadable csv' do
get :profile
expect(response.content_type).to eq('text/csv')
end

it 'includes expected headers' do
get :profile
first_row = response.body.lines.first
expect(first_row).to include('csv_header')
expect(first_row).to include('required_on_form')
end

it 'includes usage' do
get :profile
profile_table = CSV.parse(response.body, headers: :first_row)
title_definition = profile_table.find { |r| r.field('attribute') == 'title' }
expect(title_definition.field('usage')).to include 'name of the resource being described' # match text extracted from ./config/emory/usage.yml
end

it 'includes a date in the filename' do
todays_date = "Wed, 03 Jul 1985".to_date
allow(Date).to receive(:current) { todays_date }

get :profile
filename = response.headers['Content-Disposition']
expect(filename).to include "1985-07-03"
end
end
end
Loading

0 comments on commit 0c53d93

Please sign in to comment.