curation_concerns-models 0.1.0

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 (84) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.md +177 -0
  5. data/README.md +42 -0
  6. data/Rakefile +1 -0
  7. data/app/actors/concerns/curation_concerns/manages_embargoes_actor.rb +99 -0
  8. data/app/actors/curation_concerns/base_actor.rb +90 -0
  9. data/app/actors/curation_concerns/generic_file_actor.rb +150 -0
  10. data/app/actors/curation_concerns/work_actor_behavior.rb +88 -0
  11. data/app/jobs/active_fedora_id_based_job.rb +22 -0
  12. data/app/jobs/active_fedora_pid_based_job.rb +6 -0
  13. data/app/jobs/audit_job.rb +58 -0
  14. data/app/jobs/characterize_job.rb +11 -0
  15. data/app/jobs/copy_permissions_job.rb +24 -0
  16. data/app/jobs/create_derivatives_job.rb +15 -0
  17. data/app/jobs/import_url_job.rb +56 -0
  18. data/app/jobs/ingest_local_file_job.rb +48 -0
  19. data/app/jobs/resolrize_job.rb +9 -0
  20. data/app/models/checksum_audit_log.rb +21 -0
  21. data/app/models/concerns/curation_concerns/ability.rb +34 -0
  22. data/app/models/concerns/curation_concerns/basic_metadata.rb +87 -0
  23. data/app/models/concerns/curation_concerns/collection_behavior.rb +47 -0
  24. data/app/models/concerns/curation_concerns/generic_file/belongs_to_works.rb +53 -0
  25. data/app/models/concerns/curation_concerns/generic_file/characterization.rb +89 -0
  26. data/app/models/concerns/curation_concerns/generic_file/content.rb +8 -0
  27. data/app/models/concerns/curation_concerns/generic_file/export.rb +343 -0
  28. data/app/models/concerns/curation_concerns/generic_file/full_text_indexing.rb +12 -0
  29. data/app/models/concerns/curation_concerns/generic_file/indexing.rb +14 -0
  30. data/app/models/concerns/curation_concerns/generic_file/versions.rb +16 -0
  31. data/app/models/concerns/curation_concerns/generic_file.rb +5 -0
  32. data/app/models/concerns/curation_concerns/generic_file_behavior.rb +44 -0
  33. data/app/models/concerns/curation_concerns/generic_work_behavior.rb +38 -0
  34. data/app/models/concerns/curation_concerns/has_representative.rb +14 -0
  35. data/app/models/concerns/curation_concerns/human_readable_type.rb +23 -0
  36. data/app/models/concerns/curation_concerns/permissions/readable.rb +19 -0
  37. data/app/models/concerns/curation_concerns/permissions/writable.rb +75 -0
  38. data/app/models/concerns/curation_concerns/permissions.rb +7 -0
  39. data/app/models/concerns/curation_concerns/serializers.rb +15 -0
  40. data/app/models/concerns/curation_concerns/solr_document_behavior.rb +135 -0
  41. data/app/models/concerns/curation_concerns/user.rb +65 -0
  42. data/app/models/concerns/curation_concerns/with_basic_metadata.rb +98 -0
  43. data/app/models/concerns/curation_concerns/with_generic_files.rb +29 -0
  44. data/app/models/curation_concerns/classify_concern.rb +47 -0
  45. data/app/models/curation_concerns/quick_classification_query.rb +31 -0
  46. data/app/models/datastreams/fits_datastream.rb +148 -0
  47. data/app/models/version_committer.rb +2 -0
  48. data/app/services/curation_concerns/characterization_service.rb +71 -0
  49. data/app/services/curation_concerns/full_text_extraction_service.rb +38 -0
  50. data/app/services/curation_concerns/generic_file_audit_service.rb +85 -0
  51. data/app/services/curation_concerns/generic_file_indexing_service.rb +14 -0
  52. data/app/services/curation_concerns/generic_work_indexing_service.rb +16 -0
  53. data/app/services/curation_concerns/noid.rb +23 -0
  54. data/app/services/curation_concerns/repository_audit_service.rb +9 -0
  55. data/app/services/curation_concerns/versioning_service.rb +27 -0
  56. data/config/locales/curation_concerns.en.yml +6 -0
  57. data/curation_concerns-models.gemspec +34 -0
  58. data/lib/curation_concerns/messages.rb +66 -0
  59. data/lib/curation_concerns/models/engine.rb +61 -0
  60. data/lib/curation_concerns/models/resque.rb +36 -0
  61. data/lib/curation_concerns/models/utils.rb +22 -0
  62. data/lib/curation_concerns/models/version.rb +5 -0
  63. data/lib/curation_concerns/models.rb +32 -0
  64. data/lib/generators/curation_concerns/models/abstract_migration_generator.rb +30 -0
  65. data/lib/generators/curation_concerns/models/clamav_generator.rb +19 -0
  66. data/lib/generators/curation_concerns/models/fulltext_generator.rb +28 -0
  67. data/lib/generators/curation_concerns/models/install_generator.rb +70 -0
  68. data/lib/generators/curation_concerns/models/templates/app/models/collection.rb +4 -0
  69. data/lib/generators/curation_concerns/models/templates/app/models/generic_file.rb +4 -0
  70. data/lib/generators/curation_concerns/models/templates/config/clamav.rb +1 -0
  71. data/lib/generators/curation_concerns/models/templates/config/curation_concerns.rb +123 -0
  72. data/lib/generators/curation_concerns/models/templates/config/mime_types.rb +6 -0
  73. data/lib/generators/curation_concerns/models/templates/config/redis.yml +9 -0
  74. data/lib/generators/curation_concerns/models/templates/config/redis_config.rb +32 -0
  75. data/lib/generators/curation_concerns/models/templates/config/resque-pool.yml +1 -0
  76. data/lib/generators/curation_concerns/models/templates/config/resque_admin.rb +10 -0
  77. data/lib/generators/curation_concerns/models/templates/config/resque_config.rb +5 -0
  78. data/lib/generators/curation_concerns/models/templates/migrations/create_checksum_audit_logs.rb +19 -0
  79. data/lib/generators/curation_concerns/models/templates/migrations/create_version_committers.rb +15 -0
  80. data/lib/tasks/curation_concerns-models_tasks.rake +75 -0
  81. data/lib/tasks/migrate.rake +13 -0
  82. data/lib/tasks/resque.rake +13 -0
  83. data/lib/tasks/solr_reindex.rake +8 -0
  84. metadata +282 -0
@@ -0,0 +1,22 @@
1
+ class ActiveFedoraIdBasedJob
2
+ def queue_name
3
+ :id_based
4
+ end
5
+
6
+ attr_accessor :id
7
+
8
+ def initialize(id)
9
+ self.id = id
10
+ end
11
+
12
+ def object
13
+ @object ||= ActiveFedora::Base.find(id)
14
+ end
15
+
16
+ alias_method :generic_file, :object
17
+ alias_method :generic_file_id, :id
18
+
19
+ def run
20
+ raise RuntimeError, "Define #run in a subclass"
21
+ end
22
+ end
@@ -0,0 +1,6 @@
1
+ class ActiveFedoraPidBasedJob < ActiveFedoraIdBasedJob
2
+ extend Deprecation
3
+ def self.extended(document)
4
+ Deprecation.warn ActiveFedoraPidBasedJob, "ActiveFedoraPidBasedJob is deprecated; use ActiveFedoraIdBasedJob instead."
5
+ end
6
+ end
@@ -0,0 +1,58 @@
1
+ class AuditJob < ActiveFedoraIdBasedJob
2
+ def queue_name
3
+ :audit
4
+ end
5
+
6
+ attr_accessor :uri, :id, :file_id
7
+
8
+ # URI of the resource to audit.
9
+ # This URI could include the actual resource (e.g. content) and the version to audit:
10
+ # http://localhost:8983/fedora/rest/test/a/b/c/abcxyz/content/fcr:versions/version1
11
+ # but it could also just be:
12
+ # http://localhost:8983/fedora/rest/test/a/b/c/abcxyz/content
13
+ # @param [String] id of the parent object
14
+ # @param [String] file_id used to find the file within its parent object (usually "original_file")
15
+ # @param [String] uri of the specific file/version to be audited
16
+ def initialize(id, file_id, uri)
17
+ super(id)
18
+ self.file_id = file_id
19
+ self.uri = uri
20
+ end
21
+
22
+ def run
23
+ fixity_ok = false
24
+ log = run_audit
25
+ fixity_ok = (log.pass == 1)
26
+ unless fixity_ok
27
+ if CurationConcerns.config.respond_to?(:after_audit_failure)
28
+ login = generic_file.depositor
29
+ user = User.find_by_user_key(login)
30
+ CurationConcerns.config.after_audit_failure.call(generic_file, user, log.created_at)
31
+ end
32
+ end
33
+ fixity_ok
34
+ end
35
+
36
+ protected
37
+
38
+ def run_audit
39
+ begin
40
+ fixity_ok = ActiveFedora::FixityService.new(uri).check
41
+ rescue Ldp::NotFound
42
+ error_msg = "resource not found"
43
+ end
44
+
45
+ if fixity_ok
46
+ passing = 1
47
+ ChecksumAuditLog.prune_history(id, file_id)
48
+ else
49
+ logger.warn "***AUDIT*** Audit failed for #{uri} #{error_msg}"
50
+ passing = 0
51
+ end
52
+ ChecksumAuditLog.create!(pass: passing, generic_file_id: id, version: uri, file_id: file_id)
53
+ end
54
+
55
+ def logger
56
+ ActiveFedora::Base.logger
57
+ end
58
+ end
@@ -0,0 +1,11 @@
1
+ class CharacterizeJob < ActiveFedoraIdBasedJob
2
+ def queue_name
3
+ :characterize
4
+ end
5
+
6
+ def run
7
+ CurationConcerns::CharacterizationService.run(generic_file)
8
+ generic_file.save
9
+ CurationConcerns.queue.push(CreateDerivativesJob.new(generic_file.id))
10
+ end
11
+ end
@@ -0,0 +1,24 @@
1
+ class CopyPermissionsJob
2
+ def queue_name
3
+ :permissions
4
+ end
5
+
6
+ attr_accessor :id
7
+
8
+ def initialize(id)
9
+ self.id = id
10
+ end
11
+
12
+ def run
13
+ # work = ActiveFedora::Base.load_instance_from_solr(id)
14
+ work = ActiveFedora::Base.find(id) # Hydra::Works::GenericWork is not compatible with load_instance_from_solr. Using (slower) ActiveFedora::Base.find instead.
15
+ if work.respond_to?(:generic_files)
16
+ work.generic_files.each do |file|
17
+
18
+ work.permissions.each {|perm| file.permissions << Hydra::AccessControls::Permission.new(perm.to_hash)}
19
+ new_permissions = file.permissions.uniq! { |item| item.to_hash}
20
+ file.permissions = new_permissions unless new_permissions.blank?
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ class CreateDerivativesJob < ActiveFedoraIdBasedJob
2
+ def queue_name
3
+ :derivatives
4
+ end
5
+
6
+ def run
7
+ return unless generic_file.original_file.has_content?
8
+ if generic_file.video?
9
+ return unless CurationConcerns.config.enable_ffmpeg
10
+ end
11
+
12
+ generic_file.create_derivatives
13
+ generic_file.save
14
+ end
15
+ end
@@ -0,0 +1,56 @@
1
+ require 'net/https'
2
+ require 'uri'
3
+ require 'tempfile'
4
+
5
+ class ImportUrlJob < ActiveFedoraIdBasedJob
6
+
7
+ def queue_name
8
+ :import_url
9
+ end
10
+
11
+ def run
12
+ user = User.find_by_user_key(generic_file.depositor)
13
+
14
+ Tempfile.open(id.gsub('/', '_')) do |f|
15
+ copy_remote_file(generic_file.import_url, f)
16
+ # attach downloaded file to generic file stubbed out
17
+ if CurationConcerns::GenericFileActor.new(generic_file, user).create_content(f)
18
+
19
+ # send message to user on download success
20
+ if CurationConcerns.config.respond_to?(:after_import_url_success)
21
+ CurationConcerns.config.after_import_url_success.call(generic_file, user)
22
+ end
23
+ else
24
+
25
+ # send message to user on download failure
26
+ if CurationConcerns.config.respond_to?(:after_import_url_failure)
27
+ CurationConcerns.config.after_import_url_failure.call(generic_file, user)
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ def copy_remote_file(import_url, f)
34
+ f.binmode
35
+ # download file from url
36
+ uri = URI(generic_file.import_url)
37
+ http = Net::HTTP.new(uri.host, uri.port)
38
+ http.use_ssl = uri.scheme == "https" # enable SSL/TLS
39
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
40
+ mime_type = nil
41
+
42
+ http.start do
43
+ http.request_get(uri.request_uri) do |resp|
44
+ mime_type = resp.content_type
45
+ resp.read_body do |segment|
46
+ f.write(segment)
47
+ end
48
+ end
49
+ end
50
+ f.rewind
51
+ end
52
+
53
+ def job_user
54
+ User.batchuser
55
+ end
56
+ end
@@ -0,0 +1,48 @@
1
+ class IngestLocalFileJob
2
+ attr_accessor :directory, :filename, :user_key, :generic_file_id
3
+
4
+ def queue_name
5
+ :ingest
6
+ end
7
+
8
+ def initialize(generic_file_id, directory, filename, user_key)
9
+ self.generic_file_id = generic_file_id
10
+ self.directory = directory
11
+ self.filename = filename
12
+ self.user_key = user_key
13
+ end
14
+
15
+ def run
16
+ user = User.find_by_user_key(user_key)
17
+ raise "Unable to find user for #{user_key}" unless user
18
+ generic_file = GenericFile.find(generic_file_id)
19
+ generic_file.label ||= filename
20
+ path = File.join(directory, filename)
21
+
22
+ actor = CurationConcerns::GenericFileActor.new(generic_file, user)
23
+
24
+ if actor.create_content(File.open(path))
25
+ FileUtils.rm(path)
26
+
27
+ # send message to user on import success
28
+ if CurationConcerns.config.respond_to?(:after_import_local_file_success)
29
+ CurationConcerns.config.after_import_local_file_success.call(generic_file, user, filename)
30
+ end
31
+ else
32
+
33
+ # send message to user on import failure
34
+ if CurationConcerns.config.respond_to?(:after_import_local_file_failure)
35
+ CurationConcerns.config.after_import_local_file_failure.call(generic_file, user, filename)
36
+ end
37
+ end
38
+ end
39
+
40
+ def job_user
41
+ User.batchuser
42
+ end
43
+
44
+ def mime_type(file_name)
45
+ mime_types = MIME::Types.of(file_name)
46
+ mime_types.empty? ? "application/octet-stream" : mime_types.first.content_type
47
+ end
48
+ end
@@ -0,0 +1,9 @@
1
+ class ResolrizeJob
2
+ def queue_name
3
+ :resolrize
4
+ end
5
+
6
+ def run
7
+ ActiveFedora::Base.reindex_everything
8
+ end
9
+ end
@@ -0,0 +1,21 @@
1
+ class ChecksumAuditLog < ActiveRecord::Base
2
+
3
+ def self.get_audit_log(id, path, version_uri)
4
+ ChecksumAuditLog.find_or_create_by(generic_file_id: id, file_id: path, version: version_uri)
5
+ end
6
+
7
+ # Check to see if there are previous passing logs that we can delete
8
+ # we want to keep the first passing event after a failure, the most current passing event,
9
+ # and all failures so that this table doesn't grow too large
10
+ # Simple way (a little naieve): if the last 2 were passing, delete the first one
11
+ def self.prune_history(id, path)
12
+ list = logs_for(id, path).limit(2)
13
+ if list.size > 1 && (list[0].pass == 1) && (list[1].pass == 1)
14
+ list[0].destroy
15
+ end
16
+ end
17
+
18
+ def self.logs_for(id, path)
19
+ ChecksumAuditLog.where(generic_file_id: id, file_id: path).order('created_at desc, id desc')
20
+ end
21
+ end
@@ -0,0 +1,34 @@
1
+ module CurationConcerns
2
+ module Ability
3
+ extend ActiveSupport::Concern
4
+ included do
5
+ self.ability_logic += [:curation_concerns_permissions]
6
+ end
7
+
8
+ def curation_concerns_permissions
9
+
10
+ unless current_user.new_record?
11
+ can :create, CurationConcerns::ClassifyConcern
12
+ # TODO: Shouldn't this be in `everyone_can_create_curation_concerns` ?
13
+ can :create, ::GenericFile
14
+ end
15
+
16
+ if user_groups.include? 'admin'
17
+ can [:create, :discover, :show, :read, :edit, :update, :destroy], :all
18
+ end
19
+
20
+ can :collect, :all
21
+
22
+ end
23
+
24
+ # Add this to your ability_logic if you want all logged in users to be able
25
+ # to submit content
26
+ def everyone_can_create_curation_concerns
27
+ unless current_user.new_record?
28
+ can :create, [ CurationConcerns.configuration.curation_concerns ]
29
+ can :create, ::Collection
30
+ end
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,87 @@
1
+ module CurationConcerns
2
+ module BasicMetadata
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+
7
+ property :label, predicate: ActiveFedora::RDF::Fcrepo::Model.downloadFilename, multiple: false
8
+
9
+ property :depositor, predicate: ::RDF::URI.new("http://id.loc.gov/vocabulary/relators/dpt"), multiple: false do |index|
10
+ index.as :symbol, :stored_searchable
11
+ end
12
+
13
+ property :relative_path, predicate: ::RDF::URI.new('http://scholarsphere.psu.edu/ns#relativePath'), multiple: false
14
+
15
+ property :import_url, predicate: ::RDF::URI.new('http://scholarsphere.psu.edu/ns#importUrl'), multiple: false do |index|
16
+ index.as :symbol
17
+ end
18
+
19
+ property :part_of, predicate: ::RDF::DC.isPartOf
20
+ property :resource_type, predicate: ::RDF::DC.type do |index|
21
+ index.as :stored_searchable, :facetable
22
+ end
23
+ property :title, predicate: ::RDF::DC.title do |index|
24
+ index.as :stored_searchable, :facetable
25
+ end
26
+ property :creator, predicate: ::RDF::DC.creator do |index|
27
+ index.as :stored_searchable, :facetable
28
+ end
29
+ property :contributor, predicate: ::RDF::DC.contributor do |index|
30
+ index.as :stored_searchable, :facetable
31
+ end
32
+ property :description, predicate: ::RDF::DC.description do |index|
33
+ index.type :text
34
+ index.as :stored_searchable
35
+ end
36
+ property :tag, predicate: ::RDF::DC.relation do |index|
37
+ index.as :stored_searchable, :facetable
38
+ end
39
+ property :rights, predicate: ::RDF::DC.rights do |index|
40
+ index.as :stored_searchable
41
+ end
42
+ property :publisher, predicate: ::RDF::DC.publisher do |index|
43
+ index.as :stored_searchable, :facetable
44
+ end
45
+ property :date_created, predicate: ::RDF::DC.created do |index|
46
+ index.as :stored_searchable
47
+ end
48
+
49
+ # We reserve date_uploaded for the original creation date of the record.
50
+ # For example, when migrating data from a fedora3 repo to fedora4,
51
+ # fedora's system created date will reflect the date when the record
52
+ # was created in fedora4, but the date_uploaded will preserve the
53
+ # original creation date from the old repository.
54
+ property :date_uploaded, predicate: ::RDF::DC.dateSubmitted, multiple: false do |index|
55
+ index.type :date
56
+ index.as :stored_sortable
57
+ end
58
+
59
+ property :date_modified, predicate: ::RDF::DC.modified, multiple: false do |index|
60
+ index.type :date
61
+ index.as :stored_sortable
62
+ end
63
+ property :subject, predicate: ::RDF::DC.subject do |index|
64
+ index.as :stored_searchable, :facetable
65
+ end
66
+ property :language, predicate: ::RDF::DC.language do |index|
67
+ index.as :stored_searchable, :facetable
68
+ end
69
+ property :identifier, predicate: ::RDF::DC.identifier do |index|
70
+ index.as :stored_searchable
71
+ end
72
+ property :based_near, predicate: ::RDF::FOAF.based_near do |index|
73
+ index.as :stored_searchable, :facetable
74
+ end
75
+ property :related_url, predicate: ::RDF::RDFS.seeAlso do |index|
76
+ index.as :stored_searchable
77
+ end
78
+ property :bibliographic_citation, predicate: ::RDF::DC.bibliographicCitation do |index|
79
+ index.as :stored_searchable
80
+ end
81
+ property :source, predicate: ::RDF::DC.source do |index|
82
+ index.as :stored_searchable
83
+ end
84
+ end
85
+
86
+ end
87
+ end
@@ -0,0 +1,47 @@
1
+ module CurationConcerns
2
+ module CollectionBehavior
3
+ extend ActiveSupport::Concern
4
+
5
+ include Hydra::AccessControls::WithAccessRight
6
+ include Hydra::Collection
7
+ include CurationConcerns::Noid
8
+ include CurationConcerns::HumanReadableType
9
+ include CurationConcerns::HasRepresentative
10
+ include CurationConcerns::Permissions
11
+
12
+ included do
13
+ validates :title, presence: true
14
+ end
15
+
16
+ def add_member(collectible)
17
+ if can_add_to_members?(collectible)
18
+ self.members << collectible
19
+ save
20
+ end
21
+ end
22
+
23
+ def to_s
24
+ title.present? ? title : "No Title"
25
+ end
26
+
27
+ def bytes
28
+ members.reduce(0) { |sum, gf| sum + gf.content.size.to_i }
29
+ end
30
+
31
+ def to_solr(solr_doc={})
32
+ super(solr_doc).tap do |solr_doc|
33
+ Solrizer.set_field(solr_doc, 'generic_type', human_readable_type, :facetable)
34
+ end
35
+ end
36
+
37
+ def can_be_member_of_collection?(collection)
38
+ collection == self ? false : true
39
+ end
40
+
41
+ private
42
+
43
+ def can_add_to_members?(collectible)
44
+ collectible.try(:can_be_member_of_collection?, self)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,53 @@
1
+ module CurationConcerns
2
+ module GenericFile
3
+ module BelongsToWorks
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ before_destroy :remove_representative_relationship
8
+ end
9
+
10
+ def generic_works
11
+ self.parent_objects # parent_objects is provided by Hydra::PCDM::ObjectBehavior
12
+ end
13
+
14
+ def generic_work_ids
15
+ generic_works.map { |work| work.id }
16
+ end
17
+
18
+ # Returns the first parent object
19
+ # This is a hack to handle things like GenericFiles inheriting access controls from their parent. (see CurationConcerns::ParentContainer in app/controllers/concerns/curation_concers/parent_container.rb)
20
+ def parent
21
+ self.parent_objects.first
22
+ end
23
+
24
+ # Returns the id of first parent object
25
+ # This is a hack to handle things like GenericFiles inheriting access controls from their parent. (see CurationConcerns::ParentContainer in app/controllers/concerns/curation_concers/parent_container.rb)
26
+ def parent_id
27
+ parent.id
28
+ end
29
+
30
+ # Files with sibling relationships
31
+ # Returns all GenericFiles aggregated by any of the GenericWorks that aggregate the current object
32
+ def related_files
33
+ generic_works = self.generic_works
34
+ return [] if generic_works.empty?
35
+ generic_works.flat_map {|work| work.generic_files.select {|generic_file| generic_file.id != self.id } }
36
+ end
37
+
38
+ # If any parent works are pointing at this object as their representative, remove that pointer.
39
+ def remove_representative_relationship
40
+ generic_works = self.generic_works
41
+ return if generic_works.empty?
42
+ generic_works.each do |work|
43
+ if work.representative == self.id
44
+ work.representative = nil
45
+ work.save
46
+ end
47
+ end
48
+ end
49
+
50
+ end
51
+ end
52
+ end
53
+
@@ -0,0 +1,89 @@
1
+ module CurationConcerns
2
+ module GenericFile
3
+ module Characterization
4
+ extend ActiveSupport::Concern
5
+ included do
6
+ contains "characterization", class_name: 'FitsDatastream'
7
+ property :mime_type, delegate_to: 'characterization', multiple: false do |index|
8
+ index.as :stored_searchable
9
+ end
10
+ property :format_label, delegate_to: 'characterization'
11
+ property :file_size, delegate_to: 'characterization'
12
+ property :last_modified, delegate_to: 'characterization'
13
+ property :filename, delegate_to: 'characterization'
14
+ property :original_checksum, delegate_to: 'characterization'
15
+ property :rights_basis, delegate_to: 'characterization'
16
+ property :copyright_basis, delegate_to: 'characterization'
17
+ property :copyright_note, delegate_to: 'characterization'
18
+ property :well_formed, delegate_to: 'characterization'
19
+ property :valid, delegate_to: 'characterization'
20
+ property :status_message, delegate_to: 'characterization'
21
+ property :file_title, delegate_to: 'characterization'
22
+ property :file_author, delegate_to: 'characterization'
23
+ property :page_count, delegate_to: 'characterization'
24
+ property :file_language, delegate_to: 'characterization'
25
+ property :word_count, delegate_to: 'characterization'
26
+ property :character_count, delegate_to: 'characterization'
27
+ property :paragraph_count, delegate_to: 'characterization'
28
+ property :line_count, delegate_to: 'characterization'
29
+ property :table_count, delegate_to: 'characterization'
30
+ property :graphics_count, delegate_to: 'characterization'
31
+ property :byte_order, delegate_to: 'characterization'
32
+ property :compression, delegate_to: 'characterization'
33
+ property :color_space, delegate_to: 'characterization'
34
+ property :profile_name, delegate_to: 'characterization'
35
+ property :profile_version, delegate_to: 'characterization'
36
+ property :orientation, delegate_to: 'characterization'
37
+ property :color_map, delegate_to: 'characterization'
38
+ property :image_producer, delegate_to: 'characterization'
39
+ property :capture_device, delegate_to: 'characterization'
40
+ property :scanning_software, delegate_to: 'characterization'
41
+ property :exif_version, delegate_to: 'characterization'
42
+ property :gps_timestamp, delegate_to: 'characterization'
43
+ property :latitude, delegate_to: 'characterization'
44
+ property :longitude, delegate_to: 'characterization'
45
+ property :character_set, delegate_to: 'characterization'
46
+ property :markup_basis, delegate_to: 'characterization'
47
+ property :markup_language, delegate_to: 'characterization'
48
+ property :bit_depth, delegate_to: 'characterization'
49
+ property :channels, delegate_to: 'characterization'
50
+ property :data_format, delegate_to: 'characterization'
51
+ property :offset, delegate_to: 'characterization'
52
+ property :frame_rate, delegate_to: 'characterization'
53
+
54
+ end
55
+
56
+ def width
57
+ characterization.width.blank? ? characterization.video_width : characterization.width
58
+ end
59
+
60
+ def height
61
+ characterization.height.blank? ? characterization.video_height : characterization.height
62
+ end
63
+
64
+ def duration
65
+ characterization.duration.blank? ? characterization.video_duration : characterization.duration
66
+ end
67
+
68
+ def sample_rate
69
+ characterization.sample_rate.blank? ? characterization.video_sample_rate : characterization.sample_rate
70
+ end
71
+
72
+ def characterization_terms
73
+ h = {}
74
+ self.characterization.class.terminology.terms.each_pair do |k, v|
75
+ next unless v.respond_to? :proxied_term
76
+ term = v.proxied_term
77
+ begin
78
+ value = self.send(term.name)
79
+ h[term.name] = value unless value.empty?
80
+ rescue NoMethodError
81
+ next
82
+ end
83
+ end
84
+ h
85
+ end
86
+
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,8 @@
1
+ module CurationConcerns
2
+ module GenericFile
3
+ module Content
4
+ extend ActiveSupport::Concern
5
+
6
+ end
7
+ end
8
+ end