hyrax-preservation 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +5 -0
- data/Rakefile +15 -0
- data/app/assets/config/preservation_manifest.js +2 -0
- data/app/assets/javascripts/hyrax/preservation/application.js +13 -0
- data/app/assets/stylesheets/hyrax/preservation/application.css +15 -0
- data/app/controllers/hyrax/preservation/events_controller.rb +133 -0
- data/app/helpers/hyrax/preservation/application_helper.rb +6 -0
- data/app/indexers/hyrax/preservation/event_indexer.rb +73 -0
- data/app/jobs/hyrax/preservation/application_job.rb +6 -0
- data/app/mailers/hyrax/preservation/application_mailer.rb +8 -0
- data/app/models/hyrax/preservation/event.rb +41 -0
- data/app/models/hyrax/preservation/premis_event_type.rb +64 -0
- data/app/presenters/hyrax/preservation/event_index_presenter.rb +12 -0
- data/app/presenters/hyrax/preservation/event_show_presenter.rb +11 -0
- data/app/search_builders/hyrax/preservation/events_search_builder.rb +105 -0
- data/app/views/hyrax/preservation/events/_event.html.erb +1 -0
- data/app/views/hyrax/preservation/events/_filter_search.html.erb +6 -0
- data/app/views/hyrax/preservation/events/_index_header_list_default.html.erb +20 -0
- data/app/views/hyrax/preservation/events/_previous_next_doc.html.erb +29 -0
- data/app/views/hyrax/preservation/events/filter_search/_date_range.html.erb +18 -0
- data/app/views/hyrax/preservation/events/filter_search/_premis_agent.html.erb +15 -0
- data/app/views/hyrax/preservation/events/filter_search/_premis_event_type.html.erb +18 -0
- data/app/views/hyrax/preservation/events/index.html.erb +10 -0
- data/app/views/layouts/hyrax/preservation/application.html.erb +14 -0
- data/config/routes.rb +3 -0
- data/lib/generators/hyrax/preservation/install_generator.rb +21 -0
- data/lib/hyrax/preservation.rb +12 -0
- data/lib/hyrax/preservation/demo.rb +80 -0
- data/lib/hyrax/preservation/engine.rb +13 -0
- data/lib/hyrax/preservation/event_logger.rb +18 -0
- data/lib/hyrax/preservation/search_state.rb +9 -0
- data/lib/hyrax/preservation/service_environment.rb +65 -0
- data/lib/hyrax/preservation/version.rb +5 -0
- metadata +307 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8b640e48b5f2c1c7671aafe3cedbfa3c9eddd13e47a0b42aa710e814845bcbf6
|
4
|
+
data.tar.gz: a0046c6f6ad64f5b2ec63feb340c74699073e4d1bc47802d0ede9d59c572bbe9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d19413cfa69f75cb3e03b8c7bd83615c55e2c6859ec6f6911099a7c9851f6b2b7f094235bd11d2a71cc28e09c232f807638730485b170e51be14cdd2fb3f0abd
|
7
|
+
data.tar.gz: 4453203e60f1de3df9360fad1dbbdabba447e0c82197cd256b5bb40f35c5ad08cde371fd124d093d8b701bd9b6b30eeb6a531621682c410a33798e6163e279ae
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2016 Andrew Myers
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'bundler/gem_tasks'
|
8
|
+
load 'rails/tasks/statistics.rake'
|
9
|
+
require 'engine_cart/rake_task'
|
10
|
+
|
11
|
+
# Load tasks for gem development
|
12
|
+
Dir.glob('gem_development_rake_tasks/*.rake').each { |r| import r }
|
13
|
+
|
14
|
+
# Set the default rake task when developing this gem.
|
15
|
+
task :default => ['ci']
|
@@ -0,0 +1,13 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// compiled file. JavaScript code in this file should be added after the last require_* statement.
|
9
|
+
//
|
10
|
+
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
|
11
|
+
// about supported directives.
|
12
|
+
//
|
13
|
+
//= require_tree .
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'hyrax/preservation/search_state'
|
2
|
+
|
3
|
+
module Hyrax
|
4
|
+
module Preservation
|
5
|
+
class EventsController < ActionController::Base
|
6
|
+
include Blacklight::Controller
|
7
|
+
include Hydra::Controller::ControllerBehavior
|
8
|
+
include Hydra::Catalog
|
9
|
+
include Hyrax::Controller
|
10
|
+
|
11
|
+
# Include Blacklight helpers that are needed to avoid breakage when using
|
12
|
+
# Blacklight views.
|
13
|
+
helper CatalogHelper
|
14
|
+
helper ComponentHelper
|
15
|
+
helper LayoutHelper
|
16
|
+
|
17
|
+
# Include Hyrax helpers that are needed to avoid breakage when rendering
|
18
|
+
# Hyrax views.
|
19
|
+
helper HyraxHelper
|
20
|
+
|
21
|
+
# Override Hyrax::UrlHelper#url_for_document
|
22
|
+
# helper_method :url_for_document
|
23
|
+
helper_method :display_premis_agent
|
24
|
+
helper_method :display_premis_event_date_time
|
25
|
+
helper_method :display_related_file
|
26
|
+
|
27
|
+
# TODO: We used to include CurationConcerns::ApplicationControllerBehavior
|
28
|
+
# here, but that module was merged into Sufia::Controller, which was later
|
29
|
+
# converted to Hyrax::Controller. But we're not sure if it's still needed.
|
30
|
+
# TODO: Determine whether or not we need to include Hyrax::Controller, and
|
31
|
+
# upadate (or delete) these commets accordingly.
|
32
|
+
# include Hyrax::Controller
|
33
|
+
include Hyrax::ThemedLayoutController
|
34
|
+
with_themed_layout '1_column'
|
35
|
+
|
36
|
+
# Prevent CSRF attacks by raising an exception.
|
37
|
+
# For APIs, you may want to use :null_session instead.
|
38
|
+
protect_from_forgery with: :exception
|
39
|
+
|
40
|
+
# Override rails path for the views by appending 'catalog' as a
|
41
|
+
# place to look for views. This allows using default blacklight
|
42
|
+
# views if you don't want to override each one.
|
43
|
+
def _prefixes
|
44
|
+
@_prefixes ||= super + ['catalog']
|
45
|
+
end
|
46
|
+
|
47
|
+
configure_blacklight do |config|
|
48
|
+
|
49
|
+
config.search_builder_class = EventsSearchBuilder
|
50
|
+
|
51
|
+
# Index view config
|
52
|
+
config.index.document_presenter_class = EventIndexPresenter
|
53
|
+
# NOTE: setting `config.index.title_field` here has no effect, because
|
54
|
+
# we're currently overriding the presenter class, and the partial that
|
55
|
+
# would normally be looking for it. Instead, see the overridden partial
|
56
|
+
# in app/views/preservation/events/_index_header_list_default.html.erb
|
57
|
+
# and the EventIndexPresenter#search_result_title method.
|
58
|
+
config.add_index_field solr_name(:hasEventRelatedObject, :symbol), label: "File", helper_method: :display_related_file
|
59
|
+
config.add_index_field solr_name(:premis_event_date_time, :stored_searchable, type: :date), label: "Date", helper_method: :display_premis_event_date_time
|
60
|
+
config.add_index_field solr_name(:premis_agent, :symbol), label: "Agent", helper_method: :display_premis_agent
|
61
|
+
|
62
|
+
# Show view config
|
63
|
+
config.show.document_presenter_class = EventShowPresenter
|
64
|
+
config.add_show_field solr_name(:premis_agent, :symbol), label: "PREMIS Agent"
|
65
|
+
config.add_show_field solr_name(:premis_event_date_time, :stored_searchable, type: :date), label: "Date"
|
66
|
+
config.add_show_field solr_name(:hasEventRelatedObject, :symbol), label: "File", helper_method: :display_related_file
|
67
|
+
|
68
|
+
# Remove unused actions from the show view. Enabling these breaks the
|
69
|
+
# show view because Blacklight generates urls that don't exist. Figuring
|
70
|
+
# out how to make them work will take more digging.
|
71
|
+
config.show.document_actions.delete(:bookmark)
|
72
|
+
config.show.document_actions.delete(:email)
|
73
|
+
config.show.document_actions.delete(:sms)
|
74
|
+
config.show.document_actions.delete(:citation)
|
75
|
+
|
76
|
+
# Facet config
|
77
|
+
# config.add_facet_fields_to_solr_request!
|
78
|
+
# config.add_facet_field :premis_event_date_time_ltsi, label: 'Date', range: { segments: false }
|
79
|
+
# config.add_facet_field solr_name(:premis_event_type, :symbol), label: 'Type'
|
80
|
+
end
|
81
|
+
|
82
|
+
# Overrides CatalogController::UrlHelper#url_for_document. It would be
|
83
|
+
# nice to put this method in our own Preservation::UrlHelper module but I
|
84
|
+
# couldn't get the helper to load after Hyrax::UrlHelper in
|
85
|
+
# order to overwrite the #url_for_document method. NOTE: In any event,
|
86
|
+
# this method needs to behave roughly the same way as
|
87
|
+
# CurationCocerns::UrlHelper#url_for_document, so if that method changes
|
88
|
+
# change this one accordingly.
|
89
|
+
# def url_for_document(doc, _options = {})
|
90
|
+
# polymorphic_path([preservation, doc])
|
91
|
+
# end
|
92
|
+
|
93
|
+
def search_state
|
94
|
+
@search_state ||= Hyrax::Preservation::SearchState.new(params, blacklight_config, self)
|
95
|
+
end
|
96
|
+
|
97
|
+
def display_premis_agent(opts={})
|
98
|
+
solr_doc = opts[:document]
|
99
|
+
premis_agent_mailto_uri = solr_doc[opts[:field]]
|
100
|
+
premis_agent_mailto_uri.first.sub(/^mailto\:/, '')
|
101
|
+
end
|
102
|
+
|
103
|
+
def display_premis_event_date_time(opts={})
|
104
|
+
solr_doc = opts[:document]
|
105
|
+
premis_event_date_time = solr_doc[opts[:field]]
|
106
|
+
Date.parse(premis_event_date_time.to_s).strftime('%Y-%m-%d')
|
107
|
+
end
|
108
|
+
|
109
|
+
def display_related_file(opts={})
|
110
|
+
# TODO: Is there a better way than having the controller send back HTML?
|
111
|
+
# TODO: Is there a better way to fetch the FileSet ID and Title? This way is confusing.
|
112
|
+
solr_doc = opts[:document]
|
113
|
+
file_set_id = solr_doc[:hasEventRelatedObject_ssim].first
|
114
|
+
file_set_url = Rails.application.routes.url_helpers.hyrax_file_set_path(id: file_set_id)
|
115
|
+
|
116
|
+
# TODO: this is totally klugey. We're pulling back the FileSet object from Fedora in order to get
|
117
|
+
# a good name to display it with. Originally, we were getting this value from the Solr document of
|
118
|
+
# the PreservationEvent object, but we ran into an issue where the PreservationEventIndexer does
|
119
|
+
# not know which FileSet property has been populated with a good, representative name for the FileSet
|
120
|
+
# at the time of indexing, because that is determined by configuration within the host app in any one of:
|
121
|
+
# 1. the FileSet model
|
122
|
+
# 1. the ingest configuration of the FileSet if using hyrax-ingest.
|
123
|
+
# 1. the FileSet indexer
|
124
|
+
# So either this value needs to be configurable within the host app,
|
125
|
+
# or the PreservationEventIndexer (in the hyrax-preservation gem) needs to have similar fallback logic
|
126
|
+
# when indexing a representative name for the FileSet.
|
127
|
+
file_set = ::FileSet.find(file_set_id)
|
128
|
+
file_set_title = file_set&.title&.first || file_set&.label || file_set&.filename&.first
|
129
|
+
"<a href='#{file_set_url}'>#{file_set_title}</a>".html_safe
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Hyrax
|
2
|
+
module Preservation
|
3
|
+
class EventIndexer < ActiveFedora::IndexingService
|
4
|
+
def generate_solr_document
|
5
|
+
super.tap do |solr_doc|
|
6
|
+
# TODO: Some of the conditionals checking for existence of properties
|
7
|
+
# may be removed after require those fields with validations on the
|
8
|
+
# model.
|
9
|
+
|
10
|
+
if object.premis_event_related_object
|
11
|
+
Solrizer.set_field(solr_doc,
|
12
|
+
'related_file_title',
|
13
|
+
object.premis_event_related_object.label,
|
14
|
+
:stored_searchable)
|
15
|
+
end
|
16
|
+
|
17
|
+
unless object.premis_event_type.empty?
|
18
|
+
# Index the PREMIS event type.
|
19
|
+
# NOTE: the value we index is only the last URI segment, which is a
|
20
|
+
# 3-letter abbreviation.
|
21
|
+
Solrizer.set_field(solr_doc,
|
22
|
+
'premis_event_type',
|
23
|
+
shortened_field_val = URI(object.premis_event_type.first.id).path.split('/').last,
|
24
|
+
:symbol)
|
25
|
+
end
|
26
|
+
|
27
|
+
unless object.premis_agent.empty?
|
28
|
+
# Index the PREMIS agent, under the assumption that is a mailto: URI.
|
29
|
+
# NOTE: The value we index is only the amil address, without the "mailto:" part.
|
30
|
+
Solrizer.set_field(solr_doc,
|
31
|
+
'premis_agent',
|
32
|
+
object.premis_agent.first.id.sub(/^mailto:/, ''),
|
33
|
+
:symbol)
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
# If the PreservationEvent's agent is found in the db,
|
38
|
+
# then index that user's full name as well.
|
39
|
+
# TODO: Not sure if this is a good idea.
|
40
|
+
# How much metadata about the agent should we index for PreservationEvents?
|
41
|
+
# if object.premis_agent_db_user
|
42
|
+
# Solrizer.set_field(solr_doc,
|
43
|
+
# 'premis_agent_full_name',
|
44
|
+
# object.premis_agent_db_user.first.id,
|
45
|
+
# :stored_searchable)
|
46
|
+
# end
|
47
|
+
|
48
|
+
unless object.premis_event_date_time.empty?
|
49
|
+
# Index the PREMIS event date time as a date.
|
50
|
+
Solrizer.set_field(solr_doc,
|
51
|
+
'premis_event_date_time',
|
52
|
+
object.premis_event_date_time.first,
|
53
|
+
:stored_searchable)
|
54
|
+
|
55
|
+
# Index the PREMIS event date time as an integer, for range queries.
|
56
|
+
Solrizer.set_field(solr_doc,
|
57
|
+
'premis_event_date_time_integer',
|
58
|
+
object.premis_event_date_time.first.strftime('%Y%m%d').to_i,
|
59
|
+
Solrizer::Descriptor.new(:long, :stored, :indexed))
|
60
|
+
end
|
61
|
+
|
62
|
+
unless object.premis_event_outcome.empty?
|
63
|
+
# Index the PREMIS event outcome.
|
64
|
+
Solrizer.set_field(solr_doc,
|
65
|
+
'premis_event_outcome',
|
66
|
+
object.premis_event_outcome.first,
|
67
|
+
:stored_searchable)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Hyrax
|
2
|
+
module Preservation
|
3
|
+
class Event < ActiveFedora::Base
|
4
|
+
type ::RDF::Vocab::PREMIS.Event
|
5
|
+
|
6
|
+
belongs_to :premis_event_related_object, predicate: ::RDF::Vocab::PREMIS.hasEventRelatedObject, class_name: ::FileSet
|
7
|
+
|
8
|
+
property :premis_event_type, predicate: ::RDF::Vocab::PREMIS.hasEventType
|
9
|
+
property :premis_agent, predicate: ::RDF::Vocab::PREMIS.hasAgent
|
10
|
+
property :premis_event_date_time, predicate: ::RDF::Vocab::PREMIS.hasEventDateTime
|
11
|
+
property :premis_event_outcome, predicate: ::RDF::Vocab::PREMIS.hasEventOutcome
|
12
|
+
property :premis_event_detail, predicate: ::RDF::Vocab::PREMIS.hasEventDetail
|
13
|
+
|
14
|
+
def user_from_db
|
15
|
+
@user_from_db ||= User.where(email: premis_agent)
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return [String] the label of the PREMIS event type that corresponds
|
19
|
+
# with the URI from the first value of the #premis_event_type property.
|
20
|
+
def premis_event_type_label
|
21
|
+
premis_event_type_object.label
|
22
|
+
end
|
23
|
+
|
24
|
+
def premis_event_type_abbr
|
25
|
+
premis_event_type_object.abbr
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.indexer
|
29
|
+
EventIndexer
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
# @return [Preservation::PremisEventType] first PremisEventType instance
|
34
|
+
# found where Preservation::PremisEventType#uri matches first value
|
35
|
+
# found in #premis_event_type property.
|
36
|
+
def premis_event_type_object
|
37
|
+
@premis_event_type_object ||= Preservation::PremisEventType.find_by_uri(premis_event_type.first.id)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# A basic PORO model for PREMIS event types.
|
2
|
+
#
|
3
|
+
# The data for this model is not persisted to any data store. It is just
|
4
|
+
# hardcoded (see Preservation::PremisEventyType.all).
|
5
|
+
#
|
6
|
+
# While only the URI of a PREMIS event type is stored on the
|
7
|
+
# Preservation::Event#premis_event_type property, this PORO is used to pair
|
8
|
+
# the URI with an abbreviation and a label.
|
9
|
+
module Hyrax
|
10
|
+
module Preservation
|
11
|
+
class PremisEventType
|
12
|
+
attr_reader :abbr, :label
|
13
|
+
|
14
|
+
def initialize(abbr, label='')
|
15
|
+
@abbr = abbr
|
16
|
+
@label = label
|
17
|
+
end
|
18
|
+
|
19
|
+
def uri
|
20
|
+
::RDF::Vocab::PremisEventType.send(abbr)
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [Array] list of all available PremisEventType instances.
|
24
|
+
def self.all
|
25
|
+
@all ||= [
|
26
|
+
new('cap', 'PREMIS Capture'),
|
27
|
+
new('com', 'PREMIS Compression'),
|
28
|
+
new('cre', 'PREMIS Creation'),
|
29
|
+
new('dea', 'PREMIS Deaccession'),
|
30
|
+
new('dec', 'PREMIS Decryption'),
|
31
|
+
new('del', 'PREMIS Deletion'),
|
32
|
+
new('dig', 'PREMIS Digital Signature Validation'),
|
33
|
+
new('fix', 'PREMIS Fixity Check'),
|
34
|
+
new('ing', 'PREMIS Ingestion'),
|
35
|
+
new('mes', 'PREMIS Message Digest Calculation'),
|
36
|
+
new('mig', 'PREMIS Migration'),
|
37
|
+
new('nor', 'PREMIS Normalization'),
|
38
|
+
new('rep', 'PREMIS Replication'),
|
39
|
+
new('val', 'PREMIS Validation'),
|
40
|
+
new('vir', 'PREMIS Virus Check')
|
41
|
+
]
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param [String] URI to use for comparison. Note #to_s is called on the
|
45
|
+
# param before comparing.
|
46
|
+
# @return [Preservation::PremisEventType] first found instance with URI
|
47
|
+
# that matches parameter.
|
48
|
+
def self.find_by_uri(uri)
|
49
|
+
result = all.find { |record| record.uri.to_s == uri.to_s }
|
50
|
+
raise NotFound.new("PremisEventType with URI \"#{uri.to_s}\" was not found") unless result
|
51
|
+
result
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.find_by_abbr(abbr)
|
55
|
+
result = all.find { |record| record.abbr == abbr }
|
56
|
+
raise NotFound.new("PremisEventType with abbreviation \"#{abbr}\" was not found") unless result
|
57
|
+
result
|
58
|
+
end
|
59
|
+
|
60
|
+
# Custom Error Classes
|
61
|
+
class NotFound < StandardError; end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Hyrax
|
2
|
+
module Preservation
|
3
|
+
class EventIndexPresenter < Blacklight::IndexPresenter
|
4
|
+
# Returns the value of PremisEventType#label for the PremisEventType instance
|
5
|
+
# whose #abbr value matches that which is in the solr document.
|
6
|
+
def search_result_title
|
7
|
+
premis_event_type = PremisEventType.all.find { |premis_event_type| premis_event_type.abbr == document.first(:premis_event_type_ssim) }
|
8
|
+
premis_event_type.label
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Hyrax
|
2
|
+
module Preservation
|
3
|
+
class EventShowPresenter < Blacklight::ShowPresenter
|
4
|
+
def heading
|
5
|
+
premis_event_type_abbr = document[Solrizer.solr_name(:premis_event_type, :symbol)].first
|
6
|
+
premis_event_type = Preservation::PremisEventType.all.find { |premis_event_type| premis_event_type.abbr == premis_event_type_abbr }
|
7
|
+
premis_event_type.label
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Hyrax
|
2
|
+
module Preservation
|
3
|
+
class EventsSearchBuilder < Blacklight::SearchBuilder
|
4
|
+
include Blacklight::Solr::SearchBuilderBehavior
|
5
|
+
|
6
|
+
self.default_processor_chain += [:only_models_for_preservation_events, :apply_premis_event_date_time_filter,
|
7
|
+
:apply_premis_event_type_filter, :apply_premis_agent_filter,
|
8
|
+
:apply_premis_event_related_object_filter]
|
9
|
+
|
10
|
+
|
11
|
+
def only_models_for_preservation_events(solr_params)
|
12
|
+
solr_params[:fq] ||= []
|
13
|
+
solr_params[:fq] << "{!terms f=has_model_ssim}Hyrax::Preservation::Event"
|
14
|
+
end
|
15
|
+
|
16
|
+
def apply_premis_event_date_time_filter(solr_params)
|
17
|
+
if premis_event_date_time_filter
|
18
|
+
solr_params[:fq] ||= []
|
19
|
+
solr_params[:fq] << premis_event_date_time_filter
|
20
|
+
end
|
21
|
+
solr_params
|
22
|
+
end
|
23
|
+
|
24
|
+
def apply_premis_event_type_filter(solr_params)
|
25
|
+
if premis_event_type_filter
|
26
|
+
solr_params[:fq] ||= []
|
27
|
+
solr_params[:fq] << premis_event_type_filter
|
28
|
+
end
|
29
|
+
solr_params
|
30
|
+
end
|
31
|
+
|
32
|
+
def apply_premis_agent_filter(solr_params)
|
33
|
+
if premis_agent_filter
|
34
|
+
solr_params[:fq] ||= []
|
35
|
+
solr_params[:fq] << premis_agent_filter
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def apply_premis_event_related_object_filter(solr_params)
|
40
|
+
if premis_event_related_object_filter
|
41
|
+
solr_params[:fq] ||= []
|
42
|
+
solr_params[:fq] << premis_event_related_object_filter
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# Returns a date/time range for a Solr query for the 'after' and 'before'
|
49
|
+
# URL params.
|
50
|
+
def premis_event_date_time_filter
|
51
|
+
@premis_event_date_time_filter ||= begin
|
52
|
+
if premis_event_date_time_before || premis_event_date_time_after
|
53
|
+
range = "#{premis_event_date_time_after || '*'} TO #{premis_event_date_time_before || '*'}"
|
54
|
+
"premis_event_date_time_dtsim:[#{range}]"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns the 'before' date time formatted for a Solr query.
|
60
|
+
def premis_event_date_time_before
|
61
|
+
@premis_event_date_time_before ||= formatted_premis_event_date_time(blacklight_params['before'])
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns the 'after' date time formatted for a Solr query.
|
65
|
+
def premis_event_date_time_after
|
66
|
+
@premis_event_date_time_after ||= formatted_premis_event_date_time(blacklight_params['after'])
|
67
|
+
end
|
68
|
+
|
69
|
+
# Converts an unformatted date (as passed in via URL) to a date formatted
|
70
|
+
# for a Solr query.
|
71
|
+
def formatted_premis_event_date_time(unformatted_date)
|
72
|
+
DateTime.parse(unformatted_date.to_s).utc.strftime("%Y-%m-%dT%H:%M:%SZ")
|
73
|
+
rescue ArgumentError => e
|
74
|
+
nil
|
75
|
+
end
|
76
|
+
|
77
|
+
def premis_event_type_filter
|
78
|
+
@premis_event_type_filter ||= begin
|
79
|
+
if blacklight_params['premis_event_type']
|
80
|
+
valid_premis_abbrs = blacklight_params['premis_event_type'] & Hyrax::Preservation::PremisEventType.all.map(&:abbr)
|
81
|
+
"(#{valid_premis_abbrs.map { |abbr| "premis_event_type_ssim:#{abbr}"}.join(" OR ")})"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def premis_agent_filter
|
87
|
+
@premis_agent_filter ||= begin
|
88
|
+
if blacklight_params['agent'].present?
|
89
|
+
# TODO: sanitize URL parameters. Do not simply trust user input.
|
90
|
+
"premis_agent_ssim:#{blacklight_params['agent']}"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def premis_event_related_object_filter
|
96
|
+
@premis_event_related_object_filter ||= begin
|
97
|
+
if blacklight_params['related_object'].present?
|
98
|
+
# TODO: sanitize URL parameters. Do not simply trust user input.
|
99
|
+
"hasEventRelatedObject_ssim:#{blacklight_params['related_object']}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= render 'catalog/document', document: event, document_counter: event_counter %>
|
@@ -0,0 +1,6 @@
|
|
1
|
+
<div>
|
2
|
+
<%= link_to "Clear All Filters", hyrax_preservation.events_url %>
|
3
|
+
</div>
|
4
|
+
<%= render 'hyrax/preservation/events/filter_search/date_range' %>
|
5
|
+
<%= render 'hyrax/preservation/events/filter_search/premis_event_type' %>
|
6
|
+
<%= render 'hyrax/preservation/events/filter_search/premis_agent' %>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<%
|
2
|
+
# NOTE: This overrides Hyrax's
|
3
|
+
# app/views/catalog/_index_header_list_default.html.erb which (at the time of
|
4
|
+
# this writing) only calls `document.title_or_label`, where `document` is a
|
5
|
+
# `SolrDocument` instance. We need to use a presenter object, because we use a
|
6
|
+
# small bit of logic to return the title of a search result. Hyrax will
|
7
|
+
# probably be upgraded to use a presenter in it's own version of this view
|
8
|
+
# partial in the near future, but until then, we override it here.
|
9
|
+
|
10
|
+
# Furthermore, since we are using our own custom presenter, and our own custom
|
11
|
+
# view partial, configuring the title field using `config.index.title_file` in
|
12
|
+
# the EventsController's `configure_blacklight` block has no effect here. Instead,
|
13
|
+
# we're just overriding the default index presenter, giving it a special
|
14
|
+
# method, and calling that special method from this overridden partial.
|
15
|
+
|
16
|
+
# Confused yet? Yeah, me too.
|
17
|
+
%>
|
18
|
+
<h2>
|
19
|
+
<%= link_to index_presenter(document).search_result_title, document %>
|
20
|
+
</h2>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<%
|
2
|
+
# This is an override of a partial from Blacklight 6.7.3
|
3
|
+
# in app/views/catalog/_previous_next_doc.html.erb.
|
4
|
+
# See inline comment below for details of why the override is needed.
|
5
|
+
%>
|
6
|
+
|
7
|
+
<% #Using the Bootstrap Pagination class -%>
|
8
|
+
<% #DEPRECATED - using id="previousNextDocument" as a selector is deprecated and will be removed in Blacklight 6.0 %>
|
9
|
+
<div id='previousNextDocument' class='pagination-search-widgets'>
|
10
|
+
<% if @previous_document || @next_document %>
|
11
|
+
<div class="page_links">
|
12
|
+
<%= link_to_previous_document @previous_document %> |
|
13
|
+
|
14
|
+
<%= item_page_entry_info %> |
|
15
|
+
|
16
|
+
<%= link_to_next_document @next_document %>
|
17
|
+
</div>
|
18
|
+
<% end %>
|
19
|
+
<% if current_search_session %>
|
20
|
+
<div class="pull-right search-widgets">
|
21
|
+
<%
|
22
|
+
# Calling #link_back_to_catalog here results in a routing error: no route matches "preservatio/catalog"
|
23
|
+
# Filed a detailed bug: https://github.com/projectblacklight/blacklight/issues/1647
|
24
|
+
# In the meantime, just skip the link back to the catalog.
|
25
|
+
%>
|
26
|
+
<%=link_to t('blacklight.search.start_over'), start_over_path(current_search_session.try(:query_params) || {}), id: 'startOverLink', class: 'btn' %>
|
27
|
+
</div>
|
28
|
+
<% end %>
|
29
|
+
</div>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<h2>Date</h2>
|
2
|
+
<form id="date_time_range_filter" action="<%= hyrax_preservation.events_url %>">
|
3
|
+
<label>From</label>
|
4
|
+
<input name="after" value="<%= params['after'] %>" />
|
5
|
+
<label>To</label>
|
6
|
+
<input name="before" value="<%= params['before'] %>" />
|
7
|
+
|
8
|
+
<!-- TODO: This logic needs to be replicated for all filter forms. Better in a helper method? -->
|
9
|
+
<% Rack::Utils.parse_query(request.query_string).except("after", "before").each do |param, val| %>
|
10
|
+
<% # Sometimes `val` may be an array, but not always. So we just array-ify
|
11
|
+
# it here to cover both cases. %>
|
12
|
+
<% Array(val).each do |single_val| %>
|
13
|
+
<input type="hidden" name="<%= param %>" value="<%= single_val %>" />
|
14
|
+
<% end %>
|
15
|
+
<% end %>
|
16
|
+
|
17
|
+
<button type="submit">Submit</button>
|
18
|
+
</form>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<h2>PREMIS Agent</h2>
|
2
|
+
<form id="premis_agent_filter" action="<%= hyrax_preservation.events_url %>">
|
3
|
+
<label for="agent">Agent</label>
|
4
|
+
<input id="agent" name="agent" value="<%= params['agent'] %>" />
|
5
|
+
<!-- TODO: This logic needs to be replicated for all filter forms. Better in a helper method? -->
|
6
|
+
<% Rack::Utils.parse_query(request.query_string).except("agent").each do |param, val| %>
|
7
|
+
<% # Sometimes `val` may be an array, but not always. So we just array-ify
|
8
|
+
# it here to cover both cases. %>
|
9
|
+
<% Array(val).each do |single_val| %>
|
10
|
+
<input type="hidden" name="<%= param %>" value="<%= single_val %>" />
|
11
|
+
<% end %>
|
12
|
+
<% end %>
|
13
|
+
|
14
|
+
<button type="submit">Submit</button>
|
15
|
+
</form>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<h2>PREMIS Event Type</h2>
|
2
|
+
<form id="premis_event_type_filter" action="<%= hyrax_preservation.events_url %>">
|
3
|
+
<% Hyrax::Preservation::PremisEventType.all.each do |premis_event_type| %>
|
4
|
+
<input type="checkbox" id="premis_event_type_<%= premis_event_type.abbr %>" name="premis_event_type[]" value="<%= premis_event_type.abbr %>" <%= Array(request.params['premis_event_type']).include?(premis_event_type.abbr) ? 'checked="checked"' : '' %>/>
|
5
|
+
<label for="premis_event_type_<%= premis_event_type.abbr %>"><%= premis_event_type.label.sub(/^PREMIS/ , '') %></label>
|
6
|
+
<% end %>
|
7
|
+
|
8
|
+
<!-- TODO: This logic needs to be replicated for all filter forms. Better in a helper method? -->
|
9
|
+
<% Rack::Utils.parse_query(request.query_string).except("premis_event_type[]").each do |param, val| %>
|
10
|
+
<% # Sometimes `val` may be an array, but not always. So we just array-ify
|
11
|
+
# it here to cover both cases. %>
|
12
|
+
<% Array(val).each do |single_val| %>
|
13
|
+
<input type="hidden" name="<%= param %>" value="<%= single_val %>" />
|
14
|
+
<% end %>
|
15
|
+
<% end %>
|
16
|
+
|
17
|
+
<button type="submit">Submit</button>
|
18
|
+
</form>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Preservation</title>
|
5
|
+
<%= stylesheet_link_tag "preservation/application", media: "all" %>
|
6
|
+
<%= javascript_include_tag "preservation/application" %>
|
7
|
+
<%= csrf_meta_tags %>
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
|
11
|
+
<%= yield %>
|
12
|
+
|
13
|
+
</body>
|
14
|
+
</html>
|
data/config/routes.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Hyrax
|
2
|
+
module Preservation
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
|
5
|
+
desc <<-EOS
|
6
|
+
This generator makes the following changes to your application:
|
7
|
+
1. Adds Preservation routes to your ./config/routes.rb
|
8
|
+
EOS
|
9
|
+
|
10
|
+
# def inject_search_builder_behavior
|
11
|
+
# inject_into_file 'app/models/search_builder.rb', after: "include Hyrax::SearchFilters\n" do
|
12
|
+
# "\tinclude Hydradam::SearchBuilderBehavior\n"
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
|
16
|
+
def add_routes
|
17
|
+
route "mount Hyrax::Preservation::Engine, at: '/preservation'"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require_relative 'event_logger'
|
2
|
+
|
3
|
+
|
4
|
+
module Hyrax
|
5
|
+
module Preservation
|
6
|
+
class Demo
|
7
|
+
def self.clean_slate!
|
8
|
+
delete_all_file_sets!
|
9
|
+
delete_all_preservation_events!
|
10
|
+
delete_all_hydra_access_controls!
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.delete_all_file_sets!
|
14
|
+
FileSet.all.each { |fs| fs.delete }
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.delete_all_preservation_events!
|
18
|
+
Preservation::Event.all.each { |pe| pe.delete }
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.delete_all_hydra_access_controls!
|
22
|
+
::Hydra::AccessControl.all.each { |ac| ac.delete }
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.new_file_set
|
26
|
+
FileSet.new.tap do |fs|
|
27
|
+
fs.apply_depositor_metadata(User.first)
|
28
|
+
fs.save!
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.run_once!
|
33
|
+
file_set = new_file_set
|
34
|
+
|
35
|
+
# NOTE: PreservationEventLogger is a stateless service object that provides a "use anywhere" interface
|
36
|
+
# for logging preservation events. We don't have to use this pattern, but it has it's advantages.
|
37
|
+
|
38
|
+
# Create two sets of people for some realistic randomness in the demo records.
|
39
|
+
preservation_people = ['jlhardes@iu.edu', 'heidowdi@indiana.edu']
|
40
|
+
ingest_people = ['akhedkar@iu.edu', 'afredmyers@gmail.com']
|
41
|
+
|
42
|
+
|
43
|
+
# Create a fake capture date of sometime between now and 90 days ago.
|
44
|
+
capture_date = DateTime.now - rand(2..90).days
|
45
|
+
# Create a fake fixity check date sometime between the capture date and now.
|
46
|
+
fixity_date = rand(capture_date..DateTime.now)
|
47
|
+
# Create a fake ingest date of sometime beetween the capture date and now.
|
48
|
+
ingest_date = rand(capture_date..DateTime.now)
|
49
|
+
|
50
|
+
# Create an event for the file's capture.
|
51
|
+
Preservation::EventLogger.log_preservation_event(
|
52
|
+
file_set: file_set,
|
53
|
+
premis_event_type: 'cap',
|
54
|
+
premis_agent: preservation_people.sample,
|
55
|
+
premis_event_date_time: capture_date
|
56
|
+
)
|
57
|
+
|
58
|
+
# Create an event for the file's fixity check.
|
59
|
+
Preservation::EventLogger.log_preservation_event(
|
60
|
+
file_set: file_set,
|
61
|
+
premis_event_type: 'fix',
|
62
|
+
premis_agent: preservation_people.sample,
|
63
|
+
premis_event_date_time: fixity_date
|
64
|
+
)
|
65
|
+
|
66
|
+
# Create an event for the file's ingestion.
|
67
|
+
Preservation::EventLogger.log_preservation_event(
|
68
|
+
file_set: file_set,
|
69
|
+
premis_event_type: 'ing',
|
70
|
+
premis_agent: ingest_people.sample,
|
71
|
+
premis_event_date_time: ingest_date
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.run!(iterations=1)
|
76
|
+
iterations.times { self.run_once! }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Hyrax::Preservation
|
2
|
+
class Engine < ::Rails::Engine
|
3
|
+
isolate_namespace Hyrax::Preservation
|
4
|
+
|
5
|
+
config.autoload_paths += %W(
|
6
|
+
#{config.root}/app/helpers
|
7
|
+
#{config.root}/app/indexers
|
8
|
+
#{config.root}/app/presenters
|
9
|
+
#{config.root}/app/search_builders
|
10
|
+
#{config.root}/lib/preservation
|
11
|
+
)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# TODO: Only use this as-is for Demo. If you want to use it as a service object
|
2
|
+
# it should be moved to a different location probably.
|
3
|
+
module Hyrax
|
4
|
+
module Preservation
|
5
|
+
class EventLogger
|
6
|
+
def self.log_preservation_event(opts={})
|
7
|
+
Preservation::Event.new.tap do |pe|
|
8
|
+
pe.premis_event_type += [ Preservation::PremisEventType.all.select { |premis_event_type| premis_event_type.abbr == opts[:premis_event_type].to_sym } ]
|
9
|
+
pe.premis_event_related_object = opts[:file_set]
|
10
|
+
# Assume opts[:premis_agent] is an email address, and make a 'mailto:' RDF::URI out of it.
|
11
|
+
pe.premis_agent += [::RDF::URI.new("mailto:#{opts[:premis_agent]}")]
|
12
|
+
pe.premis_event_date_time += [opts[:premis_event_date_time]]
|
13
|
+
pe.save!
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'hyrax/preservation'
|
2
|
+
require 'solr_wrapper'
|
3
|
+
require 'fcrepo_wrapper'
|
4
|
+
require 'active_support/core_ext/hash/keys'
|
5
|
+
|
6
|
+
module Hyrax
|
7
|
+
module Preservation
|
8
|
+
class ServiceEnvironment
|
9
|
+
attr_reader :env
|
10
|
+
|
11
|
+
def initialize(env)
|
12
|
+
@env = (env || 'development').to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
def start
|
16
|
+
wrap do
|
17
|
+
begin
|
18
|
+
puts "\nServices started. Ctrl+C to stop.\n\n"
|
19
|
+
sleep
|
20
|
+
rescue Interrupt
|
21
|
+
# TODO: Why doesn't this message get printed?
|
22
|
+
puts "Stopping services..."
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def wrap
|
28
|
+
SolrWrapper.wrap(solr_wrapper_config) do |solr_wrapper_instance|
|
29
|
+
# If a solr collection exists, but is not configured to persist,
|
30
|
+
# then we must delete it before we try to re-create it. Otherwise
|
31
|
+
# SolrWrapper with throw an error. Note this is kind of an awkward
|
32
|
+
# way to check for existence of the core, but it's due to current
|
33
|
+
# limitation of the SolrWrapper interfaces.
|
34
|
+
if !solr_wrapper_config[:collection][:persist] && SolrWrapper::Client.new(solr_wrapper_instance.url).exists?(solr_wrapper_config[:collection][:name])
|
35
|
+
solr_wrapper_instance.delete solr_wrapper_config[:collection][:name]
|
36
|
+
end
|
37
|
+
|
38
|
+
solr_wrapper_instance.with_collection(solr_wrapper_config[:collection]) do
|
39
|
+
FcrepoWrapper.wrap(fcrepo_wrapper_config) do
|
40
|
+
yield
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def solr_wrapper_config
|
49
|
+
@solr_wrapper_config ||= YAML.load(File.read(solr_wrapper_config_path)).deep_symbolize_keys
|
50
|
+
end
|
51
|
+
|
52
|
+
def solr_wrapper_config_path
|
53
|
+
File.join(Hyrax::Preservation.root, ".solr_wrapper.#{env}.yml")
|
54
|
+
end
|
55
|
+
|
56
|
+
def fcrepo_wrapper_config
|
57
|
+
@fcrepo_wrapper_config ||= YAML.load(File.read(fcrepo_wrapper_config_path)).deep_symbolize_keys
|
58
|
+
end
|
59
|
+
|
60
|
+
def fcrepo_wrapper_config_path
|
61
|
+
File.join(Hyrax::Preservation.root, ".fcrepo_wrapper.#{env}.yml")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
metadata
ADDED
@@ -0,0 +1,307 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hyrax-preservation
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrew Myers
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-03-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: hyrax
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.0.4
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.0'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.0.4
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: jquery-ui-rails
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '5.0'
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 5.0.5
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '5.0'
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 5.0.5
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: sqlite3
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '1.3'
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 1.3.13
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '1.3'
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 1.3.13
|
73
|
+
- !ruby/object:Gem::Dependency
|
74
|
+
name: rspec-rails
|
75
|
+
requirement: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - "~>"
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '3.6'
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 3.6.1
|
83
|
+
type: :development
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.6'
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 3.6.1
|
93
|
+
- !ruby/object:Gem::Dependency
|
94
|
+
name: capybara
|
95
|
+
requirement: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - "~>"
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '2.15'
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 2.15.1
|
103
|
+
type: :development
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "~>"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '2.15'
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: 2.15.1
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: solr_wrapper
|
115
|
+
requirement: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - "~>"
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '1.1'
|
120
|
+
- - '='
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: 1.1.0
|
123
|
+
type: :development
|
124
|
+
prerelease: false
|
125
|
+
version_requirements: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - "~>"
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '1.1'
|
130
|
+
- - '='
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: 1.1.0
|
133
|
+
- !ruby/object:Gem::Dependency
|
134
|
+
name: fcrepo_wrapper
|
135
|
+
requirement: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - "~>"
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0.8'
|
140
|
+
type: :development
|
141
|
+
prerelease: false
|
142
|
+
version_requirements: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - "~>"
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0.8'
|
147
|
+
- !ruby/object:Gem::Dependency
|
148
|
+
name: factory_girl_rails
|
149
|
+
requirement: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - "~>"
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '4.8'
|
154
|
+
- - ">="
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: 4.8.0
|
157
|
+
type: :development
|
158
|
+
prerelease: false
|
159
|
+
version_requirements: !ruby/object:Gem::Requirement
|
160
|
+
requirements:
|
161
|
+
- - "~>"
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
version: '4.8'
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: 4.8.0
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: pry-rails
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - "~>"
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0.3'
|
174
|
+
- - ">="
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: 0.3.6
|
177
|
+
type: :development
|
178
|
+
prerelease: false
|
179
|
+
version_requirements: !ruby/object:Gem::Requirement
|
180
|
+
requirements:
|
181
|
+
- - "~>"
|
182
|
+
- !ruby/object:Gem::Version
|
183
|
+
version: '0.3'
|
184
|
+
- - ">="
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: 0.3.6
|
187
|
+
- !ruby/object:Gem::Dependency
|
188
|
+
name: pry-byebug
|
189
|
+
requirement: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - "~>"
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '3.6'
|
194
|
+
- - ">="
|
195
|
+
- !ruby/object:Gem::Version
|
196
|
+
version: 3.6.0
|
197
|
+
type: :development
|
198
|
+
prerelease: false
|
199
|
+
version_requirements: !ruby/object:Gem::Requirement
|
200
|
+
requirements:
|
201
|
+
- - "~>"
|
202
|
+
- !ruby/object:Gem::Version
|
203
|
+
version: '3.6'
|
204
|
+
- - ">="
|
205
|
+
- !ruby/object:Gem::Version
|
206
|
+
version: 3.6.0
|
207
|
+
- !ruby/object:Gem::Dependency
|
208
|
+
name: launchy
|
209
|
+
requirement: !ruby/object:Gem::Requirement
|
210
|
+
requirements:
|
211
|
+
- - "~>"
|
212
|
+
- !ruby/object:Gem::Version
|
213
|
+
version: '2.4'
|
214
|
+
- - ">="
|
215
|
+
- !ruby/object:Gem::Version
|
216
|
+
version: 2.4.3
|
217
|
+
type: :development
|
218
|
+
prerelease: false
|
219
|
+
version_requirements: !ruby/object:Gem::Requirement
|
220
|
+
requirements:
|
221
|
+
- - "~>"
|
222
|
+
- !ruby/object:Gem::Version
|
223
|
+
version: '2.4'
|
224
|
+
- - ">="
|
225
|
+
- !ruby/object:Gem::Version
|
226
|
+
version: 2.4.3
|
227
|
+
- !ruby/object:Gem::Dependency
|
228
|
+
name: rb-readline
|
229
|
+
requirement: !ruby/object:Gem::Requirement
|
230
|
+
requirements:
|
231
|
+
- - "~>"
|
232
|
+
- !ruby/object:Gem::Version
|
233
|
+
version: '0.5'
|
234
|
+
type: :development
|
235
|
+
prerelease: false
|
236
|
+
version_requirements: !ruby/object:Gem::Requirement
|
237
|
+
requirements:
|
238
|
+
- - "~>"
|
239
|
+
- !ruby/object:Gem::Version
|
240
|
+
version: '0.5'
|
241
|
+
description: Hyrax Preservation provides models for storing and searching for preservation
|
242
|
+
metadata.
|
243
|
+
email:
|
244
|
+
- afredmyers@gmail.com
|
245
|
+
executables: []
|
246
|
+
extensions: []
|
247
|
+
extra_rdoc_files: []
|
248
|
+
files:
|
249
|
+
- MIT-LICENSE
|
250
|
+
- README.md
|
251
|
+
- Rakefile
|
252
|
+
- app/assets/config/preservation_manifest.js
|
253
|
+
- app/assets/javascripts/hyrax/preservation/application.js
|
254
|
+
- app/assets/stylesheets/hyrax/preservation/application.css
|
255
|
+
- app/controllers/hyrax/preservation/events_controller.rb
|
256
|
+
- app/helpers/hyrax/preservation/application_helper.rb
|
257
|
+
- app/indexers/hyrax/preservation/event_indexer.rb
|
258
|
+
- app/jobs/hyrax/preservation/application_job.rb
|
259
|
+
- app/mailers/hyrax/preservation/application_mailer.rb
|
260
|
+
- app/models/hyrax/preservation/event.rb
|
261
|
+
- app/models/hyrax/preservation/premis_event_type.rb
|
262
|
+
- app/presenters/hyrax/preservation/event_index_presenter.rb
|
263
|
+
- app/presenters/hyrax/preservation/event_show_presenter.rb
|
264
|
+
- app/search_builders/hyrax/preservation/events_search_builder.rb
|
265
|
+
- app/views/hyrax/preservation/events/_event.html.erb
|
266
|
+
- app/views/hyrax/preservation/events/_filter_search.html.erb
|
267
|
+
- app/views/hyrax/preservation/events/_index_header_list_default.html.erb
|
268
|
+
- app/views/hyrax/preservation/events/_previous_next_doc.html.erb
|
269
|
+
- app/views/hyrax/preservation/events/filter_search/_date_range.html.erb
|
270
|
+
- app/views/hyrax/preservation/events/filter_search/_premis_agent.html.erb
|
271
|
+
- app/views/hyrax/preservation/events/filter_search/_premis_event_type.html.erb
|
272
|
+
- app/views/hyrax/preservation/events/index.html.erb
|
273
|
+
- app/views/layouts/hyrax/preservation/application.html.erb
|
274
|
+
- config/routes.rb
|
275
|
+
- lib/generators/hyrax/preservation/install_generator.rb
|
276
|
+
- lib/hyrax/preservation.rb
|
277
|
+
- lib/hyrax/preservation/demo.rb
|
278
|
+
- lib/hyrax/preservation/engine.rb
|
279
|
+
- lib/hyrax/preservation/event_logger.rb
|
280
|
+
- lib/hyrax/preservation/search_state.rb
|
281
|
+
- lib/hyrax/preservation/service_environment.rb
|
282
|
+
- lib/hyrax/preservation/version.rb
|
283
|
+
homepage: https://github.com/IUBLibTech/hyrax-preservation
|
284
|
+
licenses:
|
285
|
+
- MIT
|
286
|
+
metadata: {}
|
287
|
+
post_install_message:
|
288
|
+
rdoc_options: []
|
289
|
+
require_paths:
|
290
|
+
- lib
|
291
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
292
|
+
requirements:
|
293
|
+
- - ">="
|
294
|
+
- !ruby/object:Gem::Version
|
295
|
+
version: '0'
|
296
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
297
|
+
requirements:
|
298
|
+
- - ">="
|
299
|
+
- !ruby/object:Gem::Version
|
300
|
+
version: '0'
|
301
|
+
requirements: []
|
302
|
+
rubyforge_project:
|
303
|
+
rubygems_version: 2.7.6
|
304
|
+
signing_key:
|
305
|
+
specification_version: 4
|
306
|
+
summary: Preservation features for Hydra
|
307
|
+
test_files: []
|