Skip to content

Commit

Permalink
Merge pull request #358 from xronos-ch/lod
Browse files Browse the repository at this point in the history
Lod
  • Loading branch information
MartinHinz authored Dec 18, 2024
2 parents b6f1d3a + 3c4d5dc commit 4dd9832
Show file tree
Hide file tree
Showing 44 changed files with 1,047 additions and 60 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

## 1.0.0.9000 [unreleased]

- Introduced the ability to manage and display external linked data (e.g.,
Wikidata) within the application
- Added a new Linked Data section to the site view, providing clear and user-
friendly access to external resources
- Added options for authorized users to add external resource links (e.g.
Wikidata entries)
- Improved search interface; now shows more information and can be filtered by
record type
- Added LONG_LABEL issue for references (#260)
Expand Down
23 changes: 15 additions & 8 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ gem 'pg'
# App server
gem 'puma'

# Data cache (required to run Action Cable in production)
# In-memory cache (also required for Turbo broadcasts and ActionCable)
gem 'redis', '~> 4.0'

# Reduce boot times through caching (required in config/boot.rb)
Expand Down Expand Up @@ -94,13 +94,6 @@ gem 'countries'
gem 'country_select'
gem 'i18n_data'

# Geocoding
gem 'geocoder'

# GBIF Backbone Taxonomy
gem 'faraday', '~> 2.5', '>= 2.5.2'
gem 'gbifrb'

# Bibliographic data
gem 'bibtex-ruby'
gem 'citeproc-ruby'
Expand All @@ -110,6 +103,20 @@ gem 'csl-styles'
# lasso
gem 'activerecord-session_store'

# EXTERNAL APIS ---------------------------------------------------------------

gem 'faraday', '>= 2.5.2'

# Geocoding
gem 'geocoder'

# GBIF (Backbone Taxonomy)
gem 'gbifrb'

# Wikidata & Wikipedia
gem 'wikidata-client', require: 'wikidata'
gem 'wikipedia-client', require: 'wikipedia'

# VIEW HELPERS ----------------------------------------------------------------

# Pagination
Expand Down
16 changes: 15 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ GEM
railties (>= 6.1)
drb (2.2.1)
erubi (1.13.0)
excon (0.112.0)
execjs (2.10.0)
factory_bot (6.5.0)
activesupport (>= 5.0.0)
Expand All @@ -182,6 +183,9 @@ GEM
faraday-net_http (>= 2.0, < 3.5)
json
logger
faraday-excon (2.2.0)
excon (>= 0.109.0)
faraday (>= 2.11.0, < 3)
faraday-net_http (3.4.0)
net-http (>= 0.5.0)
feedjira (3.2.3)
Expand Down Expand Up @@ -211,6 +215,7 @@ GEM
guard (~> 2.1)
guard-compat (~> 1.1)
rspec (>= 2.99.0, < 4.0)
hashie (5.0.0)
httparty (0.22.0)
csv
mini_mime (>= 1.0.0)
Expand Down Expand Up @@ -491,6 +496,13 @@ GEM
websocket-extensions (0.1.5)
whenever (1.0.0)
chronic (>= 0.6.3)
wikidata-client (0.1.0)
excon (~> 0.92)
faraday (~> 2.2)
faraday-excon (~> 2.1)
hashie (~> 5.0)
wikipedia-client (1.17.0)
addressable (~> 2.7)
xpath (3.2.0)
nokogiri (~> 1.8)
zeitwerk (2.7.1)
Expand Down Expand Up @@ -523,7 +535,7 @@ DEPENDENCIES
dotenv-rails
factory_bot_rails
faker
faraday (~> 2.5, >= 2.5.2)
faraday (>= 2.5.2)
feedjira
gbifrb
geocoder
Expand Down Expand Up @@ -568,6 +580,8 @@ DEPENDENCIES
vega
web-console (>= 3.3.0)
whenever
wikidata-client
wikipedia-client

RUBY VERSION
ruby 3.3.6p108
Expand Down
1 change: 1 addition & 0 deletions app/assets/images/simple_icons/wikidata.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions app/assets/images/simple_icons/wikimediacommons.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions app/assets/images/simple_icons/wikipedia.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions app/assets/stylesheets/layout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,8 @@ span.hero_caption:hover {
background-color: rgba(0, 0, 0, 0.4);
}


.blockquote {
font-size: 1rem;
font-color: "red";
}
17 changes: 17 additions & 0 deletions app/assets/stylesheets/typography.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,20 @@
.dl-inline dd {
display: inline;
}

// Align embedded svg icons with text
// Adapted from https://blog.prototypr.io/align-svg-icons-to-text-and-say-goodbye-to-font-icons-d44b3d7b26b4
.svg-icon {
display: inline-flex;
align-self: center;
}

.svg-icon svg {
height: 1em;
width: 1em;
}

.svg-icon.svg-baseline svg {
top: .125em;
position: relative;
}
76 changes: 76 additions & 0 deletions app/controllers/lod_links_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
class LodLinksController < ApplicationController
load_and_authorize_resource

before_action :set_lod_link, only: [:show, :edit, :update, :destroy]

def show
if source = "Wikidata"
@wikidata_link.request_item
if @wikidata_link.item.sitelink_title("enwiki").present?
@wikidata_link.item.request_wikipedia_extract
end
end
render partial: "lod_link"
end

def new
end

def edit
end

def create
@lod_link = LodLink.new(lod_link_params)

respond_to do |format|
if @lod_link.save
format.html { redirect_back fallback_location: root_path, notice: success_notice }
format.json { render :show, status: :created, location: @lod_link }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @lod_link.errors, status: :unprocessable_entity }
end
end
end

def update
respond_to do |format|
if @lod_link.update(lod_link_params)
format.html { redirect_back fallback_location: root_path, notice: success_notice }
format.json { render :show, status: :ok, location: @lod_link }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: @lod_link.errors, status: :unprocessable_entity }
end
end
end

def destroy
end

private

def set_lod_link
@lod_link = LodLink.find(params[:id])
@wikidata_link = LodLink.where(source: "Wikidata").find(params[:id])
end

def lod_link_params
params.require(:lod_link).permit([
:external_id,
:source,
:linkable_type,
:linkable_id,
:revision_comment,
:status
])
end

def success_notice
@lod_link.linkable_type +
":" +
@lod_link.linkable_id.to_s +
" is now linked to Wikidata item Q" +
@lod_link.external_id.to_s
end
end
46 changes: 46 additions & 0 deletions app/controllers/lods/sites_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
class Lods::SitesController < LodsController
load_and_authorize_resource

# GET /issues/sites/:issue
def index
allowed_methods = lods
if lod_param.present? && allowed_methods.include?(lod_param.to_sym)
@sites = Site.public_send(lod_param)
else
@sites = Site.all
end

if params.has_key?(:search)
@sites = @sites.search params[:search]
end

if params.has_key?(:sites_order_by)
order = { params[:sites_order_by] => params.fetch(:sites_order, "asc") }
else
order = :id
end
@sites = @sites.reorder(order)

@sites = @sites.with_counts

respond_to do |format|
format.html do
@pagy, @sites = pagy(@sites)

# Fetch and cache Wikidata matches for the current page
@wikidata_matches = fetch_wikidata_matches(@sites)
end
end
end

private

def lods
Site.lods
end

def fetch_wikidata_matches(sites)
# Ensure Wikidata matches are always a hash
Site.wikidata_match_candidates_batch(sites) || {}
end
end
24 changes: 24 additions & 0 deletions app/controllers/lods_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
class LodsController < ApplicationController
include Pagy::Backend

before_action :authenticate_user!

layout "curate"

def index
end

private

def lods
[:issues, :another_allowed_method] # Add all allowed methods here
end

def lod_param
lod = params.fetch(:lod, nil)
allowed_methods = lods.map(&:to_s)
return lod.to_sym if lod.present? && allowed_methods.include?(lod)
end


end
4 changes: 3 additions & 1 deletion app/controllers/sites_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ def destroy
# Use callbacks to share common setup or constraints between actions.
def set_site
@site = Site.find(params[:id])
@wikidata_matches = Site.wikidata_match_candidates_batch([@site]) || {}
end

# Never trust parameters from the scary internet, only allow the white list through.
Expand All @@ -142,7 +143,8 @@ def site_params
{site_type_ids: []},
:country_code,
:revision_comment,
:_destroy
:_destroy,
wikidata_link_attributes: [:qid]
)
end
end
17 changes: 17 additions & 0 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,22 @@ def md(str)
.html_safe
end

def floating_button(path, options = {})
default_classes = "d-block position-absolute top-0 start-100 small"
if options.has_key?(:class)
options[:class] = options[:class] + " " + default_classes
else
options[:class] = default_classes
end

options[:title] = "Edit" unless options.has_key?(:title)

content_tag :div, class: "position-relative" do
link_to path, **options do
bs_icon "pencil"
end
end
end

end

21 changes: 21 additions & 0 deletions app/helpers/lods_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module LodsHelper
def lod_label(lod)
lod.to_s.upcase
end

def lod_description(lod)
case lod
# Sites
when :missing_wikidata_link
"No Wikidata Link has yet been provided"
else
""
end
end

def lod_badge(lod)
content_tag :span, title: lod_description(lod), class: "badge text-bg-warning" do
lod_label(lod)
end
end
end
29 changes: 29 additions & 0 deletions app/helpers/simple_icons_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module SimpleIconsHelper

def simple_icon(slug)
content_tag :span, class: "svg-icon svg-baseline" do
embedded_svg "simple_icons/#{slug}.svg", width: 32, height: 32, role: "graphics-symbol", class: "simple-icon"
end
end

# Embed SVGs directly
# adapted from https://blog.cloud66.com/using-svgs-in-a-rails-stack
def embedded_svg(filename, options = {})
assets = Rails.application.assets

asset = assets.load_path.find(filename)

if asset
#file = asset.source.force_encoding("UTF-8")
doc = Nokogiri::HTML::DocumentFragment.parse asset.content
svg = doc.at_css "svg"
options.each {|attr, value| svg[attr.to_s] = value}
#svg["class"] = options[:class] if options[:class].present?
else
doc = "<!-- SVG #{filename} not found -->"
end

raw doc
end

end
Loading

0 comments on commit 4dd9832

Please sign in to comment.