mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-09-20 14:45:56 +08:00
Add search service and normalizer for list
This commit is contained in:
parent
4f6397b5b9
commit
7fad5fc594
70
app/services/protocol_importers/search_protocols_service.rb
Normal file
70
app/services/protocol_importers/search_protocols_service.rb
Normal file
|
@ -0,0 +1,70 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ProtocolImporters
|
||||
class SearchProtocolsService
|
||||
extend Service
|
||||
|
||||
attr_reader :errors, :protocols_list
|
||||
|
||||
CONSTANTS = Constants::PROTOCOLS_IO_V3_API
|
||||
|
||||
def initialize(protocol_source:, query_params: {})
|
||||
@protocol_source = protocol_source
|
||||
@query_params = query_params
|
||||
@errors = Hash.new { |h, k| h[k] = {} }
|
||||
end
|
||||
|
||||
def call
|
||||
return self unless valid?
|
||||
|
||||
api_response = api_client.protocol_list(@query_params)
|
||||
|
||||
@protocols_list = normalizer.normalize_list(api_response)
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
def succeed?
|
||||
@errors.none?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def valid?
|
||||
# try if key is not empty
|
||||
@errors[:invalid_params][:key] = 'Key cannot be empty' if @query_params[:key].blank?
|
||||
|
||||
# try if page id is ok
|
||||
if @query_params[:page_id] && !@query_params[:page_id].positive?
|
||||
@errors[:invalid_params][:page_id] = 'Page needs to be positive'
|
||||
end
|
||||
|
||||
# try if order_field is ok
|
||||
if CONSTANTS[:available_order_fields]&.exclude? @query_params[:order_field].to_sym
|
||||
@errors[:invalid_params][:order_field] = 'Order field is not ok'
|
||||
end
|
||||
|
||||
# try if order dir is ok
|
||||
if CONSTANTS[:available_order_dirs]&.exclude? @query_params[:order_dir].to_sym
|
||||
@errors[:invalid_params][:order_dir] = 'Order dir is not ok'
|
||||
end
|
||||
|
||||
# try if endpints exists
|
||||
@errors[:invalid_params][:source_endpoint] = 'Wrong source endpoint' unless endpoint_name&.is_a?(String)
|
||||
|
||||
succeed?
|
||||
end
|
||||
|
||||
def endpoint_name
|
||||
Constants::PROTOCOLS_ENDPOINTS.dig(*@protocol_source.split('/').map(&:to_sym))
|
||||
end
|
||||
|
||||
def api_client
|
||||
"ProtocolImporters::#{endpoint_name}::ApiClient".constantize.new
|
||||
end
|
||||
|
||||
def normalizer
|
||||
"ProtocolImporters::#{endpoint_name}::ProtocolNormalizer".constantize.new
|
||||
end
|
||||
end
|
||||
end
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
module ProtocolImporters
|
||||
class ProtocolNormalizer
|
||||
def normalize_all_protocols(_client_data)
|
||||
def normalize_list(_client_data)
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
|
|
|
@ -50,6 +50,24 @@ module ProtocolImporters
|
|||
|
||||
{ protocol: normalized_data }
|
||||
end
|
||||
|
||||
def normalize_list(client_data)
|
||||
# client_data is HttpParty ApiReponse object
|
||||
protocols_hash = client_data.parsed_response.with_indifferent_access[:items]
|
||||
normalized_data = {}
|
||||
normalized_data[:protocols] = protocols_hash.map do |e|
|
||||
{
|
||||
"id": e[:id],
|
||||
"title": e[:title],
|
||||
"created_on": e[:created_on],
|
||||
"authors": e[:authors].map { |a| a[:name] }.join(', '),
|
||||
"nr_of_steps": e[:stats][:number_of_steps],
|
||||
"nr_of_views": e[:stats][:number_of_views],
|
||||
"uri": e[:uri]
|
||||
}
|
||||
end
|
||||
normalized_data
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -203,6 +203,8 @@ class Constants
|
|||
base_uri: 'https://www.protocols.io/api/v3/',
|
||||
default_timeout: 10,
|
||||
debug_level: :debug,
|
||||
available_order_fields: %i(title created_on),
|
||||
available_order_dirs: %i(asc desc),
|
||||
endpoints: {
|
||||
protocols: {
|
||||
default_query_params: {
|
||||
|
|
94
spec/fixtures/files/protocol_importers/normalized_list.json
vendored
Normal file
94
spec/fixtures/files/protocol_importers/normalized_list.json
vendored
Normal file
|
@ -0,0 +1,94 @@
|
|||
{
|
||||
"protocols": [
|
||||
{
|
||||
"id": 22532,
|
||||
"title": "Producing rooted cassava plantlets for use in pot experiments",
|
||||
"created_on": 1556012701,
|
||||
"authors": "Matema Imakumbili",
|
||||
"nr_of_steps": 13,
|
||||
"nr_of_views": 37,
|
||||
"uri": "producing-rooted-cassava-plantlets-for-use-in-pot-z9cf92w"
|
||||
},
|
||||
{
|
||||
"id": 832,
|
||||
"title": "Preparation of Virus DNA from Seawater for Metagenomics",
|
||||
"created_on": 1434495014,
|
||||
"authors": "Matthew Sullivan Lab",
|
||||
"nr_of_steps": 11,
|
||||
"nr_of_views": 457,
|
||||
"uri": "Preparation-of-Virus-DNA-from-Seawater-for-Metagen-c28yhv"
|
||||
},
|
||||
{
|
||||
"id": 14506,
|
||||
"title": "MALE CIRCUMCISION FOR PREVENTION OF HETEROSEXUAL TRANSMISSION OF HIV IN ADULT MALES IN SOWETO, what do indicators and incidence rates show?untitled protocol",
|
||||
"created_on": 1533553359,
|
||||
"authors": "Hillary Mukudu, Neil Martinson, Benn Sartorius",
|
||||
"nr_of_steps": 0,
|
||||
"nr_of_views": 5,
|
||||
"uri": "male-circumcision-for-prevention-of-heterosexual-t-seiebce"
|
||||
},
|
||||
{
|
||||
"id": 10927,
|
||||
"title": "physiological and biochemical parameters",
|
||||
"created_on": 1521454618,
|
||||
"authors": "Amor Slama, Elhem Mallek-Maalej, Hatem Ben Mohamed, Thouraya Rhim, Leila Radhouane, Amor SLAMA",
|
||||
"nr_of_steps": 0,
|
||||
"nr_of_views": 34,
|
||||
"uri": "physiological-and-biochemical-parameters-nwpdfdn"
|
||||
},
|
||||
{
|
||||
"id": 822,
|
||||
"title": "Iron Chloride Precipitation of Viruses from Seawater",
|
||||
"created_on": 1434402745,
|
||||
"authors": "Seth John, Bonnie Poulos, Christine Schirmer",
|
||||
"nr_of_steps": 17,
|
||||
"nr_of_views": 1805,
|
||||
"uri": "Iron-Chloride-Precipitation-of-Viruses-from-Seawat-c2wyfd"
|
||||
},
|
||||
{
|
||||
"id": 12115,
|
||||
"title": "Measuring specific leaf area and water content",
|
||||
"created_on": 1526074093,
|
||||
"authors": "Etienne Laliberté",
|
||||
"nr_of_steps": 33,
|
||||
"nr_of_views": 259,
|
||||
"uri": "measuring-specific-leaf-area-and-water-content-p3tdqnn"
|
||||
},
|
||||
{
|
||||
"id": 1842,
|
||||
"title": "Purification of viral assemblages from seawater in CsCl gradients",
|
||||
"created_on": 1445287995,
|
||||
"authors": "Janice E. Lawrence and Grieg F. Steward",
|
||||
"nr_of_steps": 23,
|
||||
"nr_of_views": 116,
|
||||
"uri": "Purification-of-viral-assemblages-from-seawater-in-d2s8ed"
|
||||
},
|
||||
{
|
||||
"id": 12540,
|
||||
"title": "An improved primer set and PCR amplification protocol with increased specificity and sensitivity targeting the Symbiodinium ITS2 region using the SymVar primer pair",
|
||||
"created_on": 1527418313,
|
||||
"authors": "Benjamin Hume, Maren Ziegler, Christian Voolstra, Julie Poulain, Xavier Pochon, Sarah Romac, Emilie Boissin, Colomban de Vargas, Serge Planes, Patrick Wincker",
|
||||
"nr_of_steps": 1,
|
||||
"nr_of_views": 234,
|
||||
"uri": "an-improved-primer-set-and-pcr-amplification-proto-qg4dtyw"
|
||||
},
|
||||
{
|
||||
"id": 985,
|
||||
"title": "NATURAL SEAWATER-BASED PRO99 MEDIUM",
|
||||
"created_on": 1435347035,
|
||||
"authors": "Chisholm Lab",
|
||||
"nr_of_steps": 10,
|
||||
"nr_of_views": 85,
|
||||
"uri": "NATURAL-SEAWATER-BASED-PRO99-MEDIUM-c7zzp5"
|
||||
},
|
||||
{
|
||||
"id": 1033,
|
||||
"title": "SN Maintenance Medium for Synechococcus",
|
||||
"created_on": 1435778857,
|
||||
"authors": "JB Waterbury \u0026 JM Willey",
|
||||
"nr_of_steps": 6,
|
||||
"nr_of_views": 33,
|
||||
"uri": "SN-Maintenance-Medium-for-Synechococcus-c9hz35"
|
||||
}
|
||||
]
|
||||
}
|
3072
spec/fixtures/files/protocol_importers/protocols_io/v3/protocols.json
vendored
Normal file
3072
spec/fixtures/files/protocol_importers/protocols_io/v3/protocols.json
vendored
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,52 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe ProtocolImporters::SearchProtocolsService do
|
||||
let(:service_call) do
|
||||
ProtocolImporters::SearchProtocolsService.call(protocol_source: 'protocolsio/v3',
|
||||
query_params: {
|
||||
key: 'someting',
|
||||
page_id: 5,
|
||||
order_field: 'title',
|
||||
order_dir: 'asc'
|
||||
})
|
||||
end
|
||||
|
||||
let(:service_call_with_wrong_params) do
|
||||
ProtocolImporters::SearchProtocolsService.call(protocol_source: 'protocolsio3',
|
||||
query_params: {
|
||||
key: '',
|
||||
page_id: -1,
|
||||
order_field: 'gender',
|
||||
order_dir: 'descc'
|
||||
})
|
||||
end
|
||||
let(:normalized_list) do
|
||||
JSON.parse(file_fixture('protocol_importers/normalized_list.json').read).to_h.with_indifferent_access
|
||||
end
|
||||
|
||||
context 'when have invalid attributes' do
|
||||
it 'returns an error when params are invalid' do
|
||||
expect(service_call_with_wrong_params.errors).to have_key(:invalid_params)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when have valid attributes' do
|
||||
before do
|
||||
client_data = double('api_response')
|
||||
|
||||
allow_any_instance_of(ProtocolImporters::ProtocolsIO::V3::ApiClient)
|
||||
.to(receive(:protocol_list)
|
||||
.and_return(client_data))
|
||||
|
||||
allow_any_instance_of(ProtocolImporters::ProtocolsIO::V3::ProtocolNormalizer)
|
||||
.to(receive(:normalize_list).with(client_data)
|
||||
.and_return(normalized_list))
|
||||
end
|
||||
|
||||
it 'returns an error when params are invalid' do
|
||||
expect(service_call.protocols_list).to be == normalized_list
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,11 +3,11 @@
|
|||
require 'rails_helper'
|
||||
|
||||
describe ProtocolImporters::ProtocolNormalizer do
|
||||
describe '.normalize_all_protocols' do
|
||||
it { expect { subject.normalize_all_protocols({}) }.to raise_error(NotImplementedError) }
|
||||
describe '.normalize_list' do
|
||||
it { expect { subject.normalize_list({}) }.to raise_error(NotImplementedError) }
|
||||
end
|
||||
|
||||
describe '.normalize_protocols' do
|
||||
describe '.normalize_protocol' do
|
||||
it { expect { subject.normalize_protocol({}) }.to raise_error(NotImplementedError) }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,20 +5,27 @@ require 'rails_helper'
|
|||
describe ProtocolImporters::ProtocolsIO::V3::ProtocolNormalizer do
|
||||
let(:client_data) { double('api_response') }
|
||||
|
||||
let(:response) do
|
||||
let(:protocols_io_single_protocol) do
|
||||
JSON.parse(file_fixture('protocol_importers/protocols_io/v3/single_protocol.json').read)
|
||||
.to_h.with_indifferent_access
|
||||
end
|
||||
|
||||
let(:response_without_title) do
|
||||
res_without_title = response
|
||||
res_without_title = protocols_io_single_protocol
|
||||
res_without_title[:protocol].reject! { |a| a == 'title' }
|
||||
res_without_title
|
||||
end
|
||||
|
||||
let(:normalized_result) do
|
||||
JSON.parse(file_fixture('protocol_importers/normalized_single_protocol.json').read)
|
||||
.to_h.with_indifferent_access
|
||||
let(:protocols_io_list) do
|
||||
JSON.parse(file_fixture('protocol_importers/protocols_io/v3/protocols.json').read).to_h.with_indifferent_access
|
||||
end
|
||||
|
||||
let(:normalized_protocol) do
|
||||
JSON.parse(file_fixture('protocol_importers/normalized_single_protocol.json').read).to_h.with_indifferent_access
|
||||
end
|
||||
|
||||
let(:normalized_list) do
|
||||
JSON.parse(file_fixture('protocol_importers/normalized_list.json').read).to_h.with_indifferent_access
|
||||
end
|
||||
|
||||
describe '#normalize_protocol' do
|
||||
|
@ -30,9 +37,9 @@ describe ProtocolImporters::ProtocolsIO::V3::ProtocolNormalizer do
|
|||
context 'when have all data' do
|
||||
it 'should normalize data correctly' do
|
||||
allow(client_data).to receive_message_chain(:parsed_response)
|
||||
.and_return(response)
|
||||
.and_return(protocols_io_single_protocol)
|
||||
|
||||
expect(subject.normalize_protocol(client_data).deep_stringify_keys).to be == normalized_result
|
||||
expect(subject.normalize_protocol(client_data).deep_stringify_keys).to be == normalized_protocol
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -45,4 +52,12 @@ describe ProtocolImporters::ProtocolsIO::V3::ProtocolNormalizer do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#normalize_list' do
|
||||
it 'should normalize data correctly' do
|
||||
allow(client_data).to receive_message_chain(:parsed_response).and_return(protocols_io_list)
|
||||
|
||||
expect(subject.normalize_list(client_data).deep_stringify_keys).to be == normalized_list
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue