team-umlaut/umlaut

View on GitHub
app/controllers/umlaut_configurable.rb

Summary

Maintainability
B
5 hrs
Test Coverage
# meant to be included in _controllers_, to get an
# umlaut_config method as a class_attribute (avail on class, overrideable
# on instance), exposed as helper method too, 
# that has a Confstruct configuration object that starts out
# holding global config. (right now via a direct refernce to the global
# one). 

require 'confstruct'

module UmlautConfigurable
  extend ActiveSupport::Concern
  
  included do
    class_attribute :umlaut_config
    helper_method :umlaut_config
    self.umlaut_config = Confstruct::Configuration.new
  end

  # Used for `resolve_sections` config, like an Array but
  # we add a some custom methods into the resolve_sections array, 
  # insert_section, remove_section. With a sub-class. 
  class ResolveSectionsArray < Array
    # Deprecated. This was a silly confusing way to do this. 
    # See #remove and #insert below instead. 
    def ensure_order!(first, second)
      $stderr.puts "resolve_sections.ensure_order! is deprecated, please see resolve_sections.remove and resolve_sections.insert"

      list = self
  
      index1 = list.index {|s| s[:div_id].to_s == first.to_s}
      index2 = list.index {|s| s[:div_id].to_s == second.to_s}
  
      (list[index1], list[index2] = list[index2], list[index1]) if index1 && index2 && (index1 > index2)
  
      list
    end

    # Insert a section_config hash before or after an existing
    # section, by the existing section's div_id
    #
    #      resolve_sections.insert_section({:div_id => "new"}, :after => "fulltext")
    #      resolve_sections.insert_section(  resolve_sections.remove_section("document_deliver"), :before => "fulltext")
    def insert_section(section_config, options = {})
      list = self

      if options[:before]
        i = (list.find_index {|s| s[:div_id].to_s == options[:before].to_s}) || 0
        list.insert(i, section_config)
      elsif options[:after]
        i = (list.find_index {|s| s[:div_id].to_s == options[:after].to_s}) || (list.length - 1)
        list.insert(i + 1, section_config)
      else
        # just add at end of list
        list << section_config
      end
    end

    # Remove a configuration block with a certain div_id from the configuration entirely, 
    # returning the removed configuration block (or nil if none exists). 
    # You can re-insert it with #insert if you like. 
    def remove_section(div_id)
      list = self
      i = list.find_index {|s| s[:div_id].to_s == div_id.to_s}
      return list.delete_at(i) if i
    end

    # Make deep_dup work
    def deep_dup
      self.class.new.concat super
    end

    # Make map work returning same class, to avoid breaking Hashie::Mash. 
    # Bah, this is a mess, yep. 
    def map(*args, &block)
      self.class.new.concat super
    end
    alias_method :collect, :map

  end   


  
  # Call as UmlautConfigurable.set_default_configuration!(confstruct_obj)
  # to initialize
  def self.set_default_configuration!(configuration)
    configuration.configure do
      app_name 'Find It'  
      # Different navbar title? Defaults to app_name    
      header_title deferred! {|c| c.app_name}
      # URL to image to use for link resolver, OR name of image asset in local app. 
      #link_img_url "http//something"
      
      # string used in standard layout footer to identify your app.
      # mark it html_safe if it includes html
      # footer_credit "Find It service provided by <a href='http://www.university.edu/'>My University</a>".html_safe
      
      # Sometimes Umlaut sends out email, what email addr should it be from?
      from_email_addr 'no_reply@umlaut.example.com'
          
      layout "umlaut"
      resolve_layout deferred! {|c| c.layout}    
      search_layout deferred! {|c| c.layout}
      
      # help url used on error page and a few other places.
      # help_url  "http://www.library.jhu.edu/services/askalib/index.html"
      
      # Minimum height and width of browser window. We have little control over
      # what size a content provider generates a window for a link resolver. Often
      # it's too small for umlaut. So we resize in js, if these config params
      # are given. Set to 0 to disable.
      # Sadly, only some browsers let us resize the browser window, so this
      # feature only works in some browsers. 
      minimum_window_width    820
      minimum_window_height   400
      
      
      # rfr_ids used for umlaut generated pages.
      rfr_ids do
        opensearch  "info:sid/umlaut.code4lib.org:opensearch"
        citation    "info:sid/umlaut.code4lib.org:citation"
        azlist      'info:sid/umlaut.code4lib.org:azlist'
      end
      
      # If you have a test umlaut set up at another location to stage/test
      # new features, link to it here, and a helper method in default
      # layout will provide a subtle debugging link to it in footer,
      # for current OpenURL. 
      # test_resolve_base "http://app01.mse.jhu.edu/umlaut_dev"
      
      opensearch_short_name deferred! {|c| "Find Journals with #{c.app_name}" }
      opensearch_description deferred! {|c| "Search #{c.app_name} for journal names containing your term"}
      
      
      
      # Referent filters. Sort of like SFX source parsers.
      # hash, key is regexp to match a sid, value is filter object
      # (see lib/referent_filters )        
      add_referent_filters!( :match => /.*/, :filter => DissertationCatch.new ) 
                  
      # skip_resolve_menu can be used to control 'direct' linking, skipping
      # the resolve menu to deliver a full text link or other resource
      # directly to the user.
      # Possible values:
      # false  : [default] Never skip menu
      #   A hash with one or more keys....
      # {:service_types => ['fulltext']} : list of service type values, if 
      #          they're present skip the menu with the first response available.
      # {:excluded_services => ['JH_HIP'] : list of service IDs, exclude responses
      #          from these services for direct linking. (Not yet implemented)
      # {:excluded_urls => [/regexp/, 'string'] : list of regexps or strings,
      #          exclude URLs that match this string from being skipped to. (Not yet implemented)
      # {:excluded_rfr_ids => ["info:sid/sfxit.com:citation", '"info:sid/umlaut.code4lib.org:citation"'] }
      # {:lambda => lambda {|p, l| return something}} : Not yet implemented. 
      
      # lambda expression: A lambda expression can be provided that
      #          should expect one argument, a hash with key :request
      #          and value the Umlaut Request object. Return nil to
      #          not skip menu, or a ServiceType join obj to skip
      #          menu to that response.
    
      # A pretty typical direct-linking setup, excludes queries that come
      # from citation linker/azlist/opensearch from direct linking. 
      # skip_resolve_menu  {:service_types => ['fulltext'],
      #:services=>['JH_SFX'], :excluded_rfr_ids => ["info:sid/sfxit.com:citation",
      #'info:sid/umlaut.code4lib.org:citation',
      #'info:sid/umlaut.code4lib.org:azlist',  
      #'info:sid/umlaut.code4lib.org:opensearch']}
      #
      # "umlaut.skip_resolve_menu" paramter can also be passed in per-request, with
      # 'true' or shortname of a service type. 
      skip_resolve_menu false
      
      # How many seconds between updates of the background updater for background
      # services?
      poll_wait_seconds 2.0
      # The FIRST AJAX callback for bg tasks should be much quicker. So we
      # get any bg tasks that executed nearly instantaneously, and on page
      # refresh when bg is really all loaded on back-end, but still needs JS to 
      # fetch it. 
      initial_poll_wait_seconds 0.250
      
      # if a background service hasn't returned in this many seconds, consider
      # it failed. (May actually be slow, more likely raised an exception and
      # our exception handling failed to note it as failed.)    
      background_service_timeout 30
      # If a service has status FailedTemporary, and it's older than a
      # certain value, it will be re-queued in #serviceDispatch.
      # This value defaults to 10 times background_service_timeout,
      # but can be set in app config variable requeue_failedtemporary_services
      # If you set it too low, you can wind up with a request that never completes,
      # as it constantly re-queues a service which constantly fails.
      requeue_failedtemporary_services_in deferred! {|c| c.background_service_timeout * 10}
  
      # custom view template for resolve#index
      resolve_view nil
      
      # If OpenURL came from manual entry of title/ISSN, and no match is found in
      # link resolver knowledge base, display a warning to the user of potential
      # typo?
      entry_not_in_kb_warning true
          
      nightly_maintenance do
        # How old does a request have to be to be deleted by nightly_maintenance?
        # requests are only re-used within a session. Probably no reason to
        # change this.          
        request_expire_seconds 1.day
        
        # How long to keep FAILED DispatchServices, for viewing problems/troubleshooting
        failed_dispatch_expire_seconds 4.weeks
  
      end
      
      resolve_display do
        # Where available, prefix links with year coverage summary
        # using ResolveHelper#coverage_summery helper. 
        show_coverage_summary true
      end
      
      # Configuration for the 'search' functions -- A-Z lookup
      # and citation entry. 
      search do
        # Is your SFX database connection, defined in database.yml under
        # sfx_db and used for A-Z searches, Sfx4 or do you want to use Sfx4Solr?  
        # Other SearchMethods in addition to SFX direct db may be provided later. 
        az_search_method  SearchMethods::Sfx4
        #az_search_method  SearchMethods::Sfx4Solr::Local
        
        # When talking directly to the SFX A-Z list database, you may
        # need to set this, if you have multiple A-Z profiles configured
        # and don't want to use the 'default.
        sfx_az_profile "default"    
        
        # Use your own custom search view? mention it here.   
        #search_view  "my_search"
        
        # can set to "_blank" etc. 
        result_link_target nil
        
      end
      
      # config only relevant to SFX use  
      sfx do
        # was: 'main_sfx_base_url'
        # base sfx url to use for search actions, error condition backup,
        # and some other purposes. For search actions (A-Z), direct database
        # connection to your SFX db also needs to be defined in database.yml
        # sfx_base_url  'http://sfx.library.jhu.edu:8000/jhu_sfx?'
        # 
  
        
        
        # Umlaut tries to figure out from the SFX knowledge base
        # which hosts are "SFX controlled", to avoid duplicating SFX
        # urls with urls from catalog. But sometimes it misses some, or
        # alternate hostnames for some. Regexps matching against
        # urls can be included here. Eg,
        # additional_sfx_controlled_urls  [
        #    %r{^http://([^\.]\.)*pubmedcentral\.com}
        #  ]    
        additional_sfx_controlled_urls  []
        
        # "web.archive.org" is listed in SFX, but that causes suppression
        # of MARC 856 tags from our catalog pointing to archive.org, which are
        # being used for some digitized books. We'd like to ignore that archive.org
        # is in SFX. Same for netlibrary.
        #sfx_load_ignore_hosts  [/.*\.archive\.org/, /www\.netlibrary\.com/, 'www.loc.gov']
        sfx_load_ignore_hosts  []        
      end
      
      # config only relevant to holdings display
      holdings do
        # Holding statuses that should be styled as "Available"
        available_statuses ["Not Charged", "Available"]
      end
    
      # Output timing of service execution to logs
      log_service_timing (Rails.env == "development")
      
      # Execute service wave concurrently with threads?
      # Set to false to execute serially one after the other with
      # no threads instead. At this point, believed only useful
      # for debugging and analysis. 
      threaded_service_wave true
      
      
      #####
      # Pieces of content on a Resolve page can be declaritively configured. 
      # Here are the defaults. You can add new elements to the resolve_sections
      # array in config and modify or delete existing resolve_sections elements.
      #
      # Look in comments at top of SectionRenderer class for what the keys
      # in each entry mean. 
          
      # ResolveSectionsArray is like an Array, but with
      # some additional methods making it easier to do common
      # configuration tasks. 
      resolve_sections ResolveSectionsArray.new

      ##########
      #
      # Names of these sections can be given in Rails i18n, under key
      #   umlaut.display_sections.#{section_div_id}.title
      # If not given there, will be automatically calculated from
      # the display_name of the ServiceType Value included. 
      #
      # Optional sub-head prompts can also be given in i18n, under
      #   umlaut.display_sections.#{section_div_id}.prompt
      #
      ###########

      add_resolve_sections! do
        div_id "cover_image"
        partial "cover_image"
        visibility :responses_exist
        show_heading false
        show_spinner false
      end
            
      add_resolve_sections! do
        div_id "fulltext"    
        html_area :main
        partial :fulltext
        show_partial_only true
      end      
      
      add_resolve_sections! do
        div_id "audio"        
        html_area :main
        visibility :responses_exist
      end
      
      add_resolve_sections! do
        div_id "holding"
        html_area :main
        partial 'holding'
        service_type_values ["holding","holding_search"]
      end
      
      add_resolve_sections! do
        div_id "document_delivery"
        html_area :main
        visibility :responses_exist
        #bg_update false
      end
      
      add_resolve_sections! do
        div_id "table_of_contents"
        html_area :main
        visibility :responses_exist
      end
      
      add_resolve_sections! do
        div_id "abstract"
        html_area :main
        visibility :responses_exist
      end
      
      add_resolve_sections! do
        div_id "help"
        html_area :sidebar
        bg_update false
        partial "help"
        show_heading false
        show_spinner false
        visibility :responses_exist 
      end
      
      add_resolve_sections! do
        div_id "coins"
        html_area :sidebar
        partial "coins"
        service_type_values []
        show_heading false
        show_spinner false
        bg_update false
        partial_html_api false
      end
      
      add_resolve_sections! do
        div_id "export_citation"
        html_area :sidebar
        visibility :in_progress
      end

      add_resolve_sections! do
        div_id "search_inside"
        html_area :sidebar
        partial "search_inside"
        show_partial_only true
      end
      
      add_resolve_sections! do
        div_id "excerpts"
        html_area :sidebar
        list_visible_limit 5
        visibility :responses_exist
      end
      
      add_resolve_sections! do
        div_id "related_items"
        html_area :sidebar
        partial "related_items"
        # custom visibility, show it for item-level cites,
        # or if we actually have some
        visibility(  lambda do |renderer|
                        renderer.any_services? &&
                        (! renderer.request.title_level_citation?) ||
                        (! renderer.responses_empty?)
                      end )
        service_type_values ['cited_by', 'similar']
      end
      
      add_resolve_sections! do
        div_id "highlighted_link"
        html_area :sidebar
        visibility :in_progress
        partial_locals( :show_source => true )
      end
      
      add_resolve_sections! do
        div_id "service_errors"
        partial "service_errors"
        html_area :service_errors
        service_type_values []
      end
      
    end
    
  end
  
  
  
end