fedora-migrate 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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