ddr-models 2.0.1 → 2.1.0.rc1

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 (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