diff --git a/Gemfile b/Gemfile index a8e9c98c..f2b1c6be 100644 --- a/Gemfile +++ b/Gemfile @@ -9,9 +9,6 @@ gem 'rails', '~> 5.2.8.1' gem "sqlite3", "~> 1.3.0" # Use pg as the production database for Active Record gem 'pg' -# Use sitemap -# See https://github.com/viseztrance/rails-sitemap -gem 'sitemap' # Use Passenger as the app server # Update this when we update the Passenger docker container base image version gem 'passenger', '6.0.17', require: "phusion_passenger/rack_handler" @@ -88,6 +85,8 @@ gem "ffi", "~> 1.15" gem 'json-canonicalization', '0.3.1' # https://github.com/dryruby/json-canonicalization/issues/2 +gem 'schoolie', '0.1.3' + gem 'prawn' # SAML gem 'omniauth-saml', '2.1.0' diff --git a/Gemfile.lock b/Gemfile.lock index cdfdb3fc..7da1e809 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -893,6 +893,8 @@ GEM sassc (2.4.0) ffi (~> 1.9) scanf (1.0.0) + schoolie (0.1.3) + actionview (~> 5) select2-rails (3.5.11) shacl (0.1.1) json-ld (~> 3.1, >= 3.1.7) @@ -908,7 +910,7 @@ GEM rdf-xsd (~> 3.1) sparql (~> 3.1) sxp (~> 1.1) - sidekiq (6.5.9) + sidekiq (6.5.10) connection_pool (>= 2.2.5, < 3) rack (~> 2.0) redis (>= 4.5.0, < 5) @@ -1076,6 +1078,7 @@ DEPENDENCIES rsolr (>= 1.0, < 3) rspec-rails sass-rails (~> 5.0) + schoolie (= 0.1.3) sidekiq (~> 6) simplecov sitemap diff --git a/app/assets/stylesheets/scholarspace/base/_base.scss b/app/assets/stylesheets/scholarspace/base/_base.scss index c14b4701..9a74f3f1 100644 --- a/app/assets/stylesheets/scholarspace/base/_base.scss +++ b/app/assets/stylesheets/scholarspace/base/_base.scss @@ -158,7 +158,7 @@ html { &.btn-categories { width: 100%; margin: 0.2em 0; - padding: 0.3rem 2rem; + padding: 0.3rem 1rem; border: 2px solid $gw-white; background-color: $gw-white; color: $gw-dark-blue; diff --git a/app/assets/stylesheets/scholarspace/components/_homepage.scss b/app/assets/stylesheets/scholarspace/components/_homepage.scss index 617067a3..161298d1 100644 --- a/app/assets/stylesheets/scholarspace/components/_homepage.scss +++ b/app/assets/stylesheets/scholarspace/components/_homepage.scss @@ -191,7 +191,7 @@ margin: 0; #categories-container, #categories-tooltip { - padding: 0 0 0 0.5em + padding: 1em 0 0 0.5em; } } } @@ -201,18 +201,18 @@ height: 100%; #recent_docs { - height: 100%; display: flex; flex-direction: row; justify-content: space-between; - align-items: center; + align-items: baseline; + padding-top: 0.5em; .recent-work { width: 12vw; margin: 0.5em 0.5em; display: flex; align-items: baseline; - height: 18.5vw; + min-height: 18.5vw; .image-wrapper { position: relative; @@ -258,18 +258,49 @@ align-items: center; justify-content: center; background-color: $gw-light-blue; - - h3 { - font-size: 1em; - text-decoration: underline; - &:hover { - color: $gw-hover-buff; + .title-wrapper { + -webkit-box-orient: vertical; + display: -webkit-box; + -webkit-line-clamp: 4; + padding: 0 1em; + overflow: hidden; + max-width: 100%; + text-align: center; + + h3 { + font-size: 1em; + text-decoration: underline; + --max-lines: 4; + --line-height: 1.2; + max-height: calc(var(--max-lines) * 1em * var(--line-height)); + line-height: var(--line-height); + position: relative; + + &:hover { + color: $gw-hover-buff; + } } } } } + .keyword-wrapper { + -webkit-box-orient: vertical; + display: -webkit-box; + -webkit-line-clamp: 2; + overflow: hidden; + max-width: 100%; + + .recent-field { + --max-lines: 2; + --line-height: 1.4; + height: calc(var(--max-lines) * 1em * var(--line-height)); + line-height: var(--line-height); + position: relative; + } + } + @media (max-width: 1300px) { width: 14vw; @@ -305,10 +336,14 @@ @media (max-width: $mobile-max) { flex-direction: column; + width: 80%; + align-items: center; .recent-work { - width: 100%; margin: 2em 0; + display: flex; + flex-direction: column; + align-items: center; .image-wrapper { height: 90.5vw; @@ -431,10 +466,6 @@ @media (max-width: 1280px) { flex-direction: column; - #featured-h2 { - width: 100%; - } - .home-collections { margin-bottom: 1em; } @@ -449,8 +480,12 @@ @media (max-width: 1280px) { padding: 1.5em 0; + + #featured-h2 { + width: 100%; + } } } } } -} \ No newline at end of file +} diff --git a/app/jobs/sitemap_regenerate_job.rb b/app/jobs/sitemap_regenerate_job.rb index d8dd29fa..d2b7e720 100644 --- a/app/jobs/sitemap_regenerate_job.rb +++ b/app/jobs/sitemap_regenerate_job.rb @@ -4,7 +4,6 @@ class SitemapRegenerateJob < ApplicationJob def perform - Rake::Task['sitemap:generate'].invoke - Rake::Task['sitemap:ping'].invoke + Rake::Task['schoolie:sitemap'].invoke end end diff --git a/app/models/gw_etd.rb b/app/models/gw_etd.rb index ec550926..d2c72a78 100644 --- a/app/models/gw_etd.rb +++ b/app/models/gw_etd.rb @@ -5,7 +5,7 @@ class GwEtd < ActiveFedora::Base # Change this to restrict which works can be added as a child. # self.valid_child_concerns = [] self.indexer = GwEtdIndexer - + validates :title, presence: { message: 'Your work must have a title.' } property :gw_affiliation, predicate: ::RDF::URI.new('http://scholarspace.library.gwu.edu/ns#gwaffiliation') do |index| diff --git a/app/models/gw_work.rb b/app/models/gw_work.rb index 657d9c8c..2c85a7ca 100644 --- a/app/models/gw_work.rb +++ b/app/models/gw_work.rb @@ -17,4 +17,4 @@ class GwWork < ActiveFedora::Base end include ::Hyrax::BasicMetadata -end +end \ No newline at end of file diff --git a/app/presenters/hyrax/gw_etd_presenter.rb b/app/presenters/hyrax/gw_etd_presenter.rb index c4a4887b..f331a460 100644 --- a/app/presenters/hyrax/gw_etd_presenter.rb +++ b/app/presenters/hyrax/gw_etd_presenter.rb @@ -6,5 +6,11 @@ class GwEtdPresenter < GwWorkPresenter def permanent_url Scholarspace::Application.config.permanent_url_base + "etd/#{id}" end + + # scholarly? is used to determine whether or not + # the Google Scholar meta tags are rendered + def scholarly? + true + end end end diff --git a/app/presenters/hyrax/gw_work_presenter.rb b/app/presenters/hyrax/gw_work_presenter.rb index 2c705e78..db4efb98 100644 --- a/app/presenters/hyrax/gw_work_presenter.rb +++ b/app/presenters/hyrax/gw_work_presenter.rb @@ -5,5 +5,9 @@ class GwWorkPresenter < Hyrax::WorkShowPresenter def permanent_url Scholarspace::Application.config.permanent_url_base + "work/#{id}" end + + def scholarly? + false + end end end diff --git a/app/views/hyrax/homepage/_recent_document.html.erb b/app/views/hyrax/homepage/_recent_document.html.erb index a3cff852..24dae681 100644 --- a/app/views/hyrax/homepage/_recent_document.html.erb +++ b/app/views/hyrax/homepage/_recent_document.html.erb @@ -7,14 +7,18 @@ <%= render_thumbnail_tag(recent_document, {alt: "#{recent_document} #{ t('hyrax.homepage.admin_sets.thumbnail')}" }, {suppress_link: true}) %>
-

- <%= recent_document %> -

+
+

+ <%= recent_document %> +

+
<% end %> -

- <%= t('hyrax.homepage.recently_uploaded.document.keyword_label') %>: <%= link_to_facet_list(recent_document.keyword, 'keyword', t('hyrax.homepage.recently_uploaded.document.keyword_missing')).html_safe %> -

+
+

+ <%= t('hyrax.homepage.recently_uploaded.document.keyword_label') %>: <%= link_to_facet_list(recent_document.keyword, 'keyword', t('hyrax.homepage.recently_uploaded.document.keyword_missing')).html_safe %> +

+
diff --git a/app/views/layouts/_head_tag_content.html.erb b/app/views/layouts/_head_tag_content.html.erb index beb55fa2..31afde45 100644 --- a/app/views/layouts/_head_tag_content.html.erb +++ b/app/views/layouts/_head_tag_content.html.erb @@ -12,8 +12,8 @@ signed in %> <%= yield :twitter_meta %> - -<%= yield :gscholar_meta %> + +<%= yield :schoolie_meta %> <%= content_for?(:page_title) ? yield(:page_title) : default_page_title %> diff --git a/app/views/shared/_citations.html.erb b/app/views/shared/_citations.html.erb new file mode 100644 index 00000000..49a8b09d --- /dev/null +++ b/app/views/shared/_citations.html.erb @@ -0,0 +1,2 @@ +<%= render 'shared/twitter_citations' %> +<%= render 'shared/schoolie_citations' %> \ No newline at end of file diff --git a/app/views/shared/_schoolie_citations.html.erb b/app/views/shared/_schoolie_citations.html.erb new file mode 100644 index 00000000..9bff92ec --- /dev/null +++ b/app/views/shared/_schoolie_citations.html.erb @@ -0,0 +1,5 @@ +<% content_for(:schoolie_meta) do %> + <% if @presenter.scholarly? %> + <%schoolie_tags(@presenter).html_safe%> + <% end %> +<% end %> diff --git a/app/views/shared/_twitter_citations.html.erb b/app/views/shared/_twitter_citations.html.erb new file mode 100644 index 00000000..a9afc0b9 --- /dev/null +++ b/app/views/shared/_twitter_citations.html.erb @@ -0,0 +1,15 @@ +<% content_for(:twitter_meta) do %> + + + + + + + + + + + + + +<% end %> diff --git a/config/authorities/resource_types.yml b/config/authorities/resource_types.yml index d33950ed..5d90ef40 100644 --- a/config/authorities/resource_types.yml +++ b/config/authorities/resource_types.yml @@ -15,12 +15,16 @@ terms: term: Conference Proceeding - id: Dataset term: Dataset + - id: Dissertation + term: Dissertation - id: Image term: Image - id: Journal term: Journal - id: Map or Cartographic Material term: Map or Cartographic Material + - id: Master's Thesis + term: Master's Thesis - id: Meeting Minutes term: Meeting Minutes - id: Newsletter @@ -39,8 +43,6 @@ terms: term: Research Paper - id: Software or Program Code term: Software or Program Code - - id: Thesis or Dissertation - term: Thesis or Dissertation - id: Video term: Video - id: Working Paper diff --git a/config/etd_degree_map.yml b/config/etd_degree_map.yml new file mode 100644 index 00000000..5131db02 --- /dev/null +++ b/config/etd_degree_map.yml @@ -0,0 +1,20 @@ +Master's Thesis: + - M.A. + - M.S. + - M.P.H. + - LL.M. + - M.F.A. + - M.A.T. + - M.P.S. + - M.B.A. + - M.F.S. + - M.Int.St. + - M.P.H. + - M.P.P. +Dissertation: + - Ph.D. + - Ed.D. + - D.Engr. + - Dr.P.H. + - D.Sc. + - S.J.D. diff --git a/config/schoolie.yml b/config/schoolie.yml new file mode 100644 index 00000000..8d9cc91e --- /dev/null +++ b/config/schoolie.yml @@ -0,0 +1,10 @@ +static: + citation_institution: George Washington University +attributes: + citation_title: title + citation_author: creator + citation_type: resource_type + dc.type: resource_type + citation_date: publication_date + citation_keywords: keyword + citation_pdf_url: download_url diff --git a/config/sitemap.rb b/config/sitemap.rb deleted file mode 100644 index 5c02484e..00000000 --- a/config/sitemap.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -Sitemap::Generator.instance.load(host: 'scholarspace.library.gwu.edu', protocol: 'https') do - path :root, priority: 1, change_frequency: 'weekly' - path :search_catalog, priority: 1, change_frequency: 'weekly' - - read_group = ActiveFedora.index_field_mapper.solr_name('read_access_group', :symbol) - GwWork.where(read_group => 'public').each do |f| - literal Rails.application.routes.url_helpers.hyrax_gw_work_path(f, action: 'show'), - priority: 1, change_frequency: 'weekly' - end - GwEtd.where(read_group => 'public').each do |f| - literal Rails.application.routes.url_helpers.hyrax_gw_etd_path(f, action: 'show'), - priority: 1, change_frequency: 'weekly' - end -end diff --git a/lib/tasks/gwss.rake b/lib/tasks/gwss.rake index 2070d141..f7ec4956 100644 --- a/lib/tasks/gwss.rake +++ b/lib/tasks/gwss.rake @@ -20,9 +20,9 @@ namespace :gwss do end end - desc "Queues a job to (re)generate the sitemap.xml" + desc "Executes (immediately) a job to (re)generate the sitemap.xml" task "sitemap_queue_generate" => :environment do - SitemapRegenerateJob.perform_later + SitemapRegenerateJob.perform_now end desc "Creates the default Admin Set if it doesn't exist" @@ -141,6 +141,10 @@ namespace :gwss do # problem that would be caused by referencing GwEtd first # See articles such as http://neethack.com/2015/04/rails-circular-dependency/ GwWork + + degree_hash = YAML.load_file('config/etd_degree_map.yml') + degree_categories = degree_hash.keys # Typically ["Master's Thesis", "Dissertation"] + manifest_file = options[:mfpath] if File.exist?(manifest_file) mf = File.read(manifest_file) @@ -153,7 +157,10 @@ namespace :gwss do item_attributes['degree'] = manifest_json['degree'][0] end # resource_type may need more logic around it, TBD - item_attributes['resource_type'] = ['Thesis or Dissertation'] + if manifest_json['etd_type'] + item_attributes['resource_type'] = manifest_json['etd_type'] + end + # item_attributes['resource_type'] = ['Thesis or Dissertation'] # dc:rights # Always set this license for ETDs @@ -313,4 +320,48 @@ namespace :gwss do ContentBlock.find_or_create_by(name: "help_page").update!(value: help_page_html.read) ContentBlock.find_or_create_by(name: "share_page").update!(value: share_page_html.read) end + + desc "Reassigns GwEtd resource_type values to Master's Thesis or Dissertation" + task "reassign_etd_resource_types" => :environment do + etd_degree_map = YAML.load_file('config/etd_degree_map.yml') + degree_etd_map = {} + degree_categories = etd_degree_map.keys + # Flip etd_degree_map to create degree_etd_map + # So that for any given degree, we can get back whether it's a masters or a doctorate + degree_categories.each do |degree_category| + etd_degree_map[degree_category].each do |degree_name| + # upcase each degree (just in case) and ignore "."s + degree_etd_map[degree_name.upcase.delete('.')] = degree_category + end + end + + ids = Hyrax::SolrService.new.get("has_model_ssim:GwEtd", fl: [:id], rows: 1_000_000) + ids["response"]["docs"].each do |doc| + work = GwEtd.find(doc["id"]) + if work.degree.nil? + puts "GwEtd id=#{doc["id"]} degree is empty! Skipping" + else + degree_name = work.degree.upcase.delete('.') + if degree_etd_map.keys.include?(degree_name) + work.resource_type = [degree_etd_map[degree_name]] + work.save + puts "Reassigned #{degree_name} resource type to #{degree_etd_map[degree_name]}" + else + puts "Degree name #{degree_name} not found! Skipping" + end + end + end + end + + desc "Enumerates degree types present among existing GwEtd works" + task "enumerate_degree_types" => :environment do + ids = Hyrax::SolrService.new.get("has_model_ssim:GwEtd", fl: [:id], rows: 1_000_000) + docs = ids["response"]["docs"] + # Map a list of ids to a list of degree values + degrees = docs.map {|doc| GwEtd.find(doc["id"]).degree} + degree_hash = degrees.tally + degree_hash.keys.each do |key| + puts "#{key}, #{degree_hash[key]}" + end + end end diff --git a/lib/tasks/schoolie.rake b/lib/tasks/schoolie.rake new file mode 100644 index 00000000..62b50ce0 --- /dev/null +++ b/lib/tasks/schoolie.rake @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require 'json' +require 'nokogiri' + +namespace :schoolie do + desc "Creates Google Scholar compliant sitemap for GwEtd works" + task sitemap: :environment do + date_field = 'system_modified_dtsi' + result = Hyrax::SolrService.new.get("has_model_ssim:GwEtd", + fl: "id,#{date_field}", + rows: 1_000_000) + ids = result['response']['docs'].map do |x| + ["https://scholarspace.library.gwu.edu/etd/#{x['id'].to_s}", x[date_field].to_s] + end + builder = Nokogiri::XML::Builder.new do |sitemap| + sitemap.urlset("xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance", + xmlns: "http://www.sitemaps.org/schemas/sitemap/0.9", + "xsi:schemaLocation": "http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd") { + ids.each { |url, date| + sitemap.url { + sitemap.loc url + sitemap.lastmod date + } + } + } + end + File.open(Rails.root.join("public", "sitemap.xml"), "w") { |f| f.write(builder.to_xml) } + end +end