diff --git a/app/controllers/maps_controller.rb b/app/controllers/maps_controller.rb index 189ae550..6e4a9486 100644 --- a/app/controllers/maps_controller.rb +++ b/app/controllers/maps_controller.rb @@ -20,6 +20,7 @@ class MapsController < ApplicationController end format.json { render json: @map } format.csv { redirect_to action: :export, format: :csv } + format.ttl { redirect_to action: :export, format: :ttl } end end @@ -90,10 +91,12 @@ class MapsController < ApplicationController # GET maps/:id/export def export - exporter = MapExportService.new(current_user, @map) + exporter = MapExportService.new(current_user, @map, base_url: request.base_url) + respond_to do |format| format.json { render json: exporter.json } format.csv { send_data exporter.csv } + format.ttl { render text: exporter.rdf } end end diff --git a/app/models/synapse.rb b/app/models/synapse.rb index be57dde1..d6d08bbe 100644 --- a/app/models/synapse.rb +++ b/app/models/synapse.rb @@ -51,6 +51,18 @@ class Synapse < ApplicationRecord super(methods: [:user_name, :user_image, :collaborator_ids]) end + def as_rdf + output = '' + output += %(d:synapse_#{id} a mm:Synapse ;\n) + output += %( mm:topic1 d:topic_#{topic1_id} ;\n) + output += %( mm:topic2 d:topic_#{topic2_id} ;\n) + output += %( mm:direction "#{category}" ;\n) + output += %( rdfs:comment "#{desc}" ;\n) if desc.present? + output[-2] = '.' + output += %(\n) + output + end + def after_updated attrs = ['desc', 'category', 'permission', 'defer_to_map_id'] if attrs.any? {|k| changed_attributes.key?(k)} diff --git a/app/models/topic.rb b/app/models/topic.rb index 90443862..2273fd7e 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -82,6 +82,19 @@ class Topic < ApplicationRecord map_count: map_count(options[:user]), synapse_count: synapse_count(options[:user])) end + def as_rdf + output = '' + output += %(d:topic_#{id} a mm:Topic ;\n) + output += %( rdfs:label "#{name}" ;\n) + output += %( rdfs:comment "#{desc}" ;\n) if desc.present? + output += %( foaf:homepage <#{link}> ;\n) if link.present? + output += %( mm:mapper d:mapper_#{user_id} ;\n) + output += %( mm:metacode "#{metacode.name}" ;\n) + output[-2] = '.' # change last ; to a . + output += %(\n) + output + end + def collaborator_ids if defer_to_map defer_to_map.editors.select { |mapper| mapper != user }.map(&:id) diff --git a/app/models/user.rb b/app/models/user.rb index f6fcb60e..17d9c8d4 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -67,6 +67,17 @@ class User < ApplicationRecord json end + def as_rdf(opts = {}) + base_url = opts[:base_url] || 'https://metamaps.cc' + output = '' + output += %(d:mapper_#{id} a foaf:OnlineAccount ;\n) + output += %( foaf:accountName "#{name}" ;\n) + output += %( foaf:accountServiceHomepage "#{base_url}/mapper/#{id}" ;\n) + output[-2] = '.' # change last ; to a . + output += %(\n) + output + end + def all_accessible_maps maps + shared_maps end diff --git a/app/services/map_export_service.rb b/app/services/map_export_service.rb index 3b76cea8..e500575e 100644 --- a/app/services/map_export_service.rb +++ b/app/services/map_export_service.rb @@ -1,9 +1,11 @@ # frozen_string_literal: true class MapExportService - attr_reader :user, :map - def initialize(user, map) + attr_reader :user, :map, :base_url + + def initialize(user, map, opts = {}) @user = user @map = map + @base_url = opts[:base_url] || 'https://metamaps.cc' end def json @@ -22,6 +24,25 @@ class MapExportService end end + def rdf + output = '' + output += "PREFIX d: <#{base_url}/maps/#{map.id}>\n" + output += "PREFIX mm: <#{base_url}/owl/map.owl.ttl>\n" + output += "PREFIX rdfs: \n" + output += "PREFIX foaf: \n" + output += "\n" + map.contributors.each do |mapper| + output += mapper.as_rdf(base_url: base_url) + end + map.topics.each do |topic| + output += topic.as_rdf + end + map.synapses.each do |synapse| + output += synapse.as_rdf + end + output + end + private def topic_headings diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb index 6e1d16f0..2e0132a6 100644 --- a/config/initializers/mime_types.rb +++ b/config/initializers/mime_types.rb @@ -3,3 +3,6 @@ # Add new mime types for use in respond_to blocks: # Mime::Type.register "text/richtext", :rtf + +# RDF export +Mime::Type.register 'text/turtle', :ttl diff --git a/public/owl/map.owl.ttl b/public/owl/map.owl.ttl new file mode 100644 index 00000000..725e039a --- /dev/null +++ b/public/owl/map.owl.ttl @@ -0,0 +1,40 @@ +@prefix owl: . +@prefix xsd: . +@prefix rdfs: . +@prefix foaf: . + +@prefix : . +@prefix mm: . + +: a owl:Ontology ; + rdfs:label "Metamaps Map"@en . + +mm:Topic a owl:Class ; + rdfs:label "One topic on a metamap"@en . + +mm:Synapse a owl:Class ; + rdfs:label "Link between two topics on a metamap"@en . + +mm:topic1 a owl:ObjectProperty ; + a owl:FunctionalProperty ; + rdfs:label "first topic of a synapse"@en ; + rdfs:domain mm:Synapse ; + rdfs:range mm:Topic . + +mm:topic2 a owl:ObjectProperty ; + a owl:FunctionalProperty ; + rdfs:label "second topic of a synapse"@en ; + rdfs:domain mm:Topic ; + rdfs:range mm:Topic . + +mm:mapper a owl:ObjectProperty ; + a owl:FunctionalProperty ; + rdfs:label "Metamaps user who created this topic"@en ; + rdfs:domain mm:Topic ; + rdfs:range foaf:OnlineAccount . + +mm:direction a owl:ObjectProperty ; + a owl:FunctionalProperty ; + rdfs:label "from-to, both, or none"@en ; + rdfs:domain mm:Synapse ; + rdfs:range [ owl:oneOf mm:from-to, mm:both, mm:none ] .