Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v7.8 RC3 #5970

Merged
merged 30 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a67b5d4
Retain user entered playlist item title during playback
Dananji Jul 22, 2024
9be68aa
Merge pull request #5952 from avalonmediasystem/addtoplaylist-regression
Dananji Jul 22, 2024
76f63de
Speed up section list migration by optimizing solr queries
cjcolvar Jul 23, 2024
c0d5086
Send Referer header when fetching HLS for frame extraction
cjcolvar Jul 23, 2024
f54037c
Merge pull request #5954 from avalonmediasystem/cjcolvar-patch-4
cjcolvar Jul 24, 2024
c65d675
Merge pull request #5953 from avalonmediasystem/cjcolvar-patch-3
cjcolvar Jul 24, 2024
e27f03d
New Ramp build to test latest changes
Dananji Jul 26, 2024
ff0ccb5
Add setting for alternative rack tempfile directory
masaball Jul 26, 2024
8b56950
Merge pull request #5957 from avalonmediasystem/ramp-build
Dananji Jul 26, 2024
ce70296
Ensure that thumbnails show during migration
cjcolvar Jul 26, 2024
853aeda
Merge pull request #5959 from avalonmediasystem/during_migration
cjcolvar Jul 29, 2024
5f0f09d
Fix links in footer
masaball Jul 29, 2024
d370482
Merge pull request #5960 from avalonmediasystem/footer_links
masaball Jul 29, 2024
2b55f5e
Add tests
masaball Jul 30, 2024
971fc22
Add margin along x-axis to playlist description and tags display in m…
Dananji Jul 30, 2024
0841be6
Use current_ability instead of rebuilding ability which involves solr…
cjcolvar Jul 30, 2024
9a79d5a
Use solr doc to build proxy instead of fetching a new proxy from solr
cjcolvar Jul 30, 2024
788be76
Ramp 3.2.0 bump
Dananji Jul 30, 2024
af5b08a
Merge pull request #5963 from avalonmediasystem/speed_racer
cjcolvar Jul 30, 2024
e7a4323
Merge pull request #5964 from avalonmediasystem/ramp-3.2.0
Dananji Jul 30, 2024
95b6200
Testing improvements
cjcolvar Jul 31, 2024
dd32dd9
Move TempfileFactory to start of middleware stack
masaball Jul 31, 2024
71b03a4
Merge pull request #5958 from avalonmediasystem/tempfile_location
masaball Jul 31, 2024
830a5dd
Ensure single value for statement of responsibility matching solr field
cjcolvar Jul 31, 2024
50615ec
Get rid of nil ids when migrating to section lists
cjcolvar Jul 31, 2024
26c65b4
Merge pull request #5965 from avalonmediasystem/cjcolvar-patch-3
cjcolvar Jul 31, 2024
1584d59
Merge pull request #5962 from avalonmediasystem/offscreen-tags-5956
Aug 1, 2024
d36da13
Merge pull request #5966 from avalonmediasystem/cjcolvar-patch-4
masaball Aug 1, 2024
d5c56e3
Skip transcript search if there are curly brackets in query
masaball Aug 1, 2024
783f49f
Merge pull request #5968 from avalonmediasystem/search_brackets
masaball Aug 2, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions app/assets/javascripts/player_listeners.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ let addToPlaylistListenersAdded = false;
let firstLoad = true;
let streamId = '';
let isMobile = false;
let isPlaying = false;

/**
* Bind action buttons on the page with player events and re-populate details
Expand Down Expand Up @@ -69,17 +70,21 @@ function addActionButtonListeners(player, mediaObjectId, sectionIds) {
}

/* Add player event listeners to update UI components on the page */
// Listen to 'timeupdate' event to udate add to playlist form when using while media is playing or manually seeking
player.player.on('timeupdate', () => {
// Listen to 'seeked' event to udate add to playlist form
player.player.on('seeked', () => {
if (getActiveItem() != undefined) {
activeTrack = getActiveItem(false);
if (activeTrack != undefined) {
streamId = activeTrack.streamId;
}
disableEnableCurrentTrack(activeTrack, player.player.currentTime(), true, currentSectionLabel);
disableEnableCurrentTrack(activeTrack, player.player.currentTime(), isPlaying, currentSectionLabel);
}
});

player.player.on('play', () => { isPlaying = true; });

player.player.on('pause', () => { isPlaying = false; });

/*
Disable action buttons tied to player related information on player's 'loadstart' event which functions
parallel to the player's src changes. So, that the user doesn't interact with them get corrupted data
Expand Down Expand Up @@ -273,7 +278,7 @@ function addToPlaylistListeners(sectionIds, mediaObjectId) {
disableEnableCurrentTrack(
activeTrack,
currentTime,
false,
isPlaying,
$('#playlist_item_title').val() || currentSectionLabel // Preserve user edits for the title when available
);
$('#current-section-name').text(currentSectionLabel);
Expand Down
19 changes: 12 additions & 7 deletions app/assets/javascripts/ramp_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ function getTimelineScopes() {
if (parent.length === 0) {
let begin = 0;
let end = activeItem.times.end;
scopes[0].times = { begin: 0, end: end }
scopes[0].times = { begin: 0, end: end };
}
while (parent.length > 0) {
let next = parent.closest('ul').closest('li');
Expand Down Expand Up @@ -209,10 +209,10 @@ function collapseMoreDetails() {
* disable the option otherwise enable it.
* @param {Object} activeTrack JSON object for the active timespans
* @param {Number} currentTime player's playhead position
* @param {Boolean} isSeeked flag to indicate player 'seeked' event happened/not
* @param {Boolean} isPlaying flag to inidicate media is playing or not
* @param {String} sectionTitle name of the current section
*/
function disableEnableCurrentTrack(activeTrack, currentTime, isSeeked, sectionTitle) {
function disableEnableCurrentTrack(activeTrack, currentTime, isPlaying, sectionTitle) {
// Return when add to playlist form is not visible
let playlistForm = $('#add_to_playlist')[0];
if (!playlistForm) {
Expand All @@ -222,7 +222,8 @@ function disableEnableCurrentTrack(activeTrack, currentTime, isSeeked, sectionTi
if (activeTrack != undefined) {
streamId = activeTrack.streamId;
let { label, times, sectionLabel } = activeTrack;
let starttime = currentTime || times.begin;
// Update starttime when media is not playing
let starttime = isPlaying ? times.begin : currentTime || times.begin;
$('#playlist_item_start').val(createTimestamp(starttime, true));
$('#playlist_item_end').val(createTimestamp(times.end, true));
title = `${sectionLabel} - ${label}`;
Expand All @@ -245,9 +246,7 @@ function disableEnableCurrentTrack(activeTrack, currentTime, isSeeked, sectionTi
$('#playlistitem_scope_track').prop('checked', false);
}
}
// Only change the title when user actively seeked to a different timestamp,
// persisting the user changes to the field unless the active track is changed
if (isSeeked && sectionTitle != undefined) {
if (sectionTitle != undefined) {
$('#playlist_item_title').val(title);
}
}
Expand Down Expand Up @@ -345,4 +344,10 @@ function resetAddToPlaylistForm() {
function closeAlert() {
$('#add_to_playlist_alert').slideUp();
$('#add_to_playlist_form_group').slideDown();
// Set default selection in options list when alert is closed
if ($('#playlistitem_scope_track')[0].disabled) {
$('#playlistitem_scope_section').prop('checked', true);
} else {
$('#playlistitem_scope_track').prop('checked', true);
}
}
2 changes: 1 addition & 1 deletion app/assets/stylesheets/avalon/_footer.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
width: 100%;
min-height: 2.5rem;
color: #999999;
z-index: -1000;
z-index: 0;
}

footer {
Expand Down
1 change: 1 addition & 0 deletions app/assets/stylesheets/avalon/_playlists.scss
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@

#Playlists_paginate {
float: right;
z-index: 10;
}

/* Playlist copy modal */
Expand Down
16 changes: 8 additions & 8 deletions app/controllers/catalog_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,18 +89,18 @@ class CatalogController < ApplicationController
config.add_facet_field 'unit_ssim', label: 'Unit', limit: 5
config.add_facet_field 'language_ssim', label: 'Language', limit: 5
# Hide these facets if not a Collection Manager
config.add_facet_field 'workflow_published_sim', label: 'Published', limit: 5, if: Proc.new {|context, config, opts| Ability.new(context.current_user, context.user_session).can? :create, MediaObject}, group: "workflow"
config.add_facet_field 'avalon_uploader_ssi', label: 'Created by', limit: 5, if: Proc.new {|context, config, opts| Ability.new(context.current_user, context.user_session).can? :create, MediaObject}, group: "workflow"
config.add_facet_field 'read_access_group_ssim', label: 'Item access', if: Proc.new {|context, config, opts| Ability.new(context.current_user, context.user_session).can? :create, MediaObject}, group: "workflow", query: {
config.add_facet_field 'workflow_published_sim', label: 'Published', limit: 5, if: Proc.new {|context, config, opts| context.current_ability.can? :create, MediaObject}, group: "workflow"
config.add_facet_field 'avalon_uploader_ssi', label: 'Created by', limit: 5, if: Proc.new {|context, config, opts| context.current_ability.can? :create, MediaObject}, group: "workflow"
config.add_facet_field 'read_access_group_ssim', label: 'Item access', if: Proc.new {|context, config, opts| context.current_ability.can? :create, MediaObject}, group: "workflow", query: {
public: { label: "Public", fq: "has_model_ssim:MediaObject AND read_access_group_ssim:#{Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_PUBLIC}" },
restricted: { label: "Authenticated", fq: "has_model_ssim:MediaObject AND read_access_group_ssim:#{Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_AUTHENTICATED}" },
private: { label: "Private", fq: "has_model_ssim:MediaObject AND NOT read_access_group_ssim:#{Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_PUBLIC} AND NOT read_access_group_ssim:#{Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_AUTHENTICATED}" }
}
config.add_facet_field 'read_access_virtual_group_ssim', label: 'External Group', limit: 5, if: Proc.new {|context, config, opts| Ability.new(context.current_user, context.user_session).can? :create, MediaObject}, group: "workflow", helper_method: :vgroup_display
config.add_facet_field 'date_digitized_ssim', label: 'Date Digitized', limit: 5, if: Proc.new {|context, config, opts| Ability.new(context.current_user, context.user_session).can? :create, MediaObject}, group: "workflow"#, partial: 'blacklight/hierarchy/facet_hierarchy'
config.add_facet_field 'date_ingested_ssim', label: 'Date Ingested', limit: 5, if: Proc.new {|context, config, opts| Ability.new(context.current_user, context.user_session).can? :create, MediaObject}, group: "workflow"
config.add_facet_field 'has_captions_bsi', label: 'Has Captions', if: Proc.new {|context, config, opts| Ability.new(context.current_user, context.user_session).can? :create, MediaObject}, group: "workflow", helper_method: :display_has_caption_or_transcript
config.add_facet_field 'has_transcripts_bsi', label: 'Has Transcripts', if: Proc.new {|context, config, opts| Ability.new(context.current_user, context.user_session).can? :create, MediaObject}, group: "workflow", helper_method: :display_has_caption_or_transcript
config.add_facet_field 'read_access_virtual_group_ssim', label: 'External Group', limit: 5, if: Proc.new {|context, config, opts| context.current_ability.can? :create, MediaObject}, group: "workflow", helper_method: :vgroup_display
config.add_facet_field 'date_digitized_ssim', label: 'Date Digitized', limit: 5, if: Proc.new {|context, config, opts| context.current_ability.can? :create, MediaObject}, group: "workflow"#, partial: 'blacklight/hierarchy/facet_hierarchy'
config.add_facet_field 'date_ingested_ssim', label: 'Date Ingested', limit: 5, if: Proc.new {|context, config, opts| context.current_ability.can? :create, MediaObject}, group: "workflow"
config.add_facet_field 'has_captions_bsi', label: 'Has Captions', if: Proc.new {|context, config, opts| context.current_ability.can? :create, MediaObject}, group: "workflow", helper_method: :display_has_caption_or_transcript
config.add_facet_field 'has_transcripts_bsi', label: 'Has Transcripts', if: Proc.new {|context, config, opts| context.current_ability.can? :create, MediaObject}, group: "workflow", helper_method: :display_has_caption_or_transcript

# Have BL send all facet field names to Solr, which has been the default
# previously. Simply remove these lines if you'd rather use Solr request
Expand Down
4 changes: 2 additions & 2 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ def lti_share_url_for(obj, _opts = {})
def image_for(document)
master_file_id = document["section_id_ssim"].try :first

video_count = document["avalon_resource_type_ssim"].count{|m| m.start_with?('moving image') } rescue 0
audio_count = document["avalon_resource_type_ssim"].count{|m| m.start_with?('sound recording') } rescue 0
video_count = document["avalon_resource_type_ssim"].count{|m| m.downcase.start_with?('moving image') } rescue 0
audio_count = document["avalon_resource_type_ssim"].count{|m| m.downcase.start_with?('sound recording') } rescue 0

if master_file_id
if video_count > 0
Expand Down
2 changes: 1 addition & 1 deletion app/helpers/blacklight/local_blacklight_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def facet_group_names
end

def url_for_document doc, options = {}
SpeedyAF::Base.find(doc[:id])
SpeedyAF::Base.for(doc.to_h.with_indifferent_access)
end

def contributor_index_display args
Expand Down
4 changes: 2 additions & 2 deletions app/javascript/components/PlaylistRamp.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ const Ramp = ({
</div>
</Col>
</Row>
<Row className="ramp--playlist-desc-tags">
<Row className="ramp--playlist-desc-tags mx-1 mx-sm-0">
{comment && (
<div style={{ position: 'relative' }}>
<h4>{comment_label}</h4>
Expand Down Expand Up @@ -251,7 +251,7 @@ const Ramp = ({
</Row>
{playlist_item_ids?.length > 0 && (
<React.Fragment>
<h4 className="mt-3">Playlist Items</h4>
<h4 className="mt-3 mx-1 mx-sm-0">Playlist Items</h4>
<StructuredNavigation />
</React.Fragment>
)}
Expand Down
2 changes: 1 addition & 1 deletion app/models/master_file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ def create_frame_source_hls_temp_file(offset)
# Fixes https://github.com/avalonmediasystem/avalon/issues/3474
target_location = File.basename(details[:location]).split('?')[0]
target = File.join(Dir.tmpdir, target_location)
File.open(target,'wb') { |f| URI.open(details[:location]) { |io| f.write(io.read) } }
File.open(target,'wb') { |f| URI.open(details[:location], "Referer" => Rails.application.routes.url_helpers.root_url) { |io| f.write(io.read) } }
return target, details[:offset]
end

Expand Down
2 changes: 1 addition & 1 deletion app/models/media_object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ def section_ids
return @section_ids if @section_ids

# Do migration
self.section_ids = self.ordered_master_file_ids if self.section_list.nil?
self.section_ids = self.ordered_master_file_ids.compact if self.section_list.nil?

return [] if self.section_list.nil?
@section_ids = JSON.parse(self.section_list)
Expand Down
2 changes: 1 addition & 1 deletion app/models/mods_behaviors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def to_solr(solr_doc = Hash.new, opts = {})
solr_doc['other_identifier_sim'] = gather_terms(self.find_by_terms(:other_identifier))
solr_doc['bibliographic_id_ssi'] = self.bibliographic_id.first
solr_doc['bibliographic_id_source_ssi'] = self.bibliographic_id.source.first
solr_doc['statement_of_responsibility_ssi'] = gather_terms(self.find_by_terms(:statement_of_responsibility))
solr_doc['statement_of_responsibility_ssi'] = gather_terms(self.find_by_terms(:statement_of_responsibility)).first
solr_doc['record_identifier_ssim'] = gather_terms(self.find_by_terms(:record_identifier))

# Extract 4-digit year for creation date facet in Hydra and pub_date facet in Blacklight
Expand Down
1 change: 1 addition & 0 deletions app/models/search_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def search_section_transcripts(solr_parameters)
return unless solr_parameters[:q].present? && SupplementalFile.with_tag('transcript').any? && !(blacklight_params[:controller] == 'bookmarks')

terms = solr_parameters[:q].split
return if terms.any? { |term| term.match?(/[\{\}]/) }
term_subquery = terms.map { |term| "transcript_tsim:#{RSolr.solr_escape(term)}" }.join(" OR ")
solr_parameters[:defType] = "lucene"
solr_parameters[:q] = "({!edismax v=\"#{RSolr.solr_escape(solr_parameters[:q])}\"}) {!join to=id from=isPartOf_ssim}{!join to=id from=isPartOf_ssim}#{term_subquery}"
Expand Down
3 changes: 3 additions & 0 deletions config/application.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require_relative 'boot'
require_relative '../lib/tempfile_factory'

require 'rails/all'
require 'resolv-replace'
Expand Down Expand Up @@ -56,6 +57,8 @@ class Application < Rails::Application
end
end

config.middleware.insert_before 0, TempfileFactory

config.active_storage.service = (Settings&.active_storage&.service.presence || "local").to_sym
end
end
5 changes: 5 additions & 0 deletions config/settings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,8 @@ derivative:
allow_download: true
# Maximum size for uploaded files in bytes (default is disabled)
#max_upload_size: 2147483648 # Use :none or comment out to disable limit
# Rack Multipart creates temporary files when processing multipart form data with a large payload.
# If the default system /tmp directory is storage constrained, you can define an alternative here.
# Leave commented out to use the system default.
# tempfile:
# location: '/tmp'
4 changes: 2 additions & 2 deletions lib/tasks/avalon_migrations.rake
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,15 @@ namespace :avalon do
task media_object_section_list: :environment do
error_ids = []
mo_count = MediaObject.count
ids_to_migrate = ActiveFedora::SolrService.query("has_model_ssim:MediaObject AND NOT section_list_ssim:[* TO *]", rows: mo_count).pluck("id")
ids_to_migrate = ActiveFedora::SolrService.query("has_model_ssim:MediaObject AND NOT section_list_ssim:[* TO *]", fl: [:id], rows: mo_count).pluck("id")
puts "Migrating #{ids_to_migrate.size} out of #{mo_count} Media Objects."
ids_to_migrate.each do |id|
MediaObject.find(id).save!(validate: false)
rescue StandardError => error
error_ids += [id]
puts "Error migrating #{id}: #{error.message}"
end
remaining_ids_count = ActiveFedora::SolrService.query("has_model_ssim:MediaObject AND NOT section_list_ssim:[* TO *]", rows: mo_count).size
remaining_ids_count = ActiveFedora::SolrService.query("has_model_ssim:MediaObject AND NOT section_list_ssim:[* TO *]", fl: [:id], rows: mo_count).size
if error_ids.size > 0
puts "Migration finished running but #{error_ids.size} Media Objects failed to migrate. Try running the migration again."
elsif remaining_ids_count > 0
Expand Down
30 changes: 30 additions & 0 deletions lib/tempfile_factory.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Middleware to override the default Rack::Multipart tempfile factory:
# https://www.rubydoc.info/gems/rack/Rack/Multipart/Parser#TEMPFILE_FACTORY-constant
class TempfileFactory
def initialize(app)
@app = app
return unless Settings.tempfile.present?
if Settings.tempfile&.location.present? && File.directory?(Settings.tempfile&.location) && File.writable?(Settings.tempfile&.location)
@tempfile_location = Settings.tempfile.location
else
logger.warn("[Rack::Multipart] [Tempfile] #{Settings.tempfile.location} is not a diretory or not writable. Falling back to #{Dir.tmpdir}.")
end
end

def call(env)
if @tempfile_location
env["rack.multipart.tempfile_factory"] = lambda { |filename, content_type|
extension = ::File.extname(filename.gsub("\0", '%00'))[0, 129]
Tempfile.new(["RackMultipart", extension], @tempfile_location)
}
end

@app.call(env)
end

private

def logger
@logger ||= Logger.new(File.join(Rails.root, 'log', "#{Rails.env}.log"))
end
end
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"@babel/plugin-proposal-object-rest-spread": "^7.20.7",
"@babel/preset-react": "^7.0.0",
"@babel/runtime": "7",
"@samvera/ramp": "https://github.com/samvera-labs/ramp.git#e7d98e06ceceebe7e8ba59af29d1350a3a43acee",
"@samvera/ramp": "^3.2.0",
"babel-plugin-macros": "^3.1.0",
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
"buffer": "^6.0.3",
Expand Down
16 changes: 16 additions & 0 deletions spec/controllers/catalog_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,22 @@
expect(assigns(:response).documents.count).to eq 2
expect(assigns(:response).documents.map(&:id)).to match_array [private_media_object.id, public_media_object.id]
end
context "when there are transcripts present" do
let!(:transcript) { FactoryBot.create(:supplemental_file, :with_transcript_file, :with_transcript_tag, parent_id: private_media_object.id) }

before do
private_media_object.supplemental_files = [transcript]
private_media_object.save
end

it "should not error when search includes curly brackets" do
request.headers['Avalon-Api-Key'] = 'secret_token'
get 'index', params: { q: '{8}', format: 'atom' }
expect(response).to be_successful
expect(response).to render_template('catalog/index')
expect(response.content_type).to eq "application/atom+xml; charset=utf-8"
end
end
end
context "without api key" do
it "should not show results" do
Expand Down
Loading
Loading