galter_ir_exporter 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 486d415073c83fa1d0f0005c24f7cfb0a0d0c4a4d38b5b2c6c8e3386cd0be661
4
+ data.tar.gz: d6158ac773dad20319a447caaf6720d32cb04065757f4133203078d7665bdd82
5
+ SHA512:
6
+ metadata.gz: 244f6f46624d5c1ce0f45df88d791ec2b755fe1a69fa8eee4fab94a862fc28725b3a50d980f19d74e14a1a76ebcab99af6c5a833c4c3510a4449a25930694e83
7
+ data.tar.gz: 62cce298e29260f46fa6a1cce5923a55ac8c167b297e3a21d98d4804d6ccc993835712e41c9f076679bfe5b9e62b968ea1079d9fb5ab7064e5c6b06198b49265
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+
13
+ Gemfile.lock
14
+ *.swp
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at sharpattack@users.noreply.github.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in galter_ir_exporter.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2020 Northwestern University
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # GalterIrExporter
2
+
3
+ Ruby Gem for exporting metadata from the data models available in a sufia6 application to a file in json.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your sufia6 application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'galter_ir_exporter'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Run the installer, creating the necessary migration files:
18
+
19
+ $ bundle exec rails generate galter_ir_exporter:install
20
+
21
+ Run the migration:
22
+
23
+ $ bundle exec rails db:migrate
24
+
25
+ ## Usage
26
+
27
+ Run the survey script to write the IDs for all GenericFiles and Collections to the database:
28
+
29
+ $ bundle exec galter_ir_exporter_survey -v
30
+
31
+ Run the export:
32
+
33
+ $ bundle exec galter_ir_exporter_export
34
+
35
+ This will create a .json file with metadata for each instance of GenericFile and Collection.
36
+
37
+ ### Options
38
+
39
+ Pass the `--help` option to view the ways to override the exported fields for your customized data models.
40
+
41
+ $ bundle exec galter_ir_exporter_export --help
42
+
43
+ ## Development
44
+
45
+ TODO: Add when [#7](https://github.com/galterlibrary/galter_ir_exporter/issues/7) is resolved.
46
+
47
+ ### Testing Your Changes In Your Samvera/Sufia6 App
48
+
49
+ Branch from master, make any changes to the gem, then push your branch to this repository. Then, add the
50
+ following to your samvera/sufia6 app's Gemfile. Once everything is installed add the following to the
51
+ digital-repository Gemfile:
52
+
53
+ `gem 'galter_ir_exporter', git: 'https://github.com/galterlibrary/galter_ir_exporter.git', branch: 'your-branch-name'`
54
+
55
+ Run bundler again and the changes pushed to your-branch-name will be pulled. If you have previously installed
56
+ 'galter_ir_exporter' you may need to uninstall the gem with: `gem uninstall galter_ir_exporter`.
57
+
58
+ ## Contributing
59
+
60
+ Bug reports and pull requests are welcome on GitHub at https://github.com/galterlibrary/galter_ir_exporter. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
61
+
62
+ ## Code of Conduct
63
+
64
+ Everyone interacting in the GalterIrExporter project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/galter_ir_exporter/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "galter_ir_exporter"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rails'
3
+
4
+ require ::File.join(File.dirname(Bundler.default_gemfile), 'config/environment')
5
+
6
+ options = {}
7
+
8
+ args = OptionParser.new do |opts|
9
+ opts.banner = "Exports model metdata from fedora to json files in tmp/export. Usage: galter_ir_exporter_export [options]"
10
+
11
+ opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
12
+ options[:verbose] = v
13
+ end
14
+
15
+ opts.on("--limit NUMBER_OF_OBJECTS", Integer, "Export a maximum number of objects (defaults to all)") do |v|
16
+ options[:limit] = v
17
+ end
18
+
19
+ opts.on("--ids ID_LIST", Array, "Export only the objects in the list of IDs",
20
+ "For example to export a Collection with the id abc123 and a GenericFile with an id def456:",
21
+ " --ids abc123,def456") do |v|
22
+ options[:ids] = v
23
+ end
24
+
25
+ opts.on("--models MODEL_LIST", Array, "Specify the models to be output (defaults to GenericFile,Collection)",
26
+ "To override the default converter for a model or to register a new converter add the converter after the model.",
27
+ "For example to convert GenericFiles with a new converter and Collections with the default converter:",
28
+ " --models GenericFile=Mine::NewGenericFileConverter,Collection") do |v|
29
+ options[:models] = v
30
+ end
31
+ end
32
+
33
+ begin
34
+ args.order!
35
+ args.parse!
36
+ rescue => error
37
+ $stderr.puts "ERROR: #{error}\n"
38
+ $stderr.puts args.help
39
+ exit 1
40
+ end
41
+
42
+ verbose = options[:verbose]
43
+
44
+ $stdout.puts "running with #{options}" if verbose
45
+ actor = GalterIrExporter::Export::Actor.new
46
+
47
+ if options[:models].blank?
48
+ # set model list to the default
49
+ model_list = actor.converter_registry.keys
50
+ else
51
+ model_list = []
52
+ model_options = options.delete(:models)
53
+ $stdout.puts "processing models #{model_options}" if verbose
54
+ model_options.each do |model_str|
55
+ class_name, converter_name = model_str.split('=')
56
+ model_class = Object.const_get(class_name)
57
+ model_list << model_class
58
+ next if converter_name.blank?
59
+ $stdout.puts "Registering converter Class #{class_name} converter #{converter_name}" if verbose
60
+ converter_class = Object.const_get(converter_name)
61
+ actor.register_converter model_class, converter_class
62
+ end
63
+ end
64
+
65
+ $stdout.puts "Sending call with #{model_list} and #{options}" if verbose
66
+ actor.call(model_list, options)
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rails'
3
+
4
+ require ::File.join(File.dirname(Bundler.default_gemfile), 'config/environment')
5
+
6
+ options = {}
7
+
8
+ subtext = <<HELP
9
+ Commonly used commands are:
10
+ clean : cleans all GalterIrExporter::Migration::Survey::Items from the database
11
+ See 'galter_ir_exporter_survey COMMAND --help' for more information on a specific command.
12
+ HELP
13
+
14
+ args = OptionParser.new do |opts|
15
+ opts.banner = "Survey model objects in fedora and store survey results in an ActiveRecord table. Usage: galter_ir_exporter_survey [options]"
16
+
17
+ opts.on("-v", "--[no-]verbose", "Run [not] verbosely") do |v|
18
+ options[:verbose] = v
19
+ end
20
+
21
+ opts.on("--limit NUMBER_OF_OBJECTS", Integer, "Survey a maximum number of objects (defaults to all)") do |v|
22
+ options[:limit] = v
23
+ end
24
+
25
+ opts.on("--ids ID_LIST", Array, "Survey only the objects in the list of IDs",
26
+ "For example to survey a Collection with the id abc123 and a GenericFile with an id def456:",
27
+ " --ids abc123,def456") do |v|
28
+ options[:ids] = v
29
+ end
30
+
31
+ opts.on("--models MODEL_LIST", Array, "Specify the models to be surveyed (defaults to GenericFile,Collection)") do |v|
32
+ options[:models] = v
33
+ end
34
+
35
+ opts.separator ""
36
+ opts.separator subtext
37
+ end
38
+
39
+ subcommands = {
40
+ 'clean' => OptionParser.new do |opts|
41
+ opts.banner = "Usage: galter_ir_exporter_survey clean"
42
+ end
43
+ }
44
+
45
+ begin
46
+ args.order!
47
+ command = ARGV.shift
48
+ if command
49
+ raise "Bad subcommand: #{command}" unless subcommands[command]
50
+ subcommands[command].order!
51
+ end
52
+ args.parse!
53
+ rescue => error
54
+ $stderr.puts "ERROR: #{error}\n"
55
+ $stderr.puts args.help
56
+ exit 1
57
+ end
58
+
59
+ if command == 'clean'
60
+ $stdout.puts "cleaning GalterIrExporter::Migration::Survey::Items"
61
+ GalterIrExporter::Migration::Survey::Item.delete_all
62
+ exit 0
63
+ end
64
+
65
+ verbose = options[:verbose]
66
+
67
+ $stdout.puts "running with #{options}" if verbose
68
+ id_service = GalterIrExporter::Migration::Survey::FedoraIdService.new
69
+
70
+ if options[:models]
71
+ model_options = options.delete(:models)
72
+ $stdout.puts "processing models #{model_options}" if verbose
73
+ model_options.each do |model_str|
74
+ model_class = Object.const_get(model_str)
75
+ id_service.register_model(model_class)
76
+ end
77
+ end
78
+
79
+ if options[:ids]
80
+ ids = options[:ids]
81
+ else
82
+ $stdout.puts "Sending fedora_id with #{id_service.model_registry} and #{options}" if verbose
83
+ ids = id_service.call(options[:limit] || :all)
84
+ end
85
+
86
+ $stdout.puts "Sending call with ids: #{ids}" if verbose
87
+ GalterIrExporter::Migration::Survey::Surveyor.call(ids)
Binary file
@@ -0,0 +1,42 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "galter_ir_exporter/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "galter_ir_exporter"
7
+ spec.version = GalterIrExporter::VERSION
8
+ spec.authors = ["Austin Sharp", "Eric Newman"]
9
+ spec.email = ["galter-is@listserv.it.northwestern.edu"]
10
+
11
+ spec.summary = %q{Data exporter for Sufia6}
12
+ spec.description = %q{Exports data from GenericFile and Collection to json output}
13
+ spec.homepage = "https://github.com/galterlibrary/galter_ir_exporter"
14
+ spec.license = "Apache-2.0" #Apache License, Version 2.0
15
+
16
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
17
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
18
+ if spec.respond_to?(:metadata)
19
+ # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
20
+
21
+ spec.metadata["homepage_uri"] = spec.homepage
22
+ spec.metadata["source_code_uri"] = "https://github.com/galterlibrary/galter_ir_exporter"
23
+ # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
24
+ else
25
+ raise "RubyGems 2.0 or newer is required to protect against " \
26
+ "public gem pushes."
27
+ end
28
+
29
+ # Specify which files should be added to the gem when it is released.
30
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
31
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
32
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
33
+ end
34
+ spec.bindir = "exe"
35
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
36
+ spec.require_paths = ["lib"]
37
+
38
+ spec.add_development_dependency "bundler", "~> 2.0"
39
+ spec.add_development_dependency "rake", "~> 10.0"
40
+ spec.add_development_dependency "rspec", "~> 3.0"
41
+ spec.add_development_dependency "activerecord", ["= 4.2.7"]
42
+ end
@@ -0,0 +1,3 @@
1
+ require "galter_ir_exporter/version"
2
+ require "galter_ir_exporter/export"
3
+ require "galter_ir_exporter/migration"
@@ -0,0 +1,13 @@
1
+ require 'galter_ir_exporter/export/converter'
2
+ require 'galter_ir_exporter/export/generic_file_converter'
3
+ require 'galter_ir_exporter/export/version_converter'
4
+ require 'galter_ir_exporter/export/version_graph_converter'
5
+ require 'galter_ir_exporter/export/permission_converter'
6
+ require 'galter_ir_exporter/export/collection_converter'
7
+ require 'galter_ir_exporter/export/actor'
8
+
9
+ module GalterIrExporter
10
+ module Export
11
+ VERSION = GalterIrExporter::VERSION
12
+ end
13
+ end
@@ -0,0 +1,98 @@
1
+ module GalterIrExporter
2
+ module Export
3
+ # Convert a GenericFile including metadata, permissions and version metadata into a PORO
4
+ # so that the metadata can be exported in json format using to_json
5
+ #
6
+ class Actor
7
+ attr_reader :converter_registry, :limit, :ids
8
+ attr_accessor :conversion_count
9
+
10
+ # initialize the class with the default registry
11
+ def initialize
12
+ @converter_registry = default_registry
13
+ end
14
+
15
+ # register a converter for a new class or overwrite the converter for a default class
16
+ #
17
+ # @param [Class] model_class The ActiveFedora model class to be converter to json
18
+ # @param [Class] converter_class The class that will convert from ActiveFedora to json
19
+ def register_converter(model_class, converter_class)
20
+ raise(RegistryError, "Model (#{model_class.name}) for conversion must be an ActiveFedora::Base") unless model_class.ancestors.include?(ActiveFedora::Base)
21
+ raise(RegistryError, "Converter (#{converter_class.name}) for conversion must be an GalterIrExporter::Export::Converter") unless converter_class.ancestors.include?(GalterIrExporter::Export::Converter)
22
+ converter_registry[model_class] = converter_class
23
+ end
24
+
25
+ # Convert the classes using the registered converters from ActiveFedora to json files
26
+ #
27
+ # @param [Array] model_class_list list of classes to be converter
28
+ # @param [Hash] opts
29
+ # @option opts [Number] :limit Limits the number of conversion done (defaults to -1 or all)
30
+ # @option opts [Array] :ids List of ids to be converted. Can be from any model
31
+ def call(model_class_list = converter_registry.keys, opts = {})
32
+ @conversion_count = 0
33
+ validate_class_list(model_class_list)
34
+ parse_options(opts)
35
+ export_models(model_class_list)
36
+ end
37
+
38
+ private
39
+
40
+ def parse_options(opts)
41
+ @limit = opts[:limit] || -1
42
+ @ids = opts[:ids]
43
+ end
44
+
45
+ def model_scope(model_class)
46
+ scope = model_class.all
47
+ scope = scope.where(id: ids) unless ids.blank?
48
+ scope = scope.limit(limit - conversion_count) unless limit == -1
49
+ scope
50
+ end
51
+
52
+ def validate_class_list(model_class_list)
53
+ model_class_list.each do |model_class|
54
+ converter_class = converter_registry[model_class]
55
+ raise(RegistryError, "Undefined Model for conversion (#{model_class.name})") if converter_class.blank?
56
+ end
57
+ end
58
+
59
+ def export_models(model_class_list)
60
+ model_class_list.each do |model_class|
61
+ converter_class = converter_registry[model_class]
62
+ export_model_list(model_scope(model_class), converter_class)
63
+ end
64
+ end
65
+
66
+ def export_model_list(model_list, converter_class)
67
+ model_list.each do |model|
68
+ export_one(converter_class, model)
69
+ end
70
+ end
71
+
72
+ def export_one(converter_class, model)
73
+ converter = converter_class.new(model)
74
+ path = file_name(model)
75
+ json = converter.to_json(pretty: true)
76
+ File.write(path, json)
77
+ @conversion_count += 1
78
+ end
79
+
80
+ def file_name(model)
81
+ File.join(file_path, "#{model.class.name.underscore}_#{model.id}.json")
82
+ end
83
+
84
+ def default_registry
85
+ { ::GenericFile => GalterIrExporter::Export::GenericFileConverter, ::Collection => GalterIrExporter::Export::CollectionConverter }
86
+ end
87
+
88
+ def file_path
89
+ return @file_path unless @file_path.blank?
90
+ @file_path = "tmp/export"
91
+ FileUtils.mkdir_p @file_path
92
+ @file_path
93
+ end
94
+ end
95
+
96
+ class RegistryError < RuntimeError; end
97
+ end
98
+ end
@@ -0,0 +1,48 @@
1
+ module GalterIrExporter
2
+ module Export
3
+ # Convert a Collection including metadata, permissions and member ids into a PORO
4
+ # so that the metadata can be exported in json format using to_json
5
+ #
6
+ class CollectionConverter < Converter
7
+ # Create an instance of a Collection converter containing all the metadata for json export
8
+ #
9
+ # @param [Collection] collection to be converted for export
10
+ def initialize(collection)
11
+ @id = collection.id
12
+ @title = collection.title
13
+ @description = collection.description
14
+ @creator = collection.creator.map { |c| c }
15
+ @members = collection.members.map(&:id)
16
+ @permissions = permissions(collection)
17
+ @depositor = collection.depositor
18
+ @part_of = collection.part_of
19
+ @contributor = collection.contributor
20
+ @publisher = collection.publisher
21
+ @date_created = collection.date_created
22
+ @date_uploaded = collection.date_uploaded
23
+ @date_modified = collection.date_modified
24
+ @subject = collection.subject
25
+ @language = collection.language
26
+ @language = collection.language
27
+ @resource_type = collection.resource_type
28
+ @identifier = collection.identifier
29
+ @based_near = collection.based_near
30
+ @tag = collection.tag
31
+ @related_url = collection.related_url
32
+ @abstract = collection.abstract
33
+ @bibliographic_citation = collection.bibliographic_citation
34
+ @digital_origin = collection.digital_origin
35
+ @mesh = collection.mesh
36
+ @lcsh = collection.lcsh
37
+ @subject_geographic = collection.subject_geographic
38
+ @subject_name = collection.subject_name
39
+ @multi_page = collection.multi_page
40
+ @institutional_collection = collection.institutional_collection
41
+ @private_note = collection.private_note
42
+ @member_ids = collection.member_ids
43
+ @parent_id = collection.parent_id
44
+ @combined_file_id = collection.combined_file_id
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,23 @@
1
+ module GalterIrExporter
2
+ module Export
3
+ # a base class to convert an ActiveFedora object that contains permissions and allow for pretty json.
4
+ #
5
+ class Converter
6
+ # overrides to_json to optionally allow for a pretty version of the json to be outputted
7
+ #
8
+ # @param [Boolean] pretty pass true to output formatted json using pretty_generate
9
+ def to_json(options = {})
10
+ pretty = options.delete(:pretty)
11
+ json = super
12
+ return json unless pretty
13
+ JSON.pretty_generate(JSON.parse(json))
14
+ end
15
+
16
+ private
17
+
18
+ def permissions(object)
19
+ object.permissions.map { |p| PermissionConverter.new(p) }
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,111 @@
1
+ module GalterIrExporter
2
+ module Export
3
+ # Convert a GenericFile including metadata, permissions and version metadata into a PORO
4
+ # so that the metadata can be exported in json format using to_json
5
+ #
6
+ class GenericFileConverter < Converter
7
+ # Create an instance of a GenericFile converter containing all the metadata for json export
8
+ #
9
+ # @param [GenericFile] generic_file file to be converted for export
10
+ def initialize(generic_file)
11
+ @id = generic_file.id
12
+ @label = generic_file.label
13
+ @depositor = generic_file.depositor
14
+ @arkivo_checksum = generic_file.arkivo_checksum
15
+ @relative_path = generic_file.relative_path
16
+ @import_url = generic_file.import_url
17
+ @resource_type = generic_file.resource_type
18
+ @title = generic_file.title
19
+ @creator = generic_file.creator
20
+ @contributor = generic_file.contributor
21
+ @description = generic_file.description
22
+ @tag = generic_file.tag
23
+ @rights = generic_file.rights
24
+ @publisher = generic_file.publisher
25
+ @date_created = generic_file.date_created
26
+ @date_uploaded = generic_file.date_uploaded
27
+ @date_modified = generic_file.date_modified
28
+ @subject = generic_file.subject
29
+ @language = generic_file.language
30
+ @identifier = generic_file.identifier
31
+ @based_near = generic_file.based_near
32
+ @related_url = generic_file.related_url
33
+ @bibliographic_citation = generic_file.bibliographic_citation
34
+ @source = generic_file.source
35
+ @batch_id = generic_file.batch.id if generic_file.batch
36
+ @visibility = generic_file.visibility
37
+ @versions = versions(generic_file)
38
+ @permissions = permissions(generic_file)
39
+ @mime_type = generic_file.mime_type
40
+ @format_label = generic_file.format_label
41
+ @file_size = generic_file.file_size
42
+ @last_modified = generic_file.last_modified
43
+ @filename = generic_file.filename
44
+ @original_checksum = generic_file.original_checksum
45
+ @rights_basis = generic_file.rights_basis
46
+ @copyright_basis = generic_file.copyright_basis
47
+ @copyright_note = generic_file.copyright_note
48
+ @well_formed = generic_file.well_formed
49
+ @valid = generic_file.valid
50
+ @status_message = generic_file.status_message
51
+ @file_title = generic_file.file_title
52
+ @file_author = generic_file.file_author
53
+ @page_count = generic_file.page_count
54
+ @file_language = generic_file.file_language
55
+ @word_count = generic_file.word_count
56
+ @character_count = generic_file.character_count
57
+ @paragraph_count = generic_file.paragraph_count
58
+ @line_count = generic_file.line_count
59
+ @table_count = generic_file.table_count
60
+ @graphics_count = generic_file.graphics_count
61
+ @byte_order = generic_file.byte_order
62
+ @compression = generic_file.compression
63
+ @color_space = generic_file.color_space
64
+ @profile_name = generic_file.profile_name
65
+ @profile_version = generic_file.profile_version
66
+ @orientation = generic_file.orientation
67
+ @color_map = generic_file.color_map
68
+ @image_producer = generic_file.image_producer
69
+ @capture_device = generic_file.capture_device
70
+ @scanning_software = generic_file.scanning_software
71
+ @exif_version = generic_file.exif_version
72
+ @gps_timestamp = generic_file.gps_timestamp
73
+ @latitude = generic_file.latitude
74
+ @longitude = generic_file.longitude
75
+ @character_set = generic_file.character_set
76
+ @markup_basis = generic_file.markup_basis
77
+ @markup_language = generic_file.markup_language
78
+ @bit_depth = generic_file.bit_depth
79
+ @channels = generic_file.channels
80
+ @data_format = generic_file.data_format
81
+ @offset = generic_file.offset
82
+ @frame_rate = generic_file.frame_rate
83
+ @part_of = generic_file.part_of
84
+ @proxy_depositor = generic_file.proxy_depositor
85
+ @on_behalf_of = generic_file.on_behalf_of
86
+ @abstract = generic_file.abstract
87
+ @acknowledgments = generic_file.acknowledgments
88
+ @grants_and_funding = generic_file.grants_and_funding
89
+ @digital_origin = generic_file.digital_origin
90
+ @mesh = generic_file.mesh
91
+ @lcsh = generic_file.lcsh
92
+ @subject_geographic = generic_file.subject_geographic
93
+ @subject_name = generic_file.subject_name
94
+ @page_number = generic_file.page_number
95
+ @page_number_actual = generic_file.page_number_actual
96
+ @doi = generic_file.doi
97
+ @ark = generic_file.ark
98
+ @private_note = generic_file.private_note
99
+ @parent_id = generic_file.parent_id
100
+ @combined_file_id = generic_file.combined_file_id
101
+ end
102
+
103
+ private
104
+
105
+ def versions(gf)
106
+ return [] unless gf.content.has_versions?
107
+ GalterIrExporter::Export::VersionGraphConverter.new(gf.content.versions).versions
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,19 @@
1
+ module GalterIrExporter
2
+ module Export
3
+ # Convert a permission record from a ActiveFedora:Base into a PORO so that the metadata
4
+ # can be exported in json format using to_json
5
+ #
6
+ class PermissionConverter
7
+ # Create an instance of a Object Permission containing all the metadata for the permission
8
+ #
9
+ # @param [Hydra::AccessControls::Permission] permission the permission associated with one access record
10
+ def initialize(permission)
11
+ @id = permission.id
12
+ @agent = permission.agent.first.rdf_subject.to_s
13
+ @mode = permission.mode.first.rdf_subject.to_s
14
+ # Using .id instead of .uri allows us to rebuild the URI later on with a new base URI
15
+ @access_to = permission.access_to.id
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,34 @@
1
+ module GalterIrExporter
2
+ module Export
3
+ # Convert a single version of a GenericFile content into a PORO so that the metadata
4
+ # ()including pointers to the version content) can be exported in json format using to_json
5
+ #
6
+ # @attr_reader [String] uri location of version in fedora (also id of version)
7
+ # @attr_reader [String] label version label extracted from the graph for the version identified by the url
8
+ # @attr_reader [String] created version creation date extracted from the graph for the version identified by the url
9
+ class VersionConverter
10
+ attr_reader :uri, :label, :created
11
+
12
+ # Create an instance of a GenericFile version containing all the metadata for json export
13
+ #
14
+ # @param [String] uri location of version to be converted in fedora (also id of version)
15
+ # @param [ActiveFedora::VersionsGraph] version_graph the graph of versions associated with one GenericFile (gf.content.versions)
16
+ def initialize(uri, version_graph)
17
+ @uri = content_uri(uri)
18
+ @created = find_triple(RDF::Vocab::Fcrepo4.created, version_graph)
19
+ @label = find_triple(RDF::Vocab::Fcrepo4.hasVersionLabel, version_graph)
20
+ end
21
+
22
+ private
23
+
24
+ def find_triple(predicate, graph)
25
+ triple = graph.find { |t| content_uri(t.subject) == uri && t.predicate == predicate }
26
+ triple.object.to_s
27
+ end
28
+
29
+ def content_uri(uri)
30
+ uri.to_s.gsub('/fcr:metadata', '')
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,35 @@
1
+ module GalterIrExporter
2
+ module Export
3
+ # Convert a graph of versions from a GenericFile into a list of POROs so that the metadata
4
+ # (including pointers to the version content) can be exported in json format using to_json
5
+ #
6
+ # @attr_reader [Array<VersionConverter] versions list of VersionConverters extracted from the graph
7
+ class VersionGraphConverter
8
+ attr_reader :versions
9
+
10
+ # Create an instance of a GenericFile version graph containing all the metadata for each version
11
+ #
12
+ # @param [ActiveFedora::VersionsGraph] version_graph the graph of versions associated with one GenericFile (gf.content.versions)
13
+ def initialize(version_graph)
14
+ @versions = []
15
+ parse(version_graph)
16
+ end
17
+
18
+ private
19
+
20
+ def parse(graph)
21
+ find_uris(graph).each do |uri|
22
+ versions << VersionConverter.new(uri, graph)
23
+ end
24
+ end
25
+
26
+ def find_uris(graph)
27
+ uris = []
28
+ graph.query(predicate: RDF::Vocab::Fcrepo4.hasVersion).each do |triple|
29
+ uris << triple.object.to_s
30
+ end
31
+ uris
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,7 @@
1
+ require 'galter_ir_exporter/migration/survey'
2
+
3
+ module GalterIrExporter
4
+ module Migration
5
+ VERSION = GalterIrExporter::VERSION
6
+ end
7
+ end
@@ -0,0 +1,15 @@
1
+ require 'galter_ir_exporter/migration/survey/item'
2
+ require 'galter_ir_exporter/migration/survey/fedora_id_service'
3
+ require 'galter_ir_exporter/migration/survey/surveyor'
4
+
5
+ module GalterIrExporter
6
+ module Migration
7
+ module Survey
8
+ VERSION = GalterIrExporter::VERSION
9
+
10
+ def self.table_name_prefix
11
+ 'galter_ir_exporter_migration_survey_'
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,69 @@
1
+ # Class to extract all the ids from fedora for registered classes. By default GenericFile and Collection are registered.
2
+ #
3
+ module GalterIrExporter
4
+ module Migration
5
+ module Survey
6
+ class FedoraIdService
7
+ attr_accessor :model_registry
8
+
9
+ # initialize the service with the default models (GenericFile & Collection) registered
10
+ def initialize
11
+ @model_registry = default_registry
12
+ end
13
+
14
+ # register an additional ActiveFedora Model to extract ids for
15
+ #
16
+ # @param [Class] model_class additional class that you would like to be in the output
17
+ # @raise [RegistryError] if the class is not an ActiveFedora based class
18
+ def register_model(model_class)
19
+ raise(RegistryError, "Model (#{model_class.name}) for conversion must be an ActiveFedora::Base") unless model_class.ancestors.include?(ActiveFedora::Base)
20
+ return if @model_registry.include? model_class
21
+ @model_registry << model_class
22
+ end
23
+
24
+ # returns a list of ids for all the registered classes in the repository
25
+ #
26
+ # @param [Number] limit limits the number of results (default is all)
27
+ def call(limit = :all)
28
+ ids = all_ids.select { |id| registered_model?(id) }
29
+ return ids if limit == :all
30
+ ids.take(limit)
31
+ end
32
+
33
+ private
34
+
35
+ def default_registry
36
+ [::GenericFile, ::Collection]
37
+ end
38
+
39
+ def all_ids
40
+ root_uri = ActiveFedora.fedora.host + ActiveFedora.fedora.base_path
41
+ # Fetches all the Fedora 4 descendant URIs for a given URI.
42
+ # Stolen from: https://github.com/projecthydra/active_fedora/blob/master/lib/active_fedora/indexing.rb#L72-L79
43
+ resource = Ldp::Resource::RdfSource.new(ActiveFedora.fedora.connection, root_uri)
44
+ children = resource.graph.query(predicate: ::RDF::Vocab::LDP.contains).map { |descendant| descendant.object.to_s }
45
+ children.map { |uri| uri.split("/").last }
46
+ end
47
+
48
+ def active_fedora_model(id)
49
+ query = 'id:"' + id + '"'
50
+ matches = ActiveFedora::SolrService.query(query)
51
+ return nil if matches.count == 0
52
+ model_str = matches.first["has_model_ssim"]
53
+ model_str = model_str.first if model_str.is_a?(Array)
54
+ if model_str.blank? || !Object.const_defined?(model_str)
55
+ Rails.logger.error("Invalid model #{id} #{model_str}")
56
+ return nil
57
+ end
58
+ Object.const_get(model_str)
59
+ end
60
+
61
+ def registered_model?(id)
62
+ model_registry.include?(active_fedora_model(id))
63
+ end
64
+ end
65
+
66
+ class RegistryError < RuntimeError; end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,21 @@
1
+ # ActiveRecord class to store the current migration status of an object in ActiveFedora.
2
+ #
3
+ # @attr [String] object_id fedora id of the object being migrated
4
+ # @attr [String] object_class fedora class of the object being migrated (Collection, GenericFile)
5
+ # @attr [String] object_title title of the object being migrated
6
+ # @attr [enum] migration_status - Status of the object's migration
7
+ # @option migration_status :initial_state initial state before migration
8
+ # @option migration_status :successful migrated successfully
9
+ # @option migration_status :missing Missing when verified
10
+ # @option migration_status :wrong_type Migrated but wrong type
11
+ require 'active_record'
12
+
13
+ module GalterIrExporter
14
+ module Migration
15
+ module Survey
16
+ class Item < ActiveRecord::Base
17
+ enum migration_status: [:initial_state, :successful, :missing, :wrong_type]
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # Class that will survey Fedora based on a list of ids
2
+ module GalterIrExporter
3
+ module Migration
4
+ module Survey
5
+ class Surveyor
6
+ class << self
7
+ # call causes the surveyor to create a survey item for each id in the list
8
+ #
9
+ # @param [Array] id_list a list of ids to be surveyed
10
+ def call(id_list)
11
+ ActiveFedora::Base.find(id_list).each do |object|
12
+ Item.find_or_create_by(object_id: object.id) do |item|
13
+ item.assign_attributes(object_class: object.class, object_title: object.title, migration_status: :initial_state)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ module GalterIrExporter
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,17 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/active_record'
3
+
4
+ module GalterIrExporter
5
+ class Install < Rails::Generators::Base
6
+ include ActiveRecord::Generators::Migration
7
+
8
+ source_root File.expand_path('../templates', __FILE__)
9
+
10
+ desc "galter_ir_exporter generator to create the required migrations"
11
+
12
+ # Setup the database migrations
13
+ def copy_migrations
14
+ migration_template "create_galter_ir_exporter_migration_survey_items.rb", "db/migrate/create_galter_ir_exporter_migration_survey_items.rb"
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ class CreateGalterIrExporterMigrationSurveyItems < ActiveRecord::Migration
2
+ def change
3
+ create_table :galter_ir_exporter_migration_survey_items do |t|
4
+ t.string :object_id
5
+ t.string :object_class
6
+ t.text :object_title
7
+ t.integer :migration_status
8
+
9
+ t.timestamps null: false
10
+ end
11
+ end
12
+ end
metadata ADDED
@@ -0,0 +1,134 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: galter_ir_exporter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Austin Sharp
8
+ - Eric Newman
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2020-11-12 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '2.0'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '2.0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '10.0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '10.0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '3.0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '3.0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: activerecord
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - '='
61
+ - !ruby/object:Gem::Version
62
+ version: 4.2.7
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - '='
68
+ - !ruby/object:Gem::Version
69
+ version: 4.2.7
70
+ description: Exports data from GenericFile and Collection to json output
71
+ email:
72
+ - galter-is@listserv.it.northwestern.edu
73
+ executables:
74
+ - galter_ir_exporter_export
75
+ - galter_ir_exporter_survey
76
+ extensions: []
77
+ extra_rdoc_files: []
78
+ files:
79
+ - ".gitignore"
80
+ - ".rspec"
81
+ - CODE_OF_CONDUCT.md
82
+ - Gemfile
83
+ - LICENSE
84
+ - README.md
85
+ - Rakefile
86
+ - bin/console
87
+ - bin/setup
88
+ - exe/galter_ir_exporter_export
89
+ - exe/galter_ir_exporter_survey
90
+ - galter_ir_exporter-0.0.0.gem
91
+ - galter_ir_exporter.gemspec
92
+ - lib/galter_ir_exporter.rb
93
+ - lib/galter_ir_exporter/export.rb
94
+ - lib/galter_ir_exporter/export/actor.rb
95
+ - lib/galter_ir_exporter/export/collection_converter.rb
96
+ - lib/galter_ir_exporter/export/converter.rb
97
+ - lib/galter_ir_exporter/export/generic_file_converter.rb
98
+ - lib/galter_ir_exporter/export/permission_converter.rb
99
+ - lib/galter_ir_exporter/export/version_converter.rb
100
+ - lib/galter_ir_exporter/export/version_graph_converter.rb
101
+ - lib/galter_ir_exporter/migration.rb
102
+ - lib/galter_ir_exporter/migration/survey.rb
103
+ - lib/galter_ir_exporter/migration/survey/fedora_id_service.rb
104
+ - lib/galter_ir_exporter/migration/survey/item.rb
105
+ - lib/galter_ir_exporter/migration/survey/surveyor.rb
106
+ - lib/galter_ir_exporter/version.rb
107
+ - lib/generators/galter_ir_exporter/install/install_generator.rb
108
+ - lib/generators/galter_ir_exporter/install/templates/create_galter_ir_exporter_migration_survey_items.rb
109
+ homepage: https://github.com/galterlibrary/galter_ir_exporter
110
+ licenses:
111
+ - Apache-2.0
112
+ metadata:
113
+ homepage_uri: https://github.com/galterlibrary/galter_ir_exporter
114
+ source_code_uri: https://github.com/galterlibrary/galter_ir_exporter
115
+ post_install_message:
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubygems_version: 3.0.8
131
+ signing_key:
132
+ specification_version: 4
133
+ summary: Data exporter for Sufia6
134
+ test_files: []