Skip to content
8 changes: 8 additions & 0 deletions app/controllers/gobierto_data/api/v1/datasets_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ class DatasetsController < BaseController
skip_before_action :authenticate_in_site, only: [:new, :create, :update, :destroy]
skip_before_action :set_admin_with_token, except: [:new, :create, :update, :destroy]

# GET /api/v1/data/catalog.xml
def catalog
@catalog = DatasetPresenter.new(current_site).build_catalog
respond_to do |format|
format.xml
end
end

# GET /api/v1/data/datasets
# GET /api/v1/data/datasets.json
# GET /api/v1/data/datasets.csv
Expand Down
3 changes: 3 additions & 0 deletions app/models/gobierto_data/dataset.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ class Dataset < ApplicationRecord
include GobiertoData::Favoriteable
include GobiertoAttachments::Attachable
include GobiertoCommon::Collectionable
include GobiertoCommon::HasCustomFieldRecords

belongs_to :site
has_many :queries, dependent: :destroy, class_name: "GobiertoData::Query"
has_many :visualizations, dependent: :destroy, class_name: "GobiertoData::Visualization"

scope :sorted, -> { order(data_updated_at: :desc) }
scope :visibles, -> { where(visibility_level: "active") }
scope :by_site, ->(site_id) { where(site_id: site_id) }

translates :name

Expand Down
76 changes: 76 additions & 0 deletions app/presenters/gobierto_data/dataset_presenter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
module GobiertoData
class DatasetPresenter
include ActionView::Helpers::UrlHelper

attr_reader :site

def initialize(site)
@site = site
end

def build_catalog
catalog = {
identifier_uri: url_helpers.gobierto_data_root_url(host: site.domain),
title: "dcat catalog for #{site}",
description: "this is catalog published by #{@catalog_identifier_uri} which contains datasets",
issued: site.created_at,
modified: GobiertoData::Dataset.where(site_id: site.id).maximum(:created_at) || site.created_at,
languages: site["configuration_data"]["available_locales"],
homepage: url_helpers.gobierto_data_root_url(host: site.domain),
license_url: "https://opendatacommons.org/licenses/odbl/",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alvaro said no license, right? Is it mandatory?

Copy link
Copy Markdown
Contributor Author

@stbnrivas stbnrivas Apr 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about if DCAT has mandatory xml elements, from now I think that:

  • DCAT don't define xml element required, recommended, optional.
  • DCAT-AP define some xml element as required, reccomended or optionals (but not 100% sure)

So as alvaro said I'll remove license at catalog level 👍

datasets: build_datasets_for_catalog
}
end

private

def build_datasets_for_catalog
datasets = []
Dataset.where(site_id: site.id).visibles.each do |dataset|
datasets << build_dataset_for_catalog(dataset)
end
datasets
end

def build_dataset_for_catalog(dataset)
{
url: url_helpers.gobierto_data_datasets_url(host: site.domain, id: dataset.slug),
title: dataset.name,
description: description_custom_field_record(dataset),
keywords: [],
issued: dataset.created_at,
modified: dataset.updated_at,
languages: [site_locale],
license_url: "https://opendatacommons.org/licenses/odbl/",
publisher: site.name,
publisher_mbox: site.reply_to_email,
distributions: build_distribution_for_catalog(dataset)
}
end

def build_distribution_for_catalog(dataset)
[
{
format: 'application/csv',
download_url: url_helpers.download_gobierto_data_api_v1_dataset_url(dataset, host: site.domain)
}
]
end

def url_helpers
Rails.application.routes.url_helpers
end

def site_locale
site.configuration_data["default_locale"]
end

def description_custom_field_record(dataset)
if dataset.custom_field_record_with_uid("description")
dataset.custom_field_record_with_uid("description").payload["description"][site_locale]
else
""
end
end
end
end
50 changes: 50 additions & 0 deletions app/views/gobierto_data/api/v1/datasets/catalog.xml.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8" ?>
<rdf:RDF
xmlns:time="http://www.w3.org/2006/time#"
xmlns:dct="http://purl.org/dc/terms/"
xmlns:dcat="http://www.w3.org/ns/dcat#"
xmlns:foaf="http://xmlns.com/foaf/0.1/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><% cache @catalog do %>
<dcat:Catalog rdf:about="https://data.some.org/catalog">
<dct:identifier><%= @catalog[:identifier_uri] %></dct:identifier>
<dct:title><%= @catalog[:title] %></dct:title>
<dct:description><%= @catalog[:description] %></dct:description>
<dct:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime"><%= @catalog[:issued] %></dct:issued>
<dct:modified rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime"><%= @catalog[:modified] %></dct:modified>
<%= @catalog[:languages].map { |locale| "<dct:language>#{locale}</dct:language>" }.join.html_safe %>
<foaf:homepage rdf:resource="<%= @catalog[:homepage] %>"/>
<dct:license rdf:resource="<%= @catalog[:license_url] %>"/>
<% @catalog[:datasets].each do |dataset| %><dcat:dataset>
<dcat:Dataset rdf:about="<%= dataset[:url]%>">
<dct:identifier><%= dataset[:url] %></dct:identifier>
<dct:title><%= dataset[:title] %></dct:title>
<dct:description><%= dataset[:description] %></dct:description>
<%= dataset[:keywords].map { |keyword| "<dct:keyword>#{locale}</dct:keyword>" }.join.html_safe %>
<dct:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime"><%= dataset[:issued] %></dct:issued>
<dct:modified rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime"><%= dataset[:modified] %></dct:modified>
<%= dataset[:languages].map { |lang| "<dct:language>#{lang}</dct:language>" }.join.html_safe %>
<dct:license rdf:resource="<%= dataset[:title] %>"/>
<dct:publisher>
<foaf:Organization>
<foaf:name><%= dataset[:publisher] %></foaf:name>
<foaf:mbox><%= dataset[:publisher_mbox] %></foaf:mbox>
</foaf:Organization>
</dct:publisher>
<% dataset[:distributions].each do |distribution| %>
<dcat:distribution>
<dcat:Distribution>
<dct:identifier><%= @identifier_uri %></dct:identifier>
<dct:title><%= dataset[:title] %> in CSV format</dct:title>
<dct:description><%= dataset[:description] %></dct:description>
<dcat:downloadURL rdf:datatype="http://www.w3.org/2001/XMLSchema#anyURI"><%= distribution[:download_url] %></dcat:downloadURL>
<dcat:mediaType><%= distribution[:format] %></dcat:mediaType>
<dct:license rdf:resource="<%= dataset[:license_url] %>"/>
</dcat:Distribution>
</dcat:distribution>
<% end %>
</dcat:Dataset>
</dcat:dataset><% end %>
</dcat:Catalog><% end %>
</rdf:RDF>
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,7 @@
resource :favorite, only: [:create, :destroy]
resources :favorites, only: [:index]
end
get "catalog" => "datasets#catalog"
end
end
end
Expand Down
5 changes: 5 additions & 0 deletions test/fixtures/gobierto_common/custom_field_records.yml
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,11 @@ users_dataset_md_with_translations_custom_field_record:
"md-with-translations" => { en: "Paragraph with translations!", es: "¡Párrafo con traducciones!" }
}.to_json %>

users_dataset_md_with_translations_custom_field_record:
item: users_dataset (GobiertoData::Dataset)
custom_field: madrid_data_datasets_custom_field_description
payload: <%= {"description": {"en": "This dataset contains the council' persons related.", "es": "Este dataset contiene las personas relaccionadas con el ayuntamiento."}}.to_json %>

## Users

peter_custom_field_issue:
Expand Down
8 changes: 8 additions & 0 deletions test/fixtures/gobierto_common/custom_fields.yml
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,14 @@ madrid_data_datasets_custom_field_md_with_translations:
field_type: <%= GobiertoCommon::CustomField.field_types[:localized_paragraph] %>
uid: md-with-translations

madrid_data_datasets_custom_field_description:
site: madrid
class_name: GobiertoData::Dataset
position: 4
name_translations: <%= {"en": "Description", "es": "Descripción"}.to_json %>
field_type: <%= GobiertoCommon::CustomField.field_types[:localized_paragraph] %>
uid: description

madrid_custom_field_human_resources_table_plugin:
site: madrid
class_name: GobiertoPlans::Node
Expand Down
2 changes: 2 additions & 0 deletions test/fixtures/sites.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ madrid:
organization_address: Fake St., 123
organization_document_number: 0123456789A
visibility_level: <%= Site.visibility_levels["active"] %>
created_at: <%= 1.year.ago %>
updated_at: <%= 1.week.ago %>

santander:
title_translations: <%= { 'en' => 'Transparencia Ciudadana', 'es' => 'Transparencia Ciudadana' }.to_json %>
Expand Down
57 changes: 57 additions & 0 deletions test/presenters/gobierto_data/dataset_presenter_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# frozen_string_literal: true

require "test_helper"

module GobiertoData
class DatasetPresenterTest < ActiveSupport::TestCase

def setup
super
@site = sites(:madrid)
@subject = DatasetPresenter.new(@site)
@other_site = sites(:huesca)
@other_subject = DatasetPresenter.new(@other_site)
end

def test_structure_catalog_building_do_not_show_draft_datasets
catalog = @subject.build_catalog
datasets_published = GobiertoData::Dataset.by_site(@site.id).visibles.size
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

current_site.datasets?

assert_equal datasets_published, catalog[:datasets].size
end

def test_structure_catalog_building_using_site_with_datasets
catalog = @subject.build_catalog
assert catalog.has_key? :identifier_uri
assert catalog.has_key? :title
assert catalog.has_key? :description
assert catalog.has_key? :issued
assert catalog.has_key? :modified
assert catalog.has_key? :languages
assert catalog.has_key? :homepage
assert catalog.has_key? :license_url
assert catalog.has_key? :datasets
catalog[:datasets].each do |dataset|
assert dataset.has_key? :url
assert dataset.has_key? :title
assert dataset.has_key? :description
assert dataset.has_key? :keywords
assert dataset.has_key? :issued
assert dataset.has_key? :modified
assert dataset.has_key? :languages
assert dataset.has_key? :license_url
assert dataset.has_key? :publisher
assert dataset.has_key? :publisher_mbox
assert dataset.has_key? :distributions
dataset[:distributions].each do |distribution|
assert distribution.has_key? :format
assert distribution.has_key? :download_url
end
end
end

def test_structure_catalog_building_using_site_without_datasets
catalog = @other_subject.build_catalog
assert_equal 0, catalog[:datasets].size
end
end
end