fedora-migrate 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +19 -0
  5. data/Gemfile +7 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +31 -0
  8. data/Rakefile +5 -0
  9. data/config/fedora.yml +14 -0
  10. data/config/fedora3.yml +12 -0
  11. data/config/jetty.yml +6 -0
  12. data/config/solr.yml +15 -0
  13. data/fedora-migrate.gemspec +30 -0
  14. data/lib/fedora-migrate.rb +82 -0
  15. data/lib/fedora_migrate/datastream_mover.rb +78 -0
  16. data/lib/fedora_migrate/errors.rb +7 -0
  17. data/lib/fedora_migrate/file_configurator.rb +34 -0
  18. data/lib/fedora_migrate/hooks.rb +11 -0
  19. data/lib/fedora_migrate/logger.rb +36 -0
  20. data/lib/fedora_migrate/migration_options.rb +11 -0
  21. data/lib/fedora_migrate/mover.rb +44 -0
  22. data/lib/fedora_migrate/object_mover.rb +62 -0
  23. data/lib/fedora_migrate/permissions.rb +32 -0
  24. data/lib/fedora_migrate/permissions_mover.rb +31 -0
  25. data/lib/fedora_migrate/rdf_datastream_mover.rb +28 -0
  26. data/lib/fedora_migrate/rdf_datastream_parser.rb +29 -0
  27. data/lib/fedora_migrate/rels_ext_datastream_mover.rb +90 -0
  28. data/lib/fedora_migrate/repository_migrator.rb +60 -0
  29. data/lib/fedora_migrate/rights_metadata.rb +281 -0
  30. data/lib/fedora_migrate/rubydora_connection.rb +21 -0
  31. data/lib/fedora_migrate/triple_converter.rb +39 -0
  32. data/lib/fedora_migrate/version.rb +3 -0
  33. data/lib/tasks/fedora-migrate.rake +45 -0
  34. data/spec/fixtures/datastreams/rdf_ntriples_datastream.txt +2 -0
  35. data/spec/fixtures/datastreams/sufia-rb68xc089-characterization.xml +27 -0
  36. data/spec/fixtures/objects/f3-migration-a.xml +110 -0
  37. data/spec/fixtures/objects/gf-versioned-content.xml +2776 -0
  38. data/spec/fixtures/objects/sufia-batch-gf-1.xml +94 -0
  39. data/spec/fixtures/objects/sufia-batch-gf-2.xml +93 -0
  40. data/spec/fixtures/objects/sufia-batch.xml +51 -0
  41. data/spec/integration/content_versions_spec.rb +42 -0
  42. data/spec/integration/fedora3_interface_spec.rb +23 -0
  43. data/spec/integration/object_migration_spec.rb +112 -0
  44. data/spec/integration/permission_migration_spec.rb +13 -0
  45. data/spec/integration/rdf_migration_spec.rb +22 -0
  46. data/spec/integration/relationship_migration_spec.rb +51 -0
  47. data/spec/integration/repository_migration_spec.rb +59 -0
  48. data/spec/spec_helper.rb +39 -0
  49. data/spec/support/example_model.rb +36 -0
  50. data/spec/unit/datastream_mover_spec.rb +39 -0
  51. data/spec/unit/fedora_migrate_spec.rb +19 -0
  52. data/spec/unit/file_configurator_spec.rb +17 -0
  53. data/spec/unit/mover_spec.rb +39 -0
  54. data/spec/unit/object_mover_spec.rb +38 -0
  55. data/spec/unit/permissions_mover_spec.rb +53 -0
  56. data/spec/unit/rdf_datastream_mover_spec.rb +8 -0
  57. data/spec/unit/rdf_datastream_parser_spec.rb +38 -0
  58. data/spec/unit/rels_ext_datastream_mover_spec.rb +36 -0
  59. data/spec/unit/repository_migrator_spec.rb +43 -0
  60. data/spec/unit/rubydora_connection_spec.rb +25 -0
  61. data/spec/unit/triple_converter_spec.rb +35 -0
  62. data/tasks/dev.rake +37 -0
  63. metadata +246 -0
@@ -0,0 +1,11 @@
1
+ module FedoraMigrate
2
+ module MigrationOptions
3
+
4
+ attr_accessor :options, :conversions
5
+
6
+ def conversion_options
7
+ self.conversions = options.nil? ? [] : [options[:convert]].flatten
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,44 @@
1
+ module FedoraMigrate
2
+ class Mover
3
+
4
+ include MigrationOptions
5
+ include Hooks
6
+
7
+ attr_accessor :target, :source
8
+
9
+ def initialize *args
10
+ @source = args[0]
11
+ @target = args[1]
12
+ @options = args[2]
13
+ post_initialize
14
+ end
15
+
16
+ def post_initialize
17
+ end
18
+
19
+ def save
20
+ if target.save
21
+ Logger.info "success for target UID #{target_description}"
22
+ else
23
+ raise FedoraMigrate::Errors::MigrationError, "Failed to save target: #{target_errors}"
24
+ end
25
+ end
26
+
27
+ def target_errors
28
+ if target.respond_to?(:errors)
29
+ target.errors.full_messages.join(" -- ")
30
+ else
31
+ target.inspect
32
+ end
33
+ end
34
+
35
+ def target_description
36
+ if target.respond_to?(:id)
37
+ target.id
38
+ else
39
+ target.inspect
40
+ end
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,62 @@
1
+ module FedoraMigrate
2
+ class ObjectMover < Mover
3
+
4
+ RIGHTS_DATASTREAM = "rightsMetadata".freeze
5
+
6
+ def migrate
7
+ prepare_target
8
+ migrate_content_datastreams
9
+ conversions.collect { |ds| convert_rdf_datastream(ds) }
10
+ migrate_permissions
11
+ complete_target
12
+ end
13
+
14
+ def post_initialize
15
+ conversion_options
16
+ create_target_model if target.nil?
17
+ end
18
+
19
+ def prepare_target
20
+ Logger.info "running before_object_migration hooks"
21
+ before_object_migration
22
+ save
23
+ end
24
+
25
+ def complete_target
26
+ Logger.info "running after_object_migration hooks"
27
+ after_object_migration
28
+ save
29
+ end
30
+
31
+ private
32
+
33
+ def migrate_content_datastreams
34
+ target.attached_files.keys.each do |ds|
35
+ mover = FedoraMigrate::DatastreamMover.new(source.datastreams[ds.to_s], target.attached_files[ds.to_s])
36
+ mover.migrate
37
+ end
38
+ end
39
+
40
+ def convert_rdf_datastream ds
41
+ if source.datastreams.keys.include?(ds)
42
+ mover = FedoraMigrate::RDFDatastreamMover.new(source.datastreams[ds.to_s], target)
43
+ mover.migrate
44
+ end
45
+ end
46
+
47
+ def migrate_permissions
48
+ if source.datastreams.keys.include?(RIGHTS_DATASTREAM) && target.respond_to?(:permissions)
49
+ mover = FedoraMigrate::PermissionsMover.new(source.datastreams[RIGHTS_DATASTREAM], target)
50
+ mover.migrate
51
+ end
52
+ end
53
+
54
+ def create_target_model
55
+ afmodel = source.models.map { |m| m if m.match(/afmodel/) }.compact.first.split(/:/).last
56
+ Logger.info "found #{afmodel} in source object #{source.pid}"
57
+ @target = afmodel.constantize.new(id: source.pid.split(/:/).last)
58
+ end
59
+
60
+ end
61
+
62
+ end
@@ -0,0 +1,32 @@
1
+ module FedoraMigrate::Permissions
2
+
3
+ # Taken from Hydra::AccessControls::Permissions under version 7.2.2
4
+ #
5
+ # We need the reader methods to get permissions from the Fedora3
6
+ # rightsMetadata datastreams
7
+
8
+ def read_groups
9
+ rightsMetadata.groups.map {|k, v| k if v == 'read'}.compact
10
+ end
11
+
12
+ def edit_groups
13
+ rightsMetadata.groups.map {|k, v| k if v == 'edit'}.compact
14
+ end
15
+
16
+ def discover_groups
17
+ rightsMetadata.groups.map {|k, v| k if v == 'discover'}.compact
18
+ end
19
+
20
+ def read_users
21
+ rightsMetadata.users.map {|k, v| k if v == 'read'}.compact
22
+ end
23
+
24
+ def edit_users
25
+ rightsMetadata.users.map {|k, v| k if v == 'edit'}.compact
26
+ end
27
+
28
+ def discover_users
29
+ rightsMetadata.users.map {|k, v| k if v == 'discover'}.compact
30
+ end
31
+
32
+ end
@@ -0,0 +1,31 @@
1
+ module FedoraMigrate
2
+ class PermissionsMover < Mover
3
+
4
+ include FedoraMigrate::Permissions
5
+
6
+ attr_accessor :rightsMetadata
7
+
8
+ def post_initialize
9
+ if source.respond_to?(:content)
10
+ @rightsMetadata = datastream_from_content
11
+ end
12
+ end
13
+
14
+ def migrate
15
+ FedoraMigrate::Permissions.instance_methods.each do |permission|
16
+ Logger.info "setting #{permission} to #{self.send(permission)}"
17
+ target.send(permission.to_s+"=", self.send(permission))
18
+ end
19
+ save
20
+ end
21
+
22
+
23
+ private
24
+
25
+ def datastream_from_content ds = FedoraMigrate::RightsMetadata.new
26
+ ds.ng_xml = source.content
27
+ ds
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,28 @@
1
+ module FedoraMigrate
2
+ class RDFDatastreamMover < Mover
3
+
4
+ def migrate
5
+ Logger.info "converting datastream '#{source.dsid}' to RDF"
6
+ parse_rdf_triples
7
+ force_attribute_change
8
+ save
9
+ end
10
+
11
+ def parse_rdf_triples
12
+ parser = FedoraMigrate::RDFDatastreamParser.new(target.uri, source.content)
13
+ parser.parse
14
+ parser.statements.each do |statement|
15
+ target.resource << statement
16
+ end
17
+ end
18
+
19
+ # See projecthydra/active_fedora#540
20
+ # Forcibly setting each attribute's changed status to true
21
+ def force_attribute_change
22
+ target.class.delegated_attributes.keys.each do |term|
23
+ target.send(term+"_will_change!")
24
+ end
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,29 @@
1
+ module FedoraMigrate
2
+ class RDFDatastreamParser
3
+
4
+ attr_accessor :subject, :datastream, :statements
5
+
6
+ def initialize subject, content
7
+ @subject = subject
8
+ @datastream = content
9
+ @statements = []
10
+ end
11
+
12
+ def parse
13
+ datastream.split(/\n/).each do |s|
14
+ triple = FedoraMigrate::TripleConverter.new(s)
15
+ build_statement(triple) unless triple.predicate.nil?
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def build_statement triple
22
+ statement = RDF::Statement(RDF::URI.new(subject), triple.predicate, triple.object)
23
+ Logger.info "using converted rdf triple #{statement}"
24
+ statements << statement
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,90 @@
1
+ require 'rubydora'
2
+ module FedoraMigrate
3
+ class RelsExtDatastreamMover < Mover
4
+
5
+ attr_accessor :relationships, :ng_xml, :subject
6
+
7
+ RELS_EXT = Rubydora::RelationshipsMixin::RELS_EXT
8
+ RELS_EXT_DATASTREAM = "RELS-EXT".freeze
9
+
10
+ def post_initialize
11
+ retrieve_subject
12
+ @relationships ||= {}
13
+ @ng_xml = Nokogiri::XML(source.datastreams[RELS_EXT_DATASTREAM].content)
14
+ parse_relationships if has_relationships?
15
+ end
16
+
17
+ def has_relationships?
18
+ source.datastreams.keys.include?(RELS_EXT_DATASTREAM)
19
+ end
20
+
21
+ def migrate
22
+ relationships.each do |predicate, objects|
23
+ unless objects.empty?
24
+ if is_singular?(predicate.to_s)
25
+ objects.collect { |object| migrate_incomming_relationship(predicate, object) }
26
+ else
27
+ migrate_outgoing_relationship(predicate, objects)
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ # because of projecthydra/rubydora#90
36
+ def parse_relationships
37
+ RELS_EXT.keys.each do |key|
38
+ query = "//ns0:"+RELS_EXT[key].split(/#/).last
39
+ relationships[key.to_sym] = query_results(query)
40
+ end
41
+ end
42
+
43
+ def query_results query, results = Array.new
44
+ ng_xml.xpath(query).each do |predicate|
45
+ results << retrieve_object(predicate.attribute("resource").text.split(/:/).last)
46
+ end
47
+ return results
48
+ end
49
+
50
+ def retrieve_subject
51
+ @subject = ActiveFedora::Base.find(source.pid.split(/:/).last)
52
+ rescue ActiveFedora::ObjectNotFoundError
53
+ raise FedoraMigrate::Errors::MigrationError, "Source was not found in Fedora4. Did you migrated it?"
54
+ end
55
+
56
+ def retrieve_object id
57
+ object = ActiveFedora::Base.find(id)
58
+ rescue ActiveFedora::ObjectNotFoundError
59
+ raise FedoraMigrate::Errors::MigrationError, "Could not find object with id #{id}"
60
+ end
61
+
62
+ # TODO: This is problematic and may not work in all situations (issue #7)
63
+ def migrate_incomming_relationship predicate, object
64
+ Logger.info "adding #{subject.id} to #{object.id} with predicate #{predicate.to_s}"
65
+ object.reflections.each do |key, association|
66
+ unless association.predicate.to_s.split(/#/).empty?
67
+ if association.predicate.to_s.split(/#/).last.gsub(/is/,"").underscore == predicate.to_s
68
+ object.send(key.to_s) << subject
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ # TODO: Very stinky... needs a different approach (issue #7)
75
+ def migrate_outgoing_relationship predicate, objects
76
+ Logger.info "adding #{objects.count.to_s} members to #{subject.id} with predicate #{predicate.to_s}"
77
+ subject.reflections.each do |key, association|
78
+ if key.to_s.match(/_ids$/)
79
+ subject.send(key.to_s+"=", objects.collect { |o| o.id })
80
+ subject.save
81
+ end
82
+ end
83
+ end
84
+
85
+ def is_singular?(str)
86
+ str.singularize == str
87
+ end
88
+
89
+ end
90
+ end
@@ -0,0 +1,60 @@
1
+ module FedoraMigrate
2
+ class RepositoryMigrator
3
+
4
+ include MigrationOptions
5
+
6
+ attr_accessor :source_objects, :results, :namespace
7
+
8
+ def initialize namespace = nil, options = {}
9
+ @namespace = namespace || repository_namespace
10
+ @options = options
11
+ @source_objects = get_source_objects
12
+ @results = []
13
+ conversion_options
14
+ end
15
+
16
+ def migrate_objects
17
+ source_objects.each do |source|
18
+ Logger.info "Migrating source object #{source.pid}"
19
+ begin
20
+ results << { source.pid => [FedoraMigrate::ObjectMover.new(source, nil, options).migrate] }
21
+ rescue NameError => e
22
+ results << { source.pid => e.to_s }
23
+ rescue FedoraMigrate::Errors::MigrationError => e
24
+ results << { source.pid => e.to_s }
25
+ end
26
+ end
27
+ end
28
+
29
+ # TODO: need a reporting mechanism for results (issue #4)
30
+ def migrate_relationships
31
+ source_objects.each do |source|
32
+ Logger.info "Migrating relationships for source object #{source.pid}"
33
+ begin
34
+ FedoraMigrate::RelsExtDatastreamMover.new(source).migrate
35
+ rescue FedoraMigrate::Errors::MigrationError => e
36
+ results << { source.pid => e.to_s }
37
+ rescue ActiveFedora::AssociationTypeMismatch => e
38
+ results << { source.pid => e.to_s }
39
+ end
40
+ end
41
+ end
42
+
43
+ # TODO: page through all the objects (issue #6)
44
+ def get_source_objects
45
+ FedoraMigrate.source.connection.search(nil).collect { |o| qualifying_object(o) }.compact
46
+ end
47
+
48
+ private
49
+
50
+ def repository_namespace
51
+ FedoraMigrate.source.connection.repository_profile["repositoryPID"]["repositoryPID"].split(/:/).first.strip
52
+ end
53
+
54
+ def qualifying_object object
55
+ name = object.pid.split(/:/).first
56
+ return object if name.match(namespace)
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,281 @@
1
+ require 'active_support/core_ext/string'
2
+
3
+ module FedoraMigrate
4
+ # Implements Hydra RightsMetadata XML terminology for asserting access permissions
5
+ class RightsMetadata < ActiveFedora::OmDatastream
6
+ extend Deprecation
7
+
8
+ set_terminology do |t|
9
+ t.root(:path=>"rightsMetadata", :xmlns=>"http://hydra-collab.stanford.edu/schemas/rightsMetadata/v1", :schema=>"http://github.com/projecthydra/schemas/tree/v1/rightsMetadata.xsd")
10
+ t.copyright {
11
+ ## BEGIN possible delete, justin 2012-06-22
12
+ t.machine {
13
+ t.cclicense
14
+ t.license
15
+ }
16
+ t.human_readable(:path=>"human")
17
+ t.license(:proxy=>[:machine, :license ])
18
+ t.cclicense(:proxy=>[:machine, :cclicense ])
19
+ ## END possible delete
20
+
21
+ t.title(:path=>'human', :attributes=>{:type=>'title'})
22
+ t.description(:path=>'human', :attributes=>{:type=>'description'})
23
+ t.url(:path=>'machine', :attributes=>{:type=>'uri'})
24
+ }
25
+ t.access do
26
+ t.human_readable(:path=>"human")
27
+ t.machine {
28
+ t.group
29
+ t.person
30
+ }
31
+ t.person(:proxy=>[:machine, :person])
32
+ t.group(:proxy=>[:machine, :group])
33
+ # accessor :access_person, :term=>[:access, :machine, :person]
34
+ end
35
+ t.discover_access(:ref=>[:access], :attributes=>{:type=>"discover"})
36
+ t.read_access(:ref=>[:access], :attributes=>{:type=>"read"})
37
+ t.edit_access(:ref=>[:access], :attributes=>{:type=>"edit"})
38
+ # A bug in OM prevnts us from declaring proxy terms at the root of a Terminology
39
+ # t.access_person(:proxy=>[:access,:machine,:person])
40
+ # t.access_group(:proxy=>[:access,:machine,:group])
41
+
42
+ t.embargo {
43
+ t.human_readable(path: "human")
44
+ t.machine{
45
+ t.date(type: :time, attributes: {type: "release"})
46
+ t.date_deactivated(type: "deactivated")
47
+ t.visibility_during(path: "visibility", attributes: {scope: 'during'})
48
+ t.visibility_after(path: "visibility", attributes: {scope: 'after'})
49
+ }
50
+ }
51
+
52
+ t.lease {
53
+ t.human_readable(path: "human")
54
+ t.machine{
55
+ t.date(type: :time, attributes: {type: "expire"})
56
+ t.date_deactivated(type: :time, attributes: {type: "deactivated"})
57
+ t.visibility_during(path: "visibility", attributes: {scope: 'during'})
58
+ t.visibility_after(path: "visibility", attributes: {scope: 'after'})
59
+ }
60
+ }
61
+
62
+ t.license(:ref=>[:copyright])
63
+
64
+ t.visibility_during_embargo proxy: [:embargo, :machine, :visibility_during]
65
+ t.visibility_after_embargo proxy: [:embargo, :machine, :visibility_after]
66
+ t.visibility_during_lease proxy: [:lease, :machine, :visibility_during]
67
+ t.visibility_after_lease proxy: [:lease, :machine, :visibility_after]
68
+ t.embargo_history proxy: [:embargo, :human_readable]
69
+ t.lease_history proxy: [:lease, :human_readable]
70
+ t.embargo_release_date proxy: [:embargo, :machine, :date], type: :time
71
+ t.embargo_deactivation_date proxy: [:embargo, :machine, :date_deactivated]
72
+ t.lease_expiration_date proxy: [:lease, :machine, :date], type: :time
73
+ t.lease_deactivation_date proxy: [:lease, :machine, :date_deactivated]
74
+
75
+ end
76
+
77
+ # Generates an empty Mods Article (used when you call ModsArticle.new without passing in existing xml)
78
+ def self.xml_template
79
+ builder = Nokogiri::XML::Builder.new do |xml|
80
+ xml.rightsMetadata(:version=>"0.1", "xmlns"=>"http://hydra-collab.stanford.edu/schemas/rightsMetadata/v1") {
81
+ xml.copyright {
82
+ xml.human(:type=>'title')
83
+ xml.human(:type=>'description')
84
+ xml.machine(:type=>'uri')
85
+
86
+ }
87
+ xml.access(:type=>"discover") {
88
+ xml.human
89
+ xml.machine
90
+ }
91
+ xml.access(:type=>"read") {
92
+ xml.human
93
+ xml.machine
94
+ }
95
+ xml.access(:type=>"edit") {
96
+ xml.human
97
+ xml.machine
98
+ }
99
+ xml.embargo{
100
+ xml.machine
101
+ }
102
+ xml.lease{
103
+ xml.machine
104
+ }
105
+ }
106
+ end
107
+ return builder.doc
108
+ end
109
+
110
+ # Returns the permissions for the selected person/group
111
+ # If new_access_level is provided, updates the selected person/group access_level to the one specified
112
+ # A new_access_level of "none" will remove all access_levels for the selected person/group
113
+ # @param [Hash] selector hash in format {type => identifier}
114
+ # @param new_access_level (default nil)
115
+ # @return Hash in format {type => access_level}.
116
+ #
117
+ # ie.
118
+ # permissions({:person=>"person123"})
119
+ # => {"person123"=>"edit"}
120
+ # permissions({:person=>"person123"}, "read")
121
+ # => {"person123"=>"read"}
122
+ # permissions({:person=>"person123"})
123
+ # => {"person123"=>"read"}
124
+ def permissions(selector, new_access_level=nil)
125
+ type = selector.keys.first.to_sym
126
+ actor = selector.values.first
127
+ if new_access_level.nil?
128
+ xpath = xpath(type, actor)
129
+ nodeset = self.find_by_terms(xpath)
130
+ if nodeset.empty?
131
+ return "none"
132
+ else
133
+ return nodeset.first.ancestors("access").first.attributes["type"].text
134
+ end
135
+ else
136
+ remove_all_permissions(selector)
137
+ if new_access_level == "none"
138
+ self.content = self.to_xml
139
+ else
140
+ access_type_symbol = "#{new_access_level}_access".to_sym
141
+ current_values = term_values(access_type_symbol, type)
142
+ self.update_values([access_type_symbol, type] => current_values + [actor] )
143
+ end
144
+ return new_access_level
145
+ end
146
+
147
+ end
148
+
149
+ # Reports on which groups have which permissions
150
+ # @return Hash in format {group_name => group_permissions, group_name => group_permissions}
151
+ def groups
152
+ return quick_search_by_type(:group)
153
+ end
154
+
155
+ def individuals
156
+ Deprecation.warn(RightsMetadata, "The method `individuals' is deprecated and will be removed from Hydra::Datastream::RightsMetadata in hydra-head 8.0. Use `users' instead.", caller)
157
+ users
158
+ end
159
+
160
+ # Reports on which users have which permissions
161
+ # @return Hash in format {user_name => user_permissions, user_name => user_permissions}
162
+ def users
163
+ return quick_search_by_type(:person)
164
+ end
165
+
166
+ # Updates permissions for all of the persons and groups in a hash
167
+ # @param params ex. {"group"=>{"group1"=>"discover","group2"=>"edit"}, "person"=>{"person1"=>"read","person2"=>"discover"}}
168
+ # Currently restricts actor type to group or person. Any others will be ignored
169
+ def update_permissions(params)
170
+ params.fetch("group", {}).each_pair {|group_id, access_level| self.permissions({"group"=>group_id}, access_level)}
171
+ params.fetch("person", {}).each_pair {|person_id, access_level| self.permissions({"person"=>person_id}, access_level)}
172
+ end
173
+
174
+ # Updates all permissions
175
+ # @param params ex. {"group"=>{"group1"=>"discover","group2"=>"edit"}, "person"=>{"person1"=>"read","person2"=>"discover"}}
176
+ # Restricts actor type to group or person. Any others will be ignored
177
+ def permissions= (params)
178
+ groups_for_update = params['group'] ? params['group'].keys : []
179
+ group_ids = groups.keys | groups_for_update
180
+ group_ids.each {|group_id| self.permissions({"group"=>group_id}, params['group'].fetch(group_id, 'none'))}
181
+ users_for_update = params['person'] ? params['person'].keys : []
182
+ user_ids = users.keys | users_for_update
183
+ user_ids.each {|person_id| self.permissions({"person"=>person_id}, params['person'].fetch(person_id, 'none'))}
184
+ end
185
+
186
+ # @param [Symbol] type (either :group or :person)
187
+ # @return
188
+ # This method limits the response to known access levels. Probably runs a bit faster than .permissions().
189
+ def quick_search_by_type(type)
190
+ result = {}
191
+ [{:discover_access=>"discover"},{:read_access=>"read"},{:edit_access=>"edit"}].each do |access_levels_hash|
192
+ access_level = access_levels_hash.keys.first
193
+ access_level_name = access_levels_hash.values.first
194
+ self.find_by_terms(*[access_level, type]).each do |entry|
195
+ result[entry.text] = access_level_name
196
+ end
197
+ end
198
+ return result
199
+ end
200
+
201
+ def under_embargo?
202
+ (embargo_release_date.present? && Date.today < embargo_release_date.first) ? true : false
203
+ end
204
+
205
+ def active_lease?
206
+ lease_expiration_date.present? && Date.today < lease_expiration_date.first
207
+ end
208
+
209
+ def to_solr(solr_doc=Hash.new)
210
+ [:discover, :read, :edit].each do |access|
211
+ vals = send("#{access}_access").machine.group
212
+ solr_doc[Hydra.config.permissions[access].group] = vals unless vals.empty?
213
+ vals = send("#{access}_access").machine.person
214
+ solr_doc[Hydra.config.permissions[access].individual] = vals unless vals.empty?
215
+ end
216
+ if embargo_release_date.present?
217
+ key = Hydra.config.permissions.embargo.release_date.sub(/_[^_]+$/, '') #Strip off the suffix
218
+ ::Solrizer.insert_field(solr_doc, key, embargo_release_date, :stored_sortable)
219
+ end
220
+ if lease_expiration_date.present?
221
+ key = Hydra.config.permissions.lease.expiration_date.sub(/_[^_]+$/, '') #Strip off the suffix
222
+ ::Solrizer.insert_field(solr_doc, key, lease_expiration_date, :stored_sortable)
223
+ end
224
+ solr_doc[::Solrizer.solr_name("visibility_during_embargo", :symbol)] = visibility_during_embargo unless visibility_during_embargo.nil?
225
+ solr_doc[::Solrizer.solr_name("visibility_after_embargo", :symbol)] = visibility_after_embargo unless visibility_after_embargo.nil?
226
+ solr_doc[::Solrizer.solr_name("visibility_during_lease", :symbol)] = visibility_during_lease unless visibility_during_lease.nil?
227
+ solr_doc[::Solrizer.solr_name("visibility_after_lease", :symbol)] = visibility_after_lease unless visibility_after_lease.nil?
228
+ solr_doc[::Solrizer.solr_name("embargo_history", :symbol)] = embargo_history unless embargo_history.nil?
229
+ solr_doc[::Solrizer.solr_name("lease_history", :symbol)] = lease_history unless lease_history.nil?
230
+ solr_doc
231
+ end
232
+
233
+ def indexer
234
+ self.class.indexer
235
+ end
236
+
237
+ def self.indexer
238
+ @indexer ||= Solrizer::Descriptor.new(:string, :stored, :indexed, :multivalued)
239
+ end
240
+
241
+ def date_indexer
242
+ self.class.date_indexer
243
+ end
244
+
245
+ def self.date_indexer
246
+ @date_indexer ||= Solrizer::Descriptor.new(:date, :stored, :indexed)
247
+ end
248
+
249
+ # Completely clear the permissions
250
+ def clear_permissions!
251
+ remove_all_permissions({:person=>true})
252
+ remove_all_permissions({:group=>true})
253
+ end
254
+
255
+
256
+
257
+ private
258
+ # Purge all access given group/person
259
+ def remove_all_permissions(selector)
260
+ return unless ng_xml
261
+ type = selector.keys.first.to_sym
262
+ actor = selector.values.first
263
+ xpath = xpath(type, actor)
264
+ nodes_to_purge = self.find_by_terms(xpath)
265
+ nodes_to_purge.each {|node| node.remove}
266
+ end
267
+
268
+ # @param [Symbol] type (:group, :person)
269
+ # @param [String,TrueClass] actor the user we want to find. If actor is true, then don't query.
270
+ def xpath(type, actor)
271
+ raise ArgumentError, "Type must either be ':group' or ':person'. You provided: '#{type.inspect}'" unless [:group, :person].include?(type)
272
+ path = "//oxns:access/oxns:machine/oxns:#{type}"
273
+ if actor.is_a? String
274
+ clean_actor = actor.gsub("'", '')
275
+ path += "[text() = '#{clean_actor}']"
276
+ end
277
+ path
278
+ end
279
+
280
+ end
281
+ end