Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
6285edc
Add PaN Services to home page
eilmiv Aug 13, 2025
dda7c10
Move PaN Services counter next to other counters
eilmiv Aug 13, 2025
81ffe53
Service counter counts lower and upper case now
eilmiv Aug 13, 2025
d199aa3
Initial OAI-PMH implementation
eilmiv Aug 13, 2025
8531f82
Add XSLT formating of OAI-PMH XML Results
eilmiv Aug 13, 2025
73214e7
initial oai-pmh rdf setup
eilmiv Aug 13, 2025
72849b7
Add json-ld to xml conversion
eilmiv Aug 19, 2025
9d10575
bind sdo and dc prefixes for oai-pmh rdf export
eilmiv Aug 19, 2025
19a52f9
Add rendering support for OAI-PMH rdf including prefixes
eilmiv Aug 19, 2025
786b2df
Add rdf to quicklinks to oai-pmh records html
eilmiv Aug 21, 2025
e4debaf
Map material properties to Dublin Core for oai_dc support
eilmiv Aug 21, 2025
7d98b44
Temporarily undo production config changes
eilmiv Aug 21, 2025
44ce834
Add newline to production config
eilmiv Aug 21, 2025
27b4dc6
Merge pull request #1 from eilmiv/oai_pmh
eilmiv Aug 21, 2025
38e1622
Set repository_url of OAI-PMH based on base_url
eilmiv Aug 21, 2025
f28c795
Set repository_url of OAI-PMH based on base_url and not only host
eilmiv Aug 21, 2025
59f941a
Merge pull request #2 from eilmiv/oai_pmh
eilmiv Aug 21, 2025
5b38612
Merge branch 'master' into oai_pmh
eilmiv Aug 24, 2025
ebd852e
Show longer URLs in OAI-PMH html
eilmiv Aug 24, 2025
bc1c163
Merge pull request #3 from eilmiv/oai_pmh
eilmiv Aug 24, 2025
0ebb24b
Only show visible materials
eilmiv Sep 9, 2025
8ed1115
Test oai-pmh endpoint
eilmiv Sep 9, 2025
8c45669
Add and update comments
eilmiv Sep 9, 2025
744504f
Merge pull request #4 from ElixirTeSS/master
eilmiv Sep 9, 2025
b319ce9
Merge branch 'ElixirTeSS:master' into oai_pmh
eilmiv Sep 10, 2025
d397580
Modification note in oai2xhtml.xsl
eilmiv Sep 10, 2025
cc0ff63
Improved code style of material to dublin core mapping
eilmiv Sep 10, 2025
57b3286
Revert "Add PaN Services to home page"
eilmiv Sep 10, 2025
b29873f
Change OAI-PMH ID example to be more realistic
eilmiv Sep 10, 2025
481d799
Update schema of rdf OAI-PMH
eilmiv Sep 10, 2025
ee8c087
Don't fail when database does not exist yet.
eilmiv Sep 10, 2025
7c2a9e7
Remove PublicMaterial helper class
eilmiv Sep 12, 2025
12a2501
Support PAI-PMH POST requests
eilmiv Sep 12, 2025
c757a91
Remove library dependencies that are already part of linkeddata
eilmiv Sep 12, 2025
323abaf
Improve oai-pmh tests by parsing XML
eilmiv Sep 26, 2025
a71a345
Move oai-pmh config to config/initializers
eilmiv Sep 26, 2025
8b54db2
Refactor material to Dublin Core conversion into one method
eilmiv Sep 30, 2025
a163f56
Catch more errors when database does not exist yet
eilmiv Oct 8, 2025
aa894d8
Catch more errors in oai-pmh config when database does not exist yet
eilmiv Oct 8, 2025
0d5a9ae
Hint that OAI-PMH POST without csrf is save.
eilmiv Oct 8, 2025
b12dc40
Simplify OAI-PMH initialization
eilmiv Oct 8, 2025
8653301
More general error catching during OAI-PMH config
eilmiv Oct 8, 2025
5a94a0d
Remove ignored CSRF error suppression
eilmiv Oct 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ gem 'kt-paperclip'
gem 'linkeddata'
gem 'maxmind-db'
gem 'money-rails'
gem 'oai'
gem 'omniauth_openid_connect'
gem 'omniauth-rails_csrf_protection'
gem 'pg'
Expand Down
6 changes: 6 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,11 @@ GEM
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
numerizer (0.1.1)
oai (1.3.0)
builder (>= 3.1.0)
faraday (< 3)
faraday-follow_redirects (>= 0.3.0, < 2)
rexml
omniauth (2.1.1)
hashie (>= 3.4.6)
rack (>= 2.2.3)
Expand Down Expand Up @@ -853,6 +858,7 @@ DEPENDENCIES
minitest
minitest-reporters
money-rails
oai
omniauth-rails_csrf_protection
omniauth_openid_connect
pg
Expand Down
22 changes: 22 additions & 0 deletions app/controllers/oai_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# The controller for actions related to OAI-PMH
class OaiController < ApplicationController
# CSRF token authentication causes problems with OAI-PMH POST requests and OAI-PMH POST is safe because it returns static public content
skip_before_action :verify_authenticity_token, only: [:index]

Check failure

Code scanning / CodeQL

CSRF protection weakened or disabled High

Potential CSRF vulnerability due to forgery protection being disabled or weakened.

# GET /oai-pmh
def index
provider = TrainingProvider.new
response = provider.process_request(oai_params.to_h)

# add XSLT prefix
response.sub!(/<\?xml[^>]+\?>/, "\\0\n<?xml-stylesheet type=\"text/xsl\" href=\"/oai2xhtml.xsl\"?>")

render body: response, content_type: 'text/xml'
end

private

def oai_params
params.permit(:verb, :identifier, :metadataPrefix, :set, :from, :until, :resumptionToken)
end
end
2 changes: 2 additions & 0 deletions app/helpers/oai_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module OaiHelper
end
58 changes: 58 additions & 0 deletions app/models/material.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
require 'rails/html/sanitizer'
require 'json/ld'
require 'rdf'
require 'rdf/rdfxml'
require 'builder'

class Material < ApplicationRecord
include PublicActivity::Common
Expand Down Expand Up @@ -186,4 +190,58 @@ def duplicate
def archived?
status == 'archived'
end

def to_rdf
jsonld_str = to_bioschemas[0].to_json

graph = RDF::Graph.new
JSON::LD::Reader.new(jsonld_str) do |reader|
reader.each_statement { |stmt| graph << stmt }
end

rdfxml_str = graph.dump(:rdfxml, prefixes: { sdo: 'http://schema.org/', dc: 'http://purl.org/dc/terms/' })
rdfxml_str.sub(/\A<\?xml.*?\?>\s*/, '') # remove XML declaration because this is used inside OAI-PMH response
end

def to_oai_dc
xml = ::Builder::XmlMarkup.new
xml.tag!('oai_dc:dc',
'xmlns:oai_dc' => 'http://www.openarchives.org/OAI/2.0/oai_dc/',
'xmlns:dc' => 'http://purl.org/dc/elements/1.1/',
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
'xsi:schemaLocation' => 'http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd') do
xml.tag!('dc:title', title)
xml.tag!('dc:description', description)
authors.each { |a| xml.tag!('dc:creator', a) }
contributors.each { |a| xml.tag!('dc:contributor', a) }
xml.tag!('dc:publisher', content_provider.title) if content_provider

xml.tag!('dc:format', 'text/html')
xml.tag!('dc:language', 'en')
xml.tag!('dc:rights', licence) if licence.present?

[date_published, date_created, date_modified].compact.each do |d|
xml.tag!('dc:date', d.iso8601)
end

if doi.present?
doi_iri = doi.start_with?('http://', 'https://') ? doi : "https://doi.org/#{doi}"
xml.tag!('dc:identifier', doi_iri)
else
xml.tag!('dc:identifier', url)
end

(keywords + scientific_topics.map(&:uri) + operations.map(&:uri)).each do |s|
xml.tag!('dc:subject', s)
end

xml.tag!('dc:type', 'http://purl.org/dc/dcmitype/Text')
xml.tag!('dc:type', 'https://schema.org/LearningResource')
resource_type.each { |t| xml.tag!('dc:type', t) }

xml.tag!('dc:relation', "#{TeSS::Config.base_url}#{Rails.application.routes.url_helpers.material_path(self)}")
xml.tag!('dc:relation', content_provider.url) if content_provider&.url
end
xml.target!
end
end
1 change: 0 additions & 1 deletion app/views/static/home/_counters.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

<div id='resource_count' class='resource-counter-number'> <%= @count_strings[feature] %> </div>
<div class='resource-counter-text'> <%= feature == 'events' ? 'Upcoming Events' : feature.titleize %> </div>

<% end %>
</li>
<% end %>
Expand Down
2 changes: 1 addition & 1 deletion config/environment.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Load the Rails application.
require_relative "application"
require_relative 'application'

# Initialize the Rails application.
Rails.application.initialize!
29 changes: 29 additions & 0 deletions config/initializers/oai_provider.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Configure OAI-PMH library
# see comments in: https://github.com/code4lib/ruby-oai/blob/54ea6f7f5b1e2c1be5d0a7cc61cb696b5e653d8a/lib/oai/provider.rb#L98
require 'oai'
require 'uri'

class OAIRDF < OAI::Provider::Metadata::Format
def initialize
@prefix = 'rdf'
@schema = 'http://www.openarchives.org/OAI/2.0/rdf.xsd'
@namespace = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
@element_namespace = 'rdf'
end
end

class TrainingProvider < OAI::Provider::Base
repository_name TeSS::Config.site['title']
repository_url "#{TeSS::Config.base_url}/oai-pmh"
record_prefix "oai:#{URI(TeSS::Config.base_url).host}"
admin_email TeSS::Config.contact_email
sample_id '142' # so that example id is oai:domain:142

register_format(OAIRDF.instance)
end

Rails.application.config.after_initialize do
TrainingProvider.source_model OAI::Provider::ActiveRecordWrapper.new(Material.where(visible: true))
rescue ActiveRecord::ActiveRecordError
Rails.logger.debug 'There is no database yet or some other error, so the OAI-PMH endpoint is not configured.'
end
2 changes: 2 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@

get 'up' => 'health_check#show'

match 'oai-pmh', to: "oai#index", via: [:get, :post]

# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".

Expand Down
Loading