From 649ce6ffd861af3bd0b2a9e28ffb48819d50bf86 Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Wed, 20 Sep 2023 23:59:46 -0700 Subject: [PATCH 01/60] add blacklight advances search, blacklight date ranges and order already to the gem file and configure them --- Gemfile | 3 + app/assets/javascripts/admin_font_select.js | 32 +- app/assets/javascripts/application.js | 11 + .../range_limit_distro_facets.js | 300 ++++++++++++++++++ .../range_limit_shared.js | 24 ++ .../range_limit_slider.js | 130 ++++++++ app/assets/stylesheets/application.css | 3 + app/controllers/catalog_controller.rb | 86 ++++- app/controllers/saved_searches_controller.rb | 7 + app/controllers/search_history_controller.rb | 8 + app/models/collection.rb | 1 + app/models/generic_work.rb | 3 + app/models/image.rb | 2 + app/models/search_builder.rb | 4 + .../advanced/_advanced_search_help.html.erb | 26 ++ .../_range_limit_panel.html.erb | 125 ++++++++ config/routes.rb | 4 +- 17 files changed, 757 insertions(+), 12 deletions(-) create mode 100644 app/assets/javascripts/blacklight_range_limit/range_limit_distro_facets.js create mode 100644 app/assets/javascripts/blacklight_range_limit/range_limit_shared.js create mode 100644 app/assets/javascripts/blacklight_range_limit/range_limit_slider.js create mode 100644 app/controllers/saved_searches_controller.rb create mode 100644 app/controllers/search_history_controller.rb create mode 100644 app/views/advanced/_advanced_search_help.html.erb create mode 100644 app/views/blacklight_range_limit/_range_limit_panel.html.erb diff --git a/Gemfile b/Gemfile index 868c97ba3..8cda67972 100644 --- a/Gemfile +++ b/Gemfile @@ -13,7 +13,9 @@ gem 'addressable', '2.8.1' # remove once https://github.com/postrank-labs/postra gem 'apartment' gem 'aws-sdk-sqs', group: %i[aws] gem 'blacklight', '~> 6.7' +gem 'blacklight_advanced_search' gem 'blacklight_oai_provider', '~> 6.1', '>= 6.1.1' +gem 'blacklight_range_limit', '6.5.0' gem 'bolognese', '>= 1.9.10' gem 'bootstrap-datepicker-rails' gem 'bulkrax', '~> 5.3' @@ -54,6 +56,7 @@ gem 'omniauth-multi-provider' gem 'omniauth-rails_csrf_protection', '~> 1.0' gem 'omniauth-saml', '~> 2.1' gem 'omniauth_openid_connect' +gem 'order_already' gem 'parser', '~> 2.5.3' gem 'pg' gem 'postrank-uri', '>= 1.0.24' diff --git a/app/assets/javascripts/admin_font_select.js b/app/assets/javascripts/admin_font_select.js index 7fa065108..e2c3e89cb 100644 --- a/app/assets/javascripts/admin_font_select.js +++ b/app/assets/javascripts/admin_font_select.js @@ -1,6 +1,34 @@ Blacklight.onLoad(function() { if($("#admin_appearance_body_font").length > 0){ - $("#admin_appearance_body_font").fontselect({lookahead: 20}); - $("#admin_appearance_headline_font").fontselect({lookahead: 20}); + $("#admin_appearance_body_font").fontselect({lookahead: 20}) + $("#admin_appearance_headline_font").fontselect({lookahead: 20}) } }); + +$('div.defaultable-fonts a.restore-default-font').click(function(e) { + e.preventDefault() + var defaultTarget = $(e.target).data('default-target') + var input = $("input[name='admin_appearance["+ defaultTarget +"]']") + var defaultValue = input.data('default-value').replace(';', '') + var inputDisplay = $("div[class$='"+ defaultTarget +"']").find('div.font-select span') + + input.val(defaultValue) + inputDisplay.css("font-family", defaultValue) + inputDisplay.text(defaultValue) +}) + +$('.panel-footer a.restore-all-default-fonts').click(function(e) { + e.preventDefault() + + var allFontInputs = $("input[name*='font']") + + allFontInputs.each(function() { + var thisTarget = $(this).attr('id').replace('admin_appearance_', '') + var defaultValue = $(this).data('default-value').replace(';', '') + var inputDisplay = $("div[class$='"+ thisTarget +"']").find('div.font-select span') + + $(this).val(defaultValue) + inputDisplay.css("font-family", defaultValue) + inputDisplay.text(defaultValue) + }) +}); diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index fe1ce9b26..c2e416d37 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -26,6 +26,8 @@ // Required by Blacklight //= require blacklight/blacklight //= require admin_font_select +//= require admin_color_select +//= require blacklight_advanced_search // Moved the Hyku JS *above* the Hyrax JS to resolve #1187 (following // a pattern found in ScholarSphere) @@ -49,3 +51,12 @@ //= require flot_graph //= require statistics_tab_manager //= require blacklight_gallery/default + +// Required for blacklight range limit +//= require blacklight_range_limit/range_limit_distro_facets +//= require blacklight_range_limit/range_limit_shared +//= require blacklight_range_limit/range_limit_slider +//= require bootstrap-slider +//= require jquery.flot.js + +//= require tinymce diff --git a/app/assets/javascripts/blacklight_range_limit/range_limit_distro_facets.js b/app/assets/javascripts/blacklight_range_limit/range_limit_distro_facets.js new file mode 100644 index 000000000..4b2807651 --- /dev/null +++ b/app/assets/javascripts/blacklight_range_limit/range_limit_distro_facets.js @@ -0,0 +1,300 @@ +// for Blacklight.onLoad: + +/* A custom event "plotDrawn.blacklight.rangeLimit" will be sent when flot plot + is (re-)drawn on screen possibly with a new size. target of event will be the DOM element + containing the plot. Used to resize slider to match. */ + + Blacklight.onLoad(function() { + // ratio of width to height for desired display, multiply width by this ratio + // to get height. hard-coded in for now. + var display_ratio = 1/(1.618 * 2); // half a golden rectangle, why not + var redrawnEvent = "plotDrawn.blacklight.rangeLimit"; + + + + // Facets already on the page? Turn em into a chart. + $(".range_limit .profile .distribution.chart_js ul").each(function() { + turnIntoPlot($(this).parent()); + }); + + + // Add AJAX fetched range facets if needed, and add a chart to em + $(".range_limit .profile .distribution a.load_distribution").each(function() { + var container = $(this).parent('div.distribution'); + + $(container).load($(this).attr('href'), function(response, status) { + if ($(container).hasClass("chart_js") && status == "success" ) { + turnIntoPlot(container); + } + }); + }); + + // Listen for twitter bootstrap collapsible open events, to render flot + // in previously hidden divs on open, if needed. + $("body").on("show.bs.collapse", function(event) { + // Was the target a .facet-content including a .chart-js? + var container = $(event.target).filter(".facet-content").find(".chart_js"); + + // only if it doesn't already have a canvas, it isn't already drawn + if (container && container.find("canvas").length == 0) { + // be willing to wait up to 1100ms for container to + // have width -- right away on show.bs is too soon, but + // shown.bs is later than we want, we want to start rendering + // while animation is still in progress. + turnIntoPlot(container, 1100); + } + }); + + + + // after a collapsible facet contents is fully shown, + // resize the flot chart to current conditions. This way, if you change + // browser window size, you can get chart resized to fit by closing and opening + // again, if needed. + + function redrawPlot(container) { + if (container && container.width() > 0) { + // resize the container's height, since width may have changed. + container.height( container.width() * display_ratio ); + + // redraw the chart. + var plot = container.data("plot"); + if (plot) { + // how to redraw after possible resize? + // Cribbed from https://github.com/flot/flot/blob/master/jquery.flot.resize.js + plot.resize(); + plot.setupGrid(); + plot.draw(); + // plus trigger redraw of the selection, which otherwise ain't always right + // we'll trigger a fake event on one of the boxes + var form = $(container).closest(".limit_content").find("form.range_limit"); + form.find("input.range_begin").trigger("change"); + + // send our custom event to trigger redraw of slider + $(container).trigger(redrawnEvent); + } + } + } + + $("body").on("shown.bs.collapse", function(event) { + var container = $(event.target).filter(".facet-content").find(".chart_js"); + redrawPlot(container); + }); + + // debouce borrowed from underscore + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. If `immediate` is passed, trigger the function on the + // leading edge, instead of the trailing. + debounce = function(func, wait, immediate) { + var timeout; + return function() { + var context = this, args = arguments; + var later = function() { + timeout = null; + if (!immediate) func.apply(context, args); + }; + var callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) func.apply(context, args); + }; + }; + + $(window).on("resize", debounce(function() { + $(".chart_js").each(function(i, container) { + redrawPlot($(container)); + }); + }, 350)); + + // second arg, if provided, is a number of ms we're willing to + // wait for the container to have width before giving up -- we'll + // set 50ms timers to check back until timeout is expired or the + // container is finally visible. The timeout is used when we catch + // bootstrap show event, but the animation hasn't barely begun yet -- but + // we don't want to wait until it's finished, we want to start rendering + // as soon as we can. + // + // We also will + function turnIntoPlot(container, wait_for_visible) { + // flot can only render in a a div with a defined width. + // for instance, a hidden div can't generally be rendered in (although if you set + // an explicit width on it, it might work) + // + // We'll count on later code that catch bootstrap collapse open to render + // on show, for currently hidden divs. + + // for some reason width sometimes return negative, not sure + // why but it's some kind of hidden. + if (container.width() > 0) { + var height = container.width() * display_ratio; + + // Need an explicit height to make flot happy. + container.height( height ) + + areaChart($(container)); + + $(container).trigger(redrawnEvent); + } + else if (wait_for_visible > 0) { + setTimeout(function() { + turnIntoPlot(container, wait_for_visible - 50); + }, 50); + } + } + + // Takes a div holding a ul of distribution segments produced by + // blacklight_range_limit/_range_facets and makes it into + // a flot area chart. + function areaChart(container) { + //flot loaded? And canvas element supported. + if ( domDependenciesMet() ) { + + // Grab the data from the ul div + var series_data = new Array(); + var pointer_lookup = new Array(); + var x_ticks = new Array(); + var min = BlacklightRangeLimit.parseNum($(container).find("ul li:first-child span.from").text()); + var max = BlacklightRangeLimit.parseNum($(container).find("ul li:last-child span.to").text()); + + $(container).find("ul li").each(function() { + var from = BlacklightRangeLimit.parseNum($(this).find("span.from").text()); + var to = BlacklightRangeLimit.parseNum($(this).find("span.to").text()); + var count = BlacklightRangeLimit.parseNum($(this).find("span.count").text()); + var avg = (count / (to - from + 1)); + + + //We use the avg as the y-coord, to make the area of each + //segment proportional to how many documents it holds. + series_data.push( [from, avg ] ); + series_data.push( [to+1, avg] ); + + x_ticks.push(from); + + pointer_lookup.push({'from': from, 'to': to, 'count': count, 'label': $(this).find(".facet_select").text() }); + }); + var max_plus_one = BlacklightRangeLimit.parseNum($(container).find("ul li:last-child span.to").text())+1; + x_ticks.push( max_plus_one ); + + + + var plot; + var config = $(container).closest('.facet_limit').data('plot-config') || {}; + + try { + plot = $.plot($(container), [series_data], + $.extend(true, config, { + yaxis: { ticks: [], min: 0, autoscaleMargin: 0.1}, + //xaxis: { ticks: x_ticks }, + xaxis: { tickDecimals: 0 }, // force integer ticks + series: { lines: { fill: true, steps: true }}, + grid: {clickable: true, hoverable: true, autoHighlight: false}, + selection: {mode: "x"} + })); + } + catch(err) { + alert(err); + } + + find_segment_for = function_for_find_segment(pointer_lookup); + var last_segment = null; + $(container).tooltip({'placement': 'bottom', 'trigger': 'manual', 'delay': { show: 0, hide: 100}}); + + $(container).bind("plothover", function (event, pos, item) { + segment = find_segment_for(pos.x); + + if(segment != last_segment) { + var title = find_segment_for(pos.x).label + ' (' + BlacklightRangeLimit.parseNum(segment.count) + ')'; + $(container).attr("title", title).tooltip("_fixTitle").tooltip("show"); + + last_segment = segment; + } + }); + + $(container).bind("mouseout", function() { + last_segment = null; + $(container).tooltip('hide'); + }); + $(container).bind("plotclick", function (event, pos, item) { + if ( plot.getSelection() == null) { + segment = find_segment_for(pos.x); + plot.setSelection( normalized_selection(segment.from, segment.to)); + } + }); + $(container).bind("plotselected plotselecting", function(event, ranges) { + if (ranges != null ) { + var from = Math.floor(ranges.xaxis.from); + var to = Math.floor(ranges.xaxis.to); + + var form = $(container).closest(".limit_content").find("form.range_limit"); + form.find("input.range_begin").val(from); + form.find("input.range_end").val(to); + + var slider_placeholder = $(container).closest(".limit_content").find("[data-slider-placeholder]"); + if (slider_placeholder) { + slider_placeholder.slider("setValue", [from, to+1]); + } + } + }); + + var form = $(container).closest(".limit_content").find("form.range_limit"); + form.find("input.range_begin, input.range_end").change(function () { + plot.setSelection( form_selection(form, min, max) , true ); + }); + $(container).closest(".limit_content").find(".profile .range").on("slide", function(event, ui) { + var values = $(event.target).data("slider").getValue(); + form.find("input.range_begin").val(values[0]); + form.find("input.range_end").val(values[1]); + plot.setSelection( normalized_selection(values[0], Math.max(values[0], values[1]-1)), true); + }); + + // initially entirely selected, to match slider + plot.setSelection( {xaxis: { from:min, to:max+0.9999}} ); + } + } + + + // Send endpoint to endpoint+0.99999 to have display + // more closely approximate limiting behavior esp + // at small resolutions. (Since we search on whole numbers, + // inclusive, but flot chart is decimal.) + function normalized_selection(min, max) { + max += 0.99999; + + return {xaxis: { 'from':min, 'to':max}} + } + + function form_selection(form, min, max) { + var begin_val = BlacklightRangeLimit.parseNum($(form).find("input.range_begin").val()); + if (isNaN(begin_val) || begin_val < min) { + begin_val = min; + } + var end_val = BlacklightRangeLimit.parseNum($(form).find("input.range_end").val()); + if (isNaN(end_val) || end_val > max) { + end_val = max; + } + + return normalized_selection(begin_val, end_val); + } + + function function_for_find_segment(pointer_lookup_arr) { + return function(x_coord) { + for (var i = pointer_lookup_arr.length-1 ; i >= 0 ; i--) { + var hash = pointer_lookup_arr[i]; + if (x_coord >= hash.from) + return hash; + } + return pointer_lookup_arr[0]; + }; + } + + // Check if Flot is loaded, and if browser has support for + // canvas object, either natively or via IE excanvas. + function domDependenciesMet() { + var flotLoaded = (typeof $.plot != "undefined"); + var canvasAvailable = ((typeof(document.createElement('canvas').getContext) != "undefined") || (typeof window.CanvasRenderingContext2D != 'undefined' || typeof G_vmlCanvasManager != 'undefined')); + + return (flotLoaded && canvasAvailable); + } + }); + \ No newline at end of file diff --git a/app/assets/javascripts/blacklight_range_limit/range_limit_shared.js b/app/assets/javascripts/blacklight_range_limit/range_limit_shared.js new file mode 100644 index 000000000..74aef9e9e --- /dev/null +++ b/app/assets/javascripts/blacklight_range_limit/range_limit_shared.js @@ -0,0 +1,24 @@ + +// takes a string and parses into an integer, but throws away commas first, to avoid truncation when there is a comma +// use in place of javascript's native parseInt +!function(global) { + 'use strict'; + + var previousBlacklightRangeLimit = global.BlacklightRangeLimit; + + function BlacklightRangeLimit(options) { + this.options = options || {}; + } + + BlacklightRangeLimit.parseNum = function parseNum(str) { + str = String(str).replace(/[^0-9]/g, ''); + return parseInt(str, 10); + }; + + BlacklightRangeLimit.noConflict = function noConflict() { + global.BlacklightRangeLimit = previousBlacklightRangeLimit; + return BlacklightRangeLimit; + }; + + global.BlacklightRangeLimit = BlacklightRangeLimit; +}(this); diff --git a/app/assets/javascripts/blacklight_range_limit/range_limit_slider.js b/app/assets/javascripts/blacklight_range_limit/range_limit_slider.js new file mode 100644 index 000000000..e29464229 --- /dev/null +++ b/app/assets/javascripts/blacklight_range_limit/range_limit_slider.js @@ -0,0 +1,130 @@ +// for Blacklight.onLoad: + +Blacklight.onLoad(function() { + + $(".range_limit .profile .range.slider_js").each(function() { + var range_element = $(this); + + var boundaries = min_max(this); + var min = boundaries[0]; + var max = boundaries[1]; + + if (isInt(min) && isInt(max)) { + $(this).contents().wrapAll('
'); + + var range_element = $(this); + var form = $(range_element).closest(".range_limit").find("form.range_limit"); + var begin_el = form.find("input.range_begin"); + var end_el = form.find("input.range_end"); + + var placeholder_input = $('').appendTo(range_element); + + // make sure slider is loaded + if (placeholder_input.slider !== undefined) { + placeholder_input.slider({ + min: min, + max: max+1, + value: [min, max+1], + tooltip: "hide" + }); + + // try to make slider width/orientation match chart's + var container = range_element.closest(".range_limit"); + var plot = container.find(".chart_js").data("plot"); + var slider_el = container.find(".slider"); + + if (plot && slider_el) { + slider_el.width(plot.width()); + slider_el.css("display", "block") + slider_el.css('margin-right', 'auto'); + slider_el.css('margin-left', 'auto'); + } + else if (slider_el) { + slider_el.css("width", "100%"); + } + } + + // Slider change should update text input values. + var parent = $(this).parent(); + var form = $(parent).closest(".limit_content").find("form.range_limit"); + $(parent).closest(".limit_content").find(".profile .range").on("slide", function(event, ui) { + var values = $(event.target).data("slider").getValue(); + form.find("input.range_begin").val(values[0]); + form.find("input.range_end").val(values[1]); + }); + } + + begin_el.val(min); + end_el.val(max); + + begin_el.change( function() { + var val = BlacklightRangeLimit.parseNum($(this).val()); + if ( isNaN(val) || val < min) { + //for weird data, set slider at min + val = min; + } + var values = placeholder_input.data("slider").getValue(); + values[0] = val; + placeholder_input.slider("setValue", values); + }); + + end_el.change( function() { + var val = BlacklightRangeLimit.parseNum($(this).val()); + if ( isNaN(val) || val > max ) { + //weird entry, set slider to max + val = max; + } + var values = placeholder_input.data("slider").getValue(); + values[1] = val; + placeholder_input.slider("setValue", values); + }); + + }); + + // catch event for redrawing chart, to redraw slider to match width + $("body").on("plotDrawn.blacklight.rangeLimit", function(event) { + var area = $(event.target).closest(".limit_content.range_limit"); + var plot = area.find(".chart_js").data("plot"); + var slider_el = area.find(".slider"); + + if (plot && slider_el) { + slider_el.width(plot.width()); + slider_el.css("display", "block") + slider_el.css('margin-right', 'auto'); + slider_el.css('margin-left', 'auto'); + } + }); + + // returns two element array min/max as numbers. If there is a limit applied, + // it's boundaries are are limits. Otherwise, min/max in current result + // set as sniffed from HTML. Pass in a DOM element for a div.range + // Will return NaN as min or max in case of error or other weirdness. + function min_max(range_element) { + var current_limit = $(range_element).closest(".limit_content.range_limit").find(".current") + + + + var min = max = BlacklightRangeLimit.parseNum(current_limit.find(".single").text()) + if ( isNaN(min)) { + min = BlacklightRangeLimit.parseNum(current_limit.find(".from").first().text()); + max = BlacklightRangeLimit.parseNum(current_limit.find(".to").first().text()); + } + + if (isNaN(min) || isNaN(max)) { + //no current limit, take from results min max included in spans + min = BlacklightRangeLimit.parseNum($(range_element).find(".min").first().text()); + max = BlacklightRangeLimit.parseNum($(range_element).find(".max").first().text()); + } + + return [min, max] + } + + + // Check to see if a value is an Integer + // see: http://stackoverflow.com/questions/3885817/how-to-check-if-a-number-is-float-or-integer + function isInt(n) { + return n % 1 === 0; + } + + }); + \ No newline at end of file diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 8b66c7d5d..bb4734825 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -18,5 +18,8 @@ *= require dataTables/bootstrap/3/jquery.dataTables.bootstrap *= require bootstrap-datepicker *= require single_signon + *= require blacklight_advanced_search + *= require blacklight_range_limit + *= require iiif_print/iiif_print *= require_self */ diff --git a/app/controllers/catalog_controller.rb b/app/controllers/catalog_controller.rb index 72265252c..17eca79a9 100644 --- a/app/controllers/catalog_controller.rb +++ b/app/controllers/catalog_controller.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class CatalogController < ApplicationController + include BlacklightAdvancedSearch::Controller + include BlacklightRangeLimit::ControllerOverride include Hydra::Catalog include Hydra::Controller::ControllerBehavior include BlacklightOaiProvider::Controller @@ -8,20 +10,33 @@ class CatalogController < ApplicationController # These before_action filters apply the hydra access controls before_action :enforce_show_permissions, only: :show - def self.uploaded_field - 'system_create_dtsi' + def self.created_field + 'date_created_ssim' + end + + def self.creator_field + 'creator_ssim' end def self.modified_field 'system_modified_dtsi' end + def self.title_field + 'title_ssim' + end + + def self.uploaded_field + 'system_create_dtsi' + end + # CatalogController-scope behavior and configuration for BlacklightIiifSearch include BlacklightIiifSearch::Controller configure_blacklight do |config| # IiifPrint index fields - config.add_index_field 'all_text_tsimv', highlight: true, helper_method: :render_ocr_snippets + config.add_index_field 'all_text_timv' + config.add_index_field 'file_set_text_tsimv', label: "Item contents", highlight: true, helper_method: :render_ocr_snippets # configuration for Blacklight IIIF Content Search config.iiif_search = { @@ -44,18 +59,32 @@ def self.modified_field config.advanced_search[:url_key] ||= 'advanced' config.advanced_search[:query_parser] ||= 'dismax' config.advanced_search[:form_solr_parameters] ||= {} + config.advanced_search[:form_facet_partial] ||= "advanced_search_facets_as_select" config.search_builder_class = IiifPrint::CatalogSearchBuilder + # Use locally customized AdvSearchBuilder so we can enable blacklight_advanced_search + # TODO ROB config.search_builder_class = AdvSearchBuilder + # Show gallery view config.view.gallery.partials = %i[index_header index] config.view.slideshow.partials = [:index] + # Because too many times on Samvera tech people raise a problem regarding a failed query to SOLR. + # Often, it's because they inadvertently exceeded the character limit of a GET request. + config.http_method = :post + ## Default parameters to send to solr for all search-like requests. See also SolrHelper#solr_search_params config.default_solr_params = { qt: "search", rows: 10, - qf: "title_tesim description_tesim creator_tesim keyword_tesim all_text_timv" + qf: IiifPrint.config.metadata_fields.keys.map { |attribute| "#{attribute}_tesim" } + .join(' ') << " title_tesim description_tesim all_text_timv file_set_text_tsimv", # the first space character is necessary! + "hl": true, + "hl.simple.pre": "", + "hl.simple.post": "", + "hl.snippets": 30, + "hl.fragsize": 100 } # Specify which field to use in the tag cloud on the homepage. @@ -81,11 +110,34 @@ def self.modified_field config.add_facet_field 'file_format_sim', limit: 5 config.add_facet_field 'member_of_collections_ssim', limit: 5, label: 'Collections' + + # TODO deal with part of facet changes + # config.add_facet_field solr_name("part", :facetable), limit: 5, label: 'Part' + # config.add_facet_field solr_name("part_of", :facetable), limit: 5 + # removed # config.add_facet_field solr_name("file_format", :facetable), limit: 5 + # removed # config.add_facet_field solr_name("contributor", :facetable), label: "Contributor", limit: 5 + # remvode config.add_facet_field solr_name("refereed", :facetable), limit: 5 + # 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 # handler defaults, or have no facets. config.add_facet_fields_to_solr_request! + # Prior to this change, the applications specific translations were not loaded. Dogbiscuits were assuming the translations were already loaded. + Rails.root.glob("config/locales/*.yml").each do |path| + I18n.load_path << path.to_s + end + I18n.backend.reload! + index_props = DogBiscuits.config.index_properties.collect do |prop| + { prop => index_options(prop, DogBiscuits.config.property_mappings[prop]) } + end + add_index_field config, index_props + + # solr fields to be displayed in the show (single result) view + # The ordering of the field names is the order of the display + # show_props = DogBiscuits.config.all_properties + # add_show_field config, show_props + # solr fields to be displayed in the index (search results) view # The ordering of the field names is the order of the display config.add_index_field 'title_tesim', label: "Title", itemprop: 'name', if: false @@ -150,6 +202,8 @@ def self.modified_field # since we aren't specifying it otherwise. config.add_search_field('all_fields', label: 'All Fields', include_in_advanced_search: false) do |field| all_names = config.show_fields.values.map(&:field).join(" ") +# TODO ROB all_names = (config.show_fields.values.map { |v| v.field.to_s } + + # DogBiscuits.config.all_properties.map { |p| "#{p}_tesim" }).uniq.join(" ") title_name = 'title_tesim' field.solr_parameters = { qf: "#{all_names} file_format_tesim all_text_timv", @@ -178,6 +232,7 @@ def self.modified_field end config.add_search_field('creator') do |field| + # TODO ROB field.label = "Author" field.solr_parameters = { "spellcheck.dictionary": "creator" } solr_name = 'creator_tesim' field.solr_local_parameters = { @@ -220,6 +275,8 @@ def self.modified_field } end + date_fields = ['date_created_tesim', 'sorted_date_isi', 'sorted_month_isi'] + config.add_search_field('date_created') do |field| field.solr_parameters = { "spellcheck.dictionary": "date_created" @@ -343,16 +400,27 @@ def self.modified_field } end + config.add_search_field('source') do |field| + solr_name = solr_name("source", :stored_searchable) + field.solr_local_parameters = { + qf: solr_name, + pf: solr_name + } + end + # "sort results by" select (pulldown) # label in pulldown is followed by the name of the SOLR field to sort by and # whether the sort is ascending or descending (it must be asc or desc # except in the relevancy case). # label is key, solr field is value - config.add_sort_field "score desc, #{uploaded_field} desc", label: "relevance" - config.add_sort_field "#{uploaded_field} desc", label: "date uploaded \u25BC" - config.add_sort_field "#{uploaded_field} asc", label: "date uploaded \u25B2" - config.add_sort_field "#{modified_field} desc", label: "date modified \u25BC" - config.add_sort_field "#{modified_field} asc", label: "date modified \u25B2" + config.add_sort_field "score desc, #{uploaded_field} desc", label: "Relevance" + + config.add_sort_field "#{title_field} asc", label: "Title" + config.add_sort_field "#{creator_field} asc", label: "Author" + config.add_sort_field "#{created_field} asc", label: "Published Date (Ascending)" + config.add_sort_field "#{created_field} desc", label: "Published Date (Descending)" + config.add_sort_field "#{modified_field} asc", label: "Upload Date (Ascending)" + config.add_sort_field "#{modified_field} desc", label: "Upload Date (Descending)" # OAI Config fields config.oai = { diff --git a/app/controllers/saved_searches_controller.rb b/app/controllers/saved_searches_controller.rb new file mode 100644 index 000000000..f2618be72 --- /dev/null +++ b/app/controllers/saved_searches_controller.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class SavedSearchesController < ApplicationController + include Blacklight::SavedSearches + + helper BlacklightAdvancedSearch::RenderConstraintsOverride +end diff --git a/app/controllers/search_history_controller.rb b/app/controllers/search_history_controller.rb new file mode 100644 index 000000000..a97b2e3ff --- /dev/null +++ b/app/controllers/search_history_controller.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class SearchHistoryController < ApplicationController + include Blacklight::SearchHistory + helper BlacklightAdvancedSearch::RenderConstraintsOverride + helper BlacklightRangeLimit::ViewHelperOverride + helper RangeLimitHelper +end diff --git a/app/models/collection.rb b/app/models/collection.rb index 39bd58492..2b2298fd8 100644 --- a/app/models/collection.rb +++ b/app/models/collection.rb @@ -8,6 +8,7 @@ class Collection < ActiveFedora::Base self.indexer = CollectionIndexer after_update :remove_featured, if: proc { |collection| collection.private? } after_destroy :remove_featured + prepend OrderAlready.for(:creator) def remove_featured FeaturedCollection.where(collection_id: id).destroy_all diff --git a/app/models/generic_work.rb b/app/models/generic_work.rb index b8b740217..5ee8e9c01 100644 --- a/app/models/generic_work.rb +++ b/app/models/generic_work.rb @@ -10,4 +10,7 @@ class GenericWork < ActiveFedora::Base validates :title, presence: { message: 'Your work must have a title.' } self.indexer = GenericWorkIndexer + + prepend OrderAlready.for(:creator) + end diff --git a/app/models/image.rb b/app/models/image.rb index e0218ec94..83adf2208 100644 --- a/app/models/image.rb +++ b/app/models/image.rb @@ -17,6 +17,8 @@ class Image < ActiveFedora::Base include ::Hyrax::BasicMetadata self.indexer = ImageIndexer + prepend OrderAlready.for(:creator) + # Change this to restrict which works can be added as a child. # self.valid_child_concerns = [] validates :title, presence: { message: 'Your work must have a title.' } diff --git a/app/models/search_builder.rb b/app/models/search_builder.rb index ad50b6e1e..4410a5bc8 100644 --- a/app/models/search_builder.rb +++ b/app/models/search_builder.rb @@ -2,6 +2,10 @@ class SearchBuilder < Blacklight::SearchBuilder include Blacklight::Solr::SearchBuilderBehavior + include BlacklightRangeLimit::RangeLimitBuilder + include BlacklightAdvancedSearch::AdvancedSearchBuilder include Hydra::AccessControlsEnforcement include Hyrax::SearchFilters + + self.default_processor_chain += %i[add_advanced_parse_q_to_solr add_advanced_search_to_solr] end diff --git a/app/views/advanced/_advanced_search_help.html.erb b/app/views/advanced/_advanced_search_help.html.erb new file mode 100644 index 000000000..df18fcbc5 --- /dev/null +++ b/app/views/advanced/_advanced_search_help.html.erb @@ -0,0 +1,26 @@ +
+
+

Search tips

+
    +
  • Select "match all" to require all fields. +
  • + +
  • Select "match any" to find at least one field. +
  • + +
  • Combine keywords and attributes to find specific items. +
  • + +
  • Search by date with format: YYYYMMDD, YYYYMM or YYYY. Do not use "-", "/", or any other special characters.
  • + +
  • Use quotation marks to search as a phrase. + +
  • Use "+" before a term to make it required. (Otherwise results matching only some of your terms may be included).
  • + +
  • Use "-" before a word or phrase to exclude. + +
  • Use "OR", "AND", and "NOT" to create complex boolean logic. You can use parentheses in your complex expressions.
  • +
  • Truncation and wildcards are not supported - word-stemming is done automatically.
  • +
+
+
diff --git a/app/views/blacklight_range_limit/_range_limit_panel.html.erb b/app/views/blacklight_range_limit/_range_limit_panel.html.erb new file mode 100644 index 000000000..738e6e3d7 --- /dev/null +++ b/app/views/blacklight_range_limit/_range_limit_panel.html.erb @@ -0,0 +1,125 @@ +<%- # requires solr_config local passed in + field_config = range_config(field_name) + label = facet_field_label(field_name) + + input_label_range_begin = field_config[:input_label_range_begin] || t("blacklight.range_limit.range_begin", field_label: label) + input_label_range_end = field_config[:input_label_range_end] || t("blacklight.range_limit.range_end", field_label: label) + maxlength = field_config[:maxlength] +-%> + + +<%# NOTE(dewey4iv): leaving the styling here for now so that Christy can test out what she wants this to look like %> + + +
+ <% if has_selected_range_limit?(field_name) %> +
    +
  • + + <%= range_display(field_name) %> + <%= link_to remove_range_param(field_name), :class=>"remove", :title => t('blacklight.range_limit.remove_limit') do %> + + [<%= t('blacklight.range_limit.remove_limit') %>] + <% end %> + + <%= number_with_delimiter(@response.total) %> +
  • +
+ + <% end %> + + <% unless selected_missing_for_range_limit?(field_name) %> + <%= form_tag search_action_path, :method => :get, class: [BlacklightRangeLimit.classes[:form], "range_#{field_name}"].join(' ') do %> + <%= render_hash_as_hidden_fields(search_state.params_for_search.except(:page)) %> + + + <% unless params.has_key?(:search_field) %> + <%= hidden_field_tag("search_field", "dummy_range") %> + <% end %> + +
+ Between year: + <%= render_range_input(field_name, :begin, input_label_range_begin, maxlength) %> +
+
+ and year: + <%= render_range_input(field_name, :end, input_label_range_end, maxlength) %> +
+ <%= submit_tag t('blacklight.range_limit.submit_limit'), class: "#{BlacklightRangeLimit.classes[:submit]} btn btn-default btn-block" %> + <% end %> + <% end %> + + + <% unless selected_missing_for_range_limit?(field_name) %> + +
+ <% if stats_for_field?(field_name) %> + + <% end %> + + <% if (min = range_results_endpoint(field_name, :min)) && + (max = range_results_endpoint(field_name, :max)) %> +

"> + +

+ + <% if field_config[:segments] != false %> +
+ + <% if solr_range_queries_to_a(field_name).length > 0 %> + + <%= render(:partial => "blacklight_range_limit/range_segments", :locals => {:solr_field => field_name}) %> + + <% else %> + <%= link_to('View distribution', main_app.url_for(search_state.to_h.merge(action: 'range_limit', range_field: field_name, range_start: min, range_end: max)), :class => "load_distribution") %> + <% end %> +
+ <% end %> + <% end %> + + <% if (stats = stats_for_field(field_name)) %> +
    +
  • + + <%= link_to BlacklightRangeLimit.labels[:missing], add_range_missing(field_name) %> + + + <%= number_with_delimiter(stats["missing"]) %> + +
  • +
+ <% end %> +
+ <% end %> +
diff --git a/config/routes.rb b/config/routes.rb index 73a5d0f50..49f57635c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -70,9 +70,10 @@ mount Qa::Engine => '/authorities' mount Blacklight::Engine => '/' + mount BlacklightAdvancedSearch::Engine => '/' mount Hyrax::Engine, at: '/' mount Bulkrax::Engine, at: '/' if ENV.fetch('HYKU_BULKRAX_ENABLED', 'true') == 'true' - + mount HykuKnapsack::Engine, at: '/' concern :searchable, Blacklight::Routes::Searchable.new concern :exportable, Blacklight::Routes::Exportable.new @@ -82,6 +83,7 @@ concerns :oai_provider concerns :searchable + concerns :range_searchable end resources :solr_documents, only: [:show], path: '/catalog', controller: 'catalog' do From 0a6a2667c691c216d000cd8e51d1621dddcab21a Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Thu, 21 Sep 2023 00:01:30 -0700 Subject: [PATCH 02/60] add a few content blocks in from adventist --- .../content_blocks_controller_decorator.rb | 18 ++++++++ app/views/hyrax/content_blocks/_form.html.erb | 42 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 app/controllers/hyrax/content_blocks_controller_decorator.rb diff --git a/app/controllers/hyrax/content_blocks_controller_decorator.rb b/app/controllers/hyrax/content_blocks_controller_decorator.rb new file mode 100644 index 000000000..348ac4f20 --- /dev/null +++ b/app/controllers/hyrax/content_blocks_controller_decorator.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +# OVERRIDE Hyrax v3.4.0 to add home_text to permitted_params - Adding themes +module Hyrax + module ContentBlocksControllerDecorator + # override hyrax v2.9.0 added the home_text content block to permitted_params - Adding Themes + def permitted_params + params.require(:content_block).permit(:marketing, + :announcement, + :home_text, + :homepage_about_section_heading, + :homepage_about_section_content, + :researcher) + end + end +end + +Hyrax::ContentBlocksController.prepend Hyrax::ContentBlocksControllerDecorator diff --git a/app/views/hyrax/content_blocks/_form.html.erb b/app/views/hyrax/content_blocks/_form.html.erb index ccf22f70f..76d7e0d26 100644 --- a/app/views/hyrax/content_blocks/_form.html.erb +++ b/app/views/hyrax/content_blocks/_form.html.erb @@ -15,6 +15,12 @@
  • <%= t(:'hyrax.content_blocks.tabs.featured_researcher') %>
  • +
  • + <%= t(:'hyrax.content_blocks.tabs.homepage_about_section_heading') %> +
  • +
  • + <%= t(:'hyrax.content_blocks.tabs.homepage_about_section_content') %> +
  • @@ -90,6 +96,42 @@ <% end %>
    +
    +
    + <%= simple_form_for ContentBlock.for(:homepage_about_section_heading), url: hyrax.content_block_path(ContentBlock.for(:homepage_about_section_heading)), html: {class: 'nav-safety'} do |f| %> +
    +
    + <%= f.label :homepage_about_section_heading %>
    + <%# the following line was changed from hyrax to give some context for what this context block does %> +

    <%= t(:'hyrax.content_blocks.instructions.homepage_about_section_heading_instructions') %>

    + <%= f.text_area :homepage_about_section_heading, value: f.object.value, class: 'form-control tinymce', rows: 20, cols: 120 %> +
    +
    + + <% end %> +
    +
    +
    +
    + <%= simple_form_for ContentBlock.for(:homepage_about_section_content), url: hyrax.content_block_path(ContentBlock.for(:homepage_about_section_content)), html: {class: 'nav-safety'} do |f| %> +
    +
    + <%= f.label :homepage_about_section_content %>
    + <%# the following line was changed from hyrax to give some context for what this context block does %> +

    <%= t(:'hyrax.content_blocks.instructions.homepage_about_section_content_instructions') %>

    + <%= f.text_area :homepage_about_section_content, value: f.object.value, class: 'form-control tinymce', rows: 20, cols: 120 %> +
    +
    + + <% end %> +
    +
    <%= tinymce :content_block %> From f78eb75f5aa6e08f3e3c6514affe6649975adfb1 Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Thu, 21 Sep 2023 00:02:33 -0700 Subject: [PATCH 03/60] do not need full controller override --- .../hyrax/content_blocks_controller.rb | 44 ------------------- 1 file changed, 44 deletions(-) delete mode 100644 app/controllers/hyrax/content_blocks_controller.rb diff --git a/app/controllers/hyrax/content_blocks_controller.rb b/app/controllers/hyrax/content_blocks_controller.rb deleted file mode 100644 index 60edc5286..000000000 --- a/app/controllers/hyrax/content_blocks_controller.rb +++ /dev/null @@ -1,44 +0,0 @@ -# frozen_string_literal: true - -# OVERRIDE Hyrax v3.4.0 to add home_text to permitted_params - Adding themes -module Hyrax - class ContentBlocksController < ApplicationController - load_and_authorize_resource - with_themed_layout 'dashboard' - - def edit - add_breadcrumb t(:'hyrax.controls.home'), root_path - add_breadcrumb t(:'hyrax.dashboard.breadcrumbs.admin'), hyrax.dashboard_path - add_breadcrumb t(:'hyrax.admin.sidebar.configuration'), '#' - add_breadcrumb t(:'hyrax.admin.sidebar.content_blocks'), hyrax.edit_content_blocks_path - end - - def update - respond_to do |format| - if @content_block.update(value: update_value_from_params) - format.html { redirect_to hyrax.edit_content_blocks_path, notice: t(:'hyrax.content_blocks.updated') } - else - format.html { render :edit } - end - end - end - - private - - # override hyrax v2.9.0 added the home_text content block to permitted_params - Adding Themes - def permitted_params - params.require(:content_block).permit(:marketing, - :announcement, - :home_text, - :researcher) - end - - # When a request comes to the controller, it will be for one and - # only one of the content blocks. Params always looks like: - # {'about_page' => 'Here is an awesome about page!'} - # So reach into permitted params and pull out the first value. - def update_value_from_params - permitted_params.values.first - end - end -end From 29873b1a0841f89559263718fc622993e122533d Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Thu, 21 Sep 2023 00:08:38 -0700 Subject: [PATCH 04/60] use the new content blocks --- app/controllers/hyrax/homepage_controller.rb | 131 ------------------ .../hyrax/homepage_controller_decorator.rb | 20 +++ 2 files changed, 20 insertions(+), 131 deletions(-) delete mode 100644 app/controllers/hyrax/homepage_controller.rb create mode 100644 app/controllers/hyrax/homepage_controller_decorator.rb diff --git a/app/controllers/hyrax/homepage_controller.rb b/app/controllers/hyrax/homepage_controller.rb deleted file mode 100644 index a38eda845..000000000 --- a/app/controllers/hyrax/homepage_controller.rb +++ /dev/null @@ -1,131 +0,0 @@ -# frozen_string_literal: true - -# OVERRIDE: Hyrax v2.9.0 to add home_text content block to the index method - Adding themes -# OVERRIDE: Hyrax v2.9.0 from Hyrax v2.9.0 to add facets to home page - inheriting from -# CatalogController rather than ApplicationController -# OVERRIDE: Hyrax v2.9.0 from Hyrax v2.9.0 to add inject_theme_views method for theming -# OVERRIDE: Hyrax v2.9.0 to add search_action_url method from Blacklight 6.23.0 to make facet links to go to /catalog -# OVERRIDE: Hyrax v2.9.0 to add .sort_by to return collections in alphabetical order by title on the homepage -# OVERRIDE: Hyrax v2.9.0 add all_collections page for IR theme -# OVERRIDE: Hyrax v2.9.0 to add facet counts for resource types for IR theme -# OVERRIDE: Hyrax v. 2.9.0 to add @featured_collection_list to index method - -module Hyrax - # Changed to inherit from CatalogController for home page facets - class HomepageController < CatalogController - # Adds Hydra behaviors into the application controller - include Blacklight::SearchContext - include Blacklight::SearchHelper - include Blacklight::AccessControls::Catalog - - around_action :inject_theme_views - - # The search builder for finding recent documents - # Override of Blacklight::RequestBuilders - def search_builder_class - Hyrax::HomepageSearchBuilder - end - - class_attribute :presenter_class - self.presenter_class = Hyrax::HomepagePresenter - layout 'homepage' - helper Hyrax::ContentBlockHelper - - # override hyrax v2.9.0 added @home_text - Adding Themes - def index - @presenter = presenter_class.new(current_ability, collections) - @featured_researcher = ContentBlock.for(:researcher) - @marketing_text = ContentBlock.for(:marketing) - @home_text = ContentBlock.for(:home_text) - @featured_work_list = FeaturedWorkList.new - # OVERRIDE here to add featured collection list - @featured_collection_list = FeaturedCollectionList.new - @announcement_text = ContentBlock.for(:announcement) - recent - ir_counts if home_page_theme == 'institutional_repository' - - # override hyrax v2.9.0 added for facets on homepage - Adding Themes - (@response, @document_list) = search_results(params) - - respond_to do |format| - format.html { store_preferred_view } - format.rss { render layout: false } - format.atom { render layout: false } - format.json do - @presenter = Blacklight::JsonPresenter.new(@response, - @document_list, - facets_from_request, - blacklight_config) - end - additional_response_formats(format) - document_export_formats(format) - end - end - - def browserconfig; end - - def all_collections - @presenter = presenter_class.new(current_ability, collections) - @marketing_text = ContentBlock.for(:marketing) - @announcement_text = ContentBlock.for(:announcement) - @collections = collections(rows: 100_000) - ir_counts if home_page_theme == 'institutional_repository' - end - - # Added from Blacklight 6.23.0 to change url for facets on home page - protected - - # Default route to the search action (used e.g. in global partials). Override this method - # in a controller or in your ApplicationController to introduce custom logic for choosing - # which action the search form should use - def search_action_url(options = {}) - # Rails 4.2 deprecated url helpers accepting string keys for 'controller' or 'action' - main_app.search_catalog_path(options) - end - - private - - # Return 6 collections - def collections(rows: 6) - builder = Hyrax::CollectionSearchBuilder.new(self) - .rows(rows) - response = repository.search(builder) - # adding .sort_by to return collections in alphabetical order by title on the homepage - response.documents.sort_by(&:title) - rescue Blacklight::Exceptions::ECONNREFUSED, Blacklight::Exceptions::InvalidRequest - [] - end - - def recent - # grab any recent documents - (_, @recent_documents) = search_results(q: '', sort: sort_field, rows: 6) - rescue Blacklight::Exceptions::ECONNREFUSED, Blacklight::Exceptions::InvalidRequest - @recent_documents = [] - end - - # OVERRIDE: Hyrax v2.9.0 to add facet counts for resource types for IR theme - def ir_counts - @ir_counts = get_facet_field_response('resource_type_sim', {}, "f.resource_type_sim.facet.limit" => "-1") - end - - def sort_field - "date_uploaded_dtsi desc" - end - - # Add this method to prepend the theme views into the view_paths - def inject_theme_views - if home_page_theme && home_page_theme != 'default_home' - original_paths = view_paths - home_theme_view_path = Rails.root.join('app', 'views', "themes", home_page_theme.to_s) - prepend_view_path(home_theme_view_path) - yield - # rubocop:disable Lint/UselessAssignment, Layout/SpaceAroundOperators, Style/RedundantParentheses - # Do NOT change this line. This is calling the Rails view_paths=(paths) method and not a variable assignment. - view_paths=(original_paths) - # rubocop:enable Lint/UselessAssignment, Layout/SpaceAroundOperators, Style/RedundantParentheses - else - yield - end - end - end -end diff --git a/app/controllers/hyrax/homepage_controller_decorator.rb b/app/controllers/hyrax/homepage_controller_decorator.rb new file mode 100644 index 000000000..58712bfd7 --- /dev/null +++ b/app/controllers/hyrax/homepage_controller_decorator.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +# OVERRIDE Hyrax 3.5 to add content blocks +module Hyrax + module HomepageControllerDecorator + + def index + @presenter = presenter_class.new(current_ability, collections) + @featured_researcher = ContentBlock.for(:researcher) + @marketing_text = ContentBlock.for(:marketing) + @featured_work_list = FeaturedWorkList.new + @announcement_text = ContentBlock.for(:announcement) + @homepage_about_section_heading = ContentBlock.for(:homepage_about_section_heading) + @homepage_about_section_content = ContentBlock.for(:homepage_about_section_content) + recent + end + end +end + +Hyrax::HomepageController.prepend Hyrax::HomepageControllerDecorator From 7510b7c67825cda9f468bb761a3e880f823b440c Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Thu, 21 Sep 2023 00:17:46 -0700 Subject: [PATCH 05/60] iiif rodeo includes --- config/application.rb | 61 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/config/application.rb b/config/application.rb index 850a2b515..acf7c0523 100644 --- a/config/application.rb +++ b/config/application.rb @@ -9,7 +9,35 @@ Bundler.require(*groups) module Hyku + # Providing a common method to ensure consistent UTF-8 encoding. Also removing the tricksy Byte + # Order Marker character which is an invisible 0 space character. + # + # @note In testing, we encountered errors with the file's character encoding + # (e.g. `Encoding::UndefinedConversionError`). The following will force the encoding to + # UTF-8 and replace any invalid or undefined characters from the original encoding with a + # "?". + # + # Given that we still have the original, and this is a derivative, the forced encoding + # should be acceptable. + # + # @param [String] + # @return [String] + # + # @see https://sentry.io/organizations/scientist-inc/issues/3773392603/?project=6745020&query=is%3Aunresolved&referrer=issue-stream + # @see https://github.com/samvera-labs/bulkrax/pull/689 + # @see https://github.com/samvera-labs/bulkrax/issues/688 + # @see https://github.com/scientist-softserv/adventist-dl/issues/179 + def self.utf_8_encode(string) + string + .encode(Encoding.find('UTF-8'), invalid: :replace, undef: :replace, replace: "?") + .delete("\xEF\xBB\xBF") + end + class Application < Rails::Application + # Add this line to load the lib folder first because we need + # IiifPrint::SplitPdfs::AdventistPagesToJpgsSplitter + config.autoload_paths.unshift("#{Rails.root}/lib") + # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. @@ -33,22 +61,37 @@ class Application < Rails::Application end config.to_prepare do - # Allows us to use decorator files in the app directory + + # By default plain text files are not processed for text extraction. In adding + # Adventist::TextFileTextExtractionService to the beginning of the services array we are + # enabling text extraction from plain text files. + Hyrax::DerivativeService.services = [ + Adventist::TextFileTextExtractionService, + IiifPrint::PluggableDerivativeService] + + # When you are ready to use the derivative rodeo instead of the pluggable uncomment the + # following and comment out the preceding Hyrax::DerivativeService.service + # + # Hyrax::DerivativeService.services = [ + # Adventist::TextFileTextExtractionService, + # IiifPrint::DerivativeRodeoService, + # Hyrax::FileSetDerivativesService] + + DerivativeRodeo::Generators::HocrGenerator.additional_tessearct_options = "-l eng_best" + + # Allows us to use decorator files Dir.glob(File.join(File.dirname(__FILE__), "../app/**/*_decorator*.rb")).sort.each do |c| Rails.configuration.cache_classes ? require(c) : load(c) end - end - config.to_prepare do - # Allows us to use decorator files in the app directory Dir.glob(File.join(File.dirname(__FILE__), "../lib/**/*_decorator*.rb")).sort.each do |c| Rails.configuration.cache_classes ? require(c) : load(c) end - end - # OAI additions - Dir.glob(File.join(File.dirname(__FILE__), "../lib/oai/**/*.rb")).sort.each do |c| - Rails.configuration.cache_classes ? require(c) : load(c) + # OAI additions + Dir.glob(File.join(File.dirname(__FILE__), "../lib/oai/**/*.rb")).sort.each do |c| + Rails.configuration.cache_classes ? require(c) : load(c) + end end # resolve reloading issue in dev mode @@ -67,6 +110,8 @@ class Application < Rails::Application Object.include(AccountSwitch) end + # copies tinymce assets directly into public/assets + config.tinymce.install = :copy ## # Psych Allow YAML Classes # From 3f22a3353508fa9c277b1762372182bd04b4856b Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Thu, 21 Sep 2023 01:06:38 -0700 Subject: [PATCH 06/60] remove dogbiscuit crossover, fix routes --- app/controllers/catalog_controller.rb | 19 ++++++++++--------- config/routes.rb | 1 + 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/app/controllers/catalog_controller.rb b/app/controllers/catalog_controller.rb index 17eca79a9..c50f887b0 100644 --- a/app/controllers/catalog_controller.rb +++ b/app/controllers/catalog_controller.rb @@ -123,15 +123,16 @@ def self.uploaded_field # handler defaults, or have no facets. config.add_facet_fields_to_solr_request! - # Prior to this change, the applications specific translations were not loaded. Dogbiscuits were assuming the translations were already loaded. - Rails.root.glob("config/locales/*.yml").each do |path| - I18n.load_path << path.to_s - end - I18n.backend.reload! - index_props = DogBiscuits.config.index_properties.collect do |prop| - { prop => index_options(prop, DogBiscuits.config.property_mappings[prop]) } - end - add_index_field config, index_props + # TODO ROB +# # Prior to this change, the applications specific translations were not loaded. Dogbiscuits were assuming the translations were already loaded. +# Rails.root.glob("config/locales/*.yml").each do |path| +# I18n.load_path << path.to_s +# end +# I18n.backend.reload! +# index_props = DogBiscuits.config.index_properties.collect do |prop| +# { prop => index_options(prop, DogBiscuits.config.property_mappings[prop]) } +# end +# add_index_field config, index_props # solr fields to be displayed in the show (single result) view # The ordering of the field names is the order of the display diff --git a/config/routes.rb b/config/routes.rb index 49f57635c..f0a2a3753 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -6,6 +6,7 @@ Rails.application.routes.draw do # rubocop:disable Metrics/BlockLength resources :identity_providers + concern :range_searchable, BlacklightRangeLimit::Routes::RangeSearchable.new concern :iiif_search, BlacklightIiifSearch::Routes.new concern :oai_provider, BlacklightOaiProvider::Routes.new From 36590bc0fe34569bd56cd3eba5ca6cac70bef5ba Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Thu, 21 Sep 2023 10:12:59 -0700 Subject: [PATCH 07/60] add spec for search history --- .../search_history_controller_spec.rb | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 spec/controllers/search_history_controller_spec.rb diff --git a/spec/controllers/search_history_controller_spec.rb b/spec/controllers/search_history_controller_spec.rb new file mode 100644 index 000000000..d9a349279 --- /dev/null +++ b/spec/controllers/search_history_controller_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +RSpec.describe SearchHistoryController do + routes { Blacklight::Engine.routes } + + describe 'index' do + let(:one) { Search.create } + let(:two) { Search.create } + let(:three) { Search.create } + + it 'only fetches searches with ids in the session' do + session[:history] = [one.id, three.id] + get :index + searches = assigns(:searches) + expect(searches).to include(one) + expect(searches).not_to include(two) + end + + it 'tolerates bad ids in session' do + session[:history] = [one.id, three.id, 'NOT_IN_DB'] + get :index + searches = assigns(:searches) + expect(searches).to include(one) + expect(searches).to include(three) + end + + it 'does not fetch any searches if there is no history' do + session[:history] = [] + get :index + searches = assigns(:searches) + expect(searches).to be_empty + end + end +end From 326576ecb20fe033d777f7c3276e533744825609 Mon Sep 17 00:00:00 2001 From: Shana Moore Date: Thu, 21 Sep 2023 10:25:09 -0700 Subject: [PATCH 08/60] add missing methods to avoid content block errors --- .../hyrax/homepage_controller_decorator.rb | 20 +++++++++++++++++++ app/models/content_block.rb | 20 ++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 app/controllers/hyrax/homepage_controller_decorator.rb diff --git a/app/controllers/hyrax/homepage_controller_decorator.rb b/app/controllers/hyrax/homepage_controller_decorator.rb new file mode 100644 index 000000000..826a8599b --- /dev/null +++ b/app/controllers/hyrax/homepage_controller_decorator.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +# OVERRIDE Hyrax 3.5 to add content blocks +module Hyrax + module HomepageControllerDecorator + + def index + @presenter = presenter_class.new(current_ability, collections) + @featured_researcher = ContentBlock.for(:researcher) + @marketing_text = ContentBlock.for(:marketing) + @featured_work_list = FeaturedWorkList.new + @announcement_text = ContentBlock.for(:announcement) + @homepage_about_section_heading = ContentBlock.for(:homepage_about_section_heading) + @homepage_about_section_content = ContentBlock.for(:homepage_about_section_content) + recent + end + end +end + +Hyrax::HomepageController.prepend Hyrax::HomepageControllerDecorator diff --git a/app/models/content_block.rb b/app/models/content_block.rb index c9e72b26e..4c00535b3 100644 --- a/app/models/content_block.rb +++ b/app/models/content_block.rb @@ -16,7 +16,9 @@ class ContentBlock < ApplicationRecord help: :help_page, terms: :terms_page, agreement: :agreement_page, - home_text: :home_text + home_text: :home_text, + homepage_about_section_heading: :homepage_about_section_heading, + homepage_about_section_content: :homepage_about_section_content }.freeze # NOTE: method defined outside the metaclass wrapper below because @@ -90,6 +92,22 @@ def home_text=(value) home_text.update(value: value) end + def homepage_about_section_heading + find_or_create_by(name: 'homepage_about_section_heading') + end + + def homepage_about_section_heading=(value) + homepage_about_section_heading.update(value: value) + end + + def homepage_about_section_content + find_or_create_by(name: 'homepage_about_section_content') + end + + def homepage_about_section_content=(value) + homepage_about_section_content.update(value: value) + end + def about_page find_or_create_by(name: 'about_page') end From 189917593629103f6c21031d575fab6fcc404ec2 Mon Sep 17 00:00:00 2001 From: LaRita Robinson Date: Fri, 22 Sep 2023 15:28:48 -0400 Subject: [PATCH 09/60] Update Hyku Gemfile.lock --- Gemfile.lock | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Gemfile.lock b/Gemfile.lock index 4436734e8..f471801a6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -210,6 +210,9 @@ GEM bootstrap-sass (~> 3.0) openseadragon (>= 0.2.0) rails + blacklight_advanced_search (6.4.1) + blacklight (~> 6.0, >= 6.0.1) + parslet blacklight_iiif_search (1.0.0) blacklight (~> 6.0) iiif-presentation @@ -217,6 +220,10 @@ GEM blacklight_oai_provider (6.1.1) blacklight (~> 6.0) oai (~> 1.0) + blacklight_range_limit (6.5.0) + blacklight (~> 6.10) + jquery-rails + rails (>= 4.2, < 6) bolognese (1.11.0) activesupport (>= 4.2.5) benchmark_methods (~> 0.7) @@ -871,6 +878,8 @@ GEM openseadragon (0.6.0) rails (> 3.2.0) optimist (3.0.1) + order_already (0.3.1) + rails-html-sanitizer (~> 1.4) orm_adapter (0.5.0) os (1.1.4) parallel (1.23.0) @@ -1296,7 +1305,9 @@ DEPENDENCIES apartment aws-sdk-sqs blacklight (~> 6.7) + blacklight_advanced_search blacklight_oai_provider (~> 6.1, >= 6.1.1) + blacklight_range_limit (= 6.5.0) bolognese (>= 1.9.10) bootstrap-datepicker-rails bulkrax (~> 5.3) @@ -1338,6 +1349,7 @@ DEPENDENCIES omniauth-rails_csrf_protection (~> 1.0) omniauth-saml (~> 2.1) omniauth_openid_connect + order_already parser (~> 2.5.3) pg postrank-uri (>= 1.0.24) From 4dc0dcd362a56c5ed94cacaff8f881305a121175 Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Fri, 22 Sep 2023 13:08:16 -0700 Subject: [PATCH 10/60] add option to support good job for background jobs instead of sidekiq --- Gemfile | 1 + Gemfile.lock | 17 +++++++ bin/worker | 8 +++- config/environments/development.rb | 7 ++- config/initializers/good_job.rb | 44 +++++++++++++++++++ config/initializers/sidekiq.rb | 17 ++++--- config/routes.rb | 12 ++++- db/migrate/20230406183814_create_good_jobs.rb | 38 ++++++++++++++++ 8 files changed, 133 insertions(+), 11 deletions(-) create mode 100644 config/initializers/good_job.rb create mode 100644 db/migrate/20230406183814_create_good_jobs.rb diff --git a/Gemfile b/Gemfile index 868c97ba3..630f95a0f 100644 --- a/Gemfile +++ b/Gemfile @@ -35,6 +35,7 @@ gem 'factory_bot_rails', group: %i[test] gem 'fcrepo_wrapper', '~> 0.4', group: %i[development test] gem 'flipflop', '~> 2.6.0' # waiting for hyrax 4 upgrade gem 'flutie' +gem 'good_job' gem 'hyrax', '~> 3.5.0' gem 'hyrax-doi', github: 'samvera-labs/hyrax-doi', branch: 'main' gem 'hyrax-iiif_av', github: 'samvera-labs/hyrax-iiif_av', branch: 'main' diff --git a/Gemfile.lock b/Gemfile.lock index 4436734e8..88b7a3175 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -13,6 +13,7 @@ GIT branch: upstream_main specs: hyku_knapsack (0.0.1) + good_job rails (>= 5.2.0) GIT @@ -448,6 +449,8 @@ GEM equivalent-xml (0.6.0) nokogiri (>= 1.4.3) erubi (1.12.0) + et-orbi (1.2.7) + tzinfo ethon (0.16.0) ffi (>= 1.15.0) excon (0.71.1) @@ -473,11 +476,23 @@ GEM flutie (2.2.0) font-awesome-rails (4.7.0.8) railties (>= 3.2, < 8.0) + fugit (1.8.1) + et-orbi (~> 1, >= 1.2.7) + raabro (~> 1.4) gender_detector (0.1.2) unicode_utils (>= 1.3.0) geocoder (1.8.1) globalid (1.1.0) activesupport (>= 5.0) + good_job (2.99.0) + activejob (>= 5.2.0) + activerecord (>= 5.2.0) + concurrent-ruby (>= 1.0.2) + fugit (>= 1.1) + railties (>= 5.2.0) + thor (>= 0.14.1) + webrick (>= 1.3) + zeitwerk (>= 2.0) google-apis-core (0.11.0) addressable (~> 2.5, >= 2.5.1) googleauth (>= 0.16.2, < 2.a) @@ -904,6 +919,7 @@ GEM nokogiri (~> 1.6) rails (>= 5.0, < 7.1) rdf + raabro (1.4.0) racc (1.7.1) rack (2.2.8) rack-oauth2 (1.21.3) @@ -1318,6 +1334,7 @@ DEPENDENCIES fcrepo_wrapper (~> 0.4) flipflop (~> 2.6.0) flutie + good_job hyku_knapsack! hyrax (~> 3.5.0) hyrax-doi! diff --git a/bin/worker b/bin/worker index b7605486b..7698b346e 100755 --- a/bin/worker +++ b/bin/worker @@ -9,4 +9,10 @@ else puts 'DATABASE_URL not set, no pool change needed' end -exec "echo $DATABASE_URL && bundle exec sidekiq" +queue = ENV.fetch('HYRAX_ACTIVE_JOB_QUEUE', 'sidekiq') +case queue +when 'sidekiq' + exec "echo $DATABASE_URL && bundle exec sidekiq" +when 'good_job' + exec "echo $DATABASE_URL && bundle exec good_job start" +end diff --git a/config/environments/development.rb b/config/environments/development.rb index 9bafa102c..500278da4 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -4,7 +4,12 @@ # In the development environment your application's code is reloaded on # every request. This slows down response time but is perfect for development # since you don't have to restart the web server when you make code changes. - config.cache_classes = !!Sidekiq.server? + if ENV.fetch('HYRAX_ACTIVE_JOB_QUEUE', 'sidekiq') == 'sidekiq' + config.cache_classes = !!Sidekiq.server? + else + config.cache_classes = false + end + # Do not eager load code on boot. config.eager_load = false diff --git a/config/initializers/good_job.rb b/config/initializers/good_job.rb new file mode 100644 index 000000000..7929a5d4b --- /dev/null +++ b/config/initializers/good_job.rb @@ -0,0 +1,44 @@ + +# frozen_string_literal: true + +if ENV.fetch('HYRAX_ACTIVE_JOB_QUEUE', 'sidekiq') == 'good_job' + Rails.application.configure do + # Configure options individually... + config.good_job.preserve_job_records = true + config.good_job.retry_on_unhandled_error = false + config.good_job.on_thread_error = ->(exception) { Raven.capture_exception(exception) } + config.good_job.execution_mode = :external + # config.good_job.queues = '*' + config.good_job.shutdown_timeout = 60 # seconds + config.good_job.poll_interval = 5 + # config.good_job.enable_cron = true + # config.good_job.cron = { example: { cron: '0 * * * *', class: 'ExampleJob' } } + end + + # Wrapping this in an after_initialize block to ensure that all constants are loaded + Rails.application.config.after_initialize do + # baseline of 0, higher is sooner + + # Commented out the following two jobs because they were + # specfically used for the sdapi ingests. + # see sdapi_ingest_script directory and + # ref: https://github.com/scientist-softserv/adventist-dl/issues/468 + # CollectionMembershipJob.priority = 70 + # UpdateCollectionMembershipJob.priority = 60 + Bulkrax::ScheduleRelationshipsJob.priority = 50 + CreateDerivativesJob.priority = 40 + CharacterizeJob.priority = 30 + Hyrax::GrantEditToMembersJob.priority = 10 + ImportUrlJob.priority = 10 + IngestJob.priority = 10 + ApplicationJob.priority = 0 + AttachFilesToWorkJob.priority = -1 + Bulkrax::ImportWorkJob.priority = -5 + Bulkrax::ImportFileSetJob.priority = -15 + Bulkrax::CreateRelationshipsJob.priority = -20 + Bulkrax::ImporterJob.priority = -20 + IiifPrint::Jobs::CreateRelationshipsJob.priority = -20 + ContentDepositEventJob.priority = -50 + ContentUpdateEventJob.priority = -50 + end +end diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb index 6377db666..dc3a30bae 100644 --- a/config/initializers/sidekiq.rb +++ b/config/initializers/sidekiq.rb @@ -1,10 +1,13 @@ -config = YAML.load(ERB.new(IO.read(Rails.root + 'config' + 'redis.yml')).result)[Rails.env].with_indifferent_access -redis_config = config.merge(thread_safe: true) +if ENV.fetch('HYRAX_ACTIVE_JOB_QUEUE', 'sidekiq') == 'sidekiq' -Sidekiq.configure_server do |s| - s.redis = redis_config -end + config = YAML.load(ERB.new(IO.read(Rails.root + 'config' + 'redis.yml')).result)[Rails.env].with_indifferent_access + redis_config = config.merge(thread_safe: true) + + Sidekiq.configure_server do |s| + s.redis = redis_config + end -Sidekiq.configure_client do |s| - s.redis = redis_config + Sidekiq.configure_client do |s| + s.redis = redis_config + end end diff --git a/config/routes.rb b/config/routes.rb index 73a5d0f50..dd3a92676 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,7 +2,9 @@ # OVERRIDE Hyrax 2.9.0 to add featured collection routes -require 'sidekiq/web' +if ENV.fetch('HYRAX_ACTIVE_JOB_QUEUE', 'sidekiq') + require 'sidekiq/web' +end Rails.application.routes.draw do # rubocop:disable Metrics/BlockLength resources :identity_providers @@ -13,7 +15,13 @@ mount Riiif::Engine => 'images', as: :riiif if Hyrax.config.iiif_image_server? authenticate :user, ->(u) { u.is_superadmin || u.is_admin } do - mount Sidekiq::Web => '/jobs' + queue = ENV.fetch('HYRAX_ACTIVE_JOB_QUEUE', 'sidekiq') + case queue + when 'sideki' + mount Sidekiq::Web => '/jobs' + when 'good_job' + mount GoodJob::Engine => '/jobs' + end end if ActiveModel::Type::Boolean.new.cast(ENV.fetch('HYKU_MULTITENANT', false)) diff --git a/db/migrate/20230406183814_create_good_jobs.rb b/db/migrate/20230406183814_create_good_jobs.rb new file mode 100644 index 000000000..d86ab61ac --- /dev/null +++ b/db/migrate/20230406183814_create_good_jobs.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true +class CreateGoodJobs < ActiveRecord::Migration[5.2] + def change + enable_extension 'pgcrypto' + + create_table :good_jobs, id: :uuid do |t| + t.text :queue_name + t.integer :priority + t.jsonb :serialized_params + t.timestamp :scheduled_at + t.timestamp :performed_at + t.timestamp :finished_at + t.text :error + + t.timestamps + + t.uuid :active_job_id + t.text :concurrency_key + t.text :cron_key + t.uuid :retried_good_job_id + t.timestamp :cron_at + end + + create_table :good_job_processes, id: :uuid do |t| + t.timestamps + t.jsonb :state + end + + add_index :good_jobs, :scheduled_at, where: "(finished_at IS NULL)", name: "index_good_jobs_on_scheduled_at" + add_index :good_jobs, [:queue_name, :scheduled_at], where: "(finished_at IS NULL)", name: :index_good_jobs_on_queue_name_and_scheduled_at + add_index :good_jobs, [:active_job_id, :created_at], name: :index_good_jobs_on_active_job_id_and_created_at + add_index :good_jobs, :concurrency_key, where: "(finished_at IS NULL)", name: :index_good_jobs_on_concurrency_key_when_unfinished + add_index :good_jobs, [:cron_key, :created_at], name: :index_good_jobs_on_cron_key_and_created_at + add_index :good_jobs, [:cron_key, :cron_at], name: :index_good_jobs_on_cron_key_and_cron_at, unique: true + add_index :good_jobs, [:active_job_id], name: :index_good_jobs_on_active_job_id + add_index :good_jobs, [:finished_at], where: "retried_good_job_id IS NULL AND finished_at IS NOT NULL", name: :index_good_jobs_jobs_on_finished_at + end +end From c32a948dc1c2fb52286fde5296b2a739075c6cf0 Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Fri, 22 Sep 2023 13:10:45 -0700 Subject: [PATCH 11/60] update gemfile lock --- Gemfile.lock | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 88b7a3175..bd14970f6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -13,8 +13,8 @@ GIT branch: upstream_main specs: hyku_knapsack (0.0.1) - good_job rails (>= 5.2.0) + sentry-raven GIT remote: https://github.com/samvera-labs/hyrax-doi.git @@ -211,6 +211,9 @@ GEM bootstrap-sass (~> 3.0) openseadragon (>= 0.2.0) rails + blacklight_advanced_search (6.4.1) + blacklight (~> 6.0, >= 6.0.1) + parslet blacklight_iiif_search (1.0.0) blacklight (~> 6.0) iiif-presentation @@ -218,6 +221,10 @@ GEM blacklight_oai_provider (6.1.1) blacklight (~> 6.0) oai (~> 1.0) + blacklight_range_limit (6.5.0) + blacklight (~> 6.10) + jquery-rails + rails (>= 4.2, < 6) bolognese (1.11.0) activesupport (>= 4.2.5) benchmark_methods (~> 0.7) @@ -886,6 +893,8 @@ GEM openseadragon (0.6.0) rails (> 3.2.0) optimist (3.0.1) + order_already (0.3.1) + rails-html-sanitizer (~> 1.4) orm_adapter (0.5.0) os (1.1.4) parallel (1.23.0) @@ -1144,6 +1153,8 @@ GEM rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) + sentry-raven (2.13.0) + faraday (>= 0.7.6, < 1.0) shacl (0.1.1) json-ld (~> 3.1, >= 3.1.7) rdf (~> 3.1, >= 3.1.8) @@ -1312,7 +1323,9 @@ DEPENDENCIES apartment aws-sdk-sqs blacklight (~> 6.7) + blacklight_advanced_search blacklight_oai_provider (~> 6.1, >= 6.1.1) + blacklight_range_limit (= 6.5.0) bolognese (>= 1.9.10) bootstrap-datepicker-rails bulkrax (~> 5.3) @@ -1355,6 +1368,7 @@ DEPENDENCIES omniauth-rails_csrf_protection (~> 1.0) omniauth-saml (~> 2.1) omniauth_openid_connect + order_already parser (~> 2.5.3) pg postrank-uri (>= 1.0.24) From 8cf14c488fb4a052ceecca327ef514bdd049f534 Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Fri, 22 Sep 2023 13:13:56 -0700 Subject: [PATCH 12/60] Update good_job.rb --- config/initializers/good_job.rb | 7 ------- 1 file changed, 7 deletions(-) diff --git a/config/initializers/good_job.rb b/config/initializers/good_job.rb index 7929a5d4b..0fe0259a7 100644 --- a/config/initializers/good_job.rb +++ b/config/initializers/good_job.rb @@ -18,13 +18,6 @@ # Wrapping this in an after_initialize block to ensure that all constants are loaded Rails.application.config.after_initialize do # baseline of 0, higher is sooner - - # Commented out the following two jobs because they were - # specfically used for the sdapi ingests. - # see sdapi_ingest_script directory and - # ref: https://github.com/scientist-softserv/adventist-dl/issues/468 - # CollectionMembershipJob.priority = 70 - # UpdateCollectionMembershipJob.priority = 60 Bulkrax::ScheduleRelationshipsJob.priority = 50 CreateDerivativesJob.priority = 40 CharacterizeJob.priority = 30 From 61a9504fbe46041c9fa32285faf97b974ed0969c Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Fri, 22 Sep 2023 15:55:31 -0700 Subject: [PATCH 13/60] merge --- .env | 2 +- config/routes.rb | 4 ++-- db/schema.rb | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/.env b/.env index c8df50c68..c51b5a51e 100644 --- a/.env +++ b/.env @@ -23,7 +23,7 @@ PASSENGER_APP_ENV=development RAILS_LOG_TO_STDOUT=true REDIS_HOST=redis SECRET_KEY_BASE=asdf -HYRAX_ACTIVE_JOB_QUEUE=sidekiq +HYRAX_ACTIVE_JOB_QUEUE=good_job HYRAX_FITS_PATH=/app/fits/fits.sh NEGATIVE_CAPTCHA_SECRET=default-value-change-me SOLR_ADMIN_PASSWORD=SolrRocks diff --git a/config/routes.rb b/config/routes.rb index dd3a92676..93f74b568 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,7 +2,7 @@ # OVERRIDE Hyrax 2.9.0 to add featured collection routes -if ENV.fetch('HYRAX_ACTIVE_JOB_QUEUE', 'sidekiq') +if ENV.fetch('HYRAX_ACTIVE_JOB_QUEUE', 'sidekiq') == 'sidekiq' require 'sidekiq/web' end @@ -17,7 +17,7 @@ authenticate :user, ->(u) { u.is_superadmin || u.is_admin } do queue = ENV.fetch('HYRAX_ACTIVE_JOB_QUEUE', 'sidekiq') case queue - when 'sideki' + when 'sidekiq' mount Sidekiq::Web => '/jobs' when 'good_job' mount GoodJob::Engine => '/jobs' diff --git a/db/schema.rb b/db/schema.rb index c7e628973..c523cfd22 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -13,6 +13,7 @@ ActiveRecord::Schema.define(version: 2023_08_04_073106) do # These are extensions that must be enabled in order to support this database + enable_extension "pgcrypto" enable_extension "plpgsql" create_table "account_cross_searches", force: :cascade do |t| @@ -312,6 +313,37 @@ t.index ["user_id"], name: "index_file_view_stats_on_user_id" end + create_table "good_job_processes", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.jsonb "state" + end + + create_table "good_jobs", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.text "queue_name" + t.integer "priority" + t.jsonb "serialized_params" + t.datetime "scheduled_at" + t.datetime "performed_at" + t.datetime "finished_at" + t.text "error" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.uuid "active_job_id" + t.text "concurrency_key" + t.text "cron_key" + t.uuid "retried_good_job_id" + t.datetime "cron_at" + t.index ["active_job_id", "created_at"], name: "index_good_jobs_on_active_job_id_and_created_at" + t.index ["active_job_id"], name: "index_good_jobs_on_active_job_id" + t.index ["concurrency_key"], name: "index_good_jobs_on_concurrency_key_when_unfinished", where: "(finished_at IS NULL)" + t.index ["cron_key", "created_at"], name: "index_good_jobs_on_cron_key_and_created_at" + t.index ["cron_key", "cron_at"], name: "index_good_jobs_on_cron_key_and_cron_at", unique: true + t.index ["finished_at"], name: "index_good_jobs_jobs_on_finished_at", where: "((retried_good_job_id IS NULL) AND (finished_at IS NOT NULL))" + t.index ["queue_name", "scheduled_at"], name: "index_good_jobs_on_queue_name_and_scheduled_at", where: "(finished_at IS NULL)" + t.index ["scheduled_at"], name: "index_good_jobs_on_scheduled_at", where: "(finished_at IS NULL)" + end + create_table "group_roles", force: :cascade do |t| t.bigint "role_id" t.bigint "group_id" From 363f9ee909e04afa001f80134775a479e42321cd Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Fri, 22 Sep 2023 15:55:51 -0700 Subject: [PATCH 14/60] fix routes file, add missing js file --- app/assets/javascripts/admin_color_select.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 app/assets/javascripts/admin_color_select.js diff --git a/app/assets/javascripts/admin_color_select.js b/app/assets/javascripts/admin_color_select.js new file mode 100644 index 000000000..919193c96 --- /dev/null +++ b/app/assets/javascripts/admin_color_select.js @@ -0,0 +1,20 @@ +$(document).on('turbolinks:load', function() { + $('div.defaultable-colors a.restore-default-color').click(function(e) { + e.preventDefault() + + var defaultTarget = $(e.target).data('default-target') + var input = $("input[name='admin_appearance["+ defaultTarget +"]']") + + input.val(input.data('default-value')) + }) + + $('.panel-footer a.restore-all-default-colors').click(function(e) { + e.preventDefault() + + var allColorInputs = $("input[name*='color']") + + allColorInputs.each(function() { + $(this).val($(this).data('default-value')) + }) + }) +}); \ No newline at end of file From 03dd69e50cc46f5d6e4b6caf02a8b2464742f542 Mon Sep 17 00:00:00 2001 From: Shana Moore Date: Mon, 25 Sep 2023 09:58:43 -0700 Subject: [PATCH 15/60] :lipstick: styling fix --- .../hyrax/homepage_controller_decorator.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/controllers/hyrax/homepage_controller_decorator.rb b/app/controllers/hyrax/homepage_controller_decorator.rb index 826a8599b..0299f6a63 100644 --- a/app/controllers/hyrax/homepage_controller_decorator.rb +++ b/app/controllers/hyrax/homepage_controller_decorator.rb @@ -5,14 +5,14 @@ module Hyrax module HomepageControllerDecorator def index - @presenter = presenter_class.new(current_ability, collections) - @featured_researcher = ContentBlock.for(:researcher) - @marketing_text = ContentBlock.for(:marketing) - @featured_work_list = FeaturedWorkList.new - @announcement_text = ContentBlock.for(:announcement) - @homepage_about_section_heading = ContentBlock.for(:homepage_about_section_heading) - @homepage_about_section_content = ContentBlock.for(:homepage_about_section_content) - recent + @presenter = presenter_class.new(current_ability, collections) + @featured_researcher = ContentBlock.for(:researcher) + @marketing_text = ContentBlock.for(:marketing) + @featured_work_list = FeaturedWorkList.new + @announcement_text = ContentBlock.for(:announcement) + @homepage_about_section_heading = ContentBlock.for(:homepage_about_section_heading) + @homepage_about_section_content = ContentBlock.for(:homepage_about_section_content) + recent end end end From ed161f85c8690c66efdac1a00bd7a87b0cc6a1d9 Mon Sep 17 00:00:00 2001 From: Shana Moore Date: Mon, 25 Sep 2023 10:33:45 -0700 Subject: [PATCH 16/60] :lipstick: rubocop fixes --- app/controllers/catalog_controller.rb | 31 ++++++++++--------- .../content_blocks_controller_decorator.rb | 10 +++--- .../hyrax/homepage_controller_decorator.rb | 1 - app/models/content_block.rb | 2 +- app/models/generic_work.rb | 1 - .../find_ids_by_model_decorator.rb | 7 ++++- 6 files changed, 28 insertions(+), 24 deletions(-) diff --git a/app/controllers/catalog_controller.rb b/app/controllers/catalog_controller.rb index c50f887b0..fbaccce7d 100644 --- a/app/controllers/catalog_controller.rb +++ b/app/controllers/catalog_controller.rb @@ -110,8 +110,7 @@ def self.uploaded_field config.add_facet_field 'file_format_sim', limit: 5 config.add_facet_field 'member_of_collections_ssim', limit: 5, label: 'Collections' - - # TODO deal with part of facet changes + # TODO: deal with part of facet changes # config.add_facet_field solr_name("part", :facetable), limit: 5, label: 'Part' # config.add_facet_field solr_name("part_of", :facetable), limit: 5 # removed # config.add_facet_field solr_name("file_format", :facetable), limit: 5 @@ -123,16 +122,16 @@ def self.uploaded_field # handler defaults, or have no facets. config.add_facet_fields_to_solr_request! - # TODO ROB -# # Prior to this change, the applications specific translations were not loaded. Dogbiscuits were assuming the translations were already loaded. -# Rails.root.glob("config/locales/*.yml").each do |path| -# I18n.load_path << path.to_s -# end -# I18n.backend.reload! -# index_props = DogBiscuits.config.index_properties.collect do |prop| -# { prop => index_options(prop, DogBiscuits.config.property_mappings[prop]) } -# end -# add_index_field config, index_props + # TODO: ROB + # # Prior to this change, the applications specific translations were not loaded. Dogbiscuits were assuming the translations were already loaded. + # Rails.root.glob("config/locales/*.yml").each do |path| + # I18n.load_path << path.to_s + # end + # I18n.backend.reload! + # index_props = DogBiscuits.config.index_properties.collect do |prop| + # { prop => index_options(prop, DogBiscuits.config.property_mappings[prop]) } + # end + # add_index_field config, index_props # solr fields to be displayed in the show (single result) view # The ordering of the field names is the order of the display @@ -203,8 +202,8 @@ def self.uploaded_field # since we aren't specifying it otherwise. config.add_search_field('all_fields', label: 'All Fields', include_in_advanced_search: false) do |field| all_names = config.show_fields.values.map(&:field).join(" ") -# TODO ROB all_names = (config.show_fields.values.map { |v| v.field.to_s } + - # DogBiscuits.config.all_properties.map { |p| "#{p}_tesim" }).uniq.join(" ") + # TODO: ROB all_names = (config.show_fields.values.map { |v| v.field.to_s } + + # DogBiscuits.config.all_properties.map { |p| "#{p}_tesim" }).uniq.join(" ") title_name = 'title_tesim' field.solr_parameters = { qf: "#{all_names} file_format_tesim all_text_timv", @@ -233,7 +232,7 @@ def self.uploaded_field end config.add_search_field('creator') do |field| - # TODO ROB field.label = "Author" + # TODO: ROB field.label = "Author" field.solr_parameters = { "spellcheck.dictionary": "creator" } solr_name = 'creator_tesim' field.solr_local_parameters = { @@ -276,7 +275,9 @@ def self.uploaded_field } end + # rubocop:disable Lint/UselessAssignment date_fields = ['date_created_tesim', 'sorted_date_isi', 'sorted_month_isi'] + # rubocop:enable Lint/UselessAssignment config.add_search_field('date_created') do |field| field.solr_parameters = { diff --git a/app/controllers/hyrax/content_blocks_controller_decorator.rb b/app/controllers/hyrax/content_blocks_controller_decorator.rb index 348ac4f20..afaa2201f 100644 --- a/app/controllers/hyrax/content_blocks_controller_decorator.rb +++ b/app/controllers/hyrax/content_blocks_controller_decorator.rb @@ -6,11 +6,11 @@ module ContentBlocksControllerDecorator # override hyrax v2.9.0 added the home_text content block to permitted_params - Adding Themes def permitted_params params.require(:content_block).permit(:marketing, - :announcement, - :home_text, - :homepage_about_section_heading, - :homepage_about_section_content, - :researcher) + :announcement, + :home_text, + :homepage_about_section_heading, + :homepage_about_section_content, + :researcher) end end end diff --git a/app/controllers/hyrax/homepage_controller_decorator.rb b/app/controllers/hyrax/homepage_controller_decorator.rb index 0299f6a63..e4564a9bb 100644 --- a/app/controllers/hyrax/homepage_controller_decorator.rb +++ b/app/controllers/hyrax/homepage_controller_decorator.rb @@ -3,7 +3,6 @@ # OVERRIDE Hyrax 3.5 to add content blocks module Hyrax module HomepageControllerDecorator - def index @presenter = presenter_class.new(current_ability, collections) @featured_researcher = ContentBlock.for(:researcher) diff --git a/app/models/content_block.rb b/app/models/content_block.rb index 4c00535b3..5b383f192 100644 --- a/app/models/content_block.rb +++ b/app/models/content_block.rb @@ -16,7 +16,7 @@ class ContentBlock < ApplicationRecord help: :help_page, terms: :terms_page, agreement: :agreement_page, - home_text: :home_text, + home_text: :home_text, homepage_about_section_heading: :homepage_about_section_heading, homepage_about_section_content: :homepage_about_section_content }.freeze diff --git a/app/models/generic_work.rb b/app/models/generic_work.rb index 5ee8e9c01..0abd4f9db 100644 --- a/app/models/generic_work.rb +++ b/app/models/generic_work.rb @@ -12,5 +12,4 @@ class GenericWork < ActiveFedora::Base self.indexer = GenericWorkIndexer prepend OrderAlready.for(:creator) - end diff --git a/lib/wings/services/custom_queries/find_ids_by_model_decorator.rb b/lib/wings/services/custom_queries/find_ids_by_model_decorator.rb index 7cbaaef29..84e3b2c50 100644 --- a/lib/wings/services/custom_queries/find_ids_by_model_decorator.rb +++ b/lib/wings/services/custom_queries/find_ids_by_model_decorator.rb @@ -29,7 +29,12 @@ def find_ids_by_model(model:, ids: :all) response_docs.each { |doc| yield doc['id'] } break if (solr_response['start'] + solr_response['docs'].count) >= solr_response['numFound'] - solr_response = ActiveFedora::SolrService.post(solr_query, fl: 'id', rows: @query_rows, start: solr_response['start'] + @query_rows)['response'] + solr_response = ActiveFedora::SolrService.post( + solr_query, + fl: 'id', + rows: @query_rows, + start: solr_response['start'] + @query_rows + )['response'] end end end From 00a4b4af7a0dd18f5a3b393d60e9728322f4943e Mon Sep 17 00:00:00 2001 From: Shana Moore Date: Mon, 25 Sep 2023 10:49:34 -0700 Subject: [PATCH 17/60] remove iiif_print/iiif_print require cause of Sprockets::FileNotFound in Splash#index error. Doesn't seem necessary. --- app/assets/stylesheets/application.css | 1 - 1 file changed, 1 deletion(-) diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index bb4734825..61efe4aa9 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -20,6 +20,5 @@ *= require single_signon *= require blacklight_advanced_search *= require blacklight_range_limit - *= require iiif_print/iiif_print *= require_self */ From 2ac46251a4b01b2fc6a11e628c0e7721757d6b79 Mon Sep 17 00:00:00 2001 From: Shana Moore Date: Mon, 25 Sep 2023 12:49:21 -0700 Subject: [PATCH 18/60] :gift: :broom: add missing file and format with semicolons The previous build revealed that admin_color_select.js was missing. It also complained about missing semicolons. --- app/assets/javascripts/admin_color_select.js | 20 ++++++++ app/assets/javascripts/admin_font_select.js | 54 +++++++++++--------- 2 files changed, 49 insertions(+), 25 deletions(-) create mode 100644 app/assets/javascripts/admin_color_select.js diff --git a/app/assets/javascripts/admin_color_select.js b/app/assets/javascripts/admin_color_select.js new file mode 100644 index 000000000..5bff8eb25 --- /dev/null +++ b/app/assets/javascripts/admin_color_select.js @@ -0,0 +1,20 @@ +$(document).on("turbolinks:load", function () { + $("div.defaultable-colors a.restore-default-color").click(function (e) { + e.preventDefault(); + + var defaultTarget = $(e.target).data("default-target"); + var input = $("input[name='admin_appearance[" + defaultTarget + "]']"); + + input.val(input.data("default-value")); + }); + + $(".panel-footer a.restore-all-default-colors").click(function (e) { + e.preventDefault(); + + var allColorInputs = $("input[name*='color']"); + + allColorInputs.each(function () { + $(this).val($(this).data("default-value")); + }); + }); +}); diff --git a/app/assets/javascripts/admin_font_select.js b/app/assets/javascripts/admin_font_select.js index e2c3e89cb..26abe89fa 100644 --- a/app/assets/javascripts/admin_font_select.js +++ b/app/assets/javascripts/admin_font_select.js @@ -1,34 +1,38 @@ -Blacklight.onLoad(function() { - if($("#admin_appearance_body_font").length > 0){ - $("#admin_appearance_body_font").fontselect({lookahead: 20}) - $("#admin_appearance_headline_font").fontselect({lookahead: 20}) +Blacklight.onLoad(function () { + if ($("#admin_appearance_body_font").length > 0) { + $("#admin_appearance_body_font").fontselect({ lookahead: 20 }); + $("#admin_appearance_headline_font").fontselect({ lookahead: 20 }); } }); -$('div.defaultable-fonts a.restore-default-font').click(function(e) { - e.preventDefault() - var defaultTarget = $(e.target).data('default-target') - var input = $("input[name='admin_appearance["+ defaultTarget +"]']") - var defaultValue = input.data('default-value').replace(';', '') - var inputDisplay = $("div[class$='"+ defaultTarget +"']").find('div.font-select span') +$("div.defaultable-fonts a.restore-default-font").click(function (e) { + e.preventDefault(); + var defaultTarget = $(e.target).data("default-target"); + var input = $("input[name='admin_appearance[" + defaultTarget + "]']"); + var defaultValue = input.data("default-value").replace(";", ""); + var inputDisplay = $("div[class$='" + defaultTarget + "']").find( + "div.font-select span" + ); - input.val(defaultValue) - inputDisplay.css("font-family", defaultValue) - inputDisplay.text(defaultValue) -}) + input.val(defaultValue); + inputDisplay.css("font-family", defaultValue); + inputDisplay.text(defaultValue); +}); -$('.panel-footer a.restore-all-default-fonts').click(function(e) { - e.preventDefault() +$(".panel-footer a.restore-all-default-fonts").click(function (e) { + e.preventDefault(); - var allFontInputs = $("input[name*='font']") + var allFontInputs = $("input[name*='font']"); - allFontInputs.each(function() { - var thisTarget = $(this).attr('id').replace('admin_appearance_', '') - var defaultValue = $(this).data('default-value').replace(';', '') - var inputDisplay = $("div[class$='"+ thisTarget +"']").find('div.font-select span') + allFontInputs.each(function () { + var thisTarget = $(this).attr("id").replace("admin_appearance_", ""); + var defaultValue = $(this).data("default-value").replace(";", ""); + var inputDisplay = $("div[class$='" + thisTarget + "']").find( + "div.font-select span" + ); - $(this).val(defaultValue) - inputDisplay.css("font-family", defaultValue) - inputDisplay.text(defaultValue) - }) + $(this).val(defaultValue); + inputDisplay.css("font-family", defaultValue); + inputDisplay.text(defaultValue); + }); }); From 15d313680a84fa2401f7be7b0b94ea1900539a9e Mon Sep 17 00:00:00 2001 From: Shana Moore Date: Mon, 25 Sep 2023 12:52:25 -0700 Subject: [PATCH 19/60] :lipstick: correct missing semicolons appease the hound by formatting js file with semicolons. --- .../range_limit_distro_facets.js | 606 ++++++++++-------- 1 file changed, 327 insertions(+), 279 deletions(-) diff --git a/app/assets/javascripts/blacklight_range_limit/range_limit_distro_facets.js b/app/assets/javascripts/blacklight_range_limit/range_limit_distro_facets.js index 4b2807651..1133b8dec 100644 --- a/app/assets/javascripts/blacklight_range_limit/range_limit_distro_facets.js +++ b/app/assets/javascripts/blacklight_range_limit/range_limit_distro_facets.js @@ -4,297 +4,345 @@ is (re-)drawn on screen possibly with a new size. target of event will be the DOM element containing the plot. Used to resize slider to match. */ - Blacklight.onLoad(function() { - // ratio of width to height for desired display, multiply width by this ratio - // to get height. hard-coded in for now. - var display_ratio = 1/(1.618 * 2); // half a golden rectangle, why not - var redrawnEvent = "plotDrawn.blacklight.rangeLimit"; - - - - // Facets already on the page? Turn em into a chart. - $(".range_limit .profile .distribution.chart_js ul").each(function() { - turnIntoPlot($(this).parent()); - }); - - - // Add AJAX fetched range facets if needed, and add a chart to em - $(".range_limit .profile .distribution a.load_distribution").each(function() { - var container = $(this).parent('div.distribution'); - - $(container).load($(this).attr('href'), function(response, status) { - if ($(container).hasClass("chart_js") && status == "success" ) { - turnIntoPlot(container); - } - }); - }); - - // Listen for twitter bootstrap collapsible open events, to render flot - // in previously hidden divs on open, if needed. - $("body").on("show.bs.collapse", function(event) { - // Was the target a .facet-content including a .chart-js? - var container = $(event.target).filter(".facet-content").find(".chart_js"); - - // only if it doesn't already have a canvas, it isn't already drawn - if (container && container.find("canvas").length == 0) { - // be willing to wait up to 1100ms for container to - // have width -- right away on show.bs is too soon, but - // shown.bs is later than we want, we want to start rendering - // while animation is still in progress. - turnIntoPlot(container, 1100); - } - }); - - - - // after a collapsible facet contents is fully shown, - // resize the flot chart to current conditions. This way, if you change - // browser window size, you can get chart resized to fit by closing and opening - // again, if needed. - - function redrawPlot(container) { - if (container && container.width() > 0) { - // resize the container's height, since width may have changed. - container.height( container.width() * display_ratio ); - - // redraw the chart. - var plot = container.data("plot"); - if (plot) { - // how to redraw after possible resize? - // Cribbed from https://github.com/flot/flot/blob/master/jquery.flot.resize.js - plot.resize(); - plot.setupGrid(); - plot.draw(); - // plus trigger redraw of the selection, which otherwise ain't always right - // we'll trigger a fake event on one of the boxes - var form = $(container).closest(".limit_content").find("form.range_limit"); - form.find("input.range_begin").trigger("change"); - - // send our custom event to trigger redraw of slider - $(container).trigger(redrawnEvent); +Blacklight.onLoad(function () { + // ratio of width to height for desired display, multiply width by this ratio + // to get height. hard-coded in for now. + var display_ratio = 1 / (1.618 * 2); // half a golden rectangle, why not + var redrawnEvent = "plotDrawn.blacklight.rangeLimit"; + + // Facets already on the page? Turn em into a chart. + $(".range_limit .profile .distribution.chart_js ul").each(function () { + turnIntoPlot($(this).parent()); + }); + + // Add AJAX fetched range facets if needed, and add a chart to em + $(".range_limit .profile .distribution a.load_distribution").each( + function () { + var container = $(this).parent("div.distribution"); + + $(container).load($(this).attr("href"), function (response, status) { + if ($(container).hasClass("chart_js") && status == "success") { + turnIntoPlot(container); } + }); + } + ); + + // Listen for twitter bootstrap collapsible open events, to render flot + // in previously hidden divs on open, if needed. + $("body").on("show.bs.collapse", function (event) { + // Was the target a .facet-content including a .chart-js? + var container = $(event.target).filter(".facet-content").find(".chart_js"); + + // only if it doesn't already have a canvas, it isn't already drawn + if (container && container.find("canvas").length == 0) { + // be willing to wait up to 1100ms for container to + // have width -- right away on show.bs is too soon, but + // shown.bs is later than we want, we want to start rendering + // while animation is still in progress. + turnIntoPlot(container, 1100); + } + }); + + // after a collapsible facet contents is fully shown, + // resize the flot chart to current conditions. This way, if you change + // browser window size, you can get chart resized to fit by closing and opening + // again, if needed. + + function redrawPlot(container) { + if (container && container.width() > 0) { + // resize the container's height, since width may have changed. + container.height(container.width() * display_ratio); + + // redraw the chart. + var plot = container.data("plot"); + if (plot) { + // how to redraw after possible resize? + // Cribbed from https://github.com/flot/flot/blob/master/jquery.flot.resize.js + plot.resize(); + plot.setupGrid(); + plot.draw(); + // plus trigger redraw of the selection, which otherwise ain't always right + // we'll trigger a fake event on one of the boxes + var form = $(container) + .closest(".limit_content") + .find("form.range_limit"); + form.find("input.range_begin").trigger("change"); + + // send our custom event to trigger redraw of slider + $(container).trigger(redrawnEvent); } } - - $("body").on("shown.bs.collapse", function(event) { - var container = $(event.target).filter(".facet-content").find(".chart_js"); - redrawPlot(container); - }); - - // debouce borrowed from underscore - // Returns a function, that, as long as it continues to be invoked, will not - // be triggered. The function will be called after it stops being called for - // N milliseconds. If `immediate` is passed, trigger the function on the - // leading edge, instead of the trailing. - debounce = function(func, wait, immediate) { - var timeout; - return function() { - var context = this, args = arguments; - var later = function() { - timeout = null; - if (!immediate) func.apply(context, args); - }; - var callNow = immediate && !timeout; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - if (callNow) func.apply(context, args); + } + + $("body").on("shown.bs.collapse", function (event) { + var container = $(event.target).filter(".facet-content").find(".chart_js"); + redrawPlot(container); + }); + + // debouce borrowed from underscore + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. If `immediate` is passed, trigger the function on the + // leading edge, instead of the trailing. + debounce = function (func, wait, immediate) { + var timeout; + return function () { + var context = this, + args = arguments; + var later = function () { + timeout = null; + if (!immediate) func.apply(context, args); }; + var callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) func.apply(context, args); }; - - $(window).on("resize", debounce(function() { - $(".chart_js").each(function(i, container) { + }; + + $(window).on( + "resize", + debounce(function () { + $(".chart_js").each(function (i, container) { redrawPlot($(container)); }); - }, 350)); - - // second arg, if provided, is a number of ms we're willing to - // wait for the container to have width before giving up -- we'll - // set 50ms timers to check back until timeout is expired or the - // container is finally visible. The timeout is used when we catch - // bootstrap show event, but the animation hasn't barely begun yet -- but - // we don't want to wait until it's finished, we want to start rendering - // as soon as we can. + }, 350) + ); + + // second arg, if provided, is a number of ms we're willing to + // wait for the container to have width before giving up -- we'll + // set 50ms timers to check back until timeout is expired or the + // container is finally visible. The timeout is used when we catch + // bootstrap show event, but the animation hasn't barely begun yet -- but + // we don't want to wait until it's finished, we want to start rendering + // as soon as we can. + // + // We also will + function turnIntoPlot(container, wait_for_visible) { + // flot can only render in a a div with a defined width. + // for instance, a hidden div can't generally be rendered in (although if you set + // an explicit width on it, it might work) // - // We also will - function turnIntoPlot(container, wait_for_visible) { - // flot can only render in a a div with a defined width. - // for instance, a hidden div can't generally be rendered in (although if you set - // an explicit width on it, it might work) - // - // We'll count on later code that catch bootstrap collapse open to render - // on show, for currently hidden divs. - - // for some reason width sometimes return negative, not sure - // why but it's some kind of hidden. - if (container.width() > 0) { - var height = container.width() * display_ratio; - - // Need an explicit height to make flot happy. - container.height( height ) - - areaChart($(container)); - - $(container).trigger(redrawnEvent); - } - else if (wait_for_visible > 0) { - setTimeout(function() { - turnIntoPlot(container, wait_for_visible - 50); - }, 50); - } + // We'll count on later code that catch bootstrap collapse open to render + // on show, for currently hidden divs. + + // for some reason width sometimes return negative, not sure + // why but it's some kind of hidden. + if (container.width() > 0) { + var height = container.width() * display_ratio; + + // Need an explicit height to make flot happy. + container.height(height); + + areaChart($(container)); + + $(container).trigger(redrawnEvent); + } else if (wait_for_visible > 0) { + setTimeout(function () { + turnIntoPlot(container, wait_for_visible - 50); + }, 50); } - - // Takes a div holding a ul of distribution segments produced by - // blacklight_range_limit/_range_facets and makes it into - // a flot area chart. - function areaChart(container) { - //flot loaded? And canvas element supported. - if ( domDependenciesMet() ) { - - // Grab the data from the ul div - var series_data = new Array(); - var pointer_lookup = new Array(); - var x_ticks = new Array(); - var min = BlacklightRangeLimit.parseNum($(container).find("ul li:first-child span.from").text()); - var max = BlacklightRangeLimit.parseNum($(container).find("ul li:last-child span.to").text()); - - $(container).find("ul li").each(function() { - var from = BlacklightRangeLimit.parseNum($(this).find("span.from").text()); - var to = BlacklightRangeLimit.parseNum($(this).find("span.to").text()); - var count = BlacklightRangeLimit.parseNum($(this).find("span.count").text()); - var avg = (count / (to - from + 1)); - - - //We use the avg as the y-coord, to make the area of each - //segment proportional to how many documents it holds. - series_data.push( [from, avg ] ); - series_data.push( [to+1, avg] ); - - x_ticks.push(from); - - pointer_lookup.push({'from': from, 'to': to, 'count': count, 'label': $(this).find(".facet_select").text() }); - }); - var max_plus_one = BlacklightRangeLimit.parseNum($(container).find("ul li:last-child span.to").text())+1; - x_ticks.push( max_plus_one ); - - - - var plot; - var config = $(container).closest('.facet_limit').data('plot-config') || {}; - - try { - plot = $.plot($(container), [series_data], - $.extend(true, config, { - yaxis: { ticks: [], min: 0, autoscaleMargin: 0.1}, - //xaxis: { ticks: x_ticks }, - xaxis: { tickDecimals: 0 }, // force integer ticks - series: { lines: { fill: true, steps: true }}, - grid: {clickable: true, hoverable: true, autoHighlight: false}, - selection: {mode: "x"} - })); - } - catch(err) { - alert(err); - } - - find_segment_for = function_for_find_segment(pointer_lookup); - var last_segment = null; - $(container).tooltip({'placement': 'bottom', 'trigger': 'manual', 'delay': { show: 0, hide: 100}}); - - $(container).bind("plothover", function (event, pos, item) { - segment = find_segment_for(pos.x); - - if(segment != last_segment) { - var title = find_segment_for(pos.x).label + ' (' + BlacklightRangeLimit.parseNum(segment.count) + ')'; - $(container).attr("title", title).tooltip("_fixTitle").tooltip("show"); - - last_segment = segment; - } - }); - - $(container).bind("mouseout", function() { - last_segment = null; - $(container).tooltip('hide'); - }); - $(container).bind("plotclick", function (event, pos, item) { - if ( plot.getSelection() == null) { - segment = find_segment_for(pos.x); - plot.setSelection( normalized_selection(segment.from, segment.to)); - } - }); - $(container).bind("plotselected plotselecting", function(event, ranges) { - if (ranges != null ) { - var from = Math.floor(ranges.xaxis.from); - var to = Math.floor(ranges.xaxis.to); - - var form = $(container).closest(".limit_content").find("form.range_limit"); - form.find("input.range_begin").val(from); - form.find("input.range_end").val(to); - - var slider_placeholder = $(container).closest(".limit_content").find("[data-slider-placeholder]"); - if (slider_placeholder) { - slider_placeholder.slider("setValue", [from, to+1]); - } - } - }); - - var form = $(container).closest(".limit_content").find("form.range_limit"); - form.find("input.range_begin, input.range_end").change(function () { - plot.setSelection( form_selection(form, min, max) , true ); - }); - $(container).closest(".limit_content").find(".profile .range").on("slide", function(event, ui) { - var values = $(event.target).data("slider").getValue(); - form.find("input.range_begin").val(values[0]); - form.find("input.range_end").val(values[1]); - plot.setSelection( normalized_selection(values[0], Math.max(values[0], values[1]-1)), true); + } + + // Takes a div holding a ul of distribution segments produced by + // blacklight_range_limit/_range_facets and makes it into + // a flot area chart. + function areaChart(container) { + //flot loaded? And canvas element supported. + if (domDependenciesMet()) { + // Grab the data from the ul div + var series_data = new Array(); + var pointer_lookup = new Array(); + var x_ticks = new Array(); + var min = BlacklightRangeLimit.parseNum( + $(container).find("ul li:first-child span.from").text() + ); + var max = BlacklightRangeLimit.parseNum( + $(container).find("ul li:last-child span.to").text() + ); + + $(container) + .find("ul li") + .each(function () { + var from = BlacklightRangeLimit.parseNum( + $(this).find("span.from").text() + ); + var to = BlacklightRangeLimit.parseNum( + $(this).find("span.to").text() + ); + var count = BlacklightRangeLimit.parseNum( + $(this).find("span.count").text() + ); + var avg = count / (to - from + 1); + + //We use the avg as the y-coord, to make the area of each + //segment proportional to how many documents it holds. + series_data.push([from, avg]); + series_data.push([to + 1, avg]); + + x_ticks.push(from); + + pointer_lookup.push({ + from: from, + to: to, + count: count, + label: $(this).find(".facet_select").text(), }); - - // initially entirely selected, to match slider - plot.setSelection( {xaxis: { from:min, to:max+0.9999}} ); - } - } - - - // Send endpoint to endpoint+0.99999 to have display - // more closely approximate limiting behavior esp - // at small resolutions. (Since we search on whole numbers, - // inclusive, but flot chart is decimal.) - function normalized_selection(min, max) { - max += 0.99999; - - return {xaxis: { 'from':min, 'to':max}} + }); + var max_plus_one = + BlacklightRangeLimit.parseNum( + $(container).find("ul li:last-child span.to").text() + ) + 1; + x_ticks.push(max_plus_one); + + var plot; + var config = + $(container).closest(".facet_limit").data("plot-config") || {}; + + try { + plot = $.plot( + $(container), + [series_data], + $.extend(true, config, { + yaxis: { ticks: [], min: 0, autoscaleMargin: 0.1 }, + //xaxis: { ticks: x_ticks }, + xaxis: { tickDecimals: 0 }, // force integer ticks + series: { lines: { fill: true, steps: true } }, + grid: { clickable: true, hoverable: true, autoHighlight: false }, + selection: { mode: "x" }, + }) + ); + } catch (err) { + alert(err); } - - function form_selection(form, min, max) { - var begin_val = BlacklightRangeLimit.parseNum($(form).find("input.range_begin").val()); - if (isNaN(begin_val) || begin_val < min) { - begin_val = min; + + find_segment_for = function_for_find_segment(pointer_lookup); + var last_segment = null; + $(container).tooltip({ + placement: "bottom", + trigger: "manual", + delay: { show: 0, hide: 100 }, + }); + + $(container).bind("plothover", function (event, pos, item) { + segment = find_segment_for(pos.x); + + if (segment != last_segment) { + var title = + find_segment_for(pos.x).label + + " (" + + BlacklightRangeLimit.parseNum(segment.count) + + ")"; + $(container) + .attr("title", title) + .tooltip("_fixTitle") + .tooltip("show"); + + last_segment = segment; } - var end_val = BlacklightRangeLimit.parseNum($(form).find("input.range_end").val()); - if (isNaN(end_val) || end_val > max) { - end_val = max; + }); + + $(container).bind("mouseout", function () { + last_segment = null; + $(container).tooltip("hide"); + }); + $(container).bind("plotclick", function (event, pos, item) { + if (plot.getSelection() == null) { + segment = find_segment_for(pos.x); + plot.setSelection(normalized_selection(segment.from, segment.to)); } - - return normalized_selection(begin_val, end_val); - } - - function function_for_find_segment(pointer_lookup_arr) { - return function(x_coord) { - for (var i = pointer_lookup_arr.length-1 ; i >= 0 ; i--) { - var hash = pointer_lookup_arr[i]; - if (x_coord >= hash.from) - return hash; + }); + $(container).bind("plotselected plotselecting", function (event, ranges) { + if (ranges != null) { + var from = Math.floor(ranges.xaxis.from); + var to = Math.floor(ranges.xaxis.to); + + var form = $(container) + .closest(".limit_content") + .find("form.range_limit"); + form.find("input.range_begin").val(from); + form.find("input.range_end").val(to); + + var slider_placeholder = $(container) + .closest(".limit_content") + .find("[data-slider-placeholder]"); + if (slider_placeholder) { + slider_placeholder.slider("setValue", [from, to + 1]); } - return pointer_lookup_arr[0]; - }; - } - - // Check if Flot is loaded, and if browser has support for - // canvas object, either natively or via IE excanvas. - function domDependenciesMet() { - var flotLoaded = (typeof $.plot != "undefined"); - var canvasAvailable = ((typeof(document.createElement('canvas').getContext) != "undefined") || (typeof window.CanvasRenderingContext2D != 'undefined' || typeof G_vmlCanvasManager != 'undefined')); - - return (flotLoaded && canvasAvailable); + } + }); + + var form = $(container) + .closest(".limit_content") + .find("form.range_limit"); + form.find("input.range_begin, input.range_end").change(function () { + plot.setSelection(form_selection(form, min, max), true); + }); + $(container) + .closest(".limit_content") + .find(".profile .range") + .on("slide", function (event, ui) { + var values = $(event.target).data("slider").getValue(); + form.find("input.range_begin").val(values[0]); + form.find("input.range_end").val(values[1]); + plot.setSelection( + normalized_selection(values[0], Math.max(values[0], values[1] - 1)), + true + ); + }); + + // initially entirely selected, to match slider + plot.setSelection({ xaxis: { from: min, to: max + 0.9999 } }); + } + } + + // Send endpoint to endpoint+0.99999 to have display + // more closely approximate limiting behavior esp + // at small resolutions. (Since we search on whole numbers, + // inclusive, but flot chart is decimal.) + function normalized_selection(min, max) { + max += 0.99999; + + return { xaxis: { from: min, to: max } }; + } + + function form_selection(form, min, max) { + var begin_val = BlacklightRangeLimit.parseNum( + $(form).find("input.range_begin").val() + ); + if (isNaN(begin_val) || begin_val < min) { + begin_val = min; + } + var end_val = BlacklightRangeLimit.parseNum( + $(form).find("input.range_end").val() + ); + if (isNaN(end_val) || end_val > max) { + end_val = max; + } + + return normalized_selection(begin_val, end_val); + } + + function function_for_find_segment(pointer_lookup_arr) { + return function (x_coord) { + for (var i = pointer_lookup_arr.length - 1; i >= 0; i--) { + var hash = pointer_lookup_arr[i]; + if (x_coord >= hash.from) return hash; } - }); - \ No newline at end of file + return pointer_lookup_arr[0]; + }; + } + + // Check if Flot is loaded, and if browser has support for + // canvas object, either natively or via IE excanvas. + function domDependenciesMet() { + var flotLoaded = typeof $.plot != "undefined"; + var canvasAvailable = + typeof document.createElement("canvas").getContext != "undefined" || + typeof window.CanvasRenderingContext2D != "undefined" || + typeof G_vmlCanvasManager != "undefined"; + + return flotLoaded && canvasAvailable; + } +}); From 21133eae712b74e627c7eeef4230577aa3156621 Mon Sep 17 00:00:00 2001 From: Shana Moore Date: Mon, 25 Sep 2023 13:39:16 -0700 Subject: [PATCH 20/60] :broom: remove call to iiif_print/iiif_print Cause of build error. It's already being included in sass. --- app/assets/stylesheets/application.css | 1 - 1 file changed, 1 deletion(-) diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index bb4734825..61efe4aa9 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -20,6 +20,5 @@ *= require single_signon *= require blacklight_advanced_search *= require blacklight_range_limit - *= require iiif_print/iiif_print *= require_self */ From 05304fd3874a01d0f094cc3ce9ca3a51c6ed3084 Mon Sep 17 00:00:00 2001 From: Shana Moore Date: Mon, 25 Sep 2023 14:15:46 -0700 Subject: [PATCH 21/60] :lipstick: Rubocop fixes --- app/controllers/catalog_controller.rb | 31 ++++++++++++--------------- app/models/generic_work.rb | 1 - 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/app/controllers/catalog_controller.rb b/app/controllers/catalog_controller.rb index c50f887b0..523788a6b 100644 --- a/app/controllers/catalog_controller.rb +++ b/app/controllers/catalog_controller.rb @@ -110,8 +110,7 @@ def self.uploaded_field config.add_facet_field 'file_format_sim', limit: 5 config.add_facet_field 'member_of_collections_ssim', limit: 5, label: 'Collections' - - # TODO deal with part of facet changes + # TODO: deal with part of facet changes # config.add_facet_field solr_name("part", :facetable), limit: 5, label: 'Part' # config.add_facet_field solr_name("part_of", :facetable), limit: 5 # removed # config.add_facet_field solr_name("file_format", :facetable), limit: 5 @@ -123,16 +122,16 @@ def self.uploaded_field # handler defaults, or have no facets. config.add_facet_fields_to_solr_request! - # TODO ROB -# # Prior to this change, the applications specific translations were not loaded. Dogbiscuits were assuming the translations were already loaded. -# Rails.root.glob("config/locales/*.yml").each do |path| -# I18n.load_path << path.to_s -# end -# I18n.backend.reload! -# index_props = DogBiscuits.config.index_properties.collect do |prop| -# { prop => index_options(prop, DogBiscuits.config.property_mappings[prop]) } -# end -# add_index_field config, index_props + # TODO: ROB + # # Prior to this change, the applications specific translations were not loaded. Dogbiscuits were assuming the translations were already loaded. + # Rails.root.glob("config/locales/*.yml").each do |path| + # I18n.load_path << path.to_s + # end + # I18n.backend.reload! + # index_props = DogBiscuits.config.index_properties.collect do |prop| + # { prop => index_options(prop, DogBiscuits.config.property_mappings[prop]) } + # end + # add_index_field config, index_props # solr fields to be displayed in the show (single result) view # The ordering of the field names is the order of the display @@ -203,8 +202,8 @@ def self.uploaded_field # since we aren't specifying it otherwise. config.add_search_field('all_fields', label: 'All Fields', include_in_advanced_search: false) do |field| all_names = config.show_fields.values.map(&:field).join(" ") -# TODO ROB all_names = (config.show_fields.values.map { |v| v.field.to_s } + - # DogBiscuits.config.all_properties.map { |p| "#{p}_tesim" }).uniq.join(" ") + # TODO: ROB all_names = (config.show_fields.values.map { |v| v.field.to_s } + + # DogBiscuits.config.all_properties.map { |p| "#{p}_tesim" }).uniq.join(" ") title_name = 'title_tesim' field.solr_parameters = { qf: "#{all_names} file_format_tesim all_text_timv", @@ -233,7 +232,7 @@ def self.uploaded_field end config.add_search_field('creator') do |field| - # TODO ROB field.label = "Author" + # TODO: ROB field.label = "Author" field.solr_parameters = { "spellcheck.dictionary": "creator" } solr_name = 'creator_tesim' field.solr_local_parameters = { @@ -276,8 +275,6 @@ def self.uploaded_field } end - date_fields = ['date_created_tesim', 'sorted_date_isi', 'sorted_month_isi'] - config.add_search_field('date_created') do |field| field.solr_parameters = { "spellcheck.dictionary": "date_created" diff --git a/app/models/generic_work.rb b/app/models/generic_work.rb index 5ee8e9c01..0abd4f9db 100644 --- a/app/models/generic_work.rb +++ b/app/models/generic_work.rb @@ -12,5 +12,4 @@ class GenericWork < ActiveFedora::Base self.indexer = GenericWorkIndexer prepend OrderAlready.for(:creator) - end From 8d81514d37435ec6d1c7b60ae3f6a87785332a62 Mon Sep 17 00:00:00 2001 From: Kirk Wang Date: Mon, 25 Sep 2023 16:32:55 -0700 Subject: [PATCH 22/60] =?UTF-8?q?=E2=9C=85=20Fix=20test=20setup=20for=20ca?= =?UTF-8?q?talog=5Fcontroller=5Fspec?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit will add additional setup to the catalog_controller_spec. --- spec/requests/catalog_controller_spec.rb | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/spec/requests/catalog_controller_spec.rb b/spec/requests/catalog_controller_spec.rb index 818b80bd3..c36a9c43d 100644 --- a/spec/requests/catalog_controller_spec.rb +++ b/spec/requests/catalog_controller_spec.rb @@ -56,6 +56,18 @@ before do host! "http://#{cross_search_tenant_account.cname}/" + black_light_config.add_search_field('title') do |field| + field.solr_parameters = { + "spellcheck.dictionary": "title" + } + solr_name = 'title_tesim' + field.solr_local_parameters = { + qf: solr_name, + pf: solr_name + } + end + black_light_config.advanced_search ||= Blacklight::OpenStructWithHashAccess.new + black_light_config.advanced_search[:query_parser] ||= 'dismax' end context 'can fetch data from other tenants' do @@ -66,7 +78,7 @@ # get '/catalog', params: { q: '*' } # get search_catalog_url, params: { locale: 'en', q: 'test' } - get "http://#{cross_search_tenant_account.cname}/catalog?q=test" # , params: { q: 'test' } + get "http://#{cross_search_tenant_account.cname}/catalog?q=test", params: { q: 'title' } expect(response.status).to eq(200) end end From aa7f8c636094598c2e43dc7262b64c0715d15233 Mon Sep 17 00:00:00 2001 From: Kirk Wang Date: Tue, 26 Sep 2023 12:26:55 -0700 Subject: [PATCH 23/60] Add knapsack helper --- app/helpers/application_helper.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index e27eee4ae..44531726b 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -5,6 +5,7 @@ module ApplicationHelper include Hyrax::OverrideHelperBehavior include GroupNavigationHelper include SharedSearchHelper + include HykuKnapsack::ApplicationHelper def hint_for(term:, record_class: nil) hint = locale_for(type: 'hints', term: term, record_class: record_class) From 7740cfd6a07ee2a54de6af277b81ef56f492fb87 Mon Sep 17 00:00:00 2001 From: Kirk Wang Date: Tue, 26 Sep 2023 14:43:26 -0700 Subject: [PATCH 24/60] remove Adventist from application.rb --- config/application.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/application.rb b/config/application.rb index acf7c0523..9244f821c 100644 --- a/config/application.rb +++ b/config/application.rb @@ -66,8 +66,8 @@ class Application < Rails::Application # Adventist::TextFileTextExtractionService to the beginning of the services array we are # enabling text extraction from plain text files. Hyrax::DerivativeService.services = [ - Adventist::TextFileTextExtractionService, - IiifPrint::PluggableDerivativeService] + IiifPrint::PluggableDerivativeService + ] # When you are ready to use the derivative rodeo instead of the pluggable uncomment the # following and comment out the preceding Hyrax::DerivativeService.service From 5108af162eb56ad6947e1486b1b1e132c2896e4b Mon Sep 17 00:00:00 2001 From: Shana Moore Date: Thu, 28 Sep 2023 11:31:35 -0700 Subject: [PATCH 25/60] =?UTF-8?q?=F0=9F=8E=81=20Add=20conditional=20to=20r?= =?UTF-8?q?un=20correct=20command=20for=20worker?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a conditional to run the correct command for sidekiq or good_job, when running docker compose up. --- docker-compose.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 0d349e7e3..dafc2446b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -176,7 +176,15 @@ services: - ghcr.io/samvera/hyku/base:latest - ghcr.io/samvera/hyku:latest - ghcr.io/samvera/hyku/worker:latest - command: bundle exec sidekiq + command: + - /bin/sh + - -c + - > + if [ "$$HYRAX_ACTIVE_JOB_QUEUE" == "good_job" ]; then + exec bundle exec good_job start + else + exec bundle exec sidekiq + fi depends_on: check_volumes: condition: service_completed_successfully From b8af51e6b45486855bb6d7ba055b8c50b2b3dca2 Mon Sep 17 00:00:00 2001 From: LaRita Robinson Date: Fri, 29 Sep 2023 12:56:24 -0400 Subject: [PATCH 26/60] Make appearance constants overrideable This allows for the knapsack to override the constants by defining and using a method rather than a constant in the look-ups. --- app/forms/hyrax/forms/admin/appearance.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/forms/hyrax/forms/admin/appearance.rb b/app/forms/hyrax/forms/admin/appearance.rb index 7f20affae..ec64d6bb3 100644 --- a/app/forms/hyrax/forms/admin/appearance.rb +++ b/app/forms/hyrax/forms/admin/appearance.rb @@ -42,8 +42,6 @@ class Appearance 'facet_panel_text_color' => '#333333' }.freeze - DEFAULT_VALUES = DEFAULT_FONTS.merge(DEFAULT_COLORS).freeze - # @param [Hash] attributes the list of parameters from the form def initialize(attributes = {}) @attributes = attributes @@ -430,8 +428,12 @@ def convert_to_rgba(hex_color, alpha = 0.5) "rgba(#{rgb[0]}, #{rgb[1]}, #{rgb[2]}, #{alpha})" end + def default_values + @default_values ||= DEFAULT_FONTS.merge(DEFAULT_COLORS) + end + def block_for(name, dynamic_default = nil) - ContentBlock.block_for(name: name, fallback_value: DEFAULT_VALUES[name] || dynamic_default) + ContentBlock.block_for(name: name, fallback_value: default_values[name] || dynamic_default) end # Persist a key/value tuple as a ContentBlock From 6126bf6b5bc9eb8556775436b174e252afad5a0e Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Sat, 30 Sep 2023 23:31:01 -0400 Subject: [PATCH 27/60] add reporting fix to hyku ci --- .env | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.env b/.env index c51b5a51e..b4e6bf781 100644 --- a/.env +++ b/.env @@ -1,5 +1,6 @@ CHROME_HOSTNAME=chrome COMPOSE_DOCKER_CLI_BUILD=1 +DATABASE_CLEANER_ALLOW_REMOTE_DATABASE_URL=true DB_ADAPTER=postgresql DB_HOST=db DB_HOST=db @@ -13,19 +14,19 @@ FCREPO_BASE_PATH=/hykudemo FCREPO_HOST=fcrepo FCREPO_PORT=8080 FCREPO_REST_PATH=rest +HYRAX_ACTIVE_JOB_QUEUE=good_job +HYRAX_FITS_PATH=/app/fits/fits.sh INITIAL_ADMIN_EMAIL=admin@example.com INITIAL_ADMIN_PASSWORD=testing123 -JAVA_OPTS=-Xmx4g -Xms1g IN_DOCKER=true JAVA_OPTS= +JAVA_OPTS=-Xmx4g -Xms1g LD_LIBRARY_PATH=/opt/fits/tools/mediainfo/linux +NEGATIVE_CAPTCHA_SECRET=default-value-change-me PASSENGER_APP_ENV=development RAILS_LOG_TO_STDOUT=true REDIS_HOST=redis SECRET_KEY_BASE=asdf -HYRAX_ACTIVE_JOB_QUEUE=good_job -HYRAX_FITS_PATH=/app/fits/fits.sh -NEGATIVE_CAPTCHA_SECRET=default-value-change-me SOLR_ADMIN_PASSWORD=SolrRocks SOLR_ADMIN_USER=solr SOLR_COLLECTION_NAME=hydra-development @@ -33,6 +34,8 @@ SOLR_CONFIGSET_NAME=hyku SOLR_HOST=solr SOLR_PORT=8983 SOLR_URL=http://solr:SolrRocks@solr:8983/solr/ +TB_RSPEC_FORMATTER=progress +TB_RSPEC_OPTIONS="--format RspecJunitFormatter --out rspec.xml" # Comment out these 5 for single tenancy / Uncomment for multi HYKU_ADMIN_HOST=hyku.test From 2a80187c8e54db4c80812cb2ae56762767b3dcc0 Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Sun, 1 Oct 2023 15:44:24 -0400 Subject: [PATCH 28/60] spec loading fixes --- Gemfile.lock | 8 ++++---- spec/controllers/search_history_controller_spec.rb | 2 +- spec/tasks/rake_spec.rb | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 4436734e8..23b91297a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -786,7 +786,7 @@ GEM mini_magick (4.12.0) mini_mime (1.1.2) mini_portile2 (2.8.4) - minitest (5.18.1) + minitest (5.20.0) mods (2.4.1) edtf iso-639 @@ -933,7 +933,7 @@ GEM actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) activesupport (>= 5.0.1.rc1) - rails-dom-testing (2.1.1) + rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest nokogiri (>= 1.6) @@ -1067,7 +1067,7 @@ GEM rspec-its (1.3.0) rspec-core (>= 3.0.0) rspec-expectations (>= 3.0.0) - rspec-mocks (3.12.5) + rspec-mocks (3.12.6) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.12.0) rspec-rails (5.1.2) @@ -1080,7 +1080,7 @@ GEM rspec-support (~> 3.10) rspec-retry (0.6.2) rspec-core (> 3.3) - rspec-support (3.12.0) + rspec-support (3.12.1) rspec_junit_formatter (0.6.0) rspec-core (>= 2, < 4, != 2.12.0) rubocop (0.52.1) diff --git a/spec/controllers/search_history_controller_spec.rb b/spec/controllers/search_history_controller_spec.rb index d9a349279..379e29e59 100644 --- a/spec/controllers/search_history_controller_spec.rb +++ b/spec/controllers/search_history_controller_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -RSpec.describe SearchHistoryController do +RSpec.describe SearchHistoryController, type: :controller do routes { Blacklight::Engine.routes } describe 'index' do diff --git a/spec/tasks/rake_spec.rb b/spec/tasks/rake_spec.rb index 3543bf304..0011bf4a3 100644 --- a/spec/tasks/rake_spec.rb +++ b/spec/tasks/rake_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'rake' -load 'app/models/site.rb' +load Rails.root.join('app/models/site.rb') RSpec.describe "Rake tasks" do before(:all) do From 691dda747dae1611b8520e377caccdb4aea96bf9 Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Sun, 1 Oct 2023 15:55:20 -0400 Subject: [PATCH 29/60] rubocop --- spec/tasks/rake_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/tasks/rake_spec.rb b/spec/tasks/rake_spec.rb index 0011bf4a3..c4734c2cf 100644 --- a/spec/tasks/rake_spec.rb +++ b/spec/tasks/rake_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'rake' -load Rails.root.join('app/models/site.rb') +load Rails.root.join('app', 'models', 'site.rb') RSpec.describe "Rake tasks" do before(:all) do From deec7e2f6c5501eb99a95dddeef97617657af2df Mon Sep 17 00:00:00 2001 From: LaRita Robinson Date: Mon, 2 Oct 2023 14:31:28 -0400 Subject: [PATCH 30/60] =?UTF-8?q?=F0=9F=A7=B9Make=20appearance=20defaults?= =?UTF-8?q?=20overrideable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/forms/hyrax/forms/admin/appearance.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/forms/hyrax/forms/admin/appearance.rb b/app/forms/hyrax/forms/admin/appearance.rb index 7f20affae..ec64d6bb3 100644 --- a/app/forms/hyrax/forms/admin/appearance.rb +++ b/app/forms/hyrax/forms/admin/appearance.rb @@ -42,8 +42,6 @@ class Appearance 'facet_panel_text_color' => '#333333' }.freeze - DEFAULT_VALUES = DEFAULT_FONTS.merge(DEFAULT_COLORS).freeze - # @param [Hash] attributes the list of parameters from the form def initialize(attributes = {}) @attributes = attributes @@ -430,8 +428,12 @@ def convert_to_rgba(hex_color, alpha = 0.5) "rgba(#{rgb[0]}, #{rgb[1]}, #{rgb[2]}, #{alpha})" end + def default_values + @default_values ||= DEFAULT_FONTS.merge(DEFAULT_COLORS) + end + def block_for(name, dynamic_default = nil) - ContentBlock.block_for(name: name, fallback_value: DEFAULT_VALUES[name] || dynamic_default) + ContentBlock.block_for(name: name, fallback_value: default_values[name] || dynamic_default) end # Persist a key/value tuple as a ContentBlock From cb2e3bfc09928830ed2e3d4f2593f8fa1aba725a Mon Sep 17 00:00:00 2001 From: Shana Moore Date: Mon, 2 Oct 2023 15:01:09 -0700 Subject: [PATCH 31/60] bump bulkrax to 5.4.0 This commit pulls in a small collection of bug fixes. --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 21850c73c..976ad7d3a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -266,7 +266,7 @@ GEM signet (~> 0.8) typhoeus builder (3.2.4) - bulkrax (5.3.0) + bulkrax (5.4.0) bagit (~> 0.4) coderay dry-monads (~> 1.4.0) From c700d41d457cbe33ea58ea23f766a1fc19f510f3 Mon Sep 17 00:00:00 2001 From: LaRita Robinson Date: Mon, 2 Oct 2023 23:02:04 -0400 Subject: [PATCH 32/60] =?UTF-8?q?=F0=9F=A7=B9=20Include=20knapsack=20css?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/assets/stylesheets/application.css | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 61efe4aa9..f468cc6c3 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -21,4 +21,5 @@ *= require blacklight_advanced_search *= require blacklight_range_limit *= require_self + *= require hyku_knapsack/application */ From 35526646c157b5f2ea489f78ddb825c0e25cc245 Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Tue, 3 Oct 2023 11:26:46 -0400 Subject: [PATCH 33/60] fix job loading when selecting good job --- config/initializers/apartment.rb | 2 +- .../20230406183810_setup_good_jobs_schema.rb | 16 ++++++++++++++++ db/schema.rb | 2 ++ 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20230406183810_setup_good_jobs_schema.rb diff --git a/config/initializers/apartment.rb b/config/initializers/apartment.rb index a2647571d..53934a77b 100644 --- a/config/initializers/apartment.rb +++ b/config/initializers/apartment.rb @@ -12,7 +12,7 @@ # Add any models that you do not want to be multi-tenanted, but remain in the global (public) namespace. # A typical example would be a Customer or Tenant model that stores each Tenant's information. - config.excluded_models = %w{ Account AccountCrossSearch DomainName Endpoint User UserStat SolrEndpoint FcrepoEndpoint RedisEndpoint } + config.excluded_models = %w{ Account AccountCrossSearch DomainName Endpoint User UserStat SolrEndpoint FcrepoEndpoint RedisEndpoint GoodJob::Execution GoodJob::Job GoodJob::Process } # In order to migrate all of your Tenants you need to provide a list of Tenant names to Apartment. # You can make this dynamic by providing a Proc object to be called on migrations. diff --git a/db/migrate/20230406183810_setup_good_jobs_schema.rb b/db/migrate/20230406183810_setup_good_jobs_schema.rb new file mode 100644 index 000000000..5ffdffee0 --- /dev/null +++ b/db/migrate/20230406183810_setup_good_jobs_schema.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +# This migration pre-sets the shared_extensions schema for in prep for good_jobs +class SetupGoodJobsSchema < ActiveRecord::Migration[5.2] + def change + # Create Schema + ActiveRecord::Base.connection.execute 'CREATE SCHEMA IF NOT EXISTS shared_extensions;' + # Enable Hstore + ActiveRecord::Base.connection.execute 'CREATE EXTENSION IF NOT EXISTS HSTORE SCHEMA shared_extensions;' + # Enable UUID-OSSP + ActiveRecord::Base.connection.execute 'CREATE EXTENSION IF NOT EXISTS "uuid-ossp" SCHEMA shared_extensions;' + ActiveRecord::Base.connection.execute 'CREATE EXTENSION IF NOT EXISTS "pgcrypto" SCHEMA shared_extensions;' + # Grant usage to public + ActiveRecord::Base.connection.execute 'GRANT usage ON SCHEMA shared_extensions to public;' + end +end diff --git a/db/schema.rb b/db/schema.rb index c523cfd22..c2b964beb 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -13,8 +13,10 @@ ActiveRecord::Schema.define(version: 2023_08_04_073106) do # These are extensions that must be enabled in order to support this database + enable_extension "hstore" enable_extension "pgcrypto" enable_extension "plpgsql" + enable_extension "uuid-ossp" create_table "account_cross_searches", force: :cascade do |t| t.bigint "search_account_id" From 64d9281acf8362d4eb8e99c4ae64e5c1e9128684 Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Tue, 3 Oct 2023 11:29:05 -0400 Subject: [PATCH 34/60] adjust docker compose to use the startup script --- docker-compose.yml | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index dafc2446b..512e9bf4b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -135,7 +135,7 @@ services: web: <<: *app - # Uncomment command to access container with out starting Rails. Useful for debugging + # Uncomment command to access container with out starting bin/web. Useful for debugging # command: sleep infinity environment: - VIRTUAL_PORT=3000 @@ -167,6 +167,8 @@ services: worker: <<: *app image: ghcr.io/samvera/hyku/worker:${TAG:-latest} + # Uncomment command to access container with out starting bin/worker. Useful for debugging + # command: sleep infinity build: context: . target: hyku-worker @@ -176,15 +178,6 @@ services: - ghcr.io/samvera/hyku/base:latest - ghcr.io/samvera/hyku:latest - ghcr.io/samvera/hyku/worker:latest - command: - - /bin/sh - - -c - - > - if [ "$$HYRAX_ACTIVE_JOB_QUEUE" == "good_job" ]; then - exec bundle exec good_job start - else - exec bundle exec sidekiq - fi depends_on: check_volumes: condition: service_completed_successfully From 5feb7f429b8ba9d90d40ae40d5b0b3e4910c2b1d Mon Sep 17 00:00:00 2001 From: Shana Moore Date: Tue, 3 Oct 2023 10:54:27 -0700 Subject: [PATCH 35/60] :gift: install tesseract eng_best --- Dockerfile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Dockerfile b/Dockerfile index d13b8e942..c9d3ecdd9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -47,6 +47,11 @@ RUN wget https://github.com/ImageMagick/ImageMagick/archive/refs/tags/7.1.0-57.t && rm -rf ImageMagick* \ && rm -rf /var/cache/apk/* +# Install "best" training data for Tesseract +RUN echo "📚 Installing Tesseract Best (training data)!" && \ + cd /usr/share/tessdata/ && \ + wget https://github.com/tesseract-ocr/tessdata_best/blob/main/eng.traineddata?raw=true -O eng_best.traineddata + ARG VIPS_VERSION=8.11.3 RUN set -x -o pipefail \ From e568fbd8372f920954e261b76ac5793dfbc5e1fc Mon Sep 17 00:00:00 2001 From: Shana Moore Date: Tue, 3 Oct 2023 15:16:06 -0700 Subject: [PATCH 36/60] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20revert=20tesseract?= =?UTF-8?q?=20best=20changes=20to=20dockerfile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this change belongs in the knapsack directory instead --- Dockerfile | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index c9d3ecdd9..d13b8e942 100644 --- a/Dockerfile +++ b/Dockerfile @@ -47,11 +47,6 @@ RUN wget https://github.com/ImageMagick/ImageMagick/archive/refs/tags/7.1.0-57.t && rm -rf ImageMagick* \ && rm -rf /var/cache/apk/* -# Install "best" training data for Tesseract -RUN echo "📚 Installing Tesseract Best (training data)!" && \ - cd /usr/share/tessdata/ && \ - wget https://github.com/tesseract-ocr/tessdata_best/blob/main/eng.traineddata?raw=true -O eng_best.traineddata - ARG VIPS_VERSION=8.11.3 RUN set -x -o pipefail \ From 0f9169517d5a8651ee245d083b7a75f31383d7f0 Mon Sep 17 00:00:00 2001 From: Shana Moore Date: Tue, 3 Oct 2023 15:16:06 -0700 Subject: [PATCH 37/60] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20revert=20tesseract?= =?UTF-8?q?=20best=20changes=20to=20dockerfile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this change belongs in the knapsack directory instead --- Dockerfile | 5 ----- config/application.rb | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index c9d3ecdd9..d13b8e942 100644 --- a/Dockerfile +++ b/Dockerfile @@ -47,11 +47,6 @@ RUN wget https://github.com/ImageMagick/ImageMagick/archive/refs/tags/7.1.0-57.t && rm -rf ImageMagick* \ && rm -rf /var/cache/apk/* -# Install "best" training data for Tesseract -RUN echo "📚 Installing Tesseract Best (training data)!" && \ - cd /usr/share/tessdata/ && \ - wget https://github.com/tesseract-ocr/tessdata_best/blob/main/eng.traineddata?raw=true -O eng_best.traineddata - ARG VIPS_VERSION=8.11.3 RUN set -x -o pipefail \ diff --git a/config/application.rb b/config/application.rb index 9244f821c..2c6ceefb2 100644 --- a/config/application.rb +++ b/config/application.rb @@ -77,7 +77,7 @@ class Application < Rails::Application # IiifPrint::DerivativeRodeoService, # Hyrax::FileSetDerivativesService] - DerivativeRodeo::Generators::HocrGenerator.additional_tessearct_options = "-l eng_best" + DerivativeRodeo::Generators::HocrGenerator.additional_tessearct_options = nil # Allows us to use decorator files Dir.glob(File.join(File.dirname(__FILE__), "../app/**/*_decorator*.rb")).sort.each do |c| From 26ae01378bd9c1317869aa50964c741420076326 Mon Sep 17 00:00:00 2001 From: Kirk Wang Date: Wed, 4 Oct 2023 11:52:29 -0700 Subject: [PATCH 38/60] =?UTF-8?q?=F0=9F=90=9B=20Bring=20fix=20for=20entry?= =?UTF-8?q?=20show=20page=20not=20showing=20link?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit will bring in a fix from Bulkrax that correctly shows the object from the entry show page. ref: - https://github.com/samvera-labs/bulkrax/commit/0e68a5ea81307dc9e06f9a1e7c0c4cc8cd3de873 --- app/factories/bulkrax/object_factory_decorator.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/factories/bulkrax/object_factory_decorator.rb b/app/factories/bulkrax/object_factory_decorator.rb index 928cd8384..67f2d74a6 100644 --- a/app/factories/bulkrax/object_factory_decorator.rb +++ b/app/factories/bulkrax/object_factory_decorator.rb @@ -8,6 +8,21 @@ module ObjectFactoryDecorator def environment(attrs) Hyrax::Actors::Environment.new(object, Ability.new(@user), attrs, true) end + + # TODO: Verify and remove this once Bulkrax is updated 5.4.1 over greater and this is no longer needed + def search_by_identifier + # ref: https://github.com/samvera-labs/bulkrax/issues/866 + # ref:https://github.com/samvera-labs/bulkrax/issues/867 + # work_index = ::ActiveFedora.index_field_mapper.solr_name(work_identifier, :facetable) + work_index = work_identifier + query = { work_index => + source_identifier_value } + # Query can return partial matches (something6 matches both something6 and something68) + # so we need to weed out any that are not the correct full match. But other items might be + # in the multivalued field, so we have to go through them one at a time. + match = klass.where(query).detect { |m| m.send(work_identifier).include?(source_identifier_value) } + return match if match + end end end From 07fde572f9152d513b13f71cae90dd4fdfbfba6c Mon Sep 17 00:00:00 2001 From: Kirk Wang Date: Wed, 4 Oct 2023 12:19:18 -0700 Subject: [PATCH 39/60] =?UTF-8?q?=F0=9F=A7=B9=20Revert=20previous=20commit?= =?UTF-8?q?=20and=20update=20Bulkrax?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit will update Bulkrax to 5.4.1 instead of using the override from the last commit. We also revert the changes from the last commit. --- Gemfile | 2 +- Gemfile.lock | 4 ++-- app/factories/bulkrax/object_factory_decorator.rb | 15 --------------- 3 files changed, 3 insertions(+), 18 deletions(-) diff --git a/Gemfile b/Gemfile index 683b0b823..c4a98f9c0 100644 --- a/Gemfile +++ b/Gemfile @@ -18,7 +18,7 @@ gem 'blacklight_oai_provider', '~> 6.1', '>= 6.1.1' gem 'blacklight_range_limit', '6.5.0' gem 'bolognese', '>= 1.9.10' gem 'bootstrap-datepicker-rails' -gem 'bulkrax', '~> 5.3' +gem 'bulkrax', '~> 5.4' gem 'byebug', group: %i[development test] gem 'capybara', group: %i[test] gem 'capybara-screenshot', '~> 1.0', group: %i[test] diff --git a/Gemfile.lock b/Gemfile.lock index 976ad7d3a..1b3206776 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -266,7 +266,7 @@ GEM signet (~> 0.8) typhoeus builder (3.2.4) - bulkrax (5.4.0) + bulkrax (5.4.1) bagit (~> 0.4) coderay dry-monads (~> 1.4.0) @@ -1328,7 +1328,7 @@ DEPENDENCIES blacklight_range_limit (= 6.5.0) bolognese (>= 1.9.10) bootstrap-datepicker-rails - bulkrax (~> 5.3) + bulkrax (~> 5.4) byebug capybara capybara-screenshot (~> 1.0) diff --git a/app/factories/bulkrax/object_factory_decorator.rb b/app/factories/bulkrax/object_factory_decorator.rb index 67f2d74a6..928cd8384 100644 --- a/app/factories/bulkrax/object_factory_decorator.rb +++ b/app/factories/bulkrax/object_factory_decorator.rb @@ -8,21 +8,6 @@ module ObjectFactoryDecorator def environment(attrs) Hyrax::Actors::Environment.new(object, Ability.new(@user), attrs, true) end - - # TODO: Verify and remove this once Bulkrax is updated 5.4.1 over greater and this is no longer needed - def search_by_identifier - # ref: https://github.com/samvera-labs/bulkrax/issues/866 - # ref:https://github.com/samvera-labs/bulkrax/issues/867 - # work_index = ::ActiveFedora.index_field_mapper.solr_name(work_identifier, :facetable) - work_index = work_identifier - query = { work_index => - source_identifier_value } - # Query can return partial matches (something6 matches both something6 and something68) - # so we need to weed out any that are not the correct full match. But other items might be - # in the multivalued field, so we have to go through them one at a time. - match = klass.where(query).detect { |m| m.send(work_identifier).include?(source_identifier_value) } - return match if match - end end end From 8ae51d8d1ae8fb74768c4631ba382c42bbb7ec2d Mon Sep 17 00:00:00 2001 From: Shana Moore Date: Wed, 4 Oct 2023 13:45:47 -0700 Subject: [PATCH 40/60] :bug: subject can't be blank for the contact form Previously there was a bug because even if you typed in a subject, the contact form would error saying that it was blank. Part of issue: - https://github.com/scientist-softserv/adventist-dl/issues/608 --- app/controllers/hyrax/contact_form_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/hyrax/contact_form_controller.rb b/app/controllers/hyrax/contact_form_controller.rb index 17f6cb614..705d7e0b1 100644 --- a/app/controllers/hyrax/contact_form_controller.rb +++ b/app/controllers/hyrax/contact_form_controller.rb @@ -50,6 +50,7 @@ def create # not spam, form is valid, and captcha is valid @captcha.values[:category] = params[:contact_form][:category] @captcha.values[:contact_method] = params[:contact_form][:contact_method] + @captcha.values[:subjects] = params[:contact_form][:subject] @contact_form = model_class.new(@captcha.values) if @contact_form.valid? && @captcha.valid? ContactMailer.contact(@contact_form).deliver_now From fd32f03e0571fc21517743534b264a45e67baa7b Mon Sep 17 00:00:00 2001 From: Shana Moore Date: Wed, 4 Oct 2023 13:48:47 -0700 Subject: [PATCH 41/60] mend --- app/controllers/hyrax/contact_form_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/hyrax/contact_form_controller.rb b/app/controllers/hyrax/contact_form_controller.rb index 705d7e0b1..a420f82d4 100644 --- a/app/controllers/hyrax/contact_form_controller.rb +++ b/app/controllers/hyrax/contact_form_controller.rb @@ -50,7 +50,7 @@ def create # not spam, form is valid, and captcha is valid @captcha.values[:category] = params[:contact_form][:category] @captcha.values[:contact_method] = params[:contact_form][:contact_method] - @captcha.values[:subjects] = params[:contact_form][:subject] + @captcha.values[:subject] = params[:contact_form][:subject] @contact_form = model_class.new(@captcha.values) if @contact_form.valid? && @captcha.valid? ContactMailer.contact(@contact_form).deliver_now From 5e0cc2c05d33b25c8105bee8f182a0ae60575100 Mon Sep 17 00:00:00 2001 From: Jeremy Friesen Date: Wed, 4 Oct 2023 17:15:13 -0400 Subject: [PATCH 42/60] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Add=20handling=20for?= =?UTF-8?q?=20Knapsack=20theme=20overrides?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prior to this commit, we were looking for themes yaml files relative to the directory of the spawning script. For Hyku that was always the `Rails.root` directory. However, when running specs in Knapsack, that directory was `Knapsack::Engine.root`. This unearthed a potential configuration issue; namely that we want Knapsack's to control what themes are available, meaning we don't want to require amending Hyku's themes. So, we introduce a mechanism for looking up files first in the Knapsack then in Hyku. I discovered this bug in the specs for knapsack (below is the *Error stack trace*)
    Error stack trace ``` 2) Hyrax::Admin::AppearancesController with an administrator GET #show assigns the requested site as @site Failure/Error: get :show, params: {} Errno::ENOENT: No such file or directory @ rb_sysopen - config/home_themes.yml # /usr/local/bundle/gems/psych-3.3.4/lib/psych.rb:582:in `initialize' # /usr/local/bundle/gems/psych-3.3.4/lib/psych.rb:582:in `open' # /usr/local/bundle/gems/psych-3.3.4/lib/psych.rb:582:in `unsafe_load_file' # ./hyrax-webapp/app/controllers/hyrax/admin/appearances_controller.rb:19:in `show' # /usr/local/bundle/gems/rails-controller-testing-1.0.5/lib/rails/controller/testing/template_assertions.rb:62:in `process' # /usr/local/bundle/gems/devise-4.9.2/lib/devise/test/controller_helpers.rb:35:in `block in process' # /usr/local/bundle/gems/devise-4.9.2/lib/devise/test/controller_helpers.rb:104:in `catch' # /usr/local/bundle/gems/devise-4.9.2/lib/devise/test/controller_helpers.rb:104:in `_catch_warden' # /usr/local/bundle/gems/devise-4.9.2/lib/devise/test/controller_helpers.rb:35:in `process' # /usr/local/bundle/gems/rails-controller-testing-1.0.5/lib/rails/controller/testing/integration.rb:16:in `block (2 levels) in ' # ./spec/controllers/hyrax/hyrax/admin/appearances_controller_spec.rb:31:in `block (4 levels) in ' # /usr/local/bundle/gems/webmock-3.19.1/lib/webmock/rspec.rb:39:in `block (2 levels) in ' # ./hyrax-webapp/spec/support/multitenancy_metadata.rb:50:in `block (2 levels) in ' # /usr/local/bundle/gems/rspec-retry-0.6.2/lib/rspec/retry.rb:124:in `block in run' # /usr/local/bundle/gems/rspec-retry-0.6.2/lib/rspec/retry.rb:110:in `loop' # /usr/local/bundle/gems/rspec-retry-0.6.2/lib/rspec/retry.rb:110:in `run' # /usr/local/bundle/gems/rspec-retry-0.6.2/lib/rspec_ext/rspec_ext.rb:12:in `run_with_retry' # /usr/local/bundle/gems/rspec-retry-0.6.2/lib/rspec/retry.rb:37:in `block (2 levels) in setup' # ./spec/spec_helper.rb:10:in `block (2 levels) in ' ```
    Related to: - https://github.com/samvera/hyku/pull/2007 - https://github.com/samvera/hyku/pull/2008 The above two commits will require some reconciliation once this is incorporated. --- .../hyrax/admin/appearances_controller.rb | 4 ++-- config/application.rb | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/app/controllers/hyrax/admin/appearances_controller.rb b/app/controllers/hyrax/admin/appearances_controller.rb index b37308ebc..9130b8b11 100644 --- a/app/controllers/hyrax/admin/appearances_controller.rb +++ b/app/controllers/hyrax/admin/appearances_controller.rb @@ -16,8 +16,8 @@ def show add_breadcrumbs @form = form_class.new @fonts = [@form.headline_font, @form.body_font] - @home_theme_information = YAML.load_file('config/home_themes.yml') - @show_theme_information = YAML.load_file('config/show_themes.yml') + @home_theme_information = YAML.load_file(Hyku::Application.path_for('config/home_themes.yml')) + @show_theme_information = YAML.load_file(Hyku::Application.path_for('config/show_themes.yml')) @home_theme_names = load_home_theme_names @show_theme_names = load_show_theme_names @search_themes = load_search_themes diff --git a/config/application.rb b/config/application.rb index c221d0090..6aad688cf 100644 --- a/config/application.rb +++ b/config/application.rb @@ -37,6 +37,22 @@ class Application < Rails::Application # Add this line to load the lib folder first because we need config.autoload_paths.unshift("#{Rails.root}/lib") + ## + # @api public + # + # @param relative_path [String] lookup the relative paths first in the Knapsack then in Hyku. + # + # @return [String] the path to the file, favoring those found in the knapsack but falling back + # to those in the Rails.root. + def self.path_for(relative_path) + if defined?(HykuKnapsack) + engine_path = HykuKnapsack::Engine.root.join(relative_path) + return engine_path.to_s if engine_path.exist? + end + + Rails.root.join(relative_path).to_s + end + # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. From ff3fbcc5b0059577fdd24d841b8f5f01e66f070b Mon Sep 17 00:00:00 2001 From: Jeremy Friesen Date: Thu, 5 Oct 2023 08:47:22 -0400 Subject: [PATCH 43/60] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Favor=20Hyku::Applic?= =?UTF-8?q?ation.path=5Ffor=20over=20Rails.root?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Given the existence of Knapsack we need to consider how overrides in Knapsack will take precedence over Hyku files. This change handles cases where we want to use the Knapsack's uploaded thumbnails. Related to: - #2010 --- app/services/uploaded_collection_thumbnail_path_service.rb | 4 ++-- .../hyrax/dashboard/collections/_current_thumbnail.html.erb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/services/uploaded_collection_thumbnail_path_service.rb b/app/services/uploaded_collection_thumbnail_path_service.rb index 18a3f662e..c22ac5801 100644 --- a/app/services/uploaded_collection_thumbnail_path_service.rb +++ b/app/services/uploaded_collection_thumbnail_path_service.rb @@ -9,11 +9,11 @@ def call(object) # rubocop:disable Metrics/LineLength, Rails/FilePath, Lint/StringConversionInInterpolation def uploaded_thumbnail?(collection) - File.exist?("#{Rails.root.to_s}/public/uploads/uploaded_collection_thumbnails/#{collection.id}/#{collection.id}_card.jpg") + File.exist?(File.join(upload_dir(collection), "#{collection.id}_card.jpg")) end def upload_dir(collection) - "#{Rails.root.to_s}/public/uploads/uploaded_collection_thumbnails/#{collection.id}" + Hyku::Application.path_for("public/uploads/uploaded_collection_thumbnails/#{collection.id}") end # rubocop:enable Metrics/LineLength, Rails/FilePath, Lint/StringConversionInInterpolation end diff --git a/app/views/hyrax/dashboard/collections/_current_thumbnail.html.erb b/app/views/hyrax/dashboard/collections/_current_thumbnail.html.erb index 33306d375..fb64f8cc4 100644 --- a/app/views/hyrax/dashboard/collections/_current_thumbnail.html.erb +++ b/app/views/hyrax/dashboard/collections/_current_thumbnail.html.erb @@ -1,5 +1,5 @@ <% thumbnail_path = SolrDocument.find(@collection.id).thumbnail_path %> - <% if thumbnail_path.include?("uploaded_collection_thumbnails") and File.exist? Rails.root.join("public#{::SolrDocument.find(@collection.id).thumbnail_path}") %> + <% if thumbnail_path.include?("uploaded_collection_thumbnails") and File.exist? Hyky::Application.path_for("public#{::SolrDocument.find(@collection.id).thumbnail_path}") %> <%= image_tag(thumbnail_path, class: "current-thumbnail") %>

    Current image: <%= @thumbnail_filename %>

    <% else %> From 80e02d360760f87f2414245490b1c3f25f6923f2 Mon Sep 17 00:00:00 2001 From: Kirk Wang Date: Fri, 6 Oct 2023 08:48:40 -0700 Subject: [PATCH 44/60] =?UTF-8?q?=F0=9F=8E=81=20Add=20highlight=20key=20to?= =?UTF-8?q?=20UV?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit allows for the `parent_query` to be highlighted in the UV so users won't have to do a catalog search and also a UV search. --- config/uv/uv.html | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/config/uv/uv.html b/config/uv/uv.html index c8e8eced5..c44dbb45d 100644 --- a/config/uv/uv.html +++ b/config/uv/uv.html @@ -19,20 +19,20 @@ } - + - +
    - + From ae093f1c04e036057c17ec14e8a8ebeeac32a6bb Mon Sep 17 00:00:00 2001 From: Kirk Wang Date: Fri, 6 Oct 2023 22:12:27 -0700 Subject: [PATCH 45/60] =?UTF-8?q?=F0=9F=90=9B=20Mixin=20`HykuKnapsack::App?= =?UTF-8?q?licationHelper`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit will mixin the `HykuKnapsack::ApplicationHelper` into the ApplicationHelper which will allow us to use #render_ocr_snippets for snippet highlighting. --- app/controllers/application_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 9449da3c0..6bb33d215 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2,6 +2,7 @@ class ApplicationController < ActionController::Base include HykuHelper + include HykuKnapsack::ApplicationHelper # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception, prepend: true From 9827c14489eedde7b5fffe6642bb038fb3aa4fd8 Mon Sep 17 00:00:00 2001 From: Kirk Wang Date: Fri, 6 Oct 2023 22:25:02 -0700 Subject: [PATCH 46/60] =?UTF-8?q?Revert=20"=F0=9F=90=9B=20Mixin=20`HykuKna?= =?UTF-8?q?psack::ApplicationHelper`"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit ae093f1c04e036057c17ec14e8a8ebeeac32a6bb. --- app/controllers/application_controller.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 6bb33d215..9449da3c0 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2,7 +2,6 @@ class ApplicationController < ActionController::Base include HykuHelper - include HykuKnapsack::ApplicationHelper # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception, prepend: true From 6ccd6181287d31b6f52e46f8c3107d36ad9f811a Mon Sep 17 00:00:00 2001 From: Jeremy Friesen Date: Tue, 10 Oct 2023 09:08:32 -0400 Subject: [PATCH 47/60] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Favor=20class=5Fattr?= =?UTF-8?q?ibute=20over=20constant?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In Adventist, we're needing to override the constant's values. By making this a class_attribute we can more readily do the override via configuration instead of obliteration of a constant. --- app/forms/hyrax/forms/admin/appearance.rb | 18 ++++++++++++---- ...oaded_collection_thumbnail_path_service.rb | 4 ++-- .../appearances/_default_colors_form.html.erb | 4 ++-- .../appearances/_default_fonts_form.html.erb | 4 ++-- .../hyrax/forms/admin/appearance_spec.rb | 21 +++++++++++++++++++ 5 files changed, 41 insertions(+), 10 deletions(-) create mode 100644 spec/forms/hyrax/forms/admin/appearance_spec.rb diff --git a/app/forms/hyrax/forms/admin/appearance.rb b/app/forms/hyrax/forms/admin/appearance.rb index ec64d6bb3..a58cb732d 100644 --- a/app/forms/hyrax/forms/admin/appearance.rb +++ b/app/forms/hyrax/forms/admin/appearance.rb @@ -17,12 +17,21 @@ class Appearance delegate :default_collection_image, :default_collection_image?, to: :site delegate :default_work_image, :default_work_image?, to: :site - DEFAULT_FONTS = { + ## + # @!group Class Attributes + # + # @!attribute default_fonts + # @return [Hash] there should be at least the key "body_font" and + # "headline_font" + class_attribute :default_fonts, default: { 'body_font' => 'Helvetica Neue, Helvetica, Arial, sans-serif;', 'headline_font' => 'Helvetica Neue, Helvetica, Arial, sans-serif;' - }.freeze + } - DEFAULT_COLORS = { + ## + # @!attribute default_colors + # @return [Hash] + class_attribute :default_colors, default: { 'header_and_footer_background_color' => '#3c3c3c', 'header_and_footer_text_color' => '#dcdcdc', 'navbar_background_color' => '#000000', @@ -40,7 +49,8 @@ class Appearance # 'active_tabs_background_color' => '#337ab7', 'facet_panel_background_color' => '#f5f5f5', 'facet_panel_text_color' => '#333333' - }.freeze + } + # @!endgroup Class Attributes # @param [Hash] attributes the list of parameters from the form def initialize(attributes = {}) diff --git a/app/services/uploaded_collection_thumbnail_path_service.rb b/app/services/uploaded_collection_thumbnail_path_service.rb index c22ac5801..1abfb8013 100644 --- a/app/services/uploaded_collection_thumbnail_path_service.rb +++ b/app/services/uploaded_collection_thumbnail_path_service.rb @@ -7,7 +7,7 @@ def call(object) "/uploads/uploaded_collection_thumbnails/#{object.id}/#{object.id}_card.jpg" end - # rubocop:disable Metrics/LineLength, Rails/FilePath, Lint/StringConversionInInterpolation + # rubocop:disable Metrics/LineLength, Rails/FilePath def uploaded_thumbnail?(collection) File.exist?(File.join(upload_dir(collection), "#{collection.id}_card.jpg")) end @@ -15,6 +15,6 @@ def uploaded_thumbnail?(collection) def upload_dir(collection) Hyku::Application.path_for("public/uploads/uploaded_collection_thumbnails/#{collection.id}") end - # rubocop:enable Metrics/LineLength, Rails/FilePath, Lint/StringConversionInInterpolation + # rubocop:enable Metrics/LineLength, Rails/FilePath end end diff --git a/app/views/hyrax/admin/appearances/_default_colors_form.html.erb b/app/views/hyrax/admin/appearances/_default_colors_form.html.erb index 9a8251957..69c66108f 100644 --- a/app/views/hyrax/admin/appearances/_default_colors_form.html.erb +++ b/app/views/hyrax/admin/appearances/_default_colors_form.html.erb @@ -1,6 +1,6 @@ <%= simple_form_for @form, url: admin_appearance_path do |f| %>
    - <% @form.class::DEFAULT_COLORS.each do |color_name, hex| %> + <% @form.default_colors.each do |color_name, hex| %> <%= render 'color_input', f: f, color_name: color_name, hex: hex %> <% end %>
    @@ -8,4 +8,4 @@ <%= link_to 'Restore All Defaults', '#color', class: 'btn btn-default restore-all-default-colors' %> <%= f.submit class: 'btn btn-primary pull-right' %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/hyrax/admin/appearances/_default_fonts_form.html.erb b/app/views/hyrax/admin/appearances/_default_fonts_form.html.erb index 3df04aba3..04e6192b2 100644 --- a/app/views/hyrax/admin/appearances/_default_fonts_form.html.erb +++ b/app/views/hyrax/admin/appearances/_default_fonts_form.html.erb @@ -1,6 +1,6 @@ <%= simple_form_for @form, url: admin_appearance_path do |f| %>
    - <% df = @form.class::DEFAULT_FONTS %> + <% df = @form.default_fonts %> <% font = f.object.body_font %> <%= f.input :body_font, label: 'Select Body Font', required: false, input_html: { class: 'font-fields', data: { default_value: df['body_font'] } } %> @@ -14,4 +14,4 @@ <%= link_to 'Restore All Defaults', '#font', class: 'btn btn-default restore-all-default-fonts' %> <%= f.submit class: 'btn btn-primary pull-right' %>
    -<% end %> \ No newline at end of file +<% end %> diff --git a/spec/forms/hyrax/forms/admin/appearance_spec.rb b/spec/forms/hyrax/forms/admin/appearance_spec.rb new file mode 100644 index 000000000..466c50e3b --- /dev/null +++ b/spec/forms/hyrax/forms/admin/appearance_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Hyrax::Forms::Admin::Appearance do + describe '.default_fonts' do + subject { described_class.default_fonts } + + it { is_expected.to be_a(Hash) } + + it "has the 'body_font' and 'headline_font' keys" do + expect(subject.keys).to match_array(['body_font', 'headline_font']) + end + end + + describe '.default_colors' do + subject { described_class.default_colors } + + it { is_expected.to be_a(Hash) } + end +end From 2ff5f6c6e2a5695ffa89277049bf1ce8ac08c928 Mon Sep 17 00:00:00 2001 From: Jeremy Friesen Date: Tue, 10 Oct 2023 09:12:59 -0400 Subject: [PATCH 48/60] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Favor=20configurable?= =?UTF-8?q?=20html=20head=20title=20value?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prior to this commit, we hard-coded the page title; this is something that should be far more configurable. And this refactor is a step towards that. This also allows for downstream implementors to not have to override the view simply to change the title element. --- app/views/layouts/application.html.erb | 2 +- config/application.rb | 9 +++++++++ spec/config/application_spec.rb | 9 +++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 spec/config/application_spec.rb diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 7b0575693..f0a8e0a85 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -1,7 +1,7 @@ - Hyku + <%= Hyku::Application.html_head_title %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> <%= csrf_meta_tags %> diff --git a/config/application.rb b/config/application.rb index 1eed55d69..40f2c32f2 100644 --- a/config/application.rb +++ b/config/application.rb @@ -34,6 +34,15 @@ def self.utf_8_encode(string) end class Application < Rails::Application + ## + # @!group Class Attributes + # + # @!attribute html_head_title + # The title to render for the application's HTML > HEAD > TITLE element. + # @return [String] + class_attribute :html_head_title, default: "Hyku", attr_accessor: false + # @!endgroup Class Attributes + # Add this line to load the lib folder first because we need # IiifPrint::SplitPdfs::AdventistPagesToJpgsSplitter config.autoload_paths.unshift("#{Rails.root}/lib") diff --git a/spec/config/application_spec.rb b/spec/config/application_spec.rb new file mode 100644 index 000000000..35ce1619b --- /dev/null +++ b/spec/config/application_spec.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Hyku::Application do + describe '.html_head_title' do + it { is_expected.to be_a(String) } + end +end From 1c2a9d4912f76e80ebf221208d666669b1fdf79a Mon Sep 17 00:00:00 2001 From: Jeremy Friesen Date: Tue, 10 Oct 2023 10:11:10 -0400 Subject: [PATCH 49/60] =?UTF-8?q?=F0=9F=90=9B=20Add=20custom=20rendering?= =?UTF-8?q?=20for=20license?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prior to this commit, the License would render as a plain URL. With this change, we are now coercing the license into a URL that is labeled and titled with the name of the license. This is copied and modified based on [Rights show partial][1] Related to: - https://github.com/scientist-softserv/adventist-dl/issues/620 [1]: https://github.com/samvera/hyrax/blob/b334e186e77691d7da8ed59ff27f091be1c2a700/app/views/records/show_fields/_rights.html.erb --- .rubocop.yml | 4 ++++ app/services/uploaded_collection_thumbnail_path_service.rb | 2 -- app/views/records/show_fields/_license.html.erb | 4 ++++ 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 app/views/records/show_fields/_license.html.erb diff --git a/.rubocop.yml b/.rubocop.yml index 90961c959..4a5fb78c8 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -127,3 +127,7 @@ Metrics/BlockLength: - 'spec/**/*.rb' - 'lib/tasks/*.rake' - 'app/controllers/catalog_controller.rb' + +RSpec/FilePath: + Exclude: + - 'spec/config/application_spec.rb' diff --git a/app/services/uploaded_collection_thumbnail_path_service.rb b/app/services/uploaded_collection_thumbnail_path_service.rb index 1abfb8013..3685f9bb9 100644 --- a/app/services/uploaded_collection_thumbnail_path_service.rb +++ b/app/services/uploaded_collection_thumbnail_path_service.rb @@ -7,7 +7,6 @@ def call(object) "/uploads/uploaded_collection_thumbnails/#{object.id}/#{object.id}_card.jpg" end - # rubocop:disable Metrics/LineLength, Rails/FilePath def uploaded_thumbnail?(collection) File.exist?(File.join(upload_dir(collection), "#{collection.id}_card.jpg")) end @@ -15,6 +14,5 @@ def uploaded_thumbnail?(collection) def upload_dir(collection) Hyku::Application.path_for("public/uploads/uploaded_collection_thumbnails/#{collection.id}") end - # rubocop:enable Metrics/LineLength, Rails/FilePath end end diff --git a/app/views/records/show_fields/_license.html.erb b/app/views/records/show_fields/_license.html.erb new file mode 100644 index 000000000..15cef91e0 --- /dev/null +++ b/app/views/records/show_fields/_license.html.erb @@ -0,0 +1,4 @@ +<% service = Hyrax::LicenseService.new %> +<% record.license.each do |r| %> + <%= link_to_field('license', r, service.label(r)) %> <%= iconify_auto_link(r, false) %>
    +<% end %> From 363bc070b2e0c8d782cf4037203cb0f1bf75297d Mon Sep 17 00:00:00 2001 From: Jeremy Friesen Date: Tue, 10 Oct 2023 15:31:16 -0400 Subject: [PATCH 50/60] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Add=20option=20to=20?= =?UTF-8?q?override=20devise=20configuration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For Adventist, we wanted to disable registration of accounts as this was creating a case where folks were creating their own accounts and tenants. Related to: - https://github.com/scientist-softserv/adventist-dl/issues/492 - https://github.com/scientist-softserv/adventist-dl/issues/618 - https://github.com/samvera/hyku/pull/1964 - https://github.com/scientist-softserv/adventist-dl/pull/493 --- app/models/user.rb | 4 +--- config/application.rb | 15 +++++++++++++++ spec/config/application_spec.rb | 18 ++++++++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index 7bfdd16cf..cfdea7500 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -14,9 +14,7 @@ class User < ApplicationRecord include Blacklight::User # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable - devise :database_authenticatable, :invitable, :registerable, - :recoverable, :rememberable, :trackable, :validatable, - :omniauthable, omniauth_providers: %i[saml openid_connect cas] + devise(*Hyku::Application.user_devise_parameters) after_create :add_default_group_membership! diff --git a/config/application.rb b/config/application.rb index 40f2c32f2..3af68f13f 100644 --- a/config/application.rb +++ b/config/application.rb @@ -41,6 +41,21 @@ class Application < Rails::Application # The title to render for the application's HTML > HEAD > TITLE element. # @return [String] class_attribute :html_head_title, default: "Hyku", attr_accessor: false + + # @!attribute user_devise_parameters + # @return [Object] + # + # This is a value that you want to set in the before_initialize block. + class_attribute :user_devise_parameters, instance_accessor: false, default: [ + :database_authenticatable, + :invitable, + :registerable, + :recoverable, + :rememberable, + :trackable, + :validatable, + :omniauthable, { omniauth_providers: %i[saml openid_connect cas] }] + # @!endgroup Class Attributes # Add this line to load the lib folder first because we need diff --git a/spec/config/application_spec.rb b/spec/config/application_spec.rb index 35ce1619b..a3ab79038 100644 --- a/spec/config/application_spec.rb +++ b/spec/config/application_spec.rb @@ -4,6 +4,24 @@ RSpec.describe Hyku::Application do describe '.html_head_title' do + subject { described_class.html_head_title } + it { is_expected.to be_a(String) } end + + describe '.user_devise_parameters' do + subject { described_class.user_devise_parameters } + + it do + is_expected.to eq([:database_authenticatable, + :invitable, + :registerable, + :recoverable, + :rememberable, + :trackable, + :validatable, + :omniauthable, + { omniauth_providers: %i[saml openid_connect cas] }]) + end + end end From 961b712aeafa419c167d51996057ac636f0716b7 Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Thu, 12 Oct 2023 13:39:49 -0700 Subject: [PATCH 51/60] run asset build later in process to allow knapsack to run it only one time --- Dockerfile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index d13b8e942..8916c378e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -91,10 +91,9 @@ ONBUILD RUN git config --global --add safe.directory /app/samvera && \ ONBUILD COPY --chown=1001:101 $APP_PATH /app/samvera/hyrax-webapp -ONBUILD RUN RAILS_ENV=production SECRET_KEY_BASE=`bin/rake secret` DB_ADAPTER=nulldb DB_URL='postgresql://fake' bundle exec rake assets:precompile && yarn install - - FROM hyku-base as hyku-web +RUN RAILS_ENV=production SECRET_KEY_BASE=`bin/rake secret` DB_ADAPTER=nulldb DB_URL='postgresql://fake' bundle exec rake assets:precompile && yarn install + CMD ./bin/web FROM hyku-web as hyku-worker From 6930f7fdc71d693fb049a580eb9b7fc8cbafbba4 Mon Sep 17 00:00:00 2001 From: Jeremy Friesen Date: Fri, 13 Oct 2023 12:34:12 -0400 Subject: [PATCH 52/60] =?UTF-8?q?=F0=9F=90=9B=20Fix=20Add=20to=20Collectio?= =?UTF-8?q?n=20for=20page=202+=20of=20works?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prior to this commit, when you were on page 2 of your works and selected a work to add to a collection, the query for available collections would use the page 2 as part of the collection query. This would mean the first 100 collections (default page size) that you had access to add works to were skipped. With this commit, we omit the query parameters from the works page and then query collections. Related to: - https://github.com/samvera/hyrax/pull/5972 - https://github.com/samvera/hyrax/issues/5969 - https://github.com/scientist-softserv/adventist-dl/issues/625 Co-authored-by: LaRita Robinson --- .../hyrax/my/works_controller_decorator.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 app/controllers/hyrax/my/works_controller_decorator.rb diff --git a/app/controllers/hyrax/my/works_controller_decorator.rb b/app/controllers/hyrax/my/works_controller_decorator.rb new file mode 100644 index 000000000..2817729e9 --- /dev/null +++ b/app/controllers/hyrax/my/works_controller_decorator.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +## +# OVERRIDE Hyrax 3.5.0; when Hyrax hits v4.0.0 we can remove this. +# @see https://github.com/samvera/hyrax/pull/5972 +module Hyrax + module My + module WorksControllerDecorator + def collection_service + cloned = clone + cloned.params = {} + Hyrax::CollectionsService.new(cloned) + end + end + end +end + +Hyrax::My::WorksController.prepend(Hyrax::My::WorksControllerDecorator) From ad8444e99446afe93c188052fd0f41ff13fa3c87 Mon Sep 17 00:00:00 2001 From: Benjamin Kiah Stroud <32469930+bkiahstroud@users.noreply.github.com> Date: Fri, 13 Oct 2023 10:26:12 -0700 Subject: [PATCH 53/60] test that invited users are added to the registered group --- .../hyku/invitations_controller_spec.rb | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/spec/controllers/hyku/invitations_controller_spec.rb b/spec/controllers/hyku/invitations_controller_spec.rb index 4ed0cf5c0..bf87c4ff4 100644 --- a/spec/controllers/hyku/invitations_controller_spec.rb +++ b/spec/controllers/hyku/invitations_controller_spec.rb @@ -31,5 +31,31 @@ expect(response).to redirect_to Hyrax::Engine.routes.url_helpers.admin_users_path(locale: 'en') expect(flash[:notice]).to eq 'An invitation email has been sent to user@guest.org.' end + + context 'when user already exists' do + let(:user) { create(:user) } + + # Mimic the state of a user who is only active in other tenants; + # i.e. a user who has no roles in this tenant + before do + user.roles.destroy_all + end + + it 'adds the user to the registered group' do + expect(user.roles).to be_empty + expect(user.groups).to be_empty + + post :create, params: { + user: { + email: user.email, + role: '' + } + } + + user.reload + expect(user.roles).not_to be_empty + expect(user.groups).to eq([Ability.registered_group_name]) + end + end end end From db098e1d313624d824d1de287ffe543842f6885b Mon Sep 17 00:00:00 2001 From: Benjamin Kiah Stroud <32469930+bkiahstroud@users.noreply.github.com> Date: Thu, 12 Oct 2023 18:21:19 -0700 Subject: [PATCH 54/60] Add invited users to the registered group Fixes a bug where users who were invited with no roles would not show up in the users list at all --- app/controllers/hyku/invitations_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/hyku/invitations_controller.rb b/app/controllers/hyku/invitations_controller.rb index dbe246cda..2aa11fcac 100644 --- a/app/controllers/hyku/invitations_controller.rb +++ b/app/controllers/hyku/invitations_controller.rb @@ -14,6 +14,7 @@ def create authorize! :grant_admin_role, User if params[:user][:role] == ::RolesService::ADMIN_ROLE self.resource = User.find_by(email: params[:user][:email]) || invite_resource + resource.add_default_group_membership! resource.add_role(params[:user][:role], Site.instance) if params[:user][:role].present? yield resource if block_given? From 3919082b95d1cba35c1fbdc8f8d63422e9a74962 Mon Sep 17 00:00:00 2001 From: LaRita Robinson Date: Wed, 18 Oct 2023 12:49:43 -0400 Subject: [PATCH 55/60] =?UTF-8?q?=F0=9F=90=9B=20Change=20Hyky=20to=20Hyku?= =?UTF-8?q?=20(#2029)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Typo caused inability to upload collection thumbnail. --- .../hyrax/dashboard/collections/_current_thumbnail.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/hyrax/dashboard/collections/_current_thumbnail.html.erb b/app/views/hyrax/dashboard/collections/_current_thumbnail.html.erb index fb64f8cc4..7c78b27a4 100644 --- a/app/views/hyrax/dashboard/collections/_current_thumbnail.html.erb +++ b/app/views/hyrax/dashboard/collections/_current_thumbnail.html.erb @@ -1,5 +1,5 @@ <% thumbnail_path = SolrDocument.find(@collection.id).thumbnail_path %> - <% if thumbnail_path.include?("uploaded_collection_thumbnails") and File.exist? Hyky::Application.path_for("public#{::SolrDocument.find(@collection.id).thumbnail_path}") %> + <% if thumbnail_path.include?("uploaded_collection_thumbnails") and File.exist? Hyku::Application.path_for("public#{::SolrDocument.find(@collection.id).thumbnail_path}") %> <%= image_tag(thumbnail_path, class: "current-thumbnail") %>

    Current image: <%= @thumbnail_filename %>

    <% else %> From b0f2c442c18809c31f4cfe02e995558655dfa2b4 Mon Sep 17 00:00:00 2001 From: Kirk Wang Date: Wed, 1 Nov 2023 12:23:11 -0700 Subject: [PATCH 56/60] =?UTF-8?q?=F0=9F=8E=81=20Modify=20labels=20in=20UV?= =?UTF-8?q?=20for=20V3=20manifests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit will add the same treatment as we have for V2 manifests to V3 manifests. This will allow the UV to add a more human readable label to the pages. Ref: - https://github.com/scientist-softserv/adventist-dl/issues/628 --- .../canvas_builder_decorator.rb | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 lib/iiif_manifest/v3/manifest_builder/canvas_builder_decorator.rb diff --git a/lib/iiif_manifest/v3/manifest_builder/canvas_builder_decorator.rb b/lib/iiif_manifest/v3/manifest_builder/canvas_builder_decorator.rb new file mode 100644 index 000000000..990bd1409 --- /dev/null +++ b/lib/iiif_manifest/v3/manifest_builder/canvas_builder_decorator.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +# OVERRIDE IIIFManifest v1.3.1 to use the parent's title as the label instead of the filename + +module IIIFManifest + module V3 + module ManifestBuilderDecorator + module CanvasBuilderDecorator + def apply_record_properties + super + canvas.label = if record.to_s.present? + ManifestBuilder.language_map(record['parent_title_tesim']&.first || record.to_s) + end + end + end + end + end +end + +IIIFManifest::V3::ManifestBuilder.prepend(IIIFManifest::V3::ManifestBuilderDecorator) +IIIFManifest::V3::ManifestBuilder::CanvasBuilder.prepend(IIIFManifest::V3::ManifestBuilder::CanvasBuilderDecorator) From 7add38e9b4d8087b878714b0aa0439a1e3b23f73 Mon Sep 17 00:00:00 2001 From: Jeremy Friesen Date: Mon, 27 Nov 2023 15:46:41 -0500 Subject: [PATCH 57/60] =?UTF-8?q?=F0=9F=90=9B=20Fix=20bad=20method=20name?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related to: - https://github.com/samvera/hyku/pull/2023/files - https://github.com/scientist-softserv/atla-hyku/pull/198 --- app/controllers/hyrax/my/works_controller_decorator.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/hyrax/my/works_controller_decorator.rb b/app/controllers/hyrax/my/works_controller_decorator.rb index 2817729e9..df68ce1ca 100644 --- a/app/controllers/hyrax/my/works_controller_decorator.rb +++ b/app/controllers/hyrax/my/works_controller_decorator.rb @@ -6,7 +6,7 @@ module Hyrax module My module WorksControllerDecorator - def collection_service + def collections_service cloned = clone cloned.params = {} Hyrax::CollectionsService.new(cloned) From dbe996e71afa63a5ba8f68f55e4c50ed25d3729d Mon Sep 17 00:00:00 2001 From: Kirk Wang Date: Wed, 29 Nov 2023 13:36:24 -0800 Subject: [PATCH 58/60] =?UTF-8?q?=F0=9F=90=9B=20Move=20some=20methods=20to?= =?UTF-8?q?=20be=20public?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit will move #solr_document, #current_ability, and #request to be public methods. Since these methods in Hyrax were not private, in the decorator it should not be private either. Ref: - https://github.com/samvera/hyrax/blob/b334e186e77691d7da8ed59ff27f091be1c2a700/app/presenters/hyrax/file_set_presenter.rb#L10 --- .../iiif_av/displays_content_decorator.rb | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/app/presenters/concerns/hyrax/iiif_av/displays_content_decorator.rb b/app/presenters/concerns/hyrax/iiif_av/displays_content_decorator.rb index 8348c245f..6260e456a 100644 --- a/app/presenters/concerns/hyrax/iiif_av/displays_content_decorator.rb +++ b/app/presenters/concerns/hyrax/iiif_av/displays_content_decorator.rb @@ -8,21 +8,21 @@ module IiifAv # request.base_url => hostname # also to remove #auth_service since it was not working for now module DisplaysContentDecorator - private + def solr_document + defined?(super) ? super : object + end - def solr_document - defined?(super) ? super : object - end + def current_ability + defined?(super) ? super : @ability + end - def current_ability - defined?(super) ? super : @ability - end + def request + Request.new(base_url: hostname) + end - Request = Struct.new(:base_url, keyword_init: true) + private - def request - Request.new(base_url: hostname) - end + Request = Struct.new(:base_url, keyword_init: true) def image_content return nil unless latest_file_id From 0f67c4c259f917d02cea2053883644fca8324749 Mon Sep 17 00:00:00 2001 From: Shana Moore Date: Wed, 13 Dec 2023 09:10:22 -0800 Subject: [PATCH 59/60] =?UTF-8?q?=F0=9F=A7=B9=20use=20class=20attribute=20?= =?UTF-8?q?instead=20of=20constant=20to=20correct=20failing=20specs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/forms/hyrax/forms/admin/appearance.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/forms/hyrax/forms/admin/appearance.rb b/app/forms/hyrax/forms/admin/appearance.rb index a58cb732d..56000bd98 100644 --- a/app/forms/hyrax/forms/admin/appearance.rb +++ b/app/forms/hyrax/forms/admin/appearance.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# OVERRIDE Hyrax 3.4.0 ot add custom theming +# OVERRIDE Hyrax 3.4.0 to add custom theming # rubocop:disable Metrics/ClassLength module Hyrax @@ -439,7 +439,7 @@ def convert_to_rgba(hex_color, alpha = 0.5) end def default_values - @default_values ||= DEFAULT_FONTS.merge(DEFAULT_COLORS) + @default_values ||= default_fonts.merge(default_colors) end def block_for(name, dynamic_default = nil) From 6930a863d531286565e443876cdc8dfba3854075 Mon Sep 17 00:00:00 2001 From: Kirk Wang Date: Tue, 12 Dec 2023 19:32:41 -0800 Subject: [PATCH 60/60] Fix specs --- app/controllers/hyrax/homepage_controller.rb | 147 ++++++++++++++++++ .../hyrax/homepage_controller_decorator.rb | 19 --- .../content_blocks/edit.html.erb_spec.rb | 2 +- 3 files changed, 148 insertions(+), 20 deletions(-) create mode 100644 app/controllers/hyrax/homepage_controller.rb delete mode 100644 app/controllers/hyrax/homepage_controller_decorator.rb diff --git a/app/controllers/hyrax/homepage_controller.rb b/app/controllers/hyrax/homepage_controller.rb new file mode 100644 index 000000000..b9130eb9e --- /dev/null +++ b/app/controllers/hyrax/homepage_controller.rb @@ -0,0 +1,147 @@ +# frozen_string_literal: true + +######################################################################################### +######################################################################################### +# +# +# HACK: We have copied over the Hyrax::HomepageController to address Hyku specific +# customizations. This controller needs significant refactoring and reconciliation +# with Hyrax prime. Note, we are inheriting differently than Hyrax does and +# there are other adjustments. +# +# +######################################################################################### +######################################################################################### +# OVERRIDE: Hyrax v2.9.0 to add home_text content block to the index method - Adding themes +# OVERRIDE: Hyrax v2.9.0 from Hyrax v2.9.0 to add facets to home page - inheriting from +# CatalogController rather than ApplicationController +# OVERRIDE: Hyrax v2.9.0 from Hyrax v2.9.0 to add inject_theme_views method for theming +# OVERRIDE: Hyrax v2.9.0 to add search_action_url method from Blacklight 6.23.0 to make facet links to go to /catalog +# OVERRIDE: Hyrax v2.9.0 to add .sort_by to return collections in alphabetical order by title on the homepage +# OVERRIDE: Hyrax v2.9.0 add all_collections page for IR theme +# OVERRIDE: Hyrax v2.9.0 to add facet counts for resource types for IR theme +# OVERRIDE: Hyrax v. 2.9.0 to add @featured_collection_list to index method + +module Hyrax + # Changed to inherit from CatalogController for home page facets + class HomepageController < CatalogController + # Adds Hydra behaviors into the application controller + include Blacklight::SearchContext + include Blacklight::SearchHelper + include Blacklight::AccessControls::Catalog + + # OVERRIDE: account for Hyku themes + around_action :inject_theme_views + + # The search builder for finding recent documents + # Override of Blacklight::RequestBuilders and default CatalogController behavior + def search_builder_class + Hyrax::HomepageSearchBuilder + end + + class_attribute :presenter_class + self.presenter_class = Hyrax::HomepagePresenter + layout 'homepage' + helper Hyrax::ContentBlockHelper + + def index + # BEGIN copy Hyrax prime's Hyrax::HomepageController#index + @presenter = presenter_class.new(current_ability, collections) + @featured_researcher = ContentBlock.for(:researcher) + @marketing_text = ContentBlock.for(:marketing) + @featured_work_list = FeaturedWorkList.new + @announcement_text = ContentBlock.for(:announcement) + recent + # END copy + + # BEGIN OVERRIDE + # What follows is Hyku specific overrides + @home_text = ContentBlock.for(:home_text) # hyrax v3.5.0 added @home_text - Adding Themes + @featured_collection_list = FeaturedCollectionList.new # OVERRIDE here to add featured collection list + + ir_counts if home_page_theme == 'institutional_repository' + + (@response, @document_list) = search_results(params) + + respond_to do |format| + format.html { store_preferred_view } + format.rss { render layout: false } + format.atom { render layout: false } + format.json do + @presenter = Blacklight::JsonPresenter.new(@response, + @document_list, + facets_from_request, + blacklight_config) + end + additional_response_formats(format) + document_export_formats(format) + end + end + + def browserconfig; end + + def all_collections + @presenter = presenter_class.new(current_ability, collections) + @marketing_text = ContentBlock.for(:marketing) + @announcement_text = ContentBlock.for(:announcement) + @collections = collections(rows: 100_000) + ir_counts if home_page_theme == 'institutional_repository' + end + + # Added from Blacklight 6.23.0 to change url for facets on home page + protected + + # Default route to the search action (used e.g. in global partials). Override this method + # in a controller or in your ApplicationController to introduce custom logic for choosing + # which action the search form should use + def search_action_url(options = {}) + # Rails 4.2 deprecated url helpers accepting string keys for 'controller' or 'action' + main_app.search_catalog_path(options) + end + + private + + # Return 6 collections + def collections(rows: 6) + builder = Hyrax::CollectionSearchBuilder.new(self) + .rows(rows) + response = repository.search(builder) + # adding .sort_by to return collections in alphabetical order by title on the homepage + response.documents.sort_by(&:title) + rescue Blacklight::Exceptions::ECONNREFUSED, Blacklight::Exceptions::InvalidRequest + [] + end + + def recent + # grab any recent documents + (_, @recent_documents) = search_results(q: '', sort: sort_field, rows: 6) + rescue Blacklight::Exceptions::ECONNREFUSED, Blacklight::Exceptions::InvalidRequest + @recent_documents = [] + end + + def ir_counts + @ir_counts = get_facet_field_response('resource_type_sim', {}, "f.resource_type_sim.facet.limit" => "-1") + end + + # COPIED from Hyrax::HomepageController + def sort_field + "date_uploaded_dtsi desc" + end + + # Add this method to prepend the theme views into the view_paths + def inject_theme_views + if home_page_theme && home_page_theme != 'default_home' + original_paths = view_paths + home_theme_view_path = Rails.root.join('app', 'views', "themes", home_page_theme.to_s) + prepend_view_path(home_theme_view_path) + yield + # rubocop:disable Lint/UselessAssignment, Layout/SpaceAroundOperators, Style/RedundantParentheses + # Do NOT change this line. This is calling the Rails view_paths=(paths) method and not a variable assignment. + view_paths=(original_paths) + # rubocop:enable Lint/UselessAssignment, Layout/SpaceAroundOperators, Style/RedundantParentheses + else + yield + end + end + end +end diff --git a/app/controllers/hyrax/homepage_controller_decorator.rb b/app/controllers/hyrax/homepage_controller_decorator.rb deleted file mode 100644 index e4564a9bb..000000000 --- a/app/controllers/hyrax/homepage_controller_decorator.rb +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -# OVERRIDE Hyrax 3.5 to add content blocks -module Hyrax - module HomepageControllerDecorator - def index - @presenter = presenter_class.new(current_ability, collections) - @featured_researcher = ContentBlock.for(:researcher) - @marketing_text = ContentBlock.for(:marketing) - @featured_work_list = FeaturedWorkList.new - @announcement_text = ContentBlock.for(:announcement) - @homepage_about_section_heading = ContentBlock.for(:homepage_about_section_heading) - @homepage_about_section_content = ContentBlock.for(:homepage_about_section_content) - recent - end - end -end - -Hyrax::HomepageController.prepend Hyrax::HomepageControllerDecorator diff --git a/spec/views/hyrax/content_blocks/edit.html.erb_spec.rb b/spec/views/hyrax/content_blocks/edit.html.erb_spec.rb index 9039fa2bf..5dbd31afa 100644 --- a/spec/views/hyrax/content_blocks/edit.html.erb_spec.rb +++ b/spec/views/hyrax/content_blocks/edit.html.erb_spec.rb @@ -36,7 +36,7 @@ end it "renders the instruction blocks" do - expect(rendered).to have_xpath('//p[@class="content-block-instructions" ]', count: 4) + expect(rendered).to have_xpath('//p[@class="content-block-instructions" ]', count: 6) end # TODO: These next 4 tests are tightly coupled with the implimentation,