openbel-api 0.4.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gemspec +65 -0
- data/CHANGELOG.md +22 -0
- data/INSTALL.md +19 -0
- data/INSTALL_RUBY.md +107 -0
- data/LICENSE +191 -0
- data/README.md +208 -0
- data/app/openbel/api/app.rb +83 -0
- data/app/openbel/api/config.rb +45 -0
- data/app/openbel/api/config.ru +3 -0
- data/app/openbel/api/helpers/pager.rb +109 -0
- data/app/openbel/api/middleware/auth.rb +112 -0
- data/app/openbel/api/resources/adapters/basic_json.rb +52 -0
- data/app/openbel/api/resources/annotation.rb +141 -0
- data/app/openbel/api/resources/base.rb +16 -0
- data/app/openbel/api/resources/completion.rb +89 -0
- data/app/openbel/api/resources/evidence.rb +115 -0
- data/app/openbel/api/resources/evidence_transform.rb +143 -0
- data/app/openbel/api/resources/function.rb +98 -0
- data/app/openbel/api/resources/match_result.rb +79 -0
- data/app/openbel/api/resources/namespace.rb +174 -0
- data/app/openbel/api/routes/annotations.rb +168 -0
- data/app/openbel/api/routes/authenticate.rb +108 -0
- data/app/openbel/api/routes/base.rb +326 -0
- data/app/openbel/api/routes/datasets.rb +519 -0
- data/app/openbel/api/routes/evidence.rb +330 -0
- data/app/openbel/api/routes/expressions.rb +560 -0
- data/app/openbel/api/routes/functions.rb +41 -0
- data/app/openbel/api/routes/namespaces.rb +382 -0
- data/app/openbel/api/routes/root.rb +39 -0
- data/app/openbel/api/schemas.rb +34 -0
- data/app/openbel/api/schemas/annotation_collection.schema.json +20 -0
- data/app/openbel/api/schemas/annotation_resource.schema.json +36 -0
- data/app/openbel/api/schemas/annotation_value_collection.schema.json +21 -0
- data/app/openbel/api/schemas/annotation_value_resource.schema.json +35 -0
- data/app/openbel/api/schemas/completion_collection.schema.json +21 -0
- data/app/openbel/api/schemas/completion_resource.schema.json +146 -0
- data/app/openbel/api/schemas/evidence.schema.json +198 -0
- data/app/openbel/api/schemas/evidence_collection.schema.json +98 -0
- data/app/openbel/api/schemas/evidence_resource.schema.json +29 -0
- data/app/openbel/api/schemas/namespace_value_collection.schema.json +21 -0
- data/app/openbel/api/schemas/namespace_value_resource.schema.json +43 -0
- data/app/openbel/api/util.rb +11 -0
- data/bin/openbel-api +78 -0
- data/bin/openbel-config +46 -0
- data/config/async_evidence.rb +12 -0
- data/config/async_jena.rb +14 -0
- data/config/config.yml +31 -0
- data/config/server_config.rb +184 -0
- data/lib/openbel/api/cache/cache.rb +30 -0
- data/lib/openbel/api/config/config.rb +33 -0
- data/lib/openbel/api/evidence/api.rb +39 -0
- data/lib/openbel/api/evidence/facet_api.rb +18 -0
- data/lib/openbel/api/evidence/facet_filter.rb +83 -0
- data/lib/openbel/api/evidence/mongo.rb +247 -0
- data/lib/openbel/api/evidence/mongo_facet.rb +105 -0
- data/lib/openbel/api/helpers/dependency_graph.rb +52 -0
- data/lib/openbel/api/model/rdf_resource.rb +74 -0
- data/lib/openbel/api/plugin/cache/kyotocabinet.rb +85 -0
- data/lib/openbel/api/plugin/configure_plugins.rb +97 -0
- data/lib/openbel/api/plugin/evidence/evidence.rb +58 -0
- data/lib/openbel/api/plugin/plugin.rb +99 -0
- data/lib/openbel/api/plugin/plugin_manager.rb +20 -0
- data/lib/openbel/api/plugin/plugin_repository.rb +60 -0
- data/lib/openbel/api/storage/cache_proxy.rb +74 -0
- data/lib/openbel/api/storage/triple_storage.rb +43 -0
- metadata +379 -0
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
# TODO This should probably be in app-config.rb.
|
4
|
+
require 'jrjackson'
|
5
|
+
|
6
|
+
require_relative 'util'
|
7
|
+
|
8
|
+
require 'rack/cors'
|
9
|
+
require 'sinatra/base'
|
10
|
+
require "sinatra/reloader"
|
11
|
+
require "sinatra/cookies"
|
12
|
+
|
13
|
+
require_relative 'config'
|
14
|
+
require_relative 'routes/base'
|
15
|
+
require_relative 'routes/root'
|
16
|
+
require_relative 'routes/annotations'
|
17
|
+
require_relative 'routes/evidence'
|
18
|
+
require_relative 'routes/datasets'
|
19
|
+
require_relative 'routes/expressions'
|
20
|
+
require_relative 'routes/functions'
|
21
|
+
require_relative 'routes/namespaces'
|
22
|
+
require_relative 'routes/authenticate'
|
23
|
+
require_relative 'middleware/auth'
|
24
|
+
|
25
|
+
module OpenBEL
|
26
|
+
|
27
|
+
class Server < Sinatra::Application
|
28
|
+
|
29
|
+
configure :development do
|
30
|
+
register Sinatra::Reloader
|
31
|
+
end
|
32
|
+
|
33
|
+
configure do
|
34
|
+
config = OpenBEL::Config::load!
|
35
|
+
OpenBEL.const_set :Settings, config
|
36
|
+
end
|
37
|
+
|
38
|
+
if OpenBEL::Settings[:auth][:enabled]
|
39
|
+
enable :sessions
|
40
|
+
set :session_secret, OpenBEL::Settings['session_secret']
|
41
|
+
end
|
42
|
+
|
43
|
+
use Rack::Deflater
|
44
|
+
use Rack::Cors do
|
45
|
+
allow do
|
46
|
+
origins '*'
|
47
|
+
resource '*',
|
48
|
+
:headers => :any,
|
49
|
+
:methods => [ :get, :post, :put, :delete, :options ],
|
50
|
+
:max_age => 1,
|
51
|
+
:credentials => false,
|
52
|
+
:expose => [
|
53
|
+
'Allow',
|
54
|
+
'Content-Type',
|
55
|
+
'Content-Encoding',
|
56
|
+
'Content-Length',
|
57
|
+
'ETag',
|
58
|
+
'Last-Modified',
|
59
|
+
'Link',
|
60
|
+
'Location'
|
61
|
+
]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
disable :protection
|
65
|
+
|
66
|
+
# routes not requiring authentication
|
67
|
+
use OpenBEL::Routes::Root
|
68
|
+
use OpenBEL::Routes::Annotations
|
69
|
+
use OpenBEL::Routes::Expressions
|
70
|
+
use OpenBEL::Routes::Functions
|
71
|
+
use OpenBEL::Routes::Namespaces
|
72
|
+
use OpenBEL::Routes::Authenticate
|
73
|
+
|
74
|
+
# routes requiring authentication
|
75
|
+
if OpenBEL::Settings[:auth][:enabled]
|
76
|
+
use OpenBEL::JWTMiddleware::Authentication
|
77
|
+
end
|
78
|
+
use OpenBEL::Routes::Datasets
|
79
|
+
use OpenBEL::Routes::Evidence
|
80
|
+
end
|
81
|
+
end
|
82
|
+
# vim: ts=2 sts=2 sw=2
|
83
|
+
# encoding: utf-8
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'dot_hash'
|
2
|
+
|
3
|
+
module OpenBEL
|
4
|
+
module Config
|
5
|
+
include DotHash
|
6
|
+
|
7
|
+
CFG_VAR = 'OPENBEL_API_CONFIG_FILE'
|
8
|
+
|
9
|
+
def self.load!
|
10
|
+
config_file = ENV[CFG_VAR] || raise('No OpenBEL API configuration found. Set the OPENBEL_API_CONFIG_FILE environment variable.')
|
11
|
+
config = {}
|
12
|
+
File.open(config_file, 'r:UTF-8') do |cf|
|
13
|
+
config = YAML::load(cf)
|
14
|
+
if not config
|
15
|
+
config = {}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
cfg = Settings.new config, SilentProperties
|
19
|
+
|
20
|
+
failure = validate cfg
|
21
|
+
if failure
|
22
|
+
if block_given?
|
23
|
+
yield failure[1]
|
24
|
+
else
|
25
|
+
fail "Configuration error: #{failure[1]}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
cfg
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def self.validate(cfg)
|
35
|
+
nil
|
36
|
+
end
|
37
|
+
|
38
|
+
class SilentProperties < Properties
|
39
|
+
def method_missing(key, *args, &block)
|
40
|
+
return nil unless has_key?(key)
|
41
|
+
execute(key, *args, &block)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module OpenBEL
|
2
|
+
module Helpers
|
3
|
+
|
4
|
+
class Pager
|
5
|
+
|
6
|
+
NEGATIVE_FUNCTION = lambda { |v| v < 0 ? 0 : v }
|
7
|
+
FLOAT_FUNCTION = lambda { |v| Float(v) }
|
8
|
+
PREVIOUS_COND_FUNCTION = lambda { |pager, neg_proc, pos_proc|
|
9
|
+
[
|
10
|
+
pager.start_offset,
|
11
|
+
pager.page_size,
|
12
|
+
].any?(&(lambda { |v| v <= 0 })) ?
|
13
|
+
neg_proc.call(pager) :
|
14
|
+
pos_proc.call(pager)
|
15
|
+
}
|
16
|
+
NEXT_COND_FUNCTION = lambda { |pager, false_proc, true_proc|
|
17
|
+
test = pager.page_size > 0
|
18
|
+
test &= (pager.start_offset + pager.page_size) <= pager.total_size
|
19
|
+
|
20
|
+
test ?
|
21
|
+
true_proc.call(pager) :
|
22
|
+
false_proc.call(pager)
|
23
|
+
}
|
24
|
+
|
25
|
+
private_constant :NEGATIVE_FUNCTION
|
26
|
+
private_constant :FLOAT_FUNCTION
|
27
|
+
private_constant :PREVIOUS_COND_FUNCTION
|
28
|
+
private_constant :NEXT_COND_FUNCTION
|
29
|
+
|
30
|
+
def initialize(start_offset, page_size, total_size)
|
31
|
+
raise ArgumentError.new("start_offset must be >= 0") if start_offset < 0
|
32
|
+
raise ArgumentError.new("page_size must be >= 0") if page_size < 0
|
33
|
+
raise ArgumentError.new("total_size must be >= 0") if total_size < 0
|
34
|
+
|
35
|
+
@start_offset = NEGATIVE_FUNCTION.call(start_offset)
|
36
|
+
@page_size = FLOAT_FUNCTION.call(page_size)
|
37
|
+
@total_size = total_size
|
38
|
+
end
|
39
|
+
|
40
|
+
def start_offset
|
41
|
+
@start_offset
|
42
|
+
end
|
43
|
+
|
44
|
+
def current_page
|
45
|
+
return 0 if @total_size == 0
|
46
|
+
|
47
|
+
if @page_size > 0
|
48
|
+
((@start_offset + @page_size) / @page_size).floor
|
49
|
+
else
|
50
|
+
total_pages = total_pages()
|
51
|
+
|
52
|
+
case total_pages
|
53
|
+
when 1
|
54
|
+
1
|
55
|
+
when 2
|
56
|
+
midpoint = @total_size / total_pages
|
57
|
+
@start_offset < midpoint ? 1 : 2
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def page_size
|
63
|
+
@page_size.to_i
|
64
|
+
end
|
65
|
+
|
66
|
+
def total_pages
|
67
|
+
return 0 if @total_size == 0
|
68
|
+
|
69
|
+
if @page_size > 0
|
70
|
+
(@total_size / @page_size).ceil
|
71
|
+
else
|
72
|
+
@start_offset == 0 ? 1 : 2
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def total_size
|
77
|
+
@total_size
|
78
|
+
end
|
79
|
+
|
80
|
+
def previous_page
|
81
|
+
PREVIOUS_COND_FUNCTION.call(
|
82
|
+
self,
|
83
|
+
lambda { |_| nil },
|
84
|
+
lambda { |pager|
|
85
|
+
Pager.new(
|
86
|
+
NEGATIVE_FUNCTION.call(start_offset - page_size),
|
87
|
+
page_size,
|
88
|
+
total_size
|
89
|
+
)
|
90
|
+
}
|
91
|
+
)
|
92
|
+
end
|
93
|
+
|
94
|
+
def next_page
|
95
|
+
NEXT_COND_FUNCTION.call(
|
96
|
+
self,
|
97
|
+
lambda { |_| nil },
|
98
|
+
lambda { |pager|
|
99
|
+
Pager.new(
|
100
|
+
NEGATIVE_FUNCTION.call(start_offset + page_size),
|
101
|
+
page_size,
|
102
|
+
total_size
|
103
|
+
)
|
104
|
+
}
|
105
|
+
)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'sinatra/base'
|
3
|
+
require 'jwt'
|
4
|
+
|
5
|
+
module OpenBEL
|
6
|
+
module JWTMiddleware
|
7
|
+
|
8
|
+
def self.encode(payload, secret)
|
9
|
+
::JWT.encode(payload, secret, 'HS256')
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.decode(token, secret, verify, options)
|
13
|
+
::JWT.decode(token, secret, verify, options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.check_cookie(env)
|
17
|
+
cookie_hdr = env['HTTP_COOKIE']
|
18
|
+
auth_hdr = env['HTTP_AUTHORIZATION']
|
19
|
+
if cookie_hdr.nil? and auth_hdr.nil?
|
20
|
+
raise 'missing authorization cookie/header'
|
21
|
+
end
|
22
|
+
|
23
|
+
if not cookie_hdr.nil?
|
24
|
+
cookies = cookie_hdr.split('; ')
|
25
|
+
selected = cookies.select {|x| x.start_with?('jwt=') }
|
26
|
+
if selected.size > 0
|
27
|
+
tokens = selected[0].split('=')
|
28
|
+
if tokens.size > 1
|
29
|
+
token = tokens[1]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
if token.nil?
|
33
|
+
raise 'missing authorization cookie'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
if not auth_hdr.nil?
|
38
|
+
tokens = auth_hdr.split('Bearer ')
|
39
|
+
if tokens.size == 2
|
40
|
+
token = tokens[1]
|
41
|
+
end
|
42
|
+
if token.nil?
|
43
|
+
raise 'missing authorization header'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
secret = OpenBEL::Settings[:auth][:secret]
|
48
|
+
secret = Base64.decode64(secret)
|
49
|
+
# whether we should verify the token
|
50
|
+
verify = true
|
51
|
+
# JWT options passed to decode
|
52
|
+
options = {}
|
53
|
+
|
54
|
+
begin
|
55
|
+
decoded_token = decode(token, secret, verify, options)
|
56
|
+
rescue ::JWT::VerificationError => ve
|
57
|
+
raise 'invalid authorization token'
|
58
|
+
rescue ::JWT::DecodeError => je
|
59
|
+
puts je.inspect
|
60
|
+
raise 'malformed authorization token'
|
61
|
+
end
|
62
|
+
env['jwt.header'] = decoded_token.last unless decoded_token.nil?
|
63
|
+
env['jwt.payload'] = decoded_token.first unless decoded_token.nil?
|
64
|
+
|
65
|
+
exp = env['jwt.payload']['exp']
|
66
|
+
now = Time.now.to_i
|
67
|
+
if now > exp
|
68
|
+
raise 'token expired'
|
69
|
+
end
|
70
|
+
|
71
|
+
env['email'] = env['jwt.payload']['email']
|
72
|
+
end
|
73
|
+
|
74
|
+
class Authentication
|
75
|
+
def initialize(app, opts = {})
|
76
|
+
@app = app
|
77
|
+
@paths = opts.fetch(:paths, [])
|
78
|
+
end
|
79
|
+
|
80
|
+
def call(env)
|
81
|
+
check = false
|
82
|
+
if @paths.size == 0
|
83
|
+
# w/out paths, always check for token
|
84
|
+
check = true
|
85
|
+
else
|
86
|
+
path = env['PATH_INFO']
|
87
|
+
# w/ paths, only check for token iff matched
|
88
|
+
if @paths.any? {|x| path.start_with?(x)}
|
89
|
+
check = true
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
if check
|
94
|
+
begin
|
95
|
+
JWTMiddleware.check_cookie(env)
|
96
|
+
rescue Exception => e
|
97
|
+
return _401(e.message)
|
98
|
+
end
|
99
|
+
@app.call(env)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def _401(message)
|
106
|
+
hdrs = {'Content-Type' => 'application/json'}
|
107
|
+
msg = {error: message }
|
108
|
+
[401, hdrs, [msg.to_json]]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Oat
|
2
|
+
module Adapters
|
3
|
+
class BasicJson < Oat::Adapter
|
4
|
+
def link(rel, opts = {})
|
5
|
+
# no-op to maintain interface compatibility with hypermedia adapters
|
6
|
+
end
|
7
|
+
|
8
|
+
def link(rel, opts = {})
|
9
|
+
if opts.is_a?(Array)
|
10
|
+
data[:_links][rel] = opts.select { |link_obj| link_obj.include?(:href) }
|
11
|
+
else
|
12
|
+
data[:_links][rel] = opts if opts[:href]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def properties(&block)
|
17
|
+
data.merge! yield_props(&block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def property(key, value)
|
21
|
+
data[key] = value
|
22
|
+
end
|
23
|
+
|
24
|
+
alias_method :meta, :property
|
25
|
+
|
26
|
+
def rel(rels)
|
27
|
+
# no-op to maintain interface compatibility with the Siren adapter
|
28
|
+
end
|
29
|
+
|
30
|
+
def entity(name, obj, serializer_class = nil, context_options = {}, &block)
|
31
|
+
entity_serializer = serializer_from_block_or_class(obj, serializer_class, context_options, &block)
|
32
|
+
data[entity_name(name)] = entity_serializer ? entity_serializer.to_hash : nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def entities(name, collection, serializer_class = nil, context_options = {}, &block)
|
36
|
+
data[entity_name(name)] = collection.map do |obj|
|
37
|
+
entity_serializer = serializer_from_block_or_class(obj, serializer_class, context_options, &block)
|
38
|
+
entity_serializer ? entity_serializer.to_hash : nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
alias_method :collection, :entities
|
42
|
+
|
43
|
+
def entity_name(name)
|
44
|
+
# entity name may be an array, but HAL only uses the first
|
45
|
+
name.respond_to?(:first) ? name.first : name
|
46
|
+
end
|
47
|
+
|
48
|
+
private :entity_name
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module OpenBEL
|
4
|
+
module Resource
|
5
|
+
module Annotations
|
6
|
+
|
7
|
+
VOCABULARY_RDF = 'http://www.openbel.org/vocabulary/'
|
8
|
+
|
9
|
+
class AnnotationValueSearchResult < BEL::Resource::AnnotationValue
|
10
|
+
|
11
|
+
def match_text=(match_text)
|
12
|
+
@match_text = match_text
|
13
|
+
end
|
14
|
+
|
15
|
+
def match_text
|
16
|
+
@match_text
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class AnnotationSerializer < BaseSerializer
|
21
|
+
# adapter Oat::Adapters::HAL
|
22
|
+
schema do
|
23
|
+
type :annotation
|
24
|
+
property :rdf_uri, item.uri.to_s
|
25
|
+
property :name, item.prefLabel
|
26
|
+
property :prefix, item.prefix
|
27
|
+
property :domain, item.domain
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class AnnotationResourceSerializer < BaseSerializer
|
32
|
+
adapter Oat::Adapters::HAL
|
33
|
+
schema do
|
34
|
+
type :annotation
|
35
|
+
property :annotation, item
|
36
|
+
link :self, link_self(item[:prefix])
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def link_self(id)
|
42
|
+
{
|
43
|
+
:type => :annotation,
|
44
|
+
:href => "#{base_url}/api/annotations/#{id}"
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def link_collection
|
49
|
+
{
|
50
|
+
:type => :annotation_collection,
|
51
|
+
:href => "#{base_url}/api/annotations"
|
52
|
+
}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class AnnotationCollectionSerializer < BaseSerializer
|
57
|
+
adapter Oat::Adapters::HAL
|
58
|
+
schema do
|
59
|
+
type :annotation_collection
|
60
|
+
property :annotation_collection, item
|
61
|
+
link :self, link_self
|
62
|
+
link :start, link_start
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def link_self
|
68
|
+
{
|
69
|
+
:type => :annotation_collection,
|
70
|
+
:href => "#{base_url}/api/annotations"
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
def link_start
|
75
|
+
{
|
76
|
+
:type => :start,
|
77
|
+
:href => "#{base_url}/api/annotations/values"
|
78
|
+
}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class AnnotationValueSerializer < BaseSerializer
|
83
|
+
#adapter Oat::Adapters::HAL
|
84
|
+
schema do
|
85
|
+
type :annotation_value
|
86
|
+
property :rdf_uri, item.uri.to_s
|
87
|
+
property :type, [item.type].flatten.map(&:to_s)
|
88
|
+
property :identifier, item.identifier
|
89
|
+
property :name, item.prefLabel
|
90
|
+
entity :annotation, item.annotation, AnnotationSerializer
|
91
|
+
|
92
|
+
# Support inclusion of the matched text when annotation values are filtered by
|
93
|
+
# a full-text search.
|
94
|
+
if item.match_text
|
95
|
+
property :match_text, item.match_text
|
96
|
+
end
|
97
|
+
|
98
|
+
setup(item)
|
99
|
+
link :self, link_self
|
100
|
+
link :collection, link_annotation
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def setup(item)
|
106
|
+
@annotation_id, @annotation_value_id = URI(item.uri).path.split('/')[3..-1]
|
107
|
+
end
|
108
|
+
|
109
|
+
def link_self
|
110
|
+
{
|
111
|
+
:type => :annotation_value,
|
112
|
+
:href => "#{base_url}/api/annotations/#{@annotation_id}/values/#{@annotation_value_id}"
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
def link_annotation
|
117
|
+
{
|
118
|
+
:type => :annotation,
|
119
|
+
:href => "#{base_url}/api/annotations/#{@annotation_id}"
|
120
|
+
}
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class AnnotationValueResourceSerializer < BaseSerializer
|
125
|
+
adapter Oat::Adapters::HAL
|
126
|
+
schema do
|
127
|
+
type :annotation_value
|
128
|
+
property :annotation_value, item
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
class AnnotationValueCollectionSerializer < BaseSerializer
|
133
|
+
adapter Oat::Adapters::HAL
|
134
|
+
schema do
|
135
|
+
type :annotation_value_collection
|
136
|
+
property :annotation_value_collection, item
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|