lib/ddr/datastreams/datastream_behavior.rb
module Ddr
module Datastreams
module DatastreamBehavior
extend ActiveSupport::Concern
DEFAULT_FILE_EXTENSION = "bin"
STRFTIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%LZ"
included do
around_save :notify_save
around_destroy :notify_delete
end
def validate_checksum! checksum, checksum_type=nil
raise Ddr::Models::Error, "Checksum cannot be validated on new datastream." if new?
raise Ddr::Models::Error, "Checksum cannot be validated on unpersisted content." if content_changed?
raise Ddr::Models::ChecksumInvalid, "The repository internal checksum validation failed." unless dsChecksumValid
algorithm = checksum_type || self.checksumType
ds_checksum = if !external? && algorithm == self.checksumType
self.checksum
else
content_digest(algorithm)
end
if checksum == ds_checksum
"The checksum [#{algorithm}]#{checksum} is valid for datastream #{version_info}."
else
raise Ddr::Models::ChecksumInvalid, "The checksum [#{algorithm}]#{checksum} is not valid for datastream #{version_info}."
end
end
def version_history
versions.map(&:profile)
end
def version_uri
# E.g., info:fedora/duke:1/content/content.0
["info:fedora", pid, dsid, dsVersionID].join("/") unless new?
end
def version_info
# E.g., info:fedora/duke:1/content/content.0 [2013-09-26T20:00:03.357Z]
"#{version_uri} [#{Ddr::Utils.ds_as_of_date_time(self)}]" unless new?
end
def create_date_string
dsCreateDate.strftime(STRFTIME_FORMAT) if dsCreateDate
end
def content_digest algorithm
Ddr::Utils.digest(self.content, algorithm)
end
def file_paths
if new?
return Array(file_path)
else
versions.map(&:file_path).compact
end
end
def file_path
if external? && dsLocation.present? && dsLocation.start_with?("file:")
Ddr::Utils.path_from_uri(dsLocation)
end
end
def file_name
if path = file_path
File.basename(path)
end
end
# Returns the size of the external file for the datastream.
def file_size
if external?
if path = file_path
File.size(path)
end
else
dsSize
end
end
# Return default file extension for datastream based on MIME type
def default_file_extension
mimetypes = MIME::Types[mimeType]
return mimetypes.first.extensions.first unless mimetypes.empty?
case mimeType
when 'application/n-triples'
'txt'
else
DEFAULT_FILE_EXTENSION
end
end
# Return default file name prefix based on object PID
def default_file_prefix
[pid.sub(/:/, '_'), dsid].join("_")
end
# Return default file name
def default_file_name
[default_file_prefix, default_file_extension].join(".")
end
def tempfile(prefix: nil, suffix: nil)
if empty?
raise Ddr::Models::Error, "Refusing to create tempfile for empty datastream!"
end
prefix ||= default_file_prefix + "--"
suffix ||= "." + default_file_extension
Tempfile.open [prefix, suffix], encoding: Encoding::ASCII_8BIT do |f|
f.write(content)
f.close
yield f
end
end
private
def default_notification_payload
{ pid: pid, file_id: dsid, control_group: controlGroup }
end
def delete_notification_payload
default_notification_payload.merge(
profile: profile.dup,
version_history: version_history
)
end
def notify_save
ActiveSupport::Notifications.instrument(
Ddr::Datastreams::SAVE,
default_notification_payload.merge(attributes_changed: changes)
) do |payload|
yield
payload[:profile] = profile.dup
end
end
def notify_delete
ActiveSupport::Notifications.instrument(
Ddr::Datastreams::DELETE, delete_notification_payload
) do |payload|
yield
end
end
end
end
end