ddr-models 2.0.1 → 2.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +23 -17
  3. data/app/models/collection.rb +1 -35
  4. data/ddr-models.gemspec +2 -1
  5. data/lib/ddr/actions.rb +1 -0
  6. data/lib/ddr/actions/virus_check.rb +28 -0
  7. data/lib/ddr/auth.rb +4 -0
  8. data/lib/ddr/auth/ability_definitions/datastream_ability_definitions.rb +7 -5
  9. data/lib/ddr/auth/grouper_gateway.rb +9 -1
  10. data/lib/ddr/auth/permissions.rb +2 -1
  11. data/lib/ddr/auth/role_based_access_controls_enforcement.rb +5 -5
  12. data/lib/ddr/auth/roles/role_types.rb +2 -1
  13. data/lib/ddr/datastreams.rb +2 -2
  14. data/lib/ddr/datastreams/administrative_metadata_datastream.rb +27 -14
  15. data/lib/ddr/datastreams/datastream_behavior.rb +13 -0
  16. data/lib/ddr/datastreams/fits_datastream.rb +88 -0
  17. data/lib/ddr/derivatives/png_generator.rb +2 -0
  18. data/lib/ddr/derivatives/ptif_generator.rb +2 -0
  19. data/lib/ddr/events/fixity_check_event.rb +2 -2
  20. data/lib/ddr/events/virus_check_event.rb +2 -14
  21. data/lib/ddr/index.rb +29 -0
  22. data/lib/ddr/index/abstract_query_result.rb +23 -0
  23. data/lib/ddr/index/connection.rb +17 -0
  24. data/lib/ddr/index/csv_query_result.rb +61 -0
  25. data/lib/ddr/index/document_builder.rb +9 -0
  26. data/lib/ddr/index/field.rb +23 -0
  27. data/lib/ddr/index/fields.rb +83 -0
  28. data/lib/ddr/index/filter.rb +48 -0
  29. data/lib/ddr/index/filters.rb +19 -0
  30. data/lib/ddr/index/legacy_license_fields.rb +14 -0
  31. data/lib/ddr/index/query.rb +35 -0
  32. data/lib/ddr/index/query_builder.rb +74 -0
  33. data/lib/ddr/index/query_clause.rb +52 -0
  34. data/lib/ddr/index/query_result.rb +70 -0
  35. data/lib/ddr/index/query_value.rb +16 -0
  36. data/lib/ddr/index/response.rb +13 -0
  37. data/lib/ddr/index/unique_key_field.rb +12 -0
  38. data/lib/ddr/index_fields.rb +7 -53
  39. data/lib/ddr/jobs.rb +1 -1
  40. data/lib/ddr/jobs/fits_file_characterization.rb +51 -0
  41. data/lib/ddr/managers.rb +1 -0
  42. data/lib/ddr/managers/technical_metadata_manager.rb +104 -0
  43. data/lib/ddr/models.rb +39 -23
  44. data/lib/ddr/models/base.rb +0 -2
  45. data/lib/ddr/models/describable.rb +1 -1
  46. data/lib/ddr/models/effective_license.rb +9 -0
  47. data/lib/ddr/models/engine.rb +13 -0
  48. data/lib/ddr/models/file_management.rb +157 -160
  49. data/lib/ddr/models/governable.rb +0 -4
  50. data/lib/ddr/models/has_admin_metadata.rb +80 -72
  51. data/lib/ddr/models/has_children.rb +1 -1
  52. data/lib/ddr/models/has_content.rb +18 -0
  53. data/lib/ddr/models/has_struct_metadata.rb +5 -1
  54. data/lib/ddr/models/indexing.rb +32 -20
  55. data/lib/ddr/models/inherited_license.rb +13 -0
  56. data/lib/ddr/models/license.rb +38 -0
  57. data/lib/ddr/models/solr_document.rb +195 -211
  58. data/lib/ddr/models/version.rb +1 -1
  59. data/lib/ddr/models/year_facet.rb +154 -0
  60. data/lib/ddr/utils.rb +13 -1
  61. data/lib/ddr/vocab/roles.rb +0 -10
  62. data/spec/controllers/including_role_based_access_controls_enforcement_spec.rb +4 -4
  63. data/spec/datastreams/fits_datastream_spec.rb +84 -0
  64. data/spec/fixtures/fits/document.xml +65 -0
  65. data/spec/fixtures/fits/image.xml +59 -0
  66. data/spec/index/filter_spec.rb +47 -0
  67. data/spec/index/filters_spec.rb +17 -0
  68. data/spec/index/query_spec.rb +19 -0
  69. data/spec/jobs/fits_file_characterization_spec.rb +52 -0
  70. data/spec/managers/technical_metadata_manager_spec.rb +140 -0
  71. data/spec/models/active_fedora_datastream_spec.rb +44 -0
  72. data/spec/models/collection_spec.rb +7 -12
  73. data/spec/models/component_spec.rb +3 -6
  74. data/spec/models/effective_license_spec.rb +49 -0
  75. data/spec/models/has_admin_metadata_spec.rb +143 -194
  76. data/spec/models/has_struct_metadata_spec.rb +2 -2
  77. data/spec/models/indexing_spec.rb +40 -0
  78. data/spec/models/solr_document_spec.rb +96 -37
  79. data/spec/models/year_facet_spec.rb +65 -0
  80. data/spec/spec_helper.rb +1 -7
  81. data/spec/support/shared_examples_for_ddr_models.rb +0 -2
  82. data/spec/support/shared_examples_for_has_content.rb +37 -3
  83. metadata +79 -32
  84. data/lib/ddr/datastreams/properties_datastream.rb +0 -25
  85. data/lib/ddr/jobs/migrate_legacy_authorization.rb +0 -23
  86. data/lib/ddr/models/has_properties.rb +0 -15
  87. data/lib/ddr/models/licensable.rb +0 -28
  88. data/spec/auth/legacy_authorization_spec.rb +0 -94
  89. data/spec/auth/legacy_roles_spec.rb +0 -32
  90. data/spec/jobs/migrate_legacy_authorization_spec.rb +0 -43
  91. data/spec/support/shared_examples_for_has_properties.rb +0 -5
  92. data/spec/support/shared_examples_for_licensable.rb +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: da77038c15e029fe70bc14ba3b2fa9013606e66a
4
- data.tar.gz: 59a3733d31c8cf61c4d4fe680037ae57a343cb0e
3
+ metadata.gz: cb4f77d35e8d4b3d23267f2f32b6176f935d547d
4
+ data.tar.gz: 15ac1cebb4342dde18d4e8bfab92749c69805add
5
5
  SHA512:
6
- metadata.gz: 8d63141d8f4cda552f720a20887419c90beb1a2e41b5b6c5bee08fda01d259b2286b85af4a45caa93576371d3498613d55a9d12cae2999dc97c278bf0cd37454
7
- data.tar.gz: 131bd338a0a2190c604ce92b945f2e2a220f2beadbd94fe442e1b93a6435f1ab9d8c52a51ab6ebc377014315bbc47316ce81eea5fd285a37106d6eba50f6a7b6
6
+ metadata.gz: 706dafc8320ac5bf5ae153fc963368c143b2a7ad0dbac3a1155751102b3398016a575dc4449c46753bdc45a568ff6872fe5d3526e21323cc0d15c7207af504f5
7
+ data.tar.gz: 0309ef94db398e32ec350c0671108e5d5cca3406ad65ab71325da2eddc0581e3d7e788dee29767381b875859c204d5b5a705cee8b73ebee907f4789a36ce7462
data/README.md CHANGED
@@ -23,7 +23,6 @@ ddr-models has several runtime dependencies that are independently configurable:
23
23
 
24
24
  - [active_fedora](https://github.com/projecthydra/active_fedora)
25
25
  - [hydra-head](https://github.com/projecthydra/hydra-head)
26
- - [ddr-antivirus](https://github.com/duke-libraries/ddr-antivirus)
27
26
  - [devise](https://github.com/plataformatec/devise)
28
27
  - [omniauth-shibboleth](https://github.com/toyokazu/omniauth-shibboleth)
29
28
  - [ezid-client](https://github.com/duke-libaries/ezid-client)
@@ -36,23 +35,18 @@ ddr-models configuration options:
36
35
 
37
36
  #### User model
38
37
 
39
- Include `Ddr::Auth::User` in `app/models/user.rb` and remove content inserted by Hydra, Blacklight and Devise generators:
38
+ Include `Ddr::Auth::User` in `app/models/user.rb` and remove content inserted by Hydra and Devise generators:
40
39
 
41
40
  ```ruby
42
41
  class User
43
42
  include Ddr::Auth::User
44
43
  #
45
- # Remove content inserted by Hydra, Blacklight, or Devise generators --
46
- # it's provided by Ddr::Auth::User.
47
- #
48
- # include Blacklight::User
44
+ # REMOVE:
49
45
  # include Hydra::User
50
46
  # devise :database_authenticatable [...]
51
47
  #
52
- # ... as well as any methods.
53
- #
54
- # You can add custom methods for the app as needed.
55
- #
48
+ # DO NOT REMOVE:
49
+ # Blacklight::User
56
50
  end
57
51
  ```
58
52
 
@@ -71,20 +65,28 @@ Change the class like so:
71
65
  ```ruby
72
66
  class Ability < Ddr::Auth::Ability
73
67
  #
74
- # Ddr::Auth::Ability includes Hydra::PolicyAwareAbility
68
+ # REMOVE:
75
69
  # include Hydra::Ability
76
70
  #
77
- # Add custom methods here as needed to Ability.ability_logic:
78
- #
79
- # self.ability_logic += [:my_ability]
71
+ # Add "ability definitions" -- i.e., subclasses of Ddr::Auth::AbilityDefinitions.
80
72
  #
81
- # def my_ability
82
- # # whatever
83
- # end
73
+ # self.ability_definitions += [ ... ]
84
74
  #
85
75
  end
86
76
  ```
87
77
 
78
+ #### Controller
79
+
80
+ `Ddr::Auth::RoleBasedAccessControlsEnforcement` overrides `current_ability`, `gated_discovery_filters` and `enforce_show_permissions`, so most likely it should be included in `ApplicationController`.
81
+
82
+ ```ruby
83
+ class ApplicationController < ActionController::Base
84
+
85
+ include Ddr::Auth::RoleBasedAccessControlsEnforcement
86
+
87
+ end
88
+ ```
89
+
88
90
  #### SolrDocument model
89
91
 
90
92
  Include `Ddr::Models::SolrDocument` in `app/models/solr_document.rb`
@@ -100,6 +102,10 @@ class SolrDocument
100
102
  end
101
103
  ```
102
104
 
105
+ #### Auxiliary Web Services
106
+
107
+ In order to use the auxiliary web services, set the `DDR_AUX_API_URL` environment variable. You may wish to install the [ddr-aux](https://github.com/duke-libraries/ddr-aux) app locally and run it.
108
+
103
109
  #### Migrations
104
110
 
105
111
  Install the ddr-models migrations:
@@ -8,21 +8,6 @@ class Collection < Ddr::Models::Base
8
8
  include Ddr::Models::HasChildren
9
9
  include Ddr::Models::HasAttachments
10
10
 
11
- has_attributes :default_license_title,
12
- datastream: Ddr::Datastreams::DEFAULT_RIGHTS,
13
- at: [:license, :title],
14
- multiple: false
15
-
16
- has_attributes :default_license_description,
17
- datastream: Ddr::Datastreams::DEFAULT_RIGHTS,
18
- at: [:license, :description],
19
- multiple: false
20
-
21
- has_attributes :default_license_url,
22
- datastream: Ddr::Datastreams::DEFAULT_RIGHTS,
23
- at: [:license, :url],
24
- multiple: false
25
-
26
11
  has_many :children, property: :is_member_of_collection, class_name: 'Item'
27
12
  has_many :targets, property: :is_external_target_for, class_name: 'Target'
28
13
 
@@ -37,31 +22,12 @@ class Collection < Ddr::Models::Base
37
22
  #
38
23
  # @return A lazy enumerator of SolrDocuments.
39
24
  def components_from_solr
40
- query = "#{Ddr::IndexFields::COLLECTION_URI}:#{RSolr.solr_escape(internal_uri)}"
25
+ query = "#{Ddr::Index::Fields::COLLECTION_URI}:#{RSolr.solr_escape(internal_uri)}"
41
26
  filter = ActiveFedora::SolrService.construct_query_for_rel(:has_model => Component.to_class_uri)
42
27
  results = ActiveFedora::SolrService.query(query, fq: filter, rows: 100000)
43
28
  results.lazy.map {|doc| SolrDocument.new(doc)}
44
29
  end
45
30
 
46
- # Returns the license attributes provided as default values for objects
47
- # governed by the Collection.
48
- #
49
- # @return [Hash] the attributes, `:title`, `:description`, and `:url`.
50
- def default_license
51
- if default_license_title.present? or default_license_description.present? or default_license_url.present?
52
- {title: default_license_title, description: default_license_description, url: default_license_url}
53
- end
54
- end
55
-
56
- # Sets the default license attributes for objects governed by the Collection.
57
- def default_license=(new_license)
58
- raise ArgumentError unless new_license.is_a?(Hash) # XXX don't do this - not duck-typeable
59
- l = new_license.with_indifferent_access
60
- self.default_license_title = l[:title]
61
- self.default_license_description = l[:description]
62
- self.default_license_url = l[:url]
63
- end
64
-
65
31
  # Returns a list of entities (either users or groups) having a default access
66
32
  # level on objects governed by the Collection.
67
33
  #
@@ -22,7 +22,6 @@ Gem::Specification.new do |s|
22
22
  s.add_dependency "active-fedora", "~> 7.0"
23
23
  s.add_dependency "hydra-core", "~> 7.2"
24
24
  s.add_dependency "hydra-validations", "~> 0.5"
25
- s.add_dependency "ddr-antivirus", "~> 1.3.1"
26
25
  s.add_dependency "devise", "~> 3.4"
27
26
  s.add_dependency "omniauth-shibboleth", "~> 1.2.0"
28
27
  s.add_dependency "grouper-rest-client"
@@ -31,6 +30,8 @@ Gem::Specification.new do |s|
31
30
  s.add_dependency "rdf-vocab", "~> 0.8"
32
31
  s.add_dependency "net-ldap", "~> 0.11"
33
32
  s.add_dependency "cancancan", "~> 1.12"
33
+ s.add_dependency "ddr-aux-client", "~> 1.1"
34
+ s.add_dependency "ddr-antivirus", "2.0.0"
34
35
 
35
36
  s.add_development_dependency "bundler", "~> 1.7"
36
37
  s.add_development_dependency "rake"
@@ -3,6 +3,7 @@ module Ddr
3
3
  extend ActiveSupport::Autoload
4
4
 
5
5
  autoload :FixityCheck
6
+ autoload :VirusCheck
6
7
 
7
8
  end
8
9
  end
@@ -0,0 +1,28 @@
1
+ require "open3"
2
+ require "ostruct"
3
+ require "shellwords"
4
+
5
+ module Ddr::Actions
6
+ class VirusCheck
7
+
8
+ # @return [Hash] result data
9
+ # @raises [Ddr::Antivirus::VirusFoundError]
10
+ def self.call(file_path)
11
+ unless File.exist?(file_path)
12
+ raise Error, "File not found: #{file_path}"
13
+ end
14
+ result = {}
15
+ begin
16
+ scan_result = Ddr::Antivirus.scan(file_path)
17
+ rescue Ddr::Antivirus::ScannerError => e
18
+ result[:exception] = [e.class.name, e.to_s]
19
+ scan_result = e.result
20
+ end
21
+ result[:event_date_time] = scan_result.scanned_at
22
+ result[:software] = scan_result.version
23
+ result[:detail] = scan_result.output
24
+ result
25
+ end
26
+
27
+ end
28
+ end
@@ -102,5 +102,9 @@ module Ddr
102
102
  "::Ability"
103
103
  end
104
104
 
105
+ mattr_accessor :repository_group_filter do
106
+ ENV["REPOSITORY_GROUP_FILTER"]
107
+ end
108
+
105
109
  end
106
110
  end
@@ -8,11 +8,13 @@ module Ddr
8
8
  # Datastreams not listed cannot be downloaded, except of
9
9
  # course by the :manage ability.
10
10
  DATASTREAM_DOWNLOAD_ABILITIES = {
11
- Ddr::Datastreams::CONTENT => :download,
12
- Ddr::Datastreams::DESC_METADATA => :read,
13
- Ddr::Datastreams::EXTRACTED_TEXT => :read,
14
- Ddr::Datastreams::MULTIRES_IMAGE => :read,
15
- Ddr::Datastreams::THUMBNAIL => :read,
11
+ Ddr::Datastreams::CONTENT => :download,
12
+ Ddr::Datastreams::DESC_METADATA => :read,
13
+ Ddr::Datastreams::EXTRACTED_TEXT => :download,
14
+ Ddr::Datastreams::FITS => :read,
15
+ Ddr::Datastreams::MULTIRES_IMAGE => :read,
16
+ Ddr::Datastreams::STRUCT_METADATA => :read,
17
+ Ddr::Datastreams::THUMBNAIL => :read,
16
18
  }.freeze
17
19
 
18
20
  def call
@@ -5,10 +5,18 @@ module Ddr
5
5
  module Auth
6
6
  class GrouperGateway < SimpleDelegator
7
7
 
8
- REPOSITORY_GROUP_FILTER = "duke:library:repository:ddr:"
9
8
  SUBJECT_ID_RE = Regexp.new('[^@]+(?=@duke\.edu)')
10
9
  DEFAULT_TIMEOUT = 5
11
10
 
11
+ def self.const_missing(name)
12
+ if name == :REPOSITORY_GROUP_FILTER
13
+ warn "[DEPRECATION] The constant `#{name}` is deprecated and will be removed in ddr-models 3.0." \
14
+ " Use `Ddr::Auth.repository_group_filter` instead."
15
+ return Ddr::Auth.repository_group_filter
16
+ end
17
+ super
18
+ end
19
+
12
20
  def self.repository_groups(*args)
13
21
  new.repository_groups(*args)
14
22
  end
@@ -7,9 +7,10 @@ module Ddr::Auth
7
7
  UPDATE = :update
8
8
  REPLACE = :replace
9
9
  ARRANGE = :arrange
10
+ AUDIT = :audit
10
11
  GRANT = :grant
11
12
 
12
- ALL = [ READ, DOWNLOAD, ADD_CHILDREN, UPDATE, REPLACE, ARRANGE, GRANT ]
13
+ ALL = [ READ, DOWNLOAD, ADD_CHILDREN, UPDATE, REPLACE, ARRANGE, AUDIT, GRANT ]
13
14
 
14
15
  def self.const_missing(name)
15
16
  if name == :EDIT
@@ -21,11 +21,11 @@ module Ddr
21
21
  def policy_role_policies
22
22
  @policy_role_policies ||= Array.new.tap do |uris|
23
23
  filters = current_ability.agents.map do |agent|
24
- "#{Ddr::IndexFields::POLICY_ROLE}:\"#{agent}\""
24
+ "#{Ddr::Index::Fields::POLICY_ROLE}:\"#{agent}\""
25
25
  end.join(" OR ")
26
- query = "#{Ddr::IndexFields::ACTIVE_FEDORA_MODEL}:Collection AND (#{filters})"
27
- results = ActiveFedora::SolrService.query(query, rows: Collection.count, fl: Ddr::IndexFields::INTERNAL_URI)
28
- results.each_with_object(uris) { |r, memo| memo << r[Ddr::IndexFields::INTERNAL_URI] }
26
+ query = "#{Ddr::Index::Fields::ACTIVE_FEDORA_MODEL}:Collection AND (#{filters})"
27
+ results = ActiveFedora::SolrService.query(query, rows: Collection.count, fl: Ddr::Index::Fields::INTERNAL_URI)
28
+ results.each_with_object(uris) { |r, memo| memo << r[Ddr::Index::Fields::INTERNAL_URI] }
29
29
  end
30
30
  end
31
31
 
@@ -38,7 +38,7 @@ module Ddr
38
38
 
39
39
  def resource_role_filters
40
40
  current_ability.agents.map do |agent|
41
- ActiveFedora::SolrService.raw_query(Ddr::IndexFields::RESOURCE_ROLE, agent)
41
+ ActiveFedora::SolrService.raw_query(Ddr::Index::Fields::RESOURCE_ROLE, agent)
42
42
  end.join(" OR ")
43
43
  end
44
44
 
@@ -14,7 +14,8 @@ module Ddr
14
14
  "Editor",
15
15
  "The Editor role conveys reponsibility for managing the content, " \
16
16
  "description and structural arrangement of a resource.",
17
- Permissions::ALL - [ Permissions::GRANT ]
17
+ [ Permissions::READ, Permissions::DOWNLOAD, Permissions::ADD_CHILDREN,
18
+ Permissions::UPDATE, Permissions::REPLACE, Permissions::ARRANGE ]
18
19
  )
19
20
 
20
21
  METADATA_EDITOR = RoleType.new(
@@ -10,8 +10,8 @@ module Ddr
10
10
  DEFAULT_RIGHTS = "defaultRights"
11
11
  DESC_METADATA = "descMetadata"
12
12
  EXTRACTED_TEXT = "extractedText"
13
+ FITS = "fits".freeze
13
14
  MULTIRES_IMAGE = "multiresImage"
14
- PROPERTIES = "properties"
15
15
  RELS_EXT = "RELS-EXT"
16
16
  RIGHTS_METADATA = "rightsMetadata"
17
17
  STRUCT_METADATA = "structMetadata"
@@ -28,9 +28,9 @@ module Ddr
28
28
  autoload :AdministrativeMetadataDatastream
29
29
  autoload :DatastreamBehavior
30
30
  autoload :DescriptiveMetadataDatastream
31
+ autoload :FitsDatastream
31
32
  autoload :MetadataDatastream
32
33
  autoload :PlainTextDatastream
33
- autoload :PropertiesDatastream
34
34
  autoload :StructuralMetadataDatastream
35
35
 
36
36
  end
@@ -4,31 +4,44 @@ module Ddr
4
4
  module Datastreams
5
5
  class AdministrativeMetadataDatastream < MetadataDatastream
6
6
 
7
- property :permanent_id, predicate: Ddr::Vocab::Asset.permanentId
7
+ property :permanent_id,
8
+ predicate: Ddr::Vocab::Asset.permanentId
8
9
 
9
- property :permanent_url, predicate: Ddr::Vocab::Asset.permanentUrl
10
+ property :permanent_url,
11
+ predicate: Ddr::Vocab::Asset.permanentUrl
10
12
 
11
- property :original_filename, predicate: Ddr::Vocab::PREMIS.hasOriginalName do |index|
13
+ property :original_filename,
14
+ predicate: Ddr::Vocab::PREMIS.hasOriginalName do |index|
12
15
  index.as :stored_sortable
13
16
  end
14
17
 
15
- property :workflow_state, predicate: Ddr::Vocab::Asset.workflowState
18
+ property :workflow_state,
19
+ predicate: Ddr::Vocab::Asset.workflowState
16
20
 
17
- Ddr::Vocab::Roles::LEGACY_ROLES.each do |legacy_role|
18
- property legacy_role, predicate: Ddr::Vocab::Roles.send(legacy_role) do |index|
19
- index.as :symbol
20
- end
21
- end
21
+ property :access_role,
22
+ predicate: Ddr::Vocab::Roles.hasRole,
23
+ class_name: Ddr::Auth::Roles::Role
24
+
25
+ property :local_id,
26
+ predicate: RDF::Vocab::Identifiers.local
27
+
28
+ property :admin_set,
29
+ predicate: Ddr::Vocab::Asset.adminSet
22
30
 
23
- property :access_role, predicate: Ddr::Vocab::Roles.hasRole, class_name: Ddr::Auth::Roles::Role
31
+ property :display_format,
32
+ predicate: Ddr::Vocab::Display.format
24
33
 
25
- property :local_id, predicate: RDF::Vocab::Identifiers.local
34
+ property :research_help_contact,
35
+ predicate: Ddr::Vocab::Contact.assistance
26
36
 
27
- property :admin_set, predicate: Ddr::Vocab::Asset.adminSet
37
+ property :depositor,
38
+ predicate: RDF::Vocab::MARCRelators.dpt
28
39
 
29
- property :display_format, predicate: Ddr::Vocab::Display.format
40
+ property :doi,
41
+ predicate: RDF::Vocab::Identifiers.doi
30
42
 
31
- property :research_help_contact, predicate: Ddr::Vocab::Contact.assistance
43
+ property :license,
44
+ predicate: RDF::DC.license
32
45
 
33
46
  end
34
47
  end
@@ -90,6 +90,19 @@ module Ddr
90
90
  [default_file_prefix, default_file_extension].join(".")
91
91
  end
92
92
 
93
+ def tempfile(prefix: nil, suffix: nil)
94
+ if empty?
95
+ raise Ddr::Models::Error, "Refusing to create tempfile for empty datastream!"
96
+ end
97
+ prefix ||= default_file_prefix + "--"
98
+ suffix ||= "." + default_file_extension
99
+ Tempfile.open [prefix, suffix], encoding: Encoding::ASCII_8BIT do |f|
100
+ f.write(content)
101
+ f.close
102
+ yield f
103
+ end
104
+ end
105
+
93
106
  end
94
107
  end
95
108
  end
@@ -0,0 +1,88 @@
1
+ module Ddr::Datastreams
2
+ class FitsDatastream < ActiveFedora::OmDatastream
3
+
4
+ FITS_XMLNS = "http://hul.harvard.edu/ois/xml/ns/fits/fits_output".freeze
5
+ FITS_SCHEMA = "http://hul.harvard.edu/ois/xml/xsd/fits/fits_output.xsd".freeze
6
+
7
+ EXIFTOOL = "Exiftool"
8
+
9
+ set_terminology do |t|
10
+ t.root(path: "fits",
11
+ xmlns: FITS_XMLNS,
12
+ schema: FITS_SCHEMA)
13
+ t.version(path: {attribute: "version"})
14
+ t.timestamp(path: {attribute: "timestamp"})
15
+ t.identification {
16
+ t.identity {
17
+ t.mimetype(path: {attribute: "mimetype"})
18
+ t.format_label(path: {attribute: "format"})
19
+ t.version
20
+ t.externalIdentifier
21
+ t.pronom_identifier(path: "externalIdentifier", attributes: {type: "puid"})
22
+ }
23
+ }
24
+ t.fileinfo {
25
+ t.size
26
+ t.creatingApplicationName
27
+ t.created
28
+ t.lastmodified
29
+ }
30
+ t.filestatus {
31
+ t.valid
32
+ t.well_formed(path: "well-formed")
33
+ }
34
+ t.metadata {
35
+ t.image {
36
+ t.imageWidth
37
+ t.imageHeight
38
+ t.colorSpace
39
+ }
40
+ t.document {
41
+ # TODO - configure to get from Tika?
42
+ # t.encoding
43
+ }
44
+ t.text
45
+ t.audio
46
+ t.video
47
+ }
48
+
49
+ ## proxy terms
50
+ # identification / identity
51
+ t.media_type proxy: [:identification, :identity, :mimetype]
52
+ t.format_label proxy: [:identification, :identity, :format_label]
53
+ t.format_version proxy: [:identification, :identity, :version]
54
+ t.pronom_identifier proxy: [:identification, :identity, :pronom_identifier]
55
+ # filestatus
56
+ t.valid proxy: [:filestatus, :valid]
57
+ t.well_formed proxy: [:filestatus, :well_formed]
58
+ # fileinfo
59
+ t.created proxy: [:fileinfo, :created]
60
+ t.creating_application proxy: [:fileinfo, :creatingApplicationName]
61
+ t.extent proxy: [:fileinfo, :size]
62
+ # image metadata
63
+ t.image_width proxy: [:metadata, :image, :imageWidth]
64
+ t.image_height proxy: [:metadata, :image, :imageHeight]
65
+ t.color_space proxy: [:metadata, :image, :colorSpace]
66
+ end
67
+
68
+ def self.xml_template
69
+ builder = Nokogiri::XML::Builder.new do |xml|
70
+ xml.fits("xmlns"=>FITS_XMLNS,
71
+ "xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance",
72
+ "xsi:schemaLocation"=>"http://hul.harvard.edu/ois/xml/ns/fits/fits_output http://hul.harvard.edu/ois/xml/xsd/fits/fits_output.xsd")
73
+ end
74
+ builder.doc
75
+ end
76
+
77
+ def prefix
78
+ "fits__"
79
+ end
80
+
81
+ def modified
82
+ ng_xml
83
+ .xpath("//fits:fileinfo/fits:lastmodified[@toolname != '#{EXIFTOOL}']", fits: FITS_XMLNS)
84
+ .map(&:text)
85
+ end
86
+
87
+ end
88
+ end