ebsco-eds 0.0.1.pre

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.
@@ -0,0 +1,375 @@
1
+ require 'ebsco/eds/record'
2
+ require 'yaml'
3
+
4
+ module EBSCO
5
+
6
+ module EDS
7
+
8
+ # Search Results
9
+ class Results
10
+
11
+ # Raw results as Hash
12
+ attr_reader :results
13
+ # Array of EBSCO::EDS::Record results
14
+ attr_reader :records
15
+ # Array of EBSCO::EDS::Record Research Starters
16
+ attr_reader :research_starters
17
+ # Array of EBSCO::EDS::Record Exact Publication Matches
18
+ attr_reader :publication_match
19
+
20
+ # Lookup table of databases that have their labels suppressed in the response.
21
+ DBS = YAML::load_file(File.join(__dir__, 'settings.yml'))['databases']
22
+
23
+ # Creates search results from the \EDS API search response. It includes information about the results and a list
24
+ # of Record items.
25
+ def initialize(search_results)
26
+
27
+ @results = search_results
28
+
29
+ # convert all results to a list of records
30
+ @records = []
31
+ if stat_total_hits > 0
32
+ @results['SearchResult']['Data']['Records'].each { |record| @records.push(EBSCO::EDS::Record.new(record)) }
33
+ end
34
+
35
+ # create a special list of research starter records
36
+ @research_starters = []
37
+ _related_records = @results.fetch('SearchResult',{}).fetch('RelatedContent',{}).fetch('RelatedRecords',{})
38
+ if _related_records.count > 0
39
+ _related_records.each do |related_item|
40
+ if related_item['Type'] == 'rs'
41
+ rs_entries = related_item.fetch('Records',{})
42
+ if rs_entries.count > 0
43
+ rs_entries.each do |rs_record|
44
+ @research_starters.push(EBSCO::EDS::Record.new(rs_record))
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ # create a special list of exact match publications
52
+ @publication_match = []
53
+ _related_publications = @results.fetch('SearchResult',{}).fetch('RelatedContent',{}).fetch('RelatedPublications',{})
54
+ if _related_publications.count > 0
55
+ _related_publications.each do |related_item|
56
+ if related_item['Type'] == 'emp'
57
+ _publication_matches = related_item.fetch('PublicationRecords',{})
58
+ if _publication_matches.count > 0
59
+ _publication_matches.each do |publication_record|
60
+ @publication_match.push(EBSCO::EDS::Record.new(publication_record))
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ end
68
+
69
+ # returns solr search response format
70
+ def to_solr
71
+
72
+ solr_start = (page_number-1) * results_per_page
73
+ hl_hash = {}
74
+ solr_docs = []
75
+
76
+ if stat_total_hits > 0
77
+ @records.each { |record|
78
+
79
+ # todo: add solr hl.tag.pre and hl.tag.post to retrieval criteria
80
+ if retrieval_criteria.fetch('Highlight',{}) == 'y'
81
+ hl_title = record.title.gsub('&lt;highlight&gt;', '<em>').gsub('&lt;/highlight&gt;', '</em>')
82
+ hl_hash.update({ record.database_id + '-' + record.accession_number => { 'title_display' => [hl_title]} })
83
+ #hl_hash.merge title_hl
84
+ end
85
+
86
+ solr_docs.push(record.to_hash)
87
+ }
88
+ end
89
+
90
+ # solr response
91
+ {
92
+ 'responseHeader' => {
93
+ 'status' => 0,
94
+ 'QTime' => stat_total_time,
95
+ 'params' => {
96
+ 'q' => search_terms.join(' '),
97
+ 'wt' => 'ruby',
98
+ 'start' => solr_start,
99
+ 'rows' => results_per_page,
100
+ 'facet' => true,
101
+ 'f.subject_topic_facet.facet.limit' => 21,
102
+ 'f.language_facet.facet.limit' => 11,
103
+
104
+ }
105
+ },
106
+ 'response' => {
107
+ 'numFound' => stat_total_hits.to_i,
108
+ 'start' => solr_start,
109
+ 'docs' => solr_docs
110
+ },
111
+ 'highlighting' => hl_hash,
112
+ 'facet_counts' =>
113
+ {
114
+ 'facet_fields' => {
115
+ 'format' => solr_facets('SourceType'),
116
+ 'language_facet' => solr_facets('Language'),
117
+ 'subject_topic_facet' => solr_facets('SubjectEDS')
118
+ }
119
+ }
120
+ }
121
+
122
+ end
123
+
124
+ # Total number of results found.
125
+ def stat_total_hits
126
+ _hits = @results.fetch('SearchResult',{}).fetch('Statistics',{}).fetch('TotalHits',{})
127
+ _hits == {} ? 0 : _hits
128
+ end
129
+
130
+ # Time it took to complete the search in milliseconds.
131
+ def stat_total_time
132
+ @results['SearchResult']['Statistics']['TotalSearchTime']
133
+ end
134
+
135
+ # Search criteria used in the search
136
+ # Returns a hash.
137
+ # ==== Example
138
+ # {
139
+ # "Queries"=>[{"BooleanOperator"=>"AND", "Term"=>"earthquakes"}],
140
+ # "SearchMode"=>"all",
141
+ # "IncludeFacets"=>"y",
142
+ # "Expanders"=>["fulltext", "thesaurus", "relatedsubjects"],
143
+ # "Sort"=>"relevance",
144
+ # "RelatedContent"=>["rs"],
145
+ # "AutoSuggest"=>"n"
146
+ # }
147
+ def search_criteria
148
+ @results['SearchRequest']['SearchCriteria']
149
+ end
150
+
151
+ # Search criteria actions applied.
152
+ # Returns a hash.
153
+ # ==== Example
154
+ # {
155
+ # "QueriesWithAction"=>[{"Query"=>{"BooleanOperator"=>"AND", "Term"=>"earthquakes"}, "RemoveAction"=>"removequery(1)"}],
156
+ # "ExpandersWithAction"=>[{"Id"=>"fulltext", "RemoveAction"=>"removeexpander(fulltext)"}]
157
+ # }
158
+ def search_criteria_with_actions
159
+ @results['SearchRequest']['SearchCriteriaWithActions']
160
+ end
161
+
162
+ # Retrieval criteria that was applied to the search. Returns a hash.
163
+ # ==== Example
164
+ # {"View"=>"brief", "ResultsPerPage"=>20, "PageNumber"=>1, "Highlight"=>"y"}
165
+ def retrieval_criteria
166
+ @results['SearchRequest']['RetrievalCriteria']
167
+ end
168
+
169
+ # Queries used to produce the results. Returns an array of query hashes.
170
+ # ==== Example
171
+ # [{"BooleanOperator"=>"AND", "Term"=>"volcano"}]
172
+ def search_queries
173
+ @results['SearchRequest']['SearchCriteria']['Queries']
174
+ end
175
+
176
+ # Current page number for the results. Returns an integer.
177
+ def page_number
178
+ @results['SearchRequest']['RetrievalCriteria']['PageNumber'] || 1
179
+ end
180
+
181
+ # Results per page. Returns an integer.
182
+ def results_per_page
183
+ @results['SearchRequest']['RetrievalCriteria']['ResultsPerPage'] || 20
184
+ end
185
+
186
+ # List of facets applied to the search.
187
+ # ==== Example
188
+ # [{
189
+ # "FacetValue"=>{"Id"=>"SubjectGeographic", "Value"=>"massachusetts"},
190
+ # "RemoveAction"=>"removefacetfiltervalue(1,SubjectGeographic:massachusetts)"
191
+ # }]
192
+ def applied_facets
193
+ af = []
194
+ applied_facets_section = @results['SearchRequest'].fetch('SearchCriteriaWithActions',{}).fetch('FacetFiltersWithAction',{})
195
+ applied_facets_section.each do |applied_facets|
196
+ applied_facets.fetch('FacetValuesWithAction',{}).each do |applied_facet|
197
+ af.push(applied_facet)
198
+ end
199
+ end
200
+ af
201
+ end
202
+
203
+ # List of limiters applied to the search.
204
+ # ==== Example
205
+ # [{
206
+ # "Id"=>"LA99",
207
+ # "LimiterValuesWithAction"=>[{"Value"=>"French", "RemoveAction"=>"removelimitervalue(LA99:French)"}],
208
+ # "RemoveAction"=>"removelimiter(LA99)"
209
+ # }]
210
+ def applied_limiters
211
+ af = []
212
+ applied_limters_section = @results['SearchRequest'].fetch('SearchCriteriaWithActions',{}).fetch('LimitersWithAction',{})
213
+ applied_limters_section.each do |applied_limter|
214
+ af.push(applied_limter)
215
+ end
216
+ af
217
+ end
218
+
219
+ # Expanders applied to the search.
220
+ # ==== Example
221
+ # [
222
+ # {"Id"=>"fulltext", "RemoveAction"=>"removeexpander(fulltext)"},
223
+ # {"Id"=>"thesaurus", "RemoveAction"=>"removeexpander(thesaurus)"},
224
+ # {"Id"=>"relatedsubjects", "RemoveAction"=>"removeexpander(relatedsubjects)"}
225
+ # ]
226
+ def applied_expanders
227
+ af = []
228
+ applied_expanders_section = @results['SearchRequest'].fetch('SearchCriteriaWithActions',{}).fetch('ExpandersWithAction',{})
229
+ applied_expanders_section.each do |applied_explander|
230
+ af.push(applied_explander)
231
+ end
232
+ af
233
+ end
234
+
235
+ # Publications search was limited to.
236
+ # ==== Example
237
+ # [
238
+ # ["Id", "eric"],
239
+ # ["RemoveAction", "removepublication(eric)"]
240
+ # ]
241
+ def applied_publications
242
+ retval = []
243
+ applied_publications_section = @results['SearchRequest'].fetch('SearchCriteriaWithActions',{}).fetch('PublicationWithAction',{})
244
+ applied_publications_section.each do |item|
245
+ retval.push(item)
246
+ end
247
+ retval
248
+ end
249
+
250
+ # Provides a list of databases searched and the number of hits found in each one.
251
+ # ==== Example
252
+ # [
253
+ # {:id=>"nlebk", :hits=>0, :label=>"eBook Collection (EBSCOhost)"},
254
+ # {:id=>"e000xna", :hits=>30833, :label=>"eBook Academic Collection (EBSCOhost)"},
255
+ # {:id=>"edsart", :hits=>8246, :label=>"ARTstor Digital Library"},
256
+ # {:id=>"e700xna", :hits=>6701, :label=>"eBook Public Library Collection (EBSCOhost)"},
257
+ # {:id=>"cat02060a", :hits=>3464, :label=>"EDS Demo Catalog – US - U of Georgia"},
258
+ # {:id=>"ers", :hits=>1329, :label=>"Research Starters"},
259
+ # {:id=>"asn", :hits=>136406, :label=>"Academic Search Ultimate"}
260
+ # ]
261
+ def database_stats
262
+ databases = []
263
+ databases_facet = @results['SearchResult']['Statistics']['Databases']
264
+ databases_facet.each do |database|
265
+ if DBS.key?(database['Id'].upcase)
266
+ db_label = DBS[database['Id'].upcase];
267
+ else
268
+ db_label = database['Label']
269
+ end
270
+ databases.push({id: database['Id'], hits: database['Hits'], label: db_label})
271
+ end
272
+ databases
273
+ end
274
+
275
+ # Provides a list of facets for the search results.
276
+ # ==== Example
277
+ # [
278
+ # {
279
+ # :id=>"SourceType",
280
+ # :label=>"Source Type",
281
+ # :values=>[
282
+ # {
283
+ # :value=>"Academic Journals",
284
+ # :hitcount=>147,
285
+ # :action=>"addfacetfilter(SourceType:Academic Journals)"
286
+ # },
287
+ # {
288
+ # :value=>"News",
289
+ # :hitcount=>111,
290
+ # :action=>"addfacetfilter(SourceType:News)"
291
+ # },
292
+ #
293
+ # ...
294
+ #
295
+ # }
296
+ # ]
297
+ def facets (facet_provided_id = 'all')
298
+ facets_hash = []
299
+ available_facets = @results.fetch('SearchResult',{}).fetch('AvailableFacets',{})
300
+ available_facets.each do |available_facet|
301
+ if available_facet['Id'] == facet_provided_id || facet_provided_id == 'all'
302
+ facet_label = available_facet['Label']
303
+ facet_id = available_facet['Id']
304
+ facet_values = []
305
+ available_facet['AvailableFacetValues'].each do |available_facet_value|
306
+ facet_value = available_facet_value['Value']
307
+ facet_count = available_facet_value['Count']
308
+ facet_action = available_facet_value['AddAction']
309
+ facet_values.push({value: facet_value, hitcount: facet_count, action: facet_action})
310
+ end
311
+ facets_hash.push(id: facet_id, label: facet_label, values: facet_values)
312
+ end
313
+ end
314
+ facets_hash
315
+ end
316
+
317
+ def solr_facets (facet_provided_id = 'all')
318
+ facet_values = []
319
+ available_facets = @results.fetch('SearchResult',{}).fetch('AvailableFacets',{})
320
+ available_facets.each do |available_facet|
321
+ if available_facet['Id'] == facet_provided_id || facet_provided_id == 'all'
322
+ available_facet['AvailableFacetValues'].each do |available_facet_value|
323
+ facet_value = available_facet_value['Value']
324
+ facet_count = available_facet_value['Count']
325
+ facet_values.push(facet_value, facet_count)
326
+ end
327
+ end
328
+ end
329
+ facet_values
330
+ end
331
+
332
+ # Returns a hash of the date range available for the search.
333
+ # ==== Example
334
+ # {:mindate=>"1501-01", :maxdate=>"2018-04", :minyear=>"1501", :maxyear=>"2018"}
335
+ def date_range
336
+ mindate = @results['SearchResult']['AvailableCriteria']['DateRange']['MinDate']
337
+ maxdate = @results['SearchResult']['AvailableCriteria']['DateRange']['MaxDate']
338
+ minyear = mindate[0..3]
339
+ maxyear = maxdate[0..3]
340
+ {mindate: mindate, maxdate: maxdate, minyear:minyear, maxyear:maxyear}
341
+ end
342
+
343
+ # Provides alternative search terms to correct spelling, etc.
344
+ # ==== Example
345
+ # results = session.simple_search('earthquak')
346
+ # results.did_you_mean
347
+ # => "earthquake"
348
+ def did_you_mean
349
+ dym_suggestions = @results.fetch('SearchResult', {}).fetch('AutoSuggestedTerms',{})
350
+ dym_suggestions.each do |term|
351
+ return term
352
+ end
353
+ nil
354
+ end
355
+
356
+ # Returns a simple list of the search terms used. Boolean operators are not indicated.
357
+ # ==== Example
358
+ # ["earthquakes", "california"]
359
+ def search_terms
360
+ terms = []
361
+ queries = @results.fetch('SearchRequest',{}).fetch('SearchCriteriaWithActions',{}).fetch('QueriesWithAction',{})
362
+ unless queries.nil?
363
+ queries.each do |query|
364
+ query['Query']['Term'].split.each do |word|
365
+ terms.push(word)
366
+ end
367
+ end
368
+ end
369
+ terms
370
+ end
371
+
372
+ end
373
+
374
+ end
375
+ end
@@ -0,0 +1,624 @@
1
+ require 'ebsco/eds/version'
2
+ require 'ebsco/eds/info'
3
+ require 'ebsco/eds/results'
4
+ require 'faraday'
5
+ require 'faraday_middleware'
6
+ require 'logger'
7
+ require 'json'
8
+
9
+ module EBSCO
10
+
11
+ module EDS
12
+
13
+ # Sessions are used to query and retrieve information from the EDS API.
14
+ class Session
15
+
16
+ # Contains search Info available in the session profile. Includes the sort options, search fields, limiters and expanders available to the profile.
17
+ attr_accessor :info
18
+ # Contains the search Options sent as part of each request to the EDS API such as limiters, expanders, search modes, sort order, etc.
19
+ attr_accessor :search_options
20
+ # The authentication token. This is passed along in the x-authenticationToken HTTP header.
21
+ attr_accessor :auth_token # :nodoc:
22
+ # The session token. This is passed along in the x-sessionToken HTTP header.
23
+ attr_accessor :session_token # :nodoc:
24
+
25
+ # Creates a new session.
26
+ #
27
+ # This can be done in one of two ways:
28
+ #
29
+ # === 1. Environment variables
30
+ # * +EDS_AUTH+ - authentication method: 'ip' or 'user'
31
+ # * +EDS_PROFILE+ - profile ID for the EDS API
32
+ # * +EDS_USER+ - user id attached to the profile
33
+ # * +EDS_PASS+ - user password
34
+ # * +EDS_GUEST+ - allow guest access: 'y' or 'n'
35
+ # * +EDS_ORG+ - name of your institution or company
36
+ #
37
+ # ==== Example
38
+ # Once you have environment variables set, simply create a session like this:
39
+ # session = EBSCO::EDS::Session.new
40
+ #
41
+ # === 2. \Options
42
+ # * +:auth+
43
+ # * +:profile+
44
+ # * +:user+
45
+ # * +:pass+
46
+ # * +:guest+
47
+ # * +:org+
48
+ #
49
+ # ==== Example
50
+ # session = EBSCO::EDS::Session.new {
51
+ # :auth => 'user',
52
+ # :profile => 'edsapi',
53
+ # :user => 'joe'
54
+ # :pass => 'secret',
55
+ # :guest => false,
56
+ # :org => 'Acme University'
57
+ # }
58
+ def initialize(options = {})
59
+
60
+ @auth_token = ''
61
+ @session_token = ''
62
+
63
+ if options.has_key? :user
64
+ @user = options[:user]
65
+ elsif ENV.has_key? 'EDS_USER'
66
+ @user = ENV['EDS_USER']
67
+ end
68
+
69
+ if options.has_key? :pass
70
+ @pass = options[:pass]
71
+ elsif ENV.has_key? 'EDS_PASS'
72
+ @pass = ENV['EDS_PASS']
73
+ end
74
+
75
+ if options.has_key? :profile
76
+ @profile = options[:profile]
77
+ elsif ENV.has_key? 'EDS_PROFILE'
78
+ @profile = ENV['EDS_PROFILE']
79
+ end
80
+ raise EBSCO::EDS::InvalidParameter, 'Session must specify a valid api profile.' if blank?(@profile)
81
+
82
+ if options.has_key? :guest
83
+ @guest = options[:guest] ? 'y' : 'n'
84
+ elsif ENV.has_key? 'EDS_GUEST'
85
+ @guest = ENV['EDS_GUEST']
86
+ end
87
+
88
+ if options.has_key? :org
89
+ @org = options[:org]
90
+ elsif ENV.has_key? 'EDS_ORG'
91
+ @org = ENV['EDS_ORG']
92
+ end
93
+
94
+ if options.has_key? :auth
95
+ @auth_type = options[:auth]
96
+ elsif ENV.has_key? 'EDS_AUTH'
97
+ @auth_type = ENV['EDS_AUTH']
98
+ else
99
+ @auth_type = 'user'
100
+ end
101
+
102
+ @max_retries = MAX_ATTEMPTS
103
+ @auth_token = create_auth_token
104
+ @session_token = create_session_token
105
+ @info = EBSCO::EDS::Info.new(do_request(:get, path: INFO_URL))
106
+ @current_page = 0
107
+ @search_options = nil
108
+
109
+ end
110
+
111
+ # :category: Search & Retrieve Methods
112
+ # Performs a search.
113
+ #
114
+ # Returns search Results.
115
+ #
116
+ # ==== \Options
117
+ #
118
+ # * +:query+ - Required. The search terms. Format: {booleanOperator},{fieldCode}:{term}. Example: SU:Hiking
119
+ # * +:mode+ - Search mode to be used. Either: all (default), any, bool, smart
120
+ # * +:results_per_page+ - The number of records retrieved with the search results (between 1-100, default is 20).
121
+ # * +:page+ - Starting page number for the result set returned from a search (if results per page = 10, and page number = 3 , this implies: I am expecting 10 records starting at page 3).
122
+ # * +:sort+ - The sort order for the search results. Either: relevance (default), oldest, newest
123
+ # * +:highlight+ - Specifies whether or not the search term is highlighted using <highlight /> tags. Either true or false.
124
+ # * +:include_facets+ - Specifies whether or not the search term is highlighted using <highlight /> tags. Either true (default) or false.
125
+ # * +:facet_filters+ - Facets to apply to the search. Facets are used to refine previous search results. Format: \{filterID},{facetID}:{value}[,{facetID}:{value}]* Example: 1,SubjectEDS:food,SubjectEDS:fiction
126
+ # * +:view+ - Specifies the amount of data to return with the response. Either 'title': title only; 'brief' (default): Title + Source, Subjects; 'detailed': Brief + full abstract
127
+ # * +:actions+ - Actions to take on the existing query specification. Example: addfacetfilter(SubjectGeographic:massachusetts)
128
+ # * +:limiters+ - Criteria to limit the search results by. Example: LA99:English,French,German
129
+ # * +:expanders+ - Expanders that can be applied to the search. Either: thesaurus, fulltext, relatedsubjects
130
+ # * +:publication_id+ - Publication to search within.
131
+ # * +:related_content+ - Comma separated list of related content types to return with the search results. Either 'rs' (Research Starters) or 'emp' (Exact Publication Match)
132
+ # * +:auto_suggest+ - Specifies whether or not to return search suggestions along with the search results. Either true or false (default).
133
+ #
134
+ # ==== Examples
135
+ #
136
+ # results = session.search({query: 'abraham lincoln', results_per_page: 5, related_content: ['rs','emp']})
137
+ # results = session.search({query: 'volcano', results_per_page: 1, publication_id: 'eric', include_facets: false})
138
+ def search(options = {}, add_actions = false)
139
+
140
+ # create/recreate the search options if nil or not passing actions
141
+ if @search_options.nil? || !add_actions
142
+ @search_options = EBSCO::EDS::Options.new(options, @info)
143
+ end
144
+ #puts JSON.pretty_generate(@search_options)
145
+ _response = do_request(:post, path: SEARCH_URL, payload: @search_options)
146
+ @search_results = EBSCO::EDS::Results.new(_response)
147
+ @current_page = @search_results.page_number
148
+ @search_results
149
+ end
150
+
151
+ # :category: Search & Retrieve Methods
152
+ # Performs a simple search. All other search options assume default values.
153
+ #
154
+ # Returns search Results.
155
+ #
156
+ # ==== Attributes
157
+ #
158
+ # * +query+ - the search query.
159
+ #
160
+ # ==== Examples
161
+ #
162
+ # results = session.simple_search('volcanoes')
163
+ #
164
+ def simple_search(query)
165
+ search({:query => query})
166
+ end
167
+
168
+ # :category: Search & Retrieve Methods
169
+ # Returns a Record based a particular result based on a database ID and accession number.
170
+ #
171
+ # ==== Attributes
172
+ #
173
+ # * +:dbid+ - The database ID (required).
174
+ # * +:an+ - The accession number (required).
175
+ # * +highlight+ - Comma separated list of terms to highlight in the data records (optional).
176
+ # * +ebook+ - Preferred format to return ebook content in. Either ebook-pdf (default) or ebook-pdf.
177
+ #
178
+ # ==== Examples
179
+ # record = session.retrieve({dbid: 'asn', an: '108974507'})
180
+ #
181
+ def retrieve(dbid:, an:, highlight: nil, ebook: 'ebook-pdf')
182
+ payload = {:DbId => dbid, :An => an, :HighlightTerms => highlight, :EbookPreferredFormat => ebook}
183
+ retrieve_response = do_request(:post, path: RETRIEVE_URL, payload: payload)
184
+ EBSCO::EDS::Record.new(retrieve_response)
185
+ end
186
+
187
+ # :category: Search & Retrieve Methods
188
+ # Invalidates the session token. End Session should be called when you know a user has logged out.
189
+ def end
190
+ # todo: catch when there is no valid session?
191
+ do_request(:post, path: END_SESSION_URL, payload: {:SessionToken => @session_token})
192
+ connection.headers['x-sessionToken'] = ''
193
+ @session_token = ''
194
+ end
195
+
196
+ # :category: Search & Retrieve Methods
197
+ # Clear all specified query expressions, facet filters, limiters and expanders, and set the page number back to 1.
198
+ # Returns search Results.
199
+ def clear_search
200
+ add_actions 'ClearSearch()'
201
+ end
202
+
203
+ # :category: Search & Retrieve Methods
204
+ # Clears all queries and facet filters, and set the page number back to 1; limiters and expanders are not modified.
205
+ # Returns search Results.
206
+ def clear_queries
207
+ add_actions 'ClearQueries()'
208
+ end
209
+
210
+ # :category: Search & Retrieve Methods
211
+ # Add a query to the search request. When a query is added, it will be assigned an ordinal, which will be exposed
212
+ # in the search response message. It also removes any specified facet filters and sets the page number to 1.
213
+ # Returns search Results.
214
+ # ==== Examples
215
+ # results = session.add_query('AND,California')
216
+ def add_query(query)
217
+ add_actions "AddQuery(#{query})"
218
+ end
219
+
220
+ # :category: Search & Retrieve Methods
221
+ # Removes query from the currently specified search. It also removes any specified facet filters and sets the
222
+ # page number to 1.
223
+ # Returns search Results.
224
+ # ==== Examples
225
+ # results = session.remove_query(1)
226
+ def remove_query(query_id)
227
+ add_actions "removequery(#{query_id})"
228
+ end
229
+
230
+ # :category: Search & Retrieve Methods
231
+ # Add actions to an existing search session
232
+ # Returns search Results.
233
+ # ==== Examples
234
+ # results = session.add_actions('addfacetfilter(SubjectGeographic:massachusetts)')
235
+ def add_actions(actions)
236
+ # todo: create search options if nil?
237
+ search(@search_options.add_actions(actions, @info), true)
238
+ end
239
+
240
+ # :category: Setter Methods
241
+ # Sets the sort for the search. The available sorts for the specified databases can be obtained from the session’s
242
+ # info attribute. Sets the page number back to 1.
243
+ # Returns search Results.
244
+ # ==== Examples
245
+ # results = session.set_sort('newest')
246
+ def set_sort(val)
247
+ add_actions "SetSort(#{val})"
248
+ end
249
+
250
+ # :category: Setter Methods
251
+ # Sets the search mode. The available search modes are returned from the info method.
252
+ # Returns search Results.
253
+ # ==== Examples
254
+ # results = session.set_search_mode('bool')
255
+ def set_search_mode(mode)
256
+ add_actions "SetSearchMode(#{mode})"
257
+ end
258
+
259
+ # :category: Setter Methods
260
+ # Specifies the view parameter. The view representes the amount of data to return with the search.
261
+ # Returns search Results.
262
+ # ==== Examples
263
+ # results = session.set_view('detailed')
264
+ def set_view(view)
265
+ add_actions "SetView(#{view})"
266
+ end
267
+
268
+ # :category: Setter Methods
269
+ # Sets whether or not to turn highlighting on or off (y|n).
270
+ # Returns search Results.
271
+ # ==== Examples
272
+ # results = session.set_highlight('n')
273
+ def set_highlight(val)
274
+ add_actions "SetHighlight(#{val})"
275
+ end
276
+
277
+ # :category: Setter Methods
278
+ # Sets the page size on the search request.
279
+ # Returns search Results.
280
+ # ==== Examples
281
+ # results = session.results_per_page(50)
282
+ def results_per_page(num)
283
+ add_actions "SetResultsPerPage(#{num})"
284
+ end
285
+
286
+ # :category: Setter Methods
287
+ # A related content type to additionally search for and include with the search results.
288
+ # Returns search Results.
289
+ # ==== Examples
290
+ # results = session.include_related_content('rs')
291
+ def include_related_content(val)
292
+ add_actions "includerelatedcontent(#{val})"
293
+ end
294
+
295
+ # :category: Setter Methods
296
+ # Specify to include facets in the results or not. Either 'y' or 'n'.
297
+ # Returns search Results.
298
+ # ==== Examples
299
+ # results = session.set_include_facets('n')
300
+ def set_include_facets(val)
301
+ add_actions "SetIncludeFacets(#{val})"
302
+ end
303
+
304
+ # --
305
+ # ====================================================================================
306
+ # PAGINATION
307
+ # ====================================================================================
308
+ # ++
309
+
310
+ # :category: Pagination Methods
311
+ # Get the next page of results.
312
+ # Returns search Results.
313
+ def next_page
314
+ page = @current_page + 1
315
+ get_page(page)
316
+ end
317
+
318
+ # :category: Pagination Methods
319
+ # Get the previous page of results.
320
+ # Returns search Results.
321
+ def prev_page
322
+ get_page([1, @current_page - 1].sort.last)
323
+ end
324
+
325
+ # :category: Pagination Methods
326
+ # Get a specified page of results
327
+ # Returns search Results.
328
+ def get_page(page = 1)
329
+ add_actions "GoToPage(#{page})"
330
+ end
331
+
332
+ # :category: Pagination Methods
333
+ # Increments the current results page number by the value specified. If the current page was 5 and the specified value
334
+ # was 2, the page number would be set to 7.
335
+ # Returns search Results.
336
+ def move_page(num)
337
+ add_actions "MovePage(#{num})"
338
+ end
339
+
340
+ # :category: Pagination Methods
341
+ # Get the first page of results.
342
+ # Returns search Results.
343
+ def reset_page
344
+ add_actions 'ResetPaging()'
345
+ end
346
+
347
+ # --
348
+ # ====================================================================================
349
+ # FACETS
350
+ # ====================================================================================
351
+ # ++
352
+
353
+ # :category: Facet Methods
354
+ # Removes all specified facet filters. Sets the page number back to 1.
355
+ # Returns search Results.
356
+ def clear_facets
357
+ add_actions 'ClearFacetFilters()'
358
+ end
359
+
360
+ # :category: Facet Methods
361
+ # Adds a facet filter to the search request. Sets the page number back to 1.
362
+ # Returns search Results.
363
+ # ==== Examples
364
+ # results = session.add_facet('Publisher', 'wiley-blackwell')
365
+ # results = session.add_facet('SubjectEDS', 'water quality')
366
+ #
367
+ def add_facet(facet_id, facet_val)
368
+ add_actions "AddFacetFilter(#{facet_id}:#{facet_val})"
369
+ end
370
+
371
+ # :category: Facet Methods
372
+ # Removes a specified facet filter id. Sets the page number back to 1.
373
+ # Returns search Results.
374
+ # ==== Examples
375
+ # results = session.remove_facet(45)
376
+ def remove_facet(group_id)
377
+ add_actions "RemoveFacetFilter(#{group_id})"
378
+ end
379
+
380
+ # :category: Facet Methods
381
+ # Removes a specific facet filter value from a group. Sets the page number back to 1.
382
+ # Returns search Results.
383
+ # ==== Examples
384
+ # results = session.remove_facet_value(2, 'DE', 'Psychology')
385
+ def remove_facet_value(group_id, facet_id, facet_val)
386
+ add_actions "RemoveFacetFilterValue(#{group_id},#{facet_id}:#{facet_val})"
387
+ end
388
+
389
+ # --
390
+ # ====================================================================================
391
+ # LIMITERS
392
+ # ====================================================================================
393
+ # ++
394
+
395
+ # :category: Limiter Methods
396
+ # Clears all currently specified limiters and sets the page number back to 1.
397
+ # Returns search Results.
398
+ def clear_limiters
399
+ add_actions 'ClearLimiters()'
400
+ end
401
+
402
+ # :category: Limiter Methods
403
+ # Adds a limiter to the currently defined search and sets the page number back to 1.
404
+ # Returns search Results.
405
+ # ==== Examples
406
+ # results = session.add_limiter('FT','y')
407
+ def add_limiter(id, val)
408
+ add_actions "AddLimiter(#{id}:#{val})"
409
+ end
410
+
411
+ # :category: Limiter Methods
412
+ # Removes the specified limiter and sets the page number back to 1.
413
+ # Returns search Results.
414
+ # ==== Examples
415
+ # results = session.remove_limiter('FT')
416
+ def remove_limiter(id)
417
+ add_actions "RemoveLimiter(#{id})"
418
+ end
419
+
420
+ # :category: Limiter Methods
421
+ # Removes a specified limiter value and sets the page number back to 1.
422
+ # Returns search Results.
423
+ # ==== Examples
424
+ # results = session.remove_limiter_value('LA99','French')
425
+ def remove_limiter_value(id, val)
426
+ add_actions "RemoveLimiterValue(#{id}:#{val})"
427
+ end
428
+
429
+ # --
430
+ # ====================================================================================
431
+ # EXPANDERS
432
+ # ====================================================================================
433
+ # ++
434
+
435
+ # :category: Expander Methods
436
+ # Removes all specified expanders and sets the page number back to 1.
437
+ # Returns search Results.
438
+ def clear_expanders
439
+ add_actions 'ClearExpanders()'
440
+ end
441
+
442
+ # :category: Expander Methods
443
+ # Adds expanders and sets the page number back to 1. Multiple expanders should be comma separated.
444
+ # Returns search Results.
445
+ # ==== Examples
446
+ # results = session.add_expander('thesaurus,fulltext')
447
+ def add_expander(val)
448
+ add_actions "AddExpander(#{val})"
449
+ end
450
+
451
+ # :category: Expander Methods
452
+ # Removes a specified expander. Sets the page number to 1.
453
+ # Returns search Results.
454
+ # ==== Examples
455
+ # results = session.remove_expander('fulltext')
456
+ def remove_expander(val)
457
+ add_actions "RemoveExpander(#{val})"
458
+ end
459
+
460
+ # --
461
+ # ====================================================================================
462
+ # PUBLICATION (this is only used for profiles configured for publication searching)
463
+ # ====================================================================================
464
+ # ++
465
+
466
+ # :category: Publication Methods
467
+ # Specifies a publication to search within. Sets the pages number back to 1.
468
+ # Returns search Results.
469
+ # ==== Examples
470
+ # results = session.add_publication('eric')
471
+ def add_publication(pub_id)
472
+ add_actions "AddPublication(#{pub_id})"
473
+ end
474
+
475
+ # :category: Publication Methods
476
+ # Removes a publication from the search. Sets the page number back to 1.
477
+ # Returns search Results.
478
+ def remove_publication(pub_id)
479
+ add_actions "RemovePublication(#{pub_id})"
480
+ end
481
+
482
+ # :category: Publication Methods
483
+ # Removes all publications from the search. Sets the page number back to 1.
484
+ # Returns search Results.
485
+ def remove_all_publications
486
+ add_actions 'RemovePublication()'
487
+ end
488
+
489
+ # --
490
+ # ====================================================================================
491
+ # INTERNAL METHODS
492
+ # ====================================================================================
493
+ # ++
494
+
495
+ def do_request(method, path:, payload: nil, attempt: 0) # :nodoc:
496
+
497
+ if attempt > MAX_ATTEMPTS
498
+ raise EBSCO::EDS::ApiError, 'EBSCO API error: Multiple attempts to perform request failed.'
499
+ end
500
+
501
+ begin
502
+ resp = connection.send(method) do |req|
503
+ case method
504
+ when :get
505
+ req.url path
506
+ when :post
507
+ req.url path
508
+ unless payload.nil?
509
+ req.body = JSON.generate(payload)
510
+ end
511
+ else
512
+ raise EBSCO::EDS::ApiError, "EBSCO API error: Method #{method} not supported for endpoint #{path}"
513
+ end
514
+ end
515
+ resp.body
516
+ rescue Exception => e
517
+ if e.respond_to? 'fault'
518
+ error_code = e.fault[:error_body]['ErrorNumber'] || e.fault[:error_body]['ErrorCode']
519
+ if not error_code.nil?
520
+ case error_code
521
+ # session token missing
522
+ when '108', '109'
523
+ @session_token = create_session_token
524
+ do_request(method, path: path, payload: payload, attempt: attempt+1)
525
+ # auth token invalid
526
+ when '104', '107'
527
+ @auth_token = nil
528
+ @auth_token = create_auth_token
529
+ do_request(method, path: path, payload: payload, attempt: attempt+1)
530
+ else
531
+ raise e
532
+ end
533
+ end
534
+ else
535
+ raise e
536
+ end
537
+ end
538
+ end
539
+
540
+ # --
541
+ # attempts to query profile capabilities
542
+ # dummy search just to get the list of available databases
543
+ # ++
544
+ def get_available_databases # :nodoc:
545
+ search({query: 'supercalifragilisticexpialidocious-supercalifragilisticexpialidocious',
546
+ results_per_page: 1,
547
+ mode: 'all',
548
+ include_facets: false}).database_stats
549
+ end
550
+
551
+ # :category: Profile Settings Methods
552
+ # Get a list of all available database IDs.
553
+ # Returns Array of IDs.
554
+ def get_available_database_ids
555
+ get_available_databases.map{|item| item[:id]}
556
+ end
557
+
558
+ # :category: Profile Settings Methods
559
+ # Determine if a database ID is available in the profile.
560
+ # Returns Boolean.
561
+ def dbid_in_profile(dbid)
562
+ get_available_database_ids.include? dbid
563
+ end
564
+
565
+ # :category: Profile Settings Methods
566
+ # Determine if publication matching is available in the profile.
567
+ # Returns Boolean.
568
+ def publication_match_in_profile
569
+ @info.available_related_content_types.include? 'emp'
570
+ end
571
+
572
+ # :category: Profile Settings Methods
573
+ # Determine if research starters are available in the profile.
574
+ # Returns Boolean.
575
+ def research_starters_match_in_profile
576
+ @info.available_related_content_types.include? 'rs'
577
+ end
578
+
579
+ private
580
+
581
+ def connection
582
+ Faraday.new(url: EDS_API_BASE) do |faraday|
583
+ faraday.headers['Content-Type'] = 'application/json;charset=UTF-8'
584
+ faraday.headers['Accept'] = 'application/json'
585
+ faraday.headers['x-sessionToken'] = @session_token ? @session_token : ''
586
+ faraday.headers['x-authenticationToken'] = @auth_token ? @auth_token : ''
587
+ faraday.headers['User-Agent'] = USER_AGENT
588
+ faraday.request :url_encoded
589
+ faraday.use FaradayMiddleware::RaiseHttpException
590
+ faraday.response :json, :content_type => /\bjson$/
591
+ #faraday.response :logger, Logger.new(LOG)
592
+ faraday.adapter Faraday.default_adapter
593
+ end
594
+ end
595
+
596
+ def create_auth_token
597
+ if blank?(@auth_token)
598
+ # ip auth
599
+ if (blank?(@user) && blank?(@pass)) || @auth_type.casecmp('ip') == 0
600
+ _response = do_request(:post, path: IP_AUTH_URL)
601
+ @auth_token = _response['AuthToken']
602
+ # user auth
603
+ else
604
+ _response = do_request(:post, path: UID_AUTH_URL, payload: {:UserId => @user, :Password => @pass})
605
+ @auth_token = _response['AuthToken']
606
+ end
607
+ end
608
+ @auth_token
609
+ end
610
+
611
+ def create_session_token
612
+ _response = do_request(:post, path: CREATE_SESSION_URL, payload: {:Profile => @profile, :Guest => @guest})
613
+ @session_token = _response['SessionToken']
614
+ end
615
+
616
+ # helper methods
617
+ def blank?(var)
618
+ var.nil? || var.respond_to?(:length) && var.length == 0
619
+ end
620
+
621
+ end
622
+
623
+ end
624
+ end