assaydepot 0.0.1 → 0.1.1
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/.gitignore +3 -0
- data/.rspec +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +3 -0
- data/LICENSE.md +10 -0
- data/README.md +30 -6
- data/Rakefile +6 -0
- data/assaydepot.gemspec +9 -3
- data/lib/assaydepot.rb +14 -17
- data/lib/assaydepot/client.rb +78 -15
- data/lib/assaydepot/configurable.rb +1 -1
- data/lib/assaydepot/core.rb +12 -0
- data/lib/assaydepot/endpoints.rb +236 -0
- data/lib/assaydepot/event.rb +21 -0
- data/lib/assaydepot/model.rb +177 -72
- data/lib/assaydepot/version.rb +1 -1
- data/spec/assaydepot_backoffice_spec.rb +30 -0
- data/spec/assaydepot_spec.rb +124 -0
- data/spec/assaydepot_wrapper_spec.rb +230 -0
- metadata +84 -22
- data/LICENSE +0 -22
- data/lib/assaydepot/provider.rb +0 -12
- data/lib/assaydepot/ware.rb +0 -12
@@ -0,0 +1,21 @@
|
|
1
|
+
require "openssl"
|
2
|
+
|
3
|
+
module AssayDepot
|
4
|
+
class Webhook
|
5
|
+
|
6
|
+
def self.construct_event(payload, signature_header, endpoint_secret)
|
7
|
+
sig_hash = {}
|
8
|
+
|
9
|
+
# get t=, v0=, v1= components of the signature
|
10
|
+
signature_header.split(',').each do |str|
|
11
|
+
sig_hash[str.split('=')[0]] = str.split('=')[1]
|
12
|
+
end
|
13
|
+
|
14
|
+
mac = OpenSSL::HMAC.hexdigest("SHA256", "#{sig_hash["t"]}0123456789abcdefghijklmnopqrstuvwxyz", payload)
|
15
|
+
raise AssayDepot::SignatureVerificationError.new "Event (#{Rails.env}) not properly signed." if Rails.env == 'test' || Rails.env == 'development' && mac != sig_hash["v0"]
|
16
|
+
mac = OpenSSL::HMAC.hexdigest("SHA256", "#{sig_hash["t"]}#{endpoint_secret}", payload)
|
17
|
+
raise AssayDepot::SignatureVerificationError.new if Rails.env != 'test' && Rails.env != 'development' && mac != sig_hash["v1"]
|
18
|
+
raise AssayDepot::SignatureVerificationError.new "Invalid timestamp." if sig_hash["t"].to_i < 5.minutes.ago.to_i
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/assaydepot/model.rb
CHANGED
@@ -1,109 +1,214 @@
|
|
1
|
+
require 'forwardable'
|
1
2
|
module AssayDepot
|
2
|
-
module
|
3
|
+
module DatabaseModel
|
3
4
|
module ClassMethods
|
5
|
+
def all(options = {})
|
6
|
+
self.new.all(options)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.included(base)
|
11
|
+
base.include AssayDepot::Model
|
12
|
+
base.extend AssayDepot::Model::ClassMethods
|
13
|
+
base.extend ClassMethods
|
14
|
+
end
|
15
|
+
|
16
|
+
def all(options = {})
|
17
|
+
result = self.clone
|
18
|
+
result.internal_options = options
|
19
|
+
result
|
20
|
+
end
|
21
|
+
|
22
|
+
# Overridden from Model
|
23
|
+
def internal_results
|
24
|
+
unless @internal_results
|
25
|
+
@internal_results = JSON.parse(Client.new(endpoint: self.class.endpoint(nil)).get(params: @internal_options))
|
26
|
+
end
|
27
|
+
@internal_results
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module SearchModel
|
32
|
+
module ClassMethods
|
33
|
+
# find and where to modify params
|
4
34
|
def find(query)
|
5
35
|
self.new.find(query)
|
6
36
|
end
|
37
|
+
|
7
38
|
def where(conditions={})
|
8
39
|
self.new.where(conditions)
|
9
40
|
end
|
10
|
-
def get(id)
|
11
|
-
Client.new(:search_type => search_type).get(id)
|
12
|
-
end
|
13
41
|
end
|
14
42
|
|
15
43
|
def self.included(base)
|
44
|
+
base.extend AssayDepot::Model::ClassMethods
|
16
45
|
base.extend ClassMethods
|
17
|
-
base.
|
18
|
-
base.
|
19
|
-
:each,
|
20
|
-
:[],
|
21
|
-
:count,
|
22
|
-
:collect,
|
23
|
-
:map,
|
24
|
-
:tap,
|
25
|
-
:<=>,
|
26
|
-
:compact,
|
27
|
-
:each_index,
|
28
|
-
:each_with_index,
|
29
|
-
:empty?,
|
30
|
-
:flatten,
|
31
|
-
:include?,
|
32
|
-
:index,
|
33
|
-
:length,
|
34
|
-
:first,
|
35
|
-
:last,
|
36
|
-
:keep_if,
|
37
|
-
:reject,
|
38
|
-
:reverse
|
46
|
+
base.include AssayDepot::Model
|
47
|
+
base.include AssayDepot::Pageable
|
39
48
|
|
40
49
|
attr_accessor :search_query
|
41
50
|
attr_accessor :search_facets
|
42
|
-
|
51
|
+
end
|
43
52
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
53
|
+
def initialize(options={})
|
54
|
+
@internal_options = options[:search_options] || { }
|
55
|
+
@search_query = options[:search_query] || ""
|
56
|
+
@search_facets = options[:search_facets] || { }
|
57
|
+
end
|
49
58
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
@search_facets = @search_facets.dup
|
54
|
-
end
|
59
|
+
def facets
|
60
|
+
internal_results["facets"]
|
61
|
+
end
|
55
62
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
63
|
+
def find(query)
|
64
|
+
result = self.clone
|
65
|
+
result.search_query = query
|
66
|
+
result
|
67
|
+
end
|
68
|
+
|
69
|
+
def where(conditions={})
|
70
|
+
result = self.clone
|
71
|
+
result.search_facets = self.search_facets ? self.search_facets.merge(conditions) : conditions
|
72
|
+
result
|
73
|
+
end
|
74
|
+
|
75
|
+
# Overridden from Model
|
76
|
+
def internal_results
|
77
|
+
unless @internal_results
|
78
|
+
results = Client.new(endpoint: self.class.endpoint(nil)).search(query: search_query, facets: search_facets, params: internal_options)
|
79
|
+
@internal_results = JSON.parse(results)
|
70
80
|
end
|
81
|
+
@internal_results
|
82
|
+
end
|
83
|
+
end
|
71
84
|
|
72
|
-
|
73
|
-
|
85
|
+
module Model
|
86
|
+
module ClassMethods
|
87
|
+
def get_token(client_id, client_secret, site)
|
88
|
+
response = Client.new.request(AssayDepot::TokenAuth.endpoint(site), {}, {}, {:username => client_id, :password => client_secret})
|
89
|
+
response[AssayDepot::TokenAuth.ref_name]
|
74
90
|
end
|
75
91
|
|
76
|
-
def
|
77
|
-
|
92
|
+
def get_endpoint(id, endpoint, format = "json")
|
93
|
+
id = id[0] if id && id.kind_of?(Array)
|
94
|
+
id ? "#{endpoint}/#{id}.#{format}" : "#{endpoint}.#{format}"
|
78
95
|
end
|
79
96
|
|
80
|
-
|
81
|
-
|
82
|
-
|
97
|
+
# HTTP request verbs
|
98
|
+
# optional "id" followed by optional hash
|
99
|
+
def get(id: nil, params: {}, format: "json")
|
100
|
+
puts "GET id #{id}, params #{params}" if ENV["DEBUG"] == "true"
|
101
|
+
result = Client.new(endpoint: endpoint(id, format)).get(params: params)
|
102
|
+
return JSON.parse(result) if format == "json"
|
83
103
|
result
|
84
104
|
end
|
85
105
|
|
86
|
-
def
|
87
|
-
|
88
|
-
result
|
106
|
+
def put(id: nil, body: nil, params: {}, format: "json")
|
107
|
+
puts "PUT id #{id}, body #{body.to_s}, params #{params}" if ENV["DEBUG"] == "true"
|
108
|
+
result = Client.new(endpoint: endpoint(id, format)).put( body: body, params: params )
|
109
|
+
return JSON.parse(result) if format == "json"
|
89
110
|
result
|
90
111
|
end
|
91
112
|
|
92
|
-
def
|
93
|
-
|
94
|
-
result
|
113
|
+
def patch(id: nil, body: nil, params: {}, format: "json")
|
114
|
+
puts "PATCH id #{id}, body #{body.to_s}, params #{params}" if ENV["DEBUG"] == "true"
|
115
|
+
result = Client.new(endpoint: endpoint(id, format)).put( body: body, params: params )
|
116
|
+
return JSON.parse(result) if format == "json"
|
95
117
|
result
|
96
118
|
end
|
97
119
|
|
98
|
-
def
|
99
|
-
|
120
|
+
def post(id: nil, body: nil, params: {}, format: "json")
|
121
|
+
puts "POST id #{id}, body #{body.to_s}, params #{params}" if ENV["DEBUG"] == "true"
|
122
|
+
result = Client.new(endpoint: endpoint(id, format)).post( body: body, params: params )
|
123
|
+
return JSON.parse(result) if format == "json"
|
124
|
+
result
|
100
125
|
end
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
126
|
+
|
127
|
+
def delete(id: nil, body: nil, params: {}, format: "json")
|
128
|
+
puts "DELETE id #{id}, params #{params}" if ENV["DEBUG"] == "true"
|
129
|
+
result = Client.new(endpoint: endpoint(id, format)).delete(params: params)
|
130
|
+
return JSON.parse(result) if format == "json"
|
131
|
+
result
|
106
132
|
end
|
107
133
|
end
|
134
|
+
|
135
|
+
def self.included(base)
|
136
|
+
base.extend ClassMethods
|
137
|
+
base.extend Forwardable
|
138
|
+
base.def_delegators :private_results,
|
139
|
+
:each,
|
140
|
+
:[],
|
141
|
+
:count,
|
142
|
+
:collect,
|
143
|
+
:map,
|
144
|
+
:tap,
|
145
|
+
:<=>,
|
146
|
+
:compact,
|
147
|
+
:each_index,
|
148
|
+
:each_with_index,
|
149
|
+
:empty?,
|
150
|
+
:flatten,
|
151
|
+
:include?,
|
152
|
+
:index,
|
153
|
+
:length,
|
154
|
+
:first,
|
155
|
+
:last,
|
156
|
+
:keep_if,
|
157
|
+
:reject,
|
158
|
+
:reverse
|
159
|
+
|
160
|
+
attr_accessor :internal_options
|
161
|
+
end
|
162
|
+
|
163
|
+
def initialize(options={})
|
164
|
+
@internal_options = options[:search_options] || { }
|
165
|
+
end
|
166
|
+
|
167
|
+
def initialize_copy(source)
|
168
|
+
super
|
169
|
+
@search_query = @search_query.dup
|
170
|
+
@search_facets = @search_facets.dup
|
171
|
+
end
|
172
|
+
|
173
|
+
def query_time
|
174
|
+
internal_results["query_time"]
|
175
|
+
end
|
176
|
+
|
177
|
+
def total
|
178
|
+
internal_results["total"]
|
179
|
+
end
|
180
|
+
|
181
|
+
def options(options={})
|
182
|
+
result = self.clone
|
183
|
+
result.internal_options = self.internal_options ? self.internal_options.merge(options) : options
|
184
|
+
result
|
185
|
+
end
|
186
|
+
|
187
|
+
def private_results
|
188
|
+
internal_results[self.class.ref_name]
|
189
|
+
end
|
190
|
+
|
191
|
+
# def internal_results
|
192
|
+
# # To be overridden
|
193
|
+
# # If I leave this method in, it gets called, possibly a problem with the order of inclusion
|
194
|
+
# end
|
195
|
+
end
|
196
|
+
|
197
|
+
module Pageable
|
198
|
+
def page
|
199
|
+
internal_results["page"]
|
200
|
+
end
|
201
|
+
|
202
|
+
def per_page
|
203
|
+
internal_results["per_page"]
|
204
|
+
end
|
205
|
+
|
206
|
+
def page(page_num)
|
207
|
+
options( { "page" => page_num } )
|
208
|
+
end
|
209
|
+
|
210
|
+
def per_page(page_size)
|
211
|
+
options( { "per_page" => page_size } )
|
212
|
+
end
|
108
213
|
end
|
109
|
-
end
|
214
|
+
end
|
data/lib/assaydepot/version.rb
CHANGED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'assaydepot'
|
2
|
+
require 'dotenv'
|
3
|
+
Dotenv.load
|
4
|
+
|
5
|
+
describe AssayDepot do
|
6
|
+
context "scientist_api backoffice tests" do
|
7
|
+
before(:all) do
|
8
|
+
AssayDepot.configure do |config|
|
9
|
+
config.access_token = ENV['BACKOFFICE_ACCESS_TOKEN']
|
10
|
+
config.url = "#{ENV['BACKOFFICE_SITE']}/api/v2"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context "info" do
|
15
|
+
let(:info) { AssayDepot::Info.get() }
|
16
|
+
|
17
|
+
it "info version V2" do
|
18
|
+
info["api_version"].should == "V2"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "quoted wares" do
|
23
|
+
let(:qw) { AssayDepot::QuotedWare.get() }
|
24
|
+
|
25
|
+
it "get all quoted wares" do
|
26
|
+
qw.is_a?(Array).should == true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'assaydepot'
|
2
|
+
require 'dotenv'
|
3
|
+
Dotenv.load
|
4
|
+
|
5
|
+
describe AssayDepot do
|
6
|
+
context "when accessing the api via token client credentials" do
|
7
|
+
before(:all) do
|
8
|
+
AssayDepot.configure do |config|
|
9
|
+
config.access_token = ENV['ACCESS_TOKEN']
|
10
|
+
config.url = "#{ENV['SITE']}/api/v2"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context "and searching for wares matching \"antibody\"" do
|
15
|
+
let(:wares) { AssayDepot::Ware.find("antibody") }
|
16
|
+
|
17
|
+
it "should return a Ware object" do
|
18
|
+
wares.class.should == AssayDepot::Ware
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should return some wares" do
|
22
|
+
wares.total.should > 1
|
23
|
+
end
|
24
|
+
|
25
|
+
context "and getting the details for the first ware" do
|
26
|
+
let(:ware_result) { AssayDepot::Ware.get(id: wares.first["id"]) }
|
27
|
+
|
28
|
+
it "should have a ware" do
|
29
|
+
ware_result["ware"].should_not be_nil
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should have a description" do
|
33
|
+
ware_result["ware"]["description"].should_not be_nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "when searching for wares of type CustomService" do
|
39
|
+
let(:wares) { AssayDepot::Ware.where(:ware_type => "CustomService") }
|
40
|
+
|
41
|
+
it "should return facets" do
|
42
|
+
wares.facets.should_not be_empty
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should include the source facet" do
|
46
|
+
wares.facets.should include("source")
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should include the ware_type facet" do
|
50
|
+
wares.facets.should include("ware_type")
|
51
|
+
end
|
52
|
+
|
53
|
+
# RR: replaced "available_provider_names"
|
54
|
+
it "should include the technology facet" do
|
55
|
+
wares.facets.should include("technology")
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should include the certifications facet" do
|
59
|
+
wares.facets.should include("certifications")
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should include the countries facet" do
|
63
|
+
wares.facets.should include("countries")
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should include the protein_type facet" do
|
67
|
+
wares.facets.should include("protein_type")
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should include the clonality facet" do
|
71
|
+
wares.facets.should include("clonality")
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should include the cell_source facet" do
|
75
|
+
wares.facets.should include("cell_source")
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should include the species facet" do
|
79
|
+
wares.facets.should include("species")
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should include the tissue facet" do
|
83
|
+
wares.facets.should include("tissue")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context "when searching for wares using a chained query" do
|
88
|
+
let(:wares) { AssayDepot::Ware.where(:ware_type => "CustomService").where(:source => "central-staging") }
|
89
|
+
|
90
|
+
it "should return wares" do
|
91
|
+
wares.total.should > 0
|
92
|
+
end
|
93
|
+
|
94
|
+
it "the ware's name should be available" do
|
95
|
+
wares.first["name"].should_not be_nil
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context "and searching for providers that start with the letter a" do
|
100
|
+
let(:starts_with) {AssayDepot::Provider.get()["facets"]["starts_with"]["buckets"].first}
|
101
|
+
let(:providers) { AssayDepot::Provider.where(:starts_with => starts_with["key"]).per_page(50) }
|
102
|
+
|
103
|
+
it "should return a Provider object" do
|
104
|
+
providers.class.should == AssayDepot::Provider
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should return some providers" do
|
108
|
+
providers.total.should == starts_with["doc_count"]
|
109
|
+
end
|
110
|
+
|
111
|
+
context "and getting the details for the first provider" do
|
112
|
+
let(:provider_result) { AssayDepot::Provider.get(id: providers.first["id"]) }
|
113
|
+
|
114
|
+
it "have a provider" do
|
115
|
+
provider_result["provider"].should_not be_nil
|
116
|
+
end
|
117
|
+
|
118
|
+
it "have keywords" do
|
119
|
+
expect(provider_result['provider']).to have_key('keywords')
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|