colrapi 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/colrapi.rb ADDED
@@ -0,0 +1,1026 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require_relative "colrapi/version"
5
+ require_relative "colrapi/request"
6
+ require "colrapi/helpers/configuration"
7
+
8
+ module Colrapi
9
+ extend Configuration
10
+
11
+ define_setting :base_url, "https://api.checklistbank.org/"
12
+ define_setting :mailto, ENV["COL_API_EMAIL"]
13
+
14
+ # Get assembly status
15
+ #
16
+ # @param dataset_id [String] The dataset id
17
+ #
18
+ # @return [Hash] A result hash of the assembly queue
19
+ def self.assembly(dataset_id, verbose: false)
20
+ endpoint = "dataset/#{dataset_id}/assembly"
21
+ Request.new(endpoint: endpoint, verbose: verbose).perform
22
+ end
23
+
24
+ # Get a dataset's original archive
25
+ #
26
+ # @param dataset_id [String] The dataset id
27
+ #
28
+ # @return [Binary] An archive of the original dataset
29
+ def self.archive(dataset_id, verbose: false)
30
+ endpoint = "dataset/#{dataset_id}/archive"
31
+ Request.new(endpoint: endpoint, verbose: verbose).perform
32
+ end
33
+
34
+ # Get dataset metadata
35
+ #
36
+ # For a specific dataset:
37
+ # @param dataset_id [String] The dataset id
38
+ # @param attempt [Integer] Returns archived metadata for a past import attempt number
39
+ #
40
+ # Search datasets:
41
+ # @param q [String] A search query for datasets
42
+ # @param short_title [String] A dataset alias
43
+ # @param code [String] The nomenclatural code (bacterial, botanical, cultivars, phytosociological, virus, zoological)
44
+ # @param private [Boolean] Whether the dataset is private or not
45
+ # @param released_from [Integer] Filter by a project id that a dataset was released from
46
+ # @param contributes_to [Integer] Filter by a project id that a dataset contributes to
47
+ # @param has_source_dataset [Boolean] Filter by if source datasets contribute to the project dataset
48
+ # @param has_gbif_id [Boolean] Whether the dataset has a GBIF registry id
49
+ # @param gbif_id [String] The GBIF registry id
50
+ # @param gbif_publisher_id [String] Filter by a GBIF publisher's id
51
+ # @param editor [Integer] Filter by an editor's user id
52
+ # @param reviewer [Integer] Filter by a reviewer's user id
53
+ # @param modified_by [Integer] Filter by a user id on last modified by
54
+ # @param origin [Array, String] Filter by the origin of a dataset (external, project, release, xrelease)
55
+ # @param type [Array, String] Filter by the dataset type (nomenclatural, taxonomic, phylogenetic, article, legal, thematic, other)
56
+ # @param license [Array, String] Filter by the license type (cc0, cc_by, cc_by_sa, cc_by_nc, cc_by_nd, cc_by_nc_sa, cc_by_nc_nd, unspecified, other)
57
+ # @param row_type [Array, String] Filter by datasets that include a row type (e.g., acef:AcceptedSpecies, col:Taxon, dwc:Taxon)
58
+ # @param created_after [Date] Filter by created after date
59
+ # @param created_before [Date] Filter by created before date
60
+ # @param issued_after [Date] Filter by issued after date
61
+ # @param issued_before [Date] Filter by issued before date
62
+ # @param modified_after [Date] Filter by modified after date
63
+ # @param modified_before [Date] Filter by modified before date
64
+ # @param min_size [Integer] Filter by minimum record size
65
+ #
66
+ # @param sort_by [String] Sort by (key, alias, title, creator, relevance, created, modified, imported, size)
67
+ # @param reverse [Boolean] Sort in reverse
68
+ # @param offset [Integer] Offset for pagination
69
+ # @param limit [Integer] Limit for pagination
70
+ # @param verbose [Boolean] Print headers to STDOUT
71
+ #
72
+ # @return [Array, Boolean] An array of hashes
73
+ def self.dataset(dataset_id: nil, attempt: nil, q: nil, short_title: nil, code: nil, private: nil, released_from: nil,
74
+ contributes_to: nil, has_source_dataset: nil, has_gbif_id: nil, gbif_id: nil, gbif_publisher_id: nil,
75
+ editor: nil, reviewer: nil, modified_by: nil, origin: nil, type: nil, license: nil, row_type: nil,
76
+ created_after: nil, created_before: nil, issued_after: nil, issued_before: nil, modified_after: nil,
77
+ modified_before: nil, min_size: nil, sort_by: nil, reverse: nil, offset: nil, limit: nil,
78
+ verbose: false)
79
+ endpoint = "dataset"
80
+ unless dataset_id.nil?
81
+ endpoint = "#{endpoint}/#{dataset_id}"
82
+ unless attempt.nil?
83
+ endpoint = "#{endpoint}/#{attempt}"
84
+ end
85
+ endpoint = "#{endpoint}.json"
86
+ Request.new(endpoint: endpoint, verbose: verbose).perform
87
+ else
88
+ Request.new(endpoint: endpoint, q: q, short_title: short_title, code: code, private: private,
89
+ released_from: released_from, contributes_to: contributes_to, has_source_dataset: has_source_dataset,
90
+ has_gbif_id: has_gbif_id, gbif_id: gbif_id, gbif_publisher_id: gbif_publisher_id, editor: editor,
91
+ reviewer: reviewer, modified_by: modified_by, origin: origin, type: type, license: license,
92
+ row_type: row_type, created_after: created_after, created_before: created_before,
93
+ issued_after: issued_after, issued_before: issued_before, modified_after: modified_after,
94
+ modified_before: modified_before, min_size: min_size, sort_by: sort_by, reverse: reverse,
95
+ offset: offset, limit: limit, verbose: verbose).perform
96
+ end
97
+ end
98
+
99
+ # Get project decisions
100
+ #
101
+ # @param dataset_id [String] The dataset id
102
+ # @param decision_id [Integer, nil] The decision id
103
+ # @param name [String, nil] The scientific name to match
104
+ # @param rank [String, nil] The rank of the scientific name
105
+ # @param modified_by [Integer, nil] Filter by a user id on last modified by
106
+ # @param broken [Boolean, nil] Whether the decision is broken or not
107
+ # @param subject_dataset_id [String, nil] The source dataset id
108
+ # @param mode [String, nil] The type of decision (block, reviewed, update, update_recursive, ignore)
109
+ # @param subject [Boolean, nil] TODO: what does this do? All decisions with subject=true are bare names, so maybe it checks if the subject taxon exists?
110
+ #
111
+ # @param offset [Integer] Offset for pagination
112
+ # @param limit [Integer] Limit for pagination
113
+ # @param verbose [Boolean] Print headers to STDOUT
114
+ #
115
+ # @return [Hash, Boolean] A result hash
116
+ def self.decision(dataset_id, decision_id: nil, name: nil, rank: nil, modified_by: nil, broken: nil,
117
+ subject_dataset_id: nil, mode: nil, subject: nil, offset: nil, limit: nil, verbose: false)
118
+ if decision_id.nil?
119
+ endpoint = "dataset/#{dataset_id}/decision"
120
+ Request.new(endpoint: endpoint, name: name, rank: rank, modified_by: modified_by, broken: broken,
121
+ subject_dataset_id: subject_dataset_id, mode: mode, subject: subject, offset: offset,
122
+ limit: limit, verbose: verbose).perform
123
+ else
124
+ endpoint = "dataset/#{dataset_id}/decision/#{decision_id}"
125
+ Request.new(endpoint: endpoint, verbose: verbose).perform
126
+ end
127
+ end
128
+
129
+ # Get duplicate names
130
+ #
131
+ # @param dataset_id [String] The dataset id
132
+ #
133
+ # @param offset [Integer] Offset for pagination
134
+ # @param limit [Integer] Limit for pagination
135
+ # @param verbose [Boolean] Print headers to STDOUT
136
+ def self.duplicate(dataset_id, offset: nil, limit: nil, verbose: false)
137
+ endpoint = "dataset/#{dataset_id}/duplicate"
138
+ Request.new(endpoint: endpoint, offset: offset, limit: limit, verbose: verbose).perform
139
+ end
140
+
141
+ # Get names diff between 2 datasets
142
+ #
143
+ # @param dataset_id [String] The first dataset id
144
+ # @param dataset2_id [String] The second dataset id
145
+ # @param root_id [Array, String, nil] The root taxon for the first dataset
146
+ # @param root2_id [Array, String, nil] The root taxon for the second dataset
147
+ # @param min_rank [String, nil] The minimum taxonomic rank
148
+ # @param authorship [Boolean, nil] Include authorship
149
+ # @param include_synonyms [Boolean, nil] Include synonyms
150
+ # @param include_parent [Boolean, nil] Include parent
151
+ # @param parent_rank [String, nil] Filter by parent rank
152
+ # @param token [String, nil] An authentication token from Colrapi.user_login()
153
+ #
154
+ # @param offset [Integer] Offset for pagination
155
+ # @param limit [Integer] Limit for pagination
156
+ # @param verbose [Boolean] Print headers to STDOUT
157
+ #
158
+ # @return [String, Boolean] A text diff of names
159
+ def self.diff(dataset_id, dataset2_id, root_id: nil, root2_id: nil, min_rank: nil,
160
+ authorship: nil, include_synonyms: nil, include_parent: nil, parent_rank: nil,
161
+ offset: nil, limit: nil, token: nil, verbose: false)
162
+ endpoint = "dataset/#{dataset_id}/diff/#{dataset2_id}"
163
+ Request.new(endpoint: endpoint, root_id: root_id, root2_id: root2_id, min_rank: min_rank,
164
+ authorship: authorship, include_synonyms: include_synonyms,
165
+ include_parent: include_parent, parent_rank: parent_rank,
166
+ offset: offset, limit: limit, token: token, verbose: verbose).perform
167
+ end
168
+
169
+ # Get editor info
170
+ #
171
+ # @param dataset_id [String] The dataset id
172
+ # @param token [String, nil] The authentication token from retrieved with Colrapi.user_login(user, password)
173
+ #
174
+ # # @return [Array, Hash, Boolean] An array of hashes
175
+ def self.editor(dataset_id, token, verbose: false)
176
+ endpoint = "dataset/#{dataset_id}/editor"
177
+ Request.new(endpoint: endpoint, token: token, verbose: verbose).perform
178
+ end
179
+
180
+ # Get estimates
181
+ # @param dataset_id [String] The dataset id
182
+ # @param estimate_id [Integer, nil] The estimate ID
183
+ # @param name [String] The scientific name
184
+ # @param rank [String, nil] taxonomic rank
185
+ # @param modified_by [Integer, nil] Filter by a user id on last modified by
186
+ # @param broken [Boolean, nil] Whether the estimate is broken or not
187
+ # @param min [Integer, nil] Filter by the minimum estimate
188
+ # @param max [Integer, nil] Filter by the maximum estimate
189
+ #
190
+ # @param offset [Integer] Offset for pagination
191
+ # @param limit [Integer] Limit for pagination
192
+ # @param verbose [Boolean] Print headers to STDOUT
193
+ #
194
+ # @return [Hash, Boolean] A results hash
195
+ def self.estimate(dataset_id, estimate_id: nil, name: nil, rank: nil, modified_by: nil, broken: nil, min: nil,
196
+ max: nil, offset: nil, limit: nil, verbose: false)
197
+ endpoint = "dataset/#{dataset_id}/estimate"
198
+ if estimate_id.nil?
199
+ Request.new(endpoint: endpoint, name: name, rank: rank, modified_by: modified_by, broken: broken,
200
+ min: min, max: max, offset: offset, limit: limit, verbose: verbose).perform
201
+ else
202
+ endpoint = "dataset/#{dataset_id}/estimate/#{estimate_id}"
203
+ Request.new(endpoint: endpoint, verbose: verbose).perform
204
+ end
205
+ end
206
+
207
+ # TODO: /dataset/{key}/export is covered, but /export and /export/{id} are not
208
+ # Get a dataset export
209
+ #
210
+ # @param dataset_id [String] The dataset id
211
+ # @param show_id [Boolean, nil] TODO: not implemented because it doesn't seem to do anything?
212
+ # @param verbose [Boolean] Print headers to STDOUT
213
+ #
214
+ # @return [Hash, Boolean] An export hash
215
+ def self.export(dataset_id, show_id: nil, verbose: false)
216
+ endpoint = "dataset/#{dataset_id}/export"
217
+ Request.new(endpoint: endpoint, verbose: verbose).perform
218
+ end
219
+
220
+ # Get data quality issues
221
+ #
222
+ # @param dataset_id [String] The dataset id
223
+ # @param issue [String] Filter by data quality issue (e.g., ACCEPTED_NAME_MISSING, DUPLICATE_NAME, URL_INVALID)
224
+ # @param mode [String] Verbatim (default) or interpreted
225
+ #
226
+ # @param offset [Integer] Offset for pagination
227
+ # @param limit [Integer] Limit for pagination
228
+ # @param verbose [Boolean] Print headers to STDOUT
229
+ #
230
+ # @return [Array, Hash, Boolean] An array of hashes
231
+ def self.issues(dataset_id, issue: nil, mode: 'verbatim', offset: nil, limit: nil, verbose: false)
232
+ if issue.nil?
233
+ metrics = Request.new(endpoint: "/dataset/#{dataset_id}/import?state=finished").perform
234
+ return {"issuesCount" => metrics[0]['issuesCount']}
235
+ else
236
+ if mode == 'interpreted'
237
+ issues = self.vocab(term: 'issue')
238
+ record_type = 'any'
239
+ issues.each do |i|
240
+ if i['name'] == issue.downcase
241
+ record_type = i['group']
242
+ end
243
+ end
244
+
245
+ # TODO: so far issues are only filterable on nameusage/search and /reference
246
+ # for other record_types, may need to add other endpoints in the future
247
+ if record_type == 'reference'
248
+ self.reference(dataset_id, issue: issue, offset: offset, limit: limit, verbose: verbose)
249
+ else
250
+ self.nameusage_search(dataset_id: dataset_id, issue: issue, facet: 'issue', offset: offset, limit: limit,
251
+ verbose: verbose)
252
+ end
253
+ else
254
+ self.verbatim(dataset_id, issue: issue, offset: offset, limit: limit, verbose: verbose)
255
+ end
256
+ end
257
+ end
258
+
259
+ # Get importer status
260
+ #
261
+ # @param dataset_id [String] Calls the dataset_id endpoint /importer/{dataset_id}
262
+ # @param dataset_id_filter [String] Filters the importer queue by dataset_id
263
+ # @param state [Array, String] The import status (e.g., waiting, preparing, downloading, processing, inserting, ...)
264
+ # @param running [Boolean] Filter by actively importing datasets
265
+ #
266
+ # @param offset [Integer] Offset for pagination
267
+ # @param limit [Integer] Limit for pagination
268
+ # @param verbose [Boolean] Print headers to STDOUT
269
+ #
270
+ # @return [Array, Boolean] An array of hashes
271
+ def self.importer(dataset_id: nil, dataset_id_filter: nil, state: nil, running: nil, offset: nil, limit: nil,
272
+ verbose: false)
273
+ endpoint = "importer"
274
+ if dataset_id.nil?
275
+ Request.new(endpoint: endpoint, dataset_id_filter: dataset_id_filter, state: state, running: running,
276
+ offset: offset, limit: limit, verbose: verbose).perform
277
+ else
278
+ endpoint = "#{endpoint}/#{dataset_id}"
279
+ Request.new(endpoint: endpoint, verbose: verbose).perform
280
+ end
281
+ end
282
+
283
+ # Get a dataset's logo
284
+ #
285
+ # @param dataset_id [String] The dataset id
286
+ # @param size [String] The size of the logo (original, large, medium, small)
287
+ #
288
+ # @return [Binary] The dataset logo
289
+ def self.logo(dataset_id, size: nil, verbose: false)
290
+ endpoint = "dataset/#{dataset_id}/logo"
291
+ Request.new(endpoint: endpoint, size: size, verbose: verbose).perform
292
+ end
293
+
294
+ # Get names or a name from a dataset
295
+ #
296
+ # @param dataset_id [String] The dataset id
297
+ # @param name [String] The scientific name to match
298
+ # @param authorship [String] The authorship string for the scientific name
299
+ # @param code [String] The nomenclatural code (bacterial, botanical, cultivars, phytosociological, virus, zoological)
300
+ # @param rank [String] The rank of the scientific name
301
+ # @param within_superkingdom [String] Restricts query to within a superkingdom
302
+ # @param within_kingdom [String] Restricts query to within a kingdom
303
+ # @param within_subkingdom [String] Restricts query to within a subkingdom
304
+ # @param within_superphylum [String] Restricts query to within a superphylum
305
+ # @param within_phylum [String] Restricts query to within a phylum
306
+ # @param within_subphylum [String] Restricts query to within a subphylum
307
+ # @param within_superclass [String] Restricts query to within a superclass
308
+ # @param within_class [String] Restricts query to within a class
309
+ # @param within_subclass [String] Restricts query to within a subclass
310
+ # @param within_superorder [String] Restricts query to within a superorder
311
+ # @param within_order [String] Restricts query to within a order
312
+ # @param within_suborder [String] Restricts query to within a suborder
313
+ # @param within_superfamily [String] Restricts query to within a superfamily
314
+ # @param within_family [String] Restricts query to within a family
315
+ # @param within_subfamily [String] Restricts query to within a subfamily
316
+ # @param within_tribe [String] Restricts query to within a tribe
317
+ # @param within_subtribe [String] Restricts query to within a subtribe
318
+ # @param within_genus [String] Restricts query to within a genus
319
+ # @param within_subgenus [String] Restricts query to within a subgenus
320
+ # @param within_section [String] Restricts query to within a section
321
+ # @param within_species [String] Restricts query to within a species
322
+ #
323
+ # @param verbose [Boolean] Print headers to STDOUT
324
+ #
325
+ # @return [Array, Boolean] An array of hashes
326
+ # def self.matching(dataset_id, name: nil, authorship: nil, code: nil, rank: nil, within_superkingdom: nil,
327
+ # within_kingdom: nil, within_subkingdom: nil, within_superphylum: nil, within_phylum: nil,
328
+ # within_subphylum: nil, within_superclass: nil, within_class: nil, within_subclass: nil,
329
+ # within_superorder: nil, within_order: nil, within_suborder: nil, within_superfamily: nil,
330
+ # within_family: nil, within_subfamily: nil, within_tribe: nil, within_subtribe: nil,
331
+ # within_genus: nil, within_subgenus: nil, within_section: nil, within_species: nil,
332
+ # verbose: false)
333
+ # endpoint = "dataset/#{dataset_id}/matching"
334
+ # Request.new(endpoint: endpoint, name: name, authorship: authorship, code: code, rank: rank,
335
+ # within_superkingdom: within_superkingdom, within_kingdom: within_kingdom,
336
+ # within_subkingdom: within_subkingdom, within_superphylum: within_superphylum,
337
+ # within_phylum: within_phylum, within_subphylum: within_subphylum, within_superclass: within_superclass,
338
+ # within_class: within_class, within_subclass: within_subclass, within_superorder: within_superorder,
339
+ # within_order: within_order, within_suborder: within_suborder, within_superfamily: within_superfamily,
340
+ # within_family: within_family, within_subfamily: within_subfamily, within_tribe: within_tribe,
341
+ # within_subtribe: within_subtribe, within_genus: within_genus, within_subgenus: within_subgenus,
342
+ # within_section: within_section, within_species: within_species, verbose: verbose).perform
343
+ # end
344
+
345
+ # Get metrics for the *last successful* import of a dataset or a specific import_attempt
346
+ #
347
+ # @param dataset_id [String] The dataset id
348
+ # @param import_attempt [Integer] The import attempt
349
+ #
350
+ # @return [Array, Hash, Boolean] An array of hashes
351
+ def self.metrics(dataset_id, import_attempt: nil, verbose: false)
352
+
353
+ import = self.importer(dataset_id: dataset_id)
354
+ unless %w[unchanged finished].include? import['state']
355
+ return {"code" => 400, 'message' => 'Dataset has not finished importing or failed to import'}
356
+ end
357
+
358
+ # it's necessary to get the last finished import attempt because status=unchanged import results don't have metrics
359
+ # project release datasets do not seem to have import_attempts or should be taken from the project dataset, e.g.:
360
+ # https://api.checklistbank.org/dataset/3/import/107 == https://api.checklistbank.org/dataset/9837/import
361
+ if import_attempt.nil?
362
+ import = self.importer(dataset_id_filter: dataset_id, state: 'finished')
363
+ if import['total'] > 0
364
+ import_attempt = import['result'][0]['attempt']
365
+ end
366
+ end
367
+
368
+ endpoint = "dataset/#{dataset_id}/import"
369
+ if !import_attempt.nil?
370
+ endpoint = "#{endpoint}/#{import_attempt}"
371
+ Request.new(endpoint: endpoint, verbose: verbose).perform
372
+ else
373
+ # /dataset/{id}/import returns an array of 1 item while /dataset/{id}/import/{attempt} doesn't
374
+ res = Request.new(endpoint: endpoint, verbose: verbose).perform
375
+ res[0]
376
+ end
377
+ end
378
+
379
+ # Get names or a name from a dataset
380
+ #
381
+ # @param dataset_id [String] The dataset id
382
+ # @param name_id [String] The name id
383
+ # @param subresource [String] The name subresource endpoint (relations, synonyms, types, or orphans)
384
+ #
385
+ # @param offset [Integer] Offset for pagination
386
+ # @param limit [Integer] Limit for pagination
387
+ # @param verbose [Boolean] Print headers to STDOUT
388
+ #
389
+ # @return [Array, Boolean] An array of hashes
390
+ def self.name(dataset_id, name_id: nil, subresource: nil, offset: nil, limit: nil, verbose: false)
391
+ endpoint = "dataset/#{dataset_id}/name"
392
+ unless name_id.nil?
393
+ endpoint = "#{endpoint}/#{name_id}"
394
+ offset = nil
395
+ limit = nil
396
+ end
397
+ if !subresource.nil? and %w[relations synonyms types orphans].include? subresource
398
+ endpoint = "#{endpoint}/#{subresource}"
399
+ end
400
+ Request.new(endpoint: endpoint, offset: offset, limit: limit, verbose: verbose).perform
401
+ end
402
+
403
+ # Get a text list of names for a dataset
404
+ #
405
+ # @param dataset_id [String] The dataset id
406
+ # @param import_attempt [Integer] The import attempt number
407
+ #
408
+ def self.name_list(dataset_id, import_attempt: nil, verbose: nil)
409
+
410
+ # get last import attempt number if none given
411
+ if import_attempt.nil?
412
+ import = self.importer(dataset_id: dataset_id)
413
+ import_attempt = import['attempt']
414
+ end
415
+
416
+ endpoint = "dataset/#{dataset_id}/import/#{import_attempt}/names"
417
+ Request.new(endpoint: endpoint, verbose: verbose).perform
418
+ end
419
+
420
+ # Get a text tree of names for a dataset
421
+ #
422
+ # @param dataset_id [String] The dataset id
423
+ # @param import_attempt [Integer] The import attempt number
424
+ #
425
+ def self.name_tree(dataset_id, import_attempt: nil, verbose: nil)
426
+
427
+ # get last import attempt number if none given
428
+ if import_attempt.nil?
429
+ import = self.importer(dataset_id: dataset_id)
430
+ import_attempt = import['attempt']
431
+ end
432
+
433
+ endpoint = "dataset/#{dataset_id}/import/#{import_attempt}/tree"
434
+ Request.new(endpoint: endpoint, verbose: verbose).perform
435
+ end
436
+
437
+ # Get name usages or a nameusage from a dataset
438
+ # Note: Queries the PSQL database, whereas nameusage_search uses Elastic Search
439
+ #
440
+ # @param dataset_id [String] The dataset id
441
+ # @param nameusage_id [String] The nameusage id
442
+ # @param q [String] The scientific name or authorship search query
443
+ # @param rank [Array, String] The rank of the taxon in the search query q
444
+ # @param nidx_id [String] The name index id
445
+ # @param subresource [String] The name subresource endpoint (relations, synonyms, types, or orphans)
446
+ #
447
+ # @param offset [Integer] Offset for pagination
448
+ # @param limit [Integer] Limit for pagination
449
+ # @param verbose [Boolean] Print headers to STDOUT
450
+ #
451
+ # @return [Array, Boolean] An array of hashes
452
+ def self.nameusage(dataset_id, nameusage_id: nil, q: nil, rank: nil, nidx_id: nil, subresource: nil,
453
+ offset: nil, limit: nil, verbose: false)
454
+ endpoint = "dataset/#{dataset_id}/nameusage"
455
+ unless nameusage_id.nil?
456
+ endpoint = "#{endpoint}/#{nameusage_id}"
457
+ offset = nil
458
+ limit = nil
459
+ end
460
+ unless subresource.nil?
461
+ endpoint = "#{endpoint}/#{subresource}"
462
+ end
463
+ Request.new(endpoint: endpoint, q: q, rank: rank, nidx_id: nidx_id, offset: offset, limit: limit,
464
+ verbose: verbose).perform
465
+ end
466
+
467
+ # TODO: /dataset/{key}/nameusage/{id}/related not covered
468
+ # TODO: /dataset/{key}/nameusage/{id}/source not covered
469
+
470
+ # Get names or a name from a dataset
471
+ #
472
+ # @param dataset_id [String] The dataset id
473
+ # @param name [String] The scientific name to match
474
+ # @param authorship [String] The authorship string for the scientific name
475
+ # @param code [String] The nomenclatural code (bacterial, botanical, cultivars, phytosociological, virus, zoological)
476
+ # @param rank [String] The rank of the scientific name
477
+ # @param within_superkingdom [String] Restricts query to within a superkingdom
478
+ # @param within_kingdom [String] Restricts query to within a kingdom
479
+ # @param within_subkingdom [String] Restricts query to within a subkingdom
480
+ # @param within_superphylum [String] Restricts query to within a superphylum
481
+ # @param within_phylum [String] Restricts query to within a phylum
482
+ # @param within_subphylum [String] Restricts query to within a subphylum
483
+ # @param within_superclass [String] Restricts query to within a superclass
484
+ # @param within_class [String] Restricts query to within a class
485
+ # @param within_subclass [String] Restricts query to within a subclass
486
+ # @param within_superorder [String] Restricts query to within a superorder
487
+ # @param within_order [String] Restricts query to within a order
488
+ # @param within_suborder [String] Restricts query to within a suborder
489
+ # @param within_superfamily [String] Restricts query to within a superfamily
490
+ # @param within_family [String] Restricts query to within a family
491
+ # @param within_subfamily [String] Restricts query to within a subfamily
492
+ # @param within_tribe [String] Restricts query to within a tribe
493
+ # @param within_subtribe [String] Restricts query to within a subtribe
494
+ # @param within_genus [String] Restricts query to within a genus
495
+ # @param within_subgenus [String] Restricts query to within a subgenus
496
+ # @param within_section [String] Restricts query to within a section
497
+ # @param within_species [String] Restricts query to within a species
498
+ #
499
+ # @param verbose [Boolean] Print headers to STDOUT
500
+ #
501
+ # @return [Array, Boolean] An array of hashes
502
+ def self.matching(dataset_id, name: nil, authorship: nil, code: nil, rank: nil, within_superkingdom: nil,
503
+ within_kingdom: nil, within_subkingdom: nil, within_superphylum: nil, within_phylum: nil,
504
+ within_subphylum: nil, within_superclass: nil, within_class: nil, within_subclass: nil,
505
+ within_superorder: nil, within_order: nil, within_suborder: nil, within_superfamily: nil,
506
+ within_family: nil, within_subfamily: nil, within_tribe: nil, within_subtribe: nil,
507
+ within_genus: nil, within_subgenus: nil, within_section: nil, within_species: nil,
508
+ verbose: false)
509
+ endpoint = "dataset/#{dataset_id}/nameusage/match"
510
+ Request.new(endpoint: endpoint, name: name, authorship: authorship, code: code, rank: rank,
511
+ within_superkingdom: within_superkingdom, within_kingdom: within_kingdom,
512
+ within_subkingdom: within_subkingdom, within_superphylum: within_superphylum,
513
+ within_phylum: within_phylum, within_subphylum: within_subphylum, within_superclass: within_superclass,
514
+ within_class: within_class, within_subclass: within_subclass, within_superorder: within_superorder,
515
+ within_order: within_order, within_suborder: within_suborder, within_superfamily: within_superfamily,
516
+ within_family: within_family, within_subfamily: within_subfamily, within_tribe: within_tribe,
517
+ within_subtribe: within_subtribe, within_genus: within_genus, within_subgenus: within_subgenus,
518
+ within_section: within_section, within_species: within_species, verbose: verbose).perform
519
+ end
520
+
521
+ # Search for a name usage with a regex pattern
522
+ #
523
+ # @param dataset_id [String, nil] restricts name usage pattern search within a dataset
524
+ # @param regexp [String] The regular expression pattern
525
+ # @param status [String, nil] The taxonomic status (accepted, provisionally_accepted, synonym, ambiguous_synonym, misapplied, bare_name)
526
+ # @param rank [String, nil] The taxonomic rank
527
+ # @param project_id [String, nil] Filter to names from project_id, required if decision_mode used
528
+ # @param decision_mode [String, nil] The type of decision (block, reviewed, update, update_recursive, ignore)
529
+ #
530
+ # @param offset [Integer] Offset for pagination
531
+ # @param limit [Integer] Limit for pagination
532
+ # @param verbose [Boolean] Print headers to STDOUT
533
+ def self.nameusage_pattern(dataset_id, regexp, status: nil, rank: nil, project_id: nil, decision_mode: nil,
534
+ offset: nil, limit: nil, verbose: false)
535
+ endpoint = "dataset/#{dataset_id}/nameusage/pattern"
536
+ Request.new(endpoint: endpoint, regexp: regexp, project_id: project_id, status: status, rank: rank,
537
+ decision_mode: decision_mode, offset: offset, limit: limit, verbose: verbose).perform
538
+ end
539
+
540
+ # Search the nameusage route, which uses Elastic Search
541
+ #
542
+ # @param q [String] A query string
543
+ # @param dataset_id [String, nil] restricts name usage search within a dataset
544
+ # @param endpoint [String, nil] some endpoints have nested options
545
+ # @param content [Array, String, nil] restrict search to SCIENTIFIC_NAME, or AUTHORSHIP
546
+ # @param issue [Array, String, nil] the data quality issue
547
+ # @param type [String, nil] sets the type of search to PREFIX, WHOLE_WORDS, or EXACT
548
+ # @param rank [String, nil] taxonomic rank of name usages
549
+ # @param min_rank [String, nil] minimum taxonomic rank of name usages
550
+ # @param max_rank [String, nil] maximum taxonomic rank of name usages
551
+ # @param facet [Array, String, nil] the search facet
552
+ #
553
+ # @param sort_by [String, nil] sort results by NAME, TAXONOMIC, INDEX_NAME_ID, NATIVE, or RELEVANCE
554
+ # @param reverse [Boolean] sort in reverse order
555
+ # @param offset [Integer] Offset for pagination
556
+ # @param limit [Integer] Limit for pagination
557
+ # @param verbose [Boolean] Print headers to STDOUT
558
+ #
559
+ # @return [Array, Boolean] An array of hashes
560
+ def self.nameusage_search(q: nil, dataset_id: nil, endpoint: 'nameusage/search', content: nil, issue: nil,
561
+ type: nil, rank: nil, min_rank: nil, max_rank: nil, facet: nil,
562
+ sort_by: nil, reverse: nil, offset: nil, limit: nil,
563
+ verbose: false)
564
+
565
+ # a nil dataset_id will search name usages from all datasets in ChecklistBank
566
+ unless dataset_id.nil?
567
+ endpoint = "dataset/#{dataset_id}/nameusage/search"
568
+ end
569
+
570
+ Request.new(endpoint: endpoint, q: q, content: content, issue: issue, type: type,
571
+ rank: rank, min_rank: min_rank, max_rank: max_rank, facet: facet,
572
+ sort_by: sort_by, reverse: reverse, offset: offset, limit: limit, verbose: verbose).perform
573
+ end
574
+
575
+ # Get a name usage suggestion
576
+ #
577
+ # @param dataset_id [String] restricts name usage search within a dataset
578
+ # @param q [String] A suggestion search query
579
+ # @param fuzzy [Boolean, nil] Whether to include fuzzy matches for misspellings (TODO: might not actually work?)
580
+ # @param min_rank [String, nil] The minimum rank to suggest
581
+ # @param max_rank [String, nil] The maximum rank to suggest
582
+ # @param sort_by [String, nil] The sorting order (name, taxonomic, index_name_id, native, relevance)
583
+ # @param reverse [Boolean, nil] Sort in opposite order
584
+ # @param accepted [Boolean, nil] Suggest only accepted names
585
+ #
586
+ # @limit [Integer, nil] Limit the suggestion number (offset not available)
587
+ # @param verbose [Boolean] Print headers to STDOUT
588
+ #
589
+ # @return [Hash, Boolean] A a hash of name usage suggestions
590
+ def self.nameusage_suggest(dataset_id, q, fuzzy: nil, min_rank: nil, max_rank: nil, sort_by: nil, reverse: nil,
591
+ accepted: nil, limit: nil, verbose: false)
592
+ endpoint = "dataset/#{dataset_id}/nameusage/suggest"
593
+ Request.new(endpoint: endpoint, q: q, fuzzy: fuzzy, min_rank: min_rank, max_rank: max_rank, sort_by: sort_by,
594
+ reverse: reverse, accepted: accepted, limit: limit, verbose: verbose).perform
595
+ end
596
+
597
+ # Get names index info
598
+ #
599
+ # @param nidx_id [Integer] a names index ID
600
+ # @param subresource [String, nil] the subresource (group)
601
+ def self.nidx(nidx_id, subresource: nil, verbose: false)
602
+ endpoint = "nidx/#{nidx_id}"
603
+ endpoint = "nidx/#{nidx_id}/#{subresource}" unless subresource.nil?
604
+ Request.new(endpoint: endpoint, verbose: verbose).perform
605
+ end
606
+
607
+ # Get names index matches
608
+ # @param q [String, nil] A match query
609
+ # @param authorship [String, nil] An authorship string
610
+ # @param rank [String, nil] The taxonomic rank
611
+ # @param code [String, nil] The nomenclatural code
612
+ #
613
+ # @param verbose [Boolean] Print headers to STDOUT
614
+ #
615
+ # @return [Hash, Boolean] A match hash
616
+ def self.nidx_match(q, authorship: nil, rank: nil, code: nil, verbose: false)
617
+ endpoint = "nidx/match"
618
+ Request.new(endpoint: endpoint, q: q, authorship: authorship, rank: rank, code: code, verbose: verbose).perform
619
+ end
620
+
621
+ # Parse a {subresource}
622
+ #
623
+ # This is the generic parser wrapper. For specialized parsers, like the names, homoglyphs, idconverter, metadata,
624
+ # use the specialized parsers below like Colrapi.parser_name(). Returns a list of parsers if no subresource given.
625
+ #
626
+ # @param subresource [String] the type of parser to use
627
+ # @param q [Array, String] a query string or array of query strings to parse
628
+ #
629
+ # @return [Array, Hash, Boolean] An array of parsers, or a parser result hash
630
+ def self.parser(subresource: nil, q: nil, verbose: false)
631
+ endpoint = "parser"
632
+ endpoint = "#{endpoint}/#{subresource}" unless subresource.nil?
633
+ Request.new(endpoint: endpoint, q: q, verbose: verbose).perform
634
+ end
635
+
636
+ # Encode or decode identifiers to different formats (e.g., proquints are used as stable identifiers in ChecklistBank)
637
+ # @param mode [String] encode or decode
638
+ # @param id [String] the identifier to convert
639
+ # @param format [String] the format (proquint, hex, latin29, latin32, latin36, base64)
640
+ #
641
+ # @param verbose [Boolean] Print headers to STDOUT
642
+ #
643
+ # @return [String, Integer, Boolean] A parser result hash
644
+ def self.parser_idconverter(mode, id, format, verbose: false)
645
+ endpoint = "parser/idconverter/#{mode}"
646
+ Request.new(endpoint: endpoint, id: id, format: format, verbose: verbose).perform
647
+ end
648
+
649
+ # Parse metadata
650
+ # @param url [String] The url to a metadata file
651
+ # @param format [String] The format of the metadata (yaml, json, eml, datacite, zenodo)
652
+ #
653
+ # @param verbose [Boolean] Print headers to STDOUT
654
+ #
655
+ # @return [String, Integer, Boolean] A parser result hash
656
+ def self.parser_metadata(url, format: nil, verbose: false)
657
+ endpoint = 'parser/metadata'
658
+ Request.new(endpoint: endpoint, url: url, format: format, verbose: verbose).perform
659
+ end
660
+
661
+ # Parse a scientific name
662
+ #
663
+ # @param name [String] The scientific name to parse
664
+ # @param authorship [String, nil] The authorship string for the scientific name
665
+ # @param rank [String, nil] The rank of the scientific name to parse
666
+ # @param code [String] The nomenclatural code (bacterial, botanical, cultivars, phytosociological, virus, zoological)
667
+ #
668
+ # @return [Hash, Boolean] A hash with the parsed scientific name
669
+ def self.parser_name(name, authorship: nil, rank: nil, code: nil, verbose: false)
670
+ endpoint = 'parser/name'
671
+ Request.new(endpoint: endpoint, name: name, authorship: authorship, rank: rank, code: code,
672
+ verbose: verbose).perform
673
+ end
674
+
675
+ # Get metadata patch
676
+ #
677
+ # @param dataset_id [String] The dataset id
678
+ # @param token [String, nil] The authentication token from retrieved with Colrapi.user_login(user, password)
679
+ def self.patch(dataset_id, patch_id: nil, token: nil, verbose: false)
680
+ endpoint = "dataset/#{dataset_id}/patch"
681
+ unless patch_id.nil?
682
+ endpoint = "#{endpoint}/#{patch_id}"
683
+ end
684
+ Request.new(endpoint: endpoint, token: token, verbose: verbose).perform
685
+ end
686
+
687
+ # Get the latest preview release metadata (or points to the project draft dataset after the preview is released?)
688
+ # (Note: you can also use 3LRC where 3 is the project_id as an ID on any endpoint with dataset_id or project_id
689
+ # to get data from the latest release candidate, or 3LR gets the latest release)
690
+ # @param project_id [String] The project id
691
+ #
692
+ # @param verbose [Boolean] Print headers to STDOUT
693
+ # @return [Array, Boolean] An array of hashes
694
+ def self.preview(project_id, verbose: false)
695
+ Request.new(endpoint: "dataset/#{project_id}/preview", verbose: verbose).perform
696
+ end
697
+
698
+ # Get a reference with @reference_id from dataset @dataset_id via the reference route
699
+ #
700
+ # @param dataset_id [String] The dataset id
701
+ # @param reference_id [String] The reference id
702
+ # @param subresource [String] The reference subresource endpoint (orphans)
703
+ # @param issue [Array, String] The data quality issue (https://api.checklistbank.org/vocab/issue)
704
+ #
705
+ # @param offset [Integer] Offset for pagination
706
+ # @param limit [Integer] Limit for pagination
707
+ # @param verbose [Boolean] Print headers to STDOUT
708
+ #
709
+ # @return [Array, Boolean] An array of hashes
710
+ def self.reference(dataset_id, reference_id: nil, subresource: nil, issue: nil, offset: nil, limit: nil,
711
+ verbose: false)
712
+ endpoint = "dataset/#{dataset_id}/reference"
713
+ if subresource == 'orphans'
714
+ reference_id = nil
715
+ endpoint = "#{endpoint}/orphans"
716
+ end
717
+ unless reference_id.nil?
718
+ endpoint = "#{endpoint}/#{reference_id}"
719
+ end
720
+ Request.new(endpoint: endpoint, issue: issue, offset: offset, limit: limit, verbose: verbose).perform
721
+ end
722
+
723
+ # Get reviewer info
724
+ #
725
+ # @param dataset_id [String] The dataset id
726
+ # @param token [String, nil] The authentication token from retrieved with Colrapi.user_login(user, password)
727
+ #
728
+ # # @return [Array, Hash, Boolean] An array of hashes
729
+ def self.reviewer(dataset_id, token, verbose: false)
730
+ endpoint = "dataset/#{dataset_id}/reviewer"
731
+ Request.new(endpoint: endpoint, token: token, verbose: verbose).perform
732
+ end
733
+
734
+ # Get sector metadata, which allows importing datasets into project subtrees
735
+ #
736
+ # @param dataset_id [String] The dataset id
737
+ # @param sector_id [Integer, nil] The sector id
738
+ # @param name [String] The scientific name to query
739
+ # @param rank [String, nil] The rank of the scientific name
740
+ # @param modified_by [Integer, nil] Filter by a user id on last modified by
741
+ # @param broken [Boolean, nil] Whether the decision is broken or not
742
+ # @param subject_dataset_id [String, nil] The source dataset id
743
+ # @param last_synced_before [Date, nil] Filter by sectors synced before this date
744
+ # @param mode [String, nil] Filter by type of sector (attach, union, merge)
745
+ # @param subject [Boolean, nil] TODO: what does this do? All decisions with subject=true are bare names, so maybe it checks if the subject taxon exists?
746
+ # @param min_size [Integer, nil] The minimum number of records in the sector
747
+ # @param without_data [Boolean, nil] Filters to empty sectors with no data synced into the project yet
748
+ #
749
+ # @param offset [Integer] Offset for pagination
750
+ # @param limit [Integer] Limit for pagination
751
+ # @param verbose [Boolean] Print headers to STDOUT
752
+ #
753
+ # @return [Hash, Boolean] An hash of results
754
+ def self.sector(dataset_id, sector_id: nil, name: nil, rank: nil, modified_by: nil, broken: nil,
755
+ subject_dataset_id: nil, last_synced_before: nil, mode: nil, subject: nil, min_size: nil, without_data: nil,
756
+ offset: nil, limit: nil, verbose: false)
757
+ endpoint = "dataset/#{dataset_id}/sector"
758
+ if sector_id.nil?
759
+ Request.new(endpoint: endpoint, name: name, rank: rank, modified_by: modified_by, broken: broken,
760
+ subject_dataset_id: subject_dataset_id, last_synced_before: last_synced_before, mode: mode,
761
+ subject: subject, min_size: min_size, without_data: without_data,
762
+ offset: offset, limit: limit, verbose: verbose).perform
763
+ else
764
+ endpoint = "#{endpoint}/#{sector_id}"
765
+ Request.new(endpoint: endpoint, verbose: verbose).perform
766
+ end
767
+ end
768
+
769
+ # Get sector sync info
770
+ #
771
+ # @param dataset_id [String] The dataset id
772
+ # @param sector_id [Integer, nil] The sector id
773
+ # @param state [Array, String, nil] The sector sync state (e.g., waiting, processing, inserting, indexing, finished, etc.)
774
+ # @param running [Boolean, nil] Filter to sector syncs that are only running
775
+ # @param attempt [Integer, nil] The sync attempt number for sector_id
776
+ # @param subresource [String, nil] The subresource for attempt (names or tree)
777
+ #
778
+ # @param offset [Integer] Offset for pagination
779
+ # @param limit [Integer] Limit for pagination
780
+ # @param verbose [Boolean] Print headers to STDOUT
781
+ #
782
+ # @return [Hash, Boolean] An hash of results
783
+ def self.sector_sync(dataset_id, sector_id: nil, attempt: nil, subresource: nil, state: nil, running: nil, offset: nil, limit: nil, verbose: false)
784
+ endpoint = "dataset/#{dataset_id}/sector/sync"
785
+ if sector_id.nil?
786
+ Request.new(endpoint: endpoint, state: state, running: running, offset: offset, limit: limit,
787
+ verbose:verbose).perform
788
+ else
789
+ if attempt.nil?
790
+ endpoint = "dataset/#{dataset_id}/sector/#{sector_id}/sync"
791
+ else
792
+ endpoint = "dataset/#{dataset_id}/sector/#{sector_id}/sync/#{attempt}"
793
+ endpoint = "#{endpoint}/#{subresource}" unless subresource.nil?
794
+ end
795
+ Request.new(endpoint: endpoint, verbose:verbose).perform
796
+ end
797
+ end
798
+
799
+ # Get source metadata for datasets assembled into a project dataset
800
+ #
801
+ # @param dataset_id [String] The project dataset id
802
+ # @param source_id [String] The source dataset id
803
+ # @param not_current_only [String] Return only not current sources
804
+ # @param original [String] TODO: what does this do?
805
+ #
806
+ # @return [Array, Hash, Boolean] An array of source hashes, or a hash of a source
807
+ def self.source(dataset_id, source_id: nil, not_current_only: nil, original: nil, verbose: false)
808
+ endpoint = "dataset/#{dataset_id}/source"
809
+ if source_id.nil?
810
+ Request.new(endpoint: endpoint, not_current_only: not_current_only, verbose: verbose).perform
811
+ else
812
+ endpoint = "dataset/#{dataset_id}/source/#{source_id}"
813
+ Request.new(endpoint: endpoint, original: original, verbose: verbose).perform
814
+ end
815
+ end
816
+
817
+
818
+ # Get the dataset settings
819
+ # @param dataset_id [String] The dataset id
820
+ #
821
+ # @return [Hash, Boolean] A hash including the dataset settings
822
+ def self.settings(dataset_id)
823
+ Request.new(endpoint: "dataset/#{dataset_id}/settings").perform
824
+ end
825
+
826
+ # Get a synonym with @synonym_id from dataset @dataset_id via the synonym route
827
+ #
828
+ # @param dataset_id [String] The dataset id
829
+ # @param synonym_id [String] The synonym id
830
+ # @param subresource [String] The synonym subresource endpoint (source)
831
+ #
832
+ # @param offset [Integer] Offset for pagination
833
+ # @param limit [Integer] Limit for pagination
834
+ # @param verbose [Boolean] Print headers to STDOUT
835
+ #
836
+ # @return [Array, Boolean] An array of hashes
837
+ def self.synonym(dataset_id, synonym_id: nil, subresource: nil, offset: nil, limit: nil, verbose: false)
838
+ endpoint = "dataset/#{dataset_id}/synonym"
839
+ unless synonym_id.nil?
840
+ endpoint = "#{endpoint}/#{synonym_id}"
841
+ end
842
+ if subresource == 'source'
843
+ endpoint = "#{endpoint}/source"
844
+ end
845
+ Request.new(endpoint: endpoint, offset: offset, limit: limit, verbose: verbose).perform
846
+ end
847
+
848
+ # Get the full list of taxon IDs for a dataset (returns 1 ID string per line, not JSON)
849
+ #
850
+ # @param dataset_id [String] The dataset id
851
+ #
852
+ # @return [Array, Boolean] An array of hashes
853
+ def self.taxon_ids(dataset_id, verbose: false)
854
+ Request.new(endpoint: "dataset/#{dataset_id}/taxon/ids", verbose: verbose).perform
855
+ end
856
+
857
+ # Get a taxon with @id from dataset @dataset_id via the taxon route
858
+ #
859
+ # @param dataset_id [String] The dataset id
860
+ # @param taxon_id [String] The taxon id
861
+ # @param subresource [String] The taxon subresource endpoint (classification, distribution, info, interaction, media,
862
+ # relation, source, synonyms, treatment, or vernacular)
863
+ # @param format [String] The format of the treatment (plain_text, markdown, xml, html, tax_pub, taxon_x, rdf)
864
+ #
865
+ # @param offset [Integer] Offset for pagination
866
+ # @param limit [Integer] Limit for pagination
867
+ # @param verbose [Boolean] Print headers to STDOUT
868
+ #
869
+ # @return [Array, Boolean] An array of hashes
870
+ def self.taxon(dataset_id, taxon_id: nil, subresource: nil, format: nil, offset: nil, limit: nil, verbose: false)
871
+ endpoint = "dataset/#{dataset_id}/taxon"
872
+ unless taxon_id.nil?
873
+ endpoint = "#{endpoint}/#{taxon_id}"
874
+ end
875
+
876
+ if !subresource.nil?
877
+ endpoint = "#{endpoint}/#{subresource}"
878
+ end
879
+ Request.new(endpoint: endpoint, offset: offset, format: format, limit: limit, verbose: verbose).perform
880
+ end
881
+
882
+ # Get the root taxa
883
+ #
884
+ # @param dataset_id [String] The dataset id
885
+ # @param taxon_id [String] The taxon id
886
+ # @param children [Boolean] Display the children of taxon_id
887
+ #
888
+ # @param offset [Integer] Offset for pagination
889
+ # @param limit [Integer] Limit for pagination
890
+ # @param verbose [Boolean] Print headers to STDOUT
891
+ #
892
+ # @return [Array, Boolean] An array of hashes
893
+ def self.tree(dataset_id, taxon_id: nil, children: false, offset: nil, limit: nil, verbose: false)
894
+ endpoint = "dataset/#{dataset_id}/tree"
895
+ endpoint = "#{endpoint}/#{taxon_id}" unless taxon_id.nil?
896
+ endpoint = "#{endpoint}/children" unless taxon_id.nil? or !children
897
+ Request.new(endpoint: endpoint, offset: offset, limit: limit, verbose: verbose).perform
898
+ end
899
+
900
+ # Get user data
901
+ #
902
+ # @param user_id [Integer, nil] The user id
903
+ # @param q [String, nil] The search query
904
+ # @param role [String, nil] The user role (admin, editor, or reviewer)
905
+ #
906
+ # @param offset [Integer] Offset for pagination
907
+ # @param limit [Integer] Limit for pagination
908
+ # @param token [String, nil] The authentication token from retrieved with Colrapi.user_login(user, password)
909
+ # @param verbose [Boolean] Print headers to STDOUT
910
+ #
911
+ # @return [Array, Boolean] An array of hashes
912
+ def self.user(user_id: nil, q: nil, role: nil, offset: nil, limit: nil, token: nil, verbose: false)
913
+ if user_id.nil?
914
+ endpoint = "user"
915
+ Request.new(endpoint: endpoint, q: q, role: role, offset: offset, limit: limit, token: token,
916
+ verbose: verbose).perform
917
+ else
918
+ endpoint = "user/#{user_id}"
919
+ Request.new(endpoint: endpoint, token: token, verbose: verbose).perform
920
+ end
921
+ end
922
+
923
+ # Get datasets user can access
924
+ # @param token [String] The access token from Colrapi.user_login()
925
+ # @param dataset_id [String, nil] A dataset id to check
926
+ # @param origin [Array, String, nil] Filter by the origin of a dataset (external, project, release, xrelease)
927
+ #
928
+ # @return [Array, Boolean] An array of datasets, or returns a boolean if dataset_id is provided
929
+ def self.user_dataset(token, dataset_id: nil, origin: nil, verbose: false)
930
+ endpoint = "user/dataset"
931
+ if dataset_id.nil?
932
+ Request.new(endpoint: endpoint, token: token, origin: origin, verbose: verbose).perform
933
+ else
934
+ endpoint = "user/dataset/#{dataset_id}"
935
+ Request.new(endpoint: endpoint, token: token, verbose: verbose).perform
936
+ end
937
+ end
938
+
939
+ # Authenticate user and get authentication token
940
+ def self.user_login(user, password, verbose: false)
941
+ Request.new(endpoint: "user/login", user: user, password: password, verbose: verbose).perform
942
+ end
943
+
944
+ # Get the authenticated user
945
+ #
946
+ # @param token [String, nil] The authentication token from retrieved with Colrapi.user_login(user, password)
947
+ # @param verbose [Boolean] Print headers to STDOUT
948
+ #
949
+ # @return [Array, Boolean] An array of hashes
950
+ def self.user_me(token, verbose: false)
951
+ Request.new(endpoint: "user/me", token: token, verbose: verbose).perform
952
+ end
953
+
954
+ # Get verbatim data
955
+ #
956
+ # @param dataset_id [String] The dataset id
957
+ # @param verbatim_id [String] The verbatim id
958
+ # @param q [String] The search query string
959
+ # @param issue [Array, String] Filter by data quality issue (e.g., ACCEPTED_NAME_MISSING, DUPLICATE_NAME, URL_INVALID)
960
+ # @param type [Array, String] The file type (e.g., acef:AcceptedSpecies, col:Taxon, dwc:Taxon)
961
+ #
962
+ # TODO: May not work yet: https://github.com/CatalogueOfLife/backend/issues/1201
963
+ # @param term [Array, String] Filter by term (http://api.checklistbank.org/vocab/term)
964
+ # @param term_operator [String] The operator to use with term ('and' or 'or')
965
+ #
966
+ # @param offset [Integer] Offset for pagination
967
+ # @param limit [Integer] Limit for pagination
968
+ # @param verbose [Boolean] Print headers to STDOUT
969
+ #
970
+ # @return [Array, Boolean] An array of hashes
971
+ def self.verbatim(dataset_id, verbatim_id: nil, q: nil, issue: nil, type: nil, term: nil, term_operator: nil,
972
+ offset: nil, limit: nil, verbose: false)
973
+ endpoint = "dataset/#{dataset_id}/verbatim"
974
+ if verbatim_id.nil?
975
+ Request.new(endpoint: endpoint, q: q, issue: issue, type: type, term: term, term_operator: term_operator,
976
+ offset: offset, limit: limit, verbose: verbose).perform
977
+ else
978
+ endpoint = "#{endpoint}/#{verbatim_id}"
979
+ Request.new(endpoint: endpoint, verbose: verbose).perform
980
+ end
981
+ end
982
+
983
+ # Get vernacular names
984
+ #
985
+ # @param dataset_id [String, nil] The dataset id
986
+ # @param q [String] A vernacular name search query
987
+ # @param language [String, nil] The language of the vernacular name (see: http://api.checklistbank.org/vocab/language)
988
+ #
989
+ # @param offset [Integer] Offset for pagination
990
+ # @param limit [Integer] Limit for pagination
991
+ # @param verbose [Boolean] Print headers to STDOUT
992
+ #
993
+ # @return [Hash] A hash of vernacular results
994
+ def self.vernacular(dataset_id: nil, q: nil, language: nil, offset: nil, limit: nil, verbose: false)
995
+ if dataset_id.nil?
996
+ endpoint = 'vernacular'
997
+ Request.new(endpoint: endpoint, q: q, language: language, offset: offset, limit: limit, verbose: verbose).perform
998
+ else
999
+ endpoint = "dataset/#{dataset_id}/vernacular"
1000
+ Request.new(endpoint: endpoint, q: q, language: language, offset: offset, limit: limit, verbose: verbose).perform
1001
+ end
1002
+ end
1003
+
1004
+ # Get backend version
1005
+ #
1006
+ # @return [String] A version string
1007
+ def self.version(verbose: false)
1008
+ Request.new(endpoint: 'version', verbose: verbose).perform
1009
+ end
1010
+
1011
+ # Get vocab
1012
+ # @param term [String] The vocab term
1013
+ # @param subresource [String] The subresource which is usually the id, code, or name
1014
+ # @param children [Boolean] Returns the geotime's children if true
1015
+ #
1016
+ # @param verbose [Boolean] Print headers to STDOUT
1017
+ #
1018
+ # @return [Array]
1019
+ def self.vocab(term: nil, subresource: nil, children: false, verbose: false)
1020
+ endpoint = "vocab"
1021
+ endpoint = "#{endpoint}/#{term}" unless term.nil?
1022
+ endpoint = "#{endpoint}/#{subresource}" unless term.nil? or subresource.nil?
1023
+ endpoint = "#{endpoint}/children" if children and term == "geotime"
1024
+ Request.new(endpoint: endpoint, verbose: verbose).perform
1025
+ end
1026
+ end