Skip to content

Commit

Permalink
Add poster resource for Hyacinth Assets; Webdriver updates to support…
Browse files Browse the repository at this point in the history
… modern versions of Google Chrome
  • Loading branch information
elohanlon committed Aug 15, 2023
1 parent 725f6d8 commit e9ca2d9
Show file tree
Hide file tree
Showing 11 changed files with 243 additions and 45 deletions.
4 changes: 2 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,9 @@ group :development, :test do
gem 'rspec-rails', '~> 3.3'
gem 'capybara', '~> 3.32'
# For testing with chromedriver
gem 'selenium-webdriver', '~> 3.142'
gem 'selenium-webdriver', '~> 4.0'
# For automatically updating chromedriver
gem 'webdrivers', '~> 4.0', require: false
gem 'webdrivers', '~> 5.3.0', require: false
gem 'factory_girl_rails', '>= 4.4.1'
gem 'rubocop', '~> 0.58.2', require: false
gem 'rubocop-rspec', '>= 1.20.1', require: false
Expand Down
21 changes: 11 additions & 10 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,7 @@ GEM
regexp_parser (~> 1.5)
xpath (~> 3.2)
charlock_holmes (0.7.6)
childprocess (2.0.0)
rake (< 13.0)
childprocess (4.1.0)
chosen-rails (1.5.2)
coffee-rails (>= 3.2)
railties (>= 3.0)
Expand Down Expand Up @@ -433,6 +432,7 @@ GEM
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
retriable (2.1.0)
rexml (3.2.6)
rsolr (1.1.2)
builder (>= 2.1.2)
rspec-core (3.3.2)
Expand Down Expand Up @@ -470,7 +470,7 @@ GEM
rubyXL (3.3.15)
nokogiri (>= 1.4.4)
rubyzip (>= 1.1.6)
rubyzip (1.2.3)
rubyzip (1.3.0)
sass (3.5.6)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
Expand All @@ -485,8 +485,9 @@ GEM
sdoc (0.4.1)
json (~> 1.7, >= 1.7.7)
rdoc (~> 4.0)
selenium-webdriver (3.142.7)
childprocess (>= 0.5, < 4.0)
selenium-webdriver (4.1.0)
childprocess (>= 0.5, < 5.0)
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2)
sequel (5.8.0)
sinatra (1.4.8)
Expand Down Expand Up @@ -557,10 +558,10 @@ GEM
binding_of_caller (>= 0.7.2)
railties (>= 4.0)
sprockets-rails (>= 2.0, < 4.0)
webdrivers (4.1.2)
webdrivers (5.3.1)
nokogiri (~> 1.6)
rubyzip (~> 1.0)
selenium-webdriver (>= 3.0, < 4.0)
rubyzip (>= 1.3.0)
selenium-webdriver (~> 4.0, < 4.11)
wowza-secure_token (0.0.1)
xml-simple (1.1.5)
xpath (3.2.0)
Expand Down Expand Up @@ -628,7 +629,7 @@ DEPENDENCIES
sass
sass-rails
sdoc
selenium-webdriver (~> 3.142)
selenium-webdriver (~> 4.0)
solrizer (>= 3.4.1)
spreadsheet
sqlite3 (~> 1.3.10)
Expand All @@ -637,7 +638,7 @@ DEPENDENCIES
underscore-rails
uri_service (= 0.5.5)
web-console (~> 2.0)
webdrivers (~> 4.0)
webdrivers (~> 5.3.0)
wowza-secure_token (= 0.0.1)

BUNDLED WITH
Expand Down
Original file line number Diff line number Diff line change
@@ -1,87 +1,99 @@
// Asset - Subclass
Hyacinth.DigitalObjectsApp.DigitalObject.Asset = function(digital_object_data){
Hyacinth.DigitalObjectsApp.DigitalObject.Asset = function (digital_object_data) {
Hyacinth.DigitalObjectsApp.DigitalObject.Base.call(this, digital_object_data); // call parent constructor
this.assetData = digital_object_data['asset_data'];
};
Hyacinth.extendClass(Hyacinth.DigitalObjectsApp.DigitalObject.Asset, Hyacinth.DigitalObjectsApp.DigitalObject.Base); //Extend


Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getFilesystemLocation = function(){
Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getFilesystemLocation = function () {
return this.assetData['filesystem_location'];
};

Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getAccessCopyLocation = function(){
Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getAccessCopyLocation = function () {
return this.assetData['access_copy_location'];
};

Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getServiceCopyLocation = function(){
Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getPosterLocation = function () {
return this.assetData['poster_location'];
};

Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getServiceCopyLocation = function () {
return this.assetData['service_copy_location'];
};

Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getFileChecksum = function(){
Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getFileChecksum = function () {
return this.assetData['checksum'];
};

Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getFileSizeInBytes = function(){
Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getFileSizeInBytes = function () {
return this.assetData['file_size_in_bytes'];
};

Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getAccessCopyFileSizeInBytes = function(){
Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getAccessCopyFileSizeInBytes = function () {
return this.assetData['access_copy_file_size_in_bytes'];
};

Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getServiceCopyFileSizeInBytes = function(){
Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getPosterFileSizeInBytes = function () {
return this.assetData['poster_file_size_in_bytes'];
};

Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getServiceCopyFileSizeInBytes = function () {
return this.assetData['service_copy_file_size_in_bytes'];
};

Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getFileSizeString = function() {
Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getFileSizeString = function () {
return this.bytesToSizeString(this.getFileSizeInBytes());
};

Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getAccessCopyFileSizeString = function() {
Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getAccessCopyFileSizeString = function () {
return this.bytesToSizeString(this.getAccessCopyFileSizeInBytes());
};

Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getServiceCopyFileSizeString = function() {
Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getPosterFileSizeString = function () {
return this.bytesToSizeString(this.getPosterFileSizeInBytes());
};

Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getServiceCopyFileSizeString = function () {
return this.bytesToSizeString(this.getServiceCopyFileSizeInBytes());
};

Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.bytesToSizeString = function(bytes) {
Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.bytesToSizeString = function (bytes) {
var sizeInBytes = parseInt(bytes);
var value = sizeInBytes;
var unit = 'B';
if(sizeInBytes < 1000) {
return value + ' ' + unit;
} else if(sizeInBytes < 1000000) {
value = sizeInBytes/1000;
if (sizeInBytes < 1000) {
return value + ' ' + unit;
} else if (sizeInBytes < 1000000) {
value = sizeInBytes / 1000;
unit = 'kB';
} else if(sizeInBytes < 1000000000) {
value = sizeInBytes/1000000;
} else if (sizeInBytes < 1000000000) {
value = sizeInBytes / 1000000;
unit = 'MB';
} else {
value = sizeInBytes/1000000000;
value = sizeInBytes / 1000000000;
unit = ' GB';
}

return parseFloat(parseFloat(value).toFixed(2)) + ' ' + unit; // the outermost parseFloat call removes trailing ".00" if present, but leaves values like ".01"
};

Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getOriginalFilename = function(){
Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getOriginalFilename = function () {
return this.assetData['original_filename'];
};

Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getOriginalFilePath = function(){
Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.getOriginalFilePath = function () {
return this.assetData['original_file_path'];
};

Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.hasImage = function(){
Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.hasImage = function () {
return Hyacinth.imageServerUrl && this.getDcType() == 'StillImage';
};

Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.isRestrictedSizeImage = function(){
Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.isRestrictedSizeImage = function () {
return this.hasRestrictions() && this.restrictions.restricted_size_image;
};

Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.isRestrictedOnsite = function(){
Hyacinth.DigitalObjectsApp.DigitalObject.Asset.prototype.isRestrictedOnsite = function () {
return this.hasRestrictions() && this.restrictions.restricted_onsite;
};
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,27 @@
<%= digitalObject.getAccessCopyLocation() == null ? 'N/A' : digitalObject.getAccessCopyLocation() %>
</div>
</div>
<div class="form-group">
<label class="col-sm-3">
Download Poster:
</label>
<div class="col-sm-9">
<% if(digitalObject.getPosterLocation() == null) { %>
N/A
<% } else { %>
<a href="<%= Hyacinth.getLocationOrigin() + '/digital_objects/' + digitalObject.getPid() + '/download_poster' %>" target="_blank"><span class="glyphicon glyphicon-download"></span> Download</a>
(<%= digitalObject.getPosterFileSizeString() %>) [<%= digitalObject.getPosterFileSizeInBytes() %> bytes]
<% } %>
</div>
</div>
<div class="form-group">
<label class="col-sm-3">
Poster Location:
</label>
<div class="col-sm-9">
<%= digitalObject.getPosterLocation() == null ? 'N/A' : digitalObject.getPosterLocation() %>
</div>
</div>
<div class="form-group">
<label class="col-sm-3">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ def download_service_copy
end
end

def download_poster
if @digital_object.is_a?(DigitalObject::Asset)
send_file @digital_object.poster_location, filename: @digital_object.fedora_object.datastreams['poster'].dsLabel
else
render text: @digital_object.digital_object_type.display_label.pluralize + ' do not have download URLs. Try downloading an Asset poster instead.'
end
end

# download_access_copy offers the ability to stream files using range requests
# because access copies are sometimes played in a video player
def download_access_copy
Expand Down
39 changes: 36 additions & 3 deletions app/controllers/digital_objects_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ class DigitalObjectsController < ApplicationController
include Hyacinth::DigitalObjects::IndexDocument
include Hyacinth::DigitalObjects::Captions

before_action :set_digital_object, only: [:show, :edit, :update, :destroy, :undestroy, :data_for_ordered_child_editor, :download, :download_access_copy, :download_service_copy,
before_action :set_digital_object, only: [:show, :edit, :update, :destroy, :undestroy, :data_for_ordered_child_editor,
:download, :download_access_copy, :download_poster, :download_service_copy,
:add_parent, :remove_parents, :mods, :xacml, :media_view, :rotate_image, :swap_order_of_first_two_child_assets,
:download_transcript, :update_transcript,
:download_index_document, :update_index_document,
:download_captions, :update_captions,
:download_synchronized_transcript, :update_synchronized_transcript, :clear_synchronized_transcript_and_reimport_transcript,
:upload_access_copy, :update_featured_region, :query_featured_region
:upload_access_copy, :upload_poster, :update_featured_region, :query_featured_region
]
before_action :set_digital_object_for_data_for_editor_action, only: [:data_for_editor]
before_action :set_contextual_nav_options
Expand Down Expand Up @@ -340,6 +341,38 @@ def upload_access_copy
end
end

def upload_poster
if @digital_object.is_a?(DigitalObject::Asset)
if params[:file].blank?
render status: :bad_request, json: { errors: ['Missing multipart/form-data file upload data with name: file'] }
return
end

@digital_object_data = {}
@digital_object_data['import_file'] = posted_file_data(DigitalObject::Asset::IMPORT_TYPE_POST_DATA)
@digital_object.set_digital_object_data({
'import_file' => {
'poster_import_path' => params[:file].tempfile.path
}
}, true)
@digital_object.updated_by = current_user

if @digital_object.save
RepublishAssetJob.perform_later(@digital_object.pid)
render json: { success: true, size: @digital_object.poster_file_size_in_bytes.to_i }
else
render json: { errors: ['An error occurred during poster upload.'] }
end
else
render json: { errors: ["This action is only allowed for Assets. This object has type: #{@digital_object.digital_object_type.display_label}"] }
end
ensure
if params[:file].present?
params[:file].tempfile.close
params[:file].tempfile.unlink
end
end

private

# Use callbacks to share common setup or constraints between actions.
Expand Down Expand Up @@ -374,7 +407,7 @@ def require_appropriate_project_permissions!
case params[:action]
when 'index', 'search', 'upload_directory_listing', 'titles_for_pids', 'search_results_to_csv'
# Do nothing. These actions are open to all logged-in users.
when 'show', 'data_for_editor', 'mods', 'download', 'data_for_ordered_child_editor', 'media_view', 'download_transcript', 'download_index_document', 'download_captions', 'download_synchronized_transcript', 'download_access_copy', 'download_service_copy', 'download'
when 'show', 'data_for_editor', 'mods', 'download', 'data_for_ordered_child_editor', 'media_view', 'download_transcript', 'download_index_document', 'download_captions', 'download_synchronized_transcript', 'download_access_copy', 'download_poster', 'download_service_copy', 'download'
require_project_permission!(@digital_object.project, :read)
when 'create'
# Access logic inside action method
Expand Down
42 changes: 40 additions & 2 deletions app/models/concerns/digital_object/assets/file_import.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ def do_access_copy_import
end

# Clear old rels_int values if present
fedora_object.rels_int.clear_relationship(access_ds, :extent)
fedora_object.rels_int.clear_relationship(access_ds, :rdf_type)
@fedora_object.rels_int.clear_relationship(access_ds, :extent)
@fedora_object.rels_int.clear_relationship(access_ds, :rdf_type)

# Set rels_int values
@fedora_object.rels_int.add_relationship(access_ds, :extent, File.size(@access_copy_import_path).to_s, true) # last param *true* means that this is a literal value rather than a relationship
Expand Down Expand Up @@ -133,6 +133,44 @@ def do_service_copy_import
@fedora_object.add_datastream(service_ds)
end

def do_poster_import
poster_filename = 'poster' + File.extname(@poster_import_path)
dest_dir = Hyacinth::Utils::PathUtils.access_directory_path_for_uuid!(self.uuid)
dest_file_path = File.join(dest_dir, poster_filename)
FileUtils.cp(@poster_import_path, dest_file_path)
# Make sure the new file's group permissions are set to rw (using 0660 permissions).
# When Derivativo 1.5 is released, this can change to 0640 permissions.
FileUtils.chmod(0660, dest_file_path)

poster_ds_location = filesystem_path_to_ds_location(dest_file_path)

# Create poster datastream if it doesn't already exist
poster_ds = @fedora_object.datastreams['poster']
if poster_ds.blank?
poster_ds = @fedora_object.create_datastream(
ActiveFedora::Datastream,
'poster',
controlGroup: 'E',
mimeType: BestType.mime_type.for_file_name(poster_filename),
dsLabel: poster_filename,
versionable: true
)
poster_ds.dsLocation = poster_ds_location
@fedora_object.add_datastream(poster_ds)
else
poster_ds.dsLocation = poster_ds_location
poster_ds.mimeType = BestType.mime_type.for_file_name(poster_filename)
poster_ds.dsLabel = poster_filename
end

# Clear old rels_int values if present
@fedora_object.rels_int.clear_relationship(poster_ds, :extent)
@fedora_object.rels_int.clear_relationship(poster_ds, :rdf_type)

# Set rels_int values
@fedora_object.rels_int.add_relationship(poster_ds, :extent, File.size(@poster_import_path).to_s, true) # last param *true* means that this is a literal value rather than a relationship
end

def copy_and_verify_file(import_file)
if [DigitalObject::Asset::IMPORT_TYPE_INTERNAL, DigitalObject::Asset::IMPORT_TYPE_POST_DATA].include? @import_file_import_type
return copy_and_verify_internal_file(import_file)
Expand Down
Loading

0 comments on commit e9ca2d9

Please sign in to comment.