figshare_api_v2 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3b830ddd5bc2ff58ce03dc8c96f2029fe21e7913c9ce360cd09078b19c446277
4
+ data.tar.gz: 682588604c24ee90a212f854815e4da68edb68f33230d7d4d019b8dd3ed50b8e
5
+ SHA512:
6
+ metadata.gz: bf62ed1ab2f35779259c09c0beee9c04d1b0caa7a06d5186de7c2d9d4010e4bcf4c24af83c06215d512e35ff9e63bd4318b3a412fc64b5c369d93465835ccc03
7
+ data.tar.gz: fde9f1ee7a1d052e25553175412d813d9ffc7dca198d05c715693e9d7601ef14cc84ba6b1976416a61a90ac052ab220e9b268db4895c4f87306c3027cbf0539c
@@ -0,0 +1,58 @@
1
+ robertburrowes Thu Nov 5 11:09:37 2020 +1300
2
+ bump version
3
+ robertburrowes Thu Nov 5 11:09:10 2020 +1300
4
+ bump version
5
+ robertburrowes Thu Nov 5 11:08:53 2020 +1300
6
+ Upload test of directory
7
+ robertburrowes Thu Nov 5 11:08:30 2020 +1300
8
+ Trying real world examples
9
+ robertburrowes Thu Nov 5 11:08:02 2020 +1300
10
+ dependency on WIKK::dir_r gem
11
+ robertburrowes Thu Nov 5 11:07:41 2020 +1300
12
+ Fixes, after tests. Added upload_dir
13
+ robertburrowes Fri Oct 30 15:07:02 2020 +1300
14
+ playing with more tests
15
+ robertburrowes Fri Oct 30 15:06:45 2020 +1300
16
+ minor tidy up. This version successfully uploaded files
17
+ robertburrowes Fri Oct 30 15:05:32 2020 +1300
18
+ check response content type, and only parse json, when json
19
+ robertburrowes Fri Oct 30 09:41:42 2020 +1300
20
+ More testing
21
+ robertburrowes Fri Oct 30 09:41:31 2020 +1300
22
+ Added trace code to upload.
23
+ robertburrowes Fri Oct 30 09:40:43 2020 +1300
24
+ Name conflict with delete. Use explicit name
25
+ robertburrowes Fri Oct 30 09:39:36 2020 +1300
26
+ Ignore test data
27
+ robertburrowes Fri Oct 30 09:06:18 2020 +1300
28
+ Init class test
29
+ robertburrowes Fri Oct 30 09:05:27 2020 +1300
30
+ Init class test
31
+ robertburrowes Fri Oct 30 09:05:17 2020 +1300
32
+ Example code
33
+ robertburrowes Fri Oct 30 09:05:03 2020 +1300
34
+ include the OAI PMH stub
35
+ robertburrowes Fri Oct 30 09:04:47 2020 +1300
36
+ Changed to use Figshare::Base calls
37
+ robertburrowes Fri Oct 30 09:03:58 2020 +1300
38
+ Stub for Stats class
39
+ robertburrowes Fri Oct 30 09:03:42 2020 +1300
40
+ stub for OAI PMH class
41
+ robertburrowes Fri Oct 30 09:03:22 2020 +1300
42
+ comment aligned with Init class initialize
43
+ robertburrowes Fri Oct 30 09:03:00 2020 +1300
44
+ Added an Init class to dynamically create subclasses
45
+ robertburrowes Thu Oct 29 19:23:55 2020 +1300
46
+ playing with tests
47
+ robertburrowes Thu Oct 29 19:23:40 2020 +1300
48
+ Update
49
+ robertburrowes Thu Oct 29 19:23:29 2020 +1300
50
+ Added in missing api calls
51
+ robertburrowes Thu Oct 29 18:13:47 2020 +1300
52
+ mode change only
53
+ robertburrowes Thu Oct 29 17:59:56 2020 +1300
54
+ Changes to build files to get first pkg created
55
+ robertburrowes Thu Oct 29 17:32:27 2020 +1300
56
+ initial version. Not tested yet
57
+ Rob Burrowes Mon Oct 19 09:52:15 2020 +1300
58
+ Initial commit
@@ -0,0 +1,18 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.md
4
+ Rakefile
5
+ lib/authors.rb
6
+ lib/base.rb
7
+ lib/figshare_api_v2.rb
8
+ lib/institutions.rb
9
+ lib/oai_pmh.rb
10
+ lib/other.rb
11
+ lib/private_articles.rb
12
+ lib/private_collections.rb
13
+ lib/private_projects.rb
14
+ lib/public_articles.rb
15
+ lib/public_collections.rb
16
+ lib/public_projects.rb
17
+ lib/stats.rb
18
+ lib/upload.rb
@@ -0,0 +1,74 @@
1
+ # figshare_api_v2
2
+
3
+ * Docs :: https://UoA-eResearch.github.io/figshare_api_v2/
4
+ * Source :: https://github.com/UoA-eResearch/figshare_api_v2
5
+ * Gem :: https://rubygems.org/gems/figshare_api_v2
6
+ * Figshare :: https://docs.figshare.com/
7
+
8
+ ## DESCRIPTION:
9
+
10
+ Figshare version 2 API.
11
+
12
+ ## FEATURES/PROBLEMS:
13
+
14
+ * Stats API not implemented.
15
+ * oai pmh api not implemented.
16
+ * Need to build a test suite
17
+ * impersonate option, for PrivateArticles, PrivateCollections and PrivateProjects ignored for DELETE, and non-json POST and PUT.
18
+
19
+ ## SYNOPSIS:
20
+
21
+ ```
22
+ require 'figshare_api_v2'
23
+
24
+ # Either initialize once, and call @figshare.authors.x @figshare.institutions.x, ...
25
+ @figshare = Figshare::Init.new(figshare_user: 'figshare_admin', conf_dir: "#{__dir__}/conf")
26
+
27
+ @figshare.authors.detail(author_id: 12345) { |a| puts a }
28
+ @figshare.institutions.private_articles { |article| puts article }
29
+ #...
30
+
31
+ # Or initialize each class individually
32
+ @authors = Figshare::Authors.new(figshare_user: 'figshare_admin', conf_dir: "#{__dir__}/conf")
33
+ @institutions = Figshare::Institutions.new(figshare_user: 'figshare_admin', conf_dir: "#{__dir__}/conf")
34
+
35
+ @authors.detail(author_id: 12345) { |a| puts a }
36
+ @institutions.private_articles { |article| puts article }
37
+
38
+ #...
39
+ ````
40
+
41
+ ## REQUIREMENTS:
42
+
43
+ * depends on 'wikk_webbrowser' gem
44
+ * depends on 'wikk_json' gem (beware: adds to_j to the base classes)
45
+
46
+ ## INSTALL:
47
+
48
+ * sudo gem install figshare_api_v2
49
+
50
+ ## LICENSE:
51
+
52
+ The MIT License
53
+
54
+ Copyright (c) 2020
55
+
56
+ Permission is hereby granted, free of charge, to any person obtaining
57
+ a copy of this software and associated documentation files (the
58
+ 'Software'), to deal in the Software without restriction, including
59
+ without limitation the rights to use, copy, modify, merge, publish,
60
+ distribute, sublicense, and/or sell copies of the Software, and to
61
+ permit persons to whom the Software is furnished to do so, subject to
62
+ the following conditions:
63
+
64
+ The above copyright notice and this permission notice shall be
65
+ included in all copies or substantial portions of the Software.
66
+
67
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
68
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
69
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
70
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
71
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
72
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
73
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
74
+
@@ -0,0 +1,31 @@
1
+ # -*- ruby -*-
2
+ require 'rubygems'
3
+ require 'hoe'
4
+ Hoe.plugin :yard
5
+ load "#{__dir__}/version"
6
+
7
+ Hoe.spec PROJECT do
8
+ self.readme_file = "README.md"
9
+ self.developer( "Rob Burrowes","r.burrowes@auckland.ac.nz")
10
+ remote_rdoc_dir = '' # Release to root
11
+
12
+ self.yard_title = PROJECT
13
+ self.yard_options = ['--markup', 'markdown', '--protected']
14
+
15
+ self.dependency "wikk_json", "~> 0.1.2"
16
+ self.dependency "wikk_webbrowser", "~> 0.9.0"
17
+ self.dependency "dir_r", "~> 1.0.0"
18
+ end
19
+
20
+
21
+ #Validate manfest.txt
22
+ #rake check_manifest
23
+
24
+ #Local checking. Creates pkg/
25
+ #rake gem
26
+
27
+ #create doc/
28
+ #rake docs
29
+
30
+ #Copy up to rubygem.org
31
+ #rake release VERSION=1.0.1
@@ -0,0 +1,41 @@
1
+ module Figshare
2
+ # Figshare Author APIs
3
+ #
4
+ class Authors < Base
5
+ # Search authors
6
+ #
7
+ # @param institution [Boolean] Just our institution
8
+ # @param group_id [Integer] Only return this group's collections
9
+ # @param orcid [String] Matches this orcid
10
+ # @param is_active [Boolean]
11
+ # @param is_public [Boolean]
12
+ # @param order [String] "published_date" Default, "modified_date", "views", "cites", "shares"
13
+ # @param order_direction [String] "desc" Default, "asc"
14
+ # @yield [Hash] {id, first_name, last_name, full_name, url_name, is_active, is_public, orcid_id, institution_id, group_id, job_title}
15
+ def search(institute: false, group_id: nil, orcid: nil,
16
+ is_active: true, is_public: true,
17
+ order: 'published_date', order_direction: 'desc',
18
+ search_for:,
19
+ &block
20
+ )
21
+ args = { 'search_for' => search_for }
22
+ args['institution'] = @institute_id if ! institute.nil?
23
+ args['group_id'] = group_id if ! group_id.nil?
24
+ args['is_active'] = is_active if ! is_active.nil?
25
+ args['is_public'] = is_public if ! is_public.nil?
26
+ args['orcid'] = orcid if ! orcid.nil?
27
+ args['order'] = order if ! order.nil?
28
+ args['order_direction'] = order_direction if ! order_direction.nil?
29
+ post(api_query: 'account/authors/search', args: args, &block)
30
+ end
31
+
32
+ # Get an authors details
33
+ #
34
+ # @param author_id [Integer] Figshare Author ID
35
+ # @yield [Hash] {id, first_name, last_name, full_name, url_name, is_active, is_public, orcid_id, institution_id, group_id, job_title}
36
+ def detail(author_id:, &block)
37
+ get(api_query: "account/authors/#{author_id}", &block)
38
+ end
39
+ end
40
+
41
+ end
@@ -0,0 +1,262 @@
1
+ module Figshare
2
+ require "wikk_webbrowser"
3
+ require "wikk_json"
4
+ require 'Time'
5
+
6
+ # Supporting web calls to the API
7
+ #
8
+ class Base
9
+ attr_accessor :auth_token
10
+ attr_accessor :base_dir
11
+ attr_accessor :article_index_file
12
+ attr_accessor :hostname
13
+ attr_accessor :api_url
14
+ attr_accessor :institute_id
15
+
16
+ # Init reads the Json configuration files, setting @course_codes_to_faculty and @academic_department_code_to_faculty
17
+ # Opens a connection to the LDAP server, setting @ldap for other methods to use.
18
+ #
19
+ # @param figshare_user [String] figshare user, in the figshare_keys.json
20
+ # @param conf_dir [String] directory for figshare_keys.json and figshare_site_params.json
21
+ def initialize(figshare_user:, conf_dir:)
22
+ figshare_token = load_json_file("#{conf_dir}/figshare_keys.json")
23
+ @auth_token = figshare_token[figshare_user]
24
+
25
+ figshare_site_params = load_json_file("#{conf_dir}/figshare_site_params.json")
26
+
27
+ @hostname = figshare_site_params['host']
28
+ @api_url = figshare_site_params['api_url']
29
+ @institute_id = figshare_site_params['institute_id']
30
+ end
31
+
32
+ # Parse the config file
33
+ #
34
+ # @param filename [String] config file name to parse
35
+ # @return [Hash|Array] parsed json configuration file.
36
+ private def load_json_file(filename)
37
+ JSON.parse(File.read(filename))
38
+ end
39
+
40
+ # get iterates through the API response, yielding each value to the passed block
41
+ # When Figshare API usually has no paging option.
42
+ # If there is no block, then the results are printed (useful for debugging)
43
+ #
44
+ # @param api_query [String] base figshare api call, to which we add parameters defined in args
45
+ # @param args [Hash] Key, value pairs which get converted to ?key=arg&key=arg...
46
+ # @param debug [Boolean] print result to stdout
47
+ # @yield [String] if given a block, iterates through the result from figshare
48
+ # @return [Integer] number of results.
49
+ private def get(api_query:, args: {}, debug: false, &block)
50
+ content_type = response = nil
51
+ WIKK::WebBrowser.https_session( host: @hostname, verify_cert: false ) do |ws|
52
+ response = ws.get_page( query: "#{@api_url}#{api_query}",
53
+ authorization: "token #{@auth_token}",
54
+ form_values: args
55
+ )
56
+ content_type = ws.header_value(key: 'Content-Type')
57
+ end
58
+ return iterate_json_response(response: response, content_type: content_type, debug: debug, &block)
59
+ end
60
+
61
+ # get_paginate iterates through the API response, yielding each value to the passed block, fetching new pages ,as needed.
62
+ # Figshare API usually has the option of page and page_size parameters, to help with large downloads.
63
+ # If there is no block, then the results are printed (useful for debugging)
64
+ #
65
+ # @param api_query [String] base figshare api call, to which we add parameters defined in args
66
+ # @param args [Hash] Key, value pairs which get converted to ?key=arg&key=arg...
67
+ # @param debug [Boolean] print result to stdout
68
+ # @param by_offset [Boolean] use offset/limit rather than page/page_size in API calls
69
+ # @yield [String] if given a block, iterates through the result from figshare
70
+ # @return [Integer] number of results.
71
+ private def get_paginate(api_query:, args: {}, debug: false, by_offset: false, &block)
72
+ args = {} if args.nil?
73
+ if ! args.is_a?(Hash)
74
+ raise "get_paginate(): Expecting args to be a Hash"
75
+ end
76
+
77
+ offset = 0
78
+ page = 1
79
+ limit = page_size = 100
80
+ result_count = 0
81
+ loop do
82
+ content_type = response = nil
83
+ form_args = by_offset ? {"limit"=>limit, "offset"=>offset} : {"page_size"=>page_size, "page"=>page}
84
+ WIKK::WebBrowser.https_session( host: @hostname, verify_cert: false ) do |ws|
85
+ response = ws.get_page( query: "#{@api_url}#{api_query}",
86
+ authorization: "token #{@auth_token}",
87
+ form_values: form_args.merge(args)
88
+ )
89
+ content_type = ws.header_value(key: 'Content-Type')
90
+ end
91
+ page_count = iterate_json_response(response: response, content_type: content_type, debug: debug, &block)
92
+ result_count += page_count
93
+ break if page_count < page_size # Got less results than we asked for, so it was the last page
94
+
95
+ page += 1 #Ready to fetch next page
96
+ offset += limit #if we use offset, then mor
97
+ end
98
+
99
+ return result_count
100
+ end
101
+
102
+ # post iterates through the API response, yielding each value to the passed block
103
+ # When Figshare API usually has no paging option.
104
+ # If there is no block, then the results are printed (useful for debugging)
105
+ #
106
+ # @param api_query [String] base figshare api call, to which we add parameters defined in args
107
+ # @param args [Hash] Key, value pairs which get converted to ?key=arg&key=arg...
108
+ # @param debug [Boolean] print result to stdout
109
+ # @param content_type [String] Assuming Json, but might need binary ('application/octet-stream')
110
+ # @yield [String] if given a block, iterates through the result from figshare
111
+ # @return [Integer] number of results.
112
+ private def post(api_query:, args: {}, data: nil, debug: false, content_type: 'application/json; charset=UTF-8', &block)
113
+ body = nil
114
+ if data.is_a?(Hash)
115
+ # Convert hash to json, and merge in additional args
116
+ body = data.merge(args).to_j
117
+ elsif data.nil? && ! args.empty?
118
+ # No data, but args, so just use the args
119
+ body = args.to_j
120
+ else
121
+ # Data isn't a Hash, so just pass it through (might be nil)
122
+ body = data
123
+ end
124
+
125
+ content_type = response = nil
126
+ WIKK::WebBrowser.https_session( host: @hostname, verify_cert: false ) do |ws|
127
+ response = ws.post_page( query: "#{@api_url}#{api_query}",
128
+ content_type: content_type,
129
+ authorization: "token #{@auth_token}",
130
+ data: body
131
+ )
132
+ content_type = ws.header_value(key: 'Content-Type')
133
+ end
134
+ return iterate_json_response(response: response, content_type: content_type, debug: debug, &block)
135
+ end
136
+
137
+ # post_paginate iterates through the API response, yielding each value to the passed block, fetching new pages ,as needed.
138
+ # Figshare API usually has the option of page and page_size parameters, to help with large downloads.
139
+ # If there is no block, then the results are printed (useful for debugging)
140
+ #
141
+ # @param api_query [String] base figshare api call, to which we add parameters defined in args
142
+ # @param args [Hash] Key, value pairs which get converted to ?key=arg&key=arg...
143
+ # @param debug [Boolean] print result to stdout
144
+ # @param by_offset [Boolean] use offset/limit rather than page/page_size in API calls
145
+ # @yield [String] if given a block, iterates through the result from figshare
146
+ # @return [Integer] number of results.
147
+ private def post_paginate(api_query:, args: {}, debug: false, by_offset: false, &block)
148
+ page = 1
149
+ offset = 0
150
+ limit = page_size = 100
151
+ result_count = 0
152
+
153
+ args = {} if args.nil?
154
+ if ! args.is_a?(Hash)
155
+ raise "post_paginate(): Expecting args to be a Hash"
156
+ end
157
+
158
+ loop do
159
+ content_type = response = nil
160
+ form_args = by_offset ? {"limit"=>limit, "offset"=>offset} : {"page_size"=>page_size, "page"=>page}
161
+ WIKK::WebBrowser.https_session( host: @hostname, verify_cert: false ) do |ws|
162
+ response = ws.post_page( query: "#{@api_url}#{api_query}",
163
+ content_type: 'application/json; charset=UTF-8',
164
+ authorization: "token #{@auth_token}",
165
+ data: args.merge(form_args).to_j
166
+ )
167
+ content_type = ws.header_value(key: 'Content-Type')
168
+ end
169
+ page_count = iterate_json_response(response: response, content_type: content_type, debug: debug, &block)
170
+ result_count += page_count
171
+ break if page_count < page_size # Got less results than we asked for, so it was the last page
172
+
173
+ page += 1 #Ready to fetch next page
174
+ offset += limit #if we use offset
175
+ end
176
+ return result_count
177
+ end
178
+
179
+ # put iterates through the API response, yielding each value to the passed block
180
+ # When Figshare API usually has no paging option.
181
+ # If there is no block, then the results are printed (useful for debugging)
182
+ #
183
+ # @param api_query [String] base figshare api call, to which we add parameters defined in args
184
+ # @param args [Hash] Key, value pairs which get converted to ?key=arg&key=arg...
185
+ # @param debug [Boolean] print result to stdout
186
+ # @param content_type [String] Assuming Json, but might need binary ('application/octet-stream')
187
+ # @yield [String] if given a block, iterates through the result from figshare
188
+ # @return [Integer] number of results
189
+ private def put(api_query:, args: {}, data: nil, debug: false, content_type: 'application/json; charset=UTF-8', &block)
190
+ body = nil
191
+ if data.is_a?(Hash)
192
+ # Convert hash to json, and merge in additional args
193
+ body = data.merge(args).to_j
194
+ elsif data.nil? && ! args.empty?
195
+ # No data, but args, so just use the args
196
+ body = args.to_j
197
+ else
198
+ # Data isn't a Hash, so just pass it through (might be nil)
199
+ body = data
200
+ end
201
+
202
+ content_type = response = nil
203
+ WIKK::WebBrowser.https_session( host: @hostname, verify_cert: false ) do |ws|
204
+ response = ws.put_page( query: "#{@api_url}#{api_query}",
205
+ content_type: content_type,
206
+ authorization: "token #{@auth_token}",
207
+ data: body
208
+ )
209
+ content_type = ws.header_value(key: 'Content-Type')
210
+ end
211
+ return iterate_json_response(response: response, content_type: content_type, debug: debug, &block)
212
+ end
213
+
214
+ # delete sends an HTML DELETE request.
215
+ # We don't expect to get a response to this call.
216
+ #
217
+ # @param api_query [String] base figshare api call
218
+ # @param debug [Boolean] print result to stdout
219
+ # @yield [Hash] Unlikely to have a result from delete calls, but if we do, we see it here
220
+ # @return [Integer] number of results (usually 0)
221
+ private def delete(api_query:, args: {}, debug: false, &block)
222
+ #ignoring args for the moment. Not sure what to do with them, if we do get them.
223
+ content_type = response = nil
224
+ WIKK::WebBrowser.https_session( host: @hostname, verify_cert: false ) do |ws|
225
+ response = ws.delete_req( query: "#{@api_url}#{api_query}",
226
+ authorization: "token #{@auth_token}"
227
+ )
228
+ content_type = ws.header_value(key: 'Content-Type')
229
+ end
230
+ return iterate_json_response(response: response, content_type: content_type, debug: debug, &block)
231
+ end
232
+
233
+ # For iterate through the api response
234
+ #
235
+ # @param response [String] response from the API call
236
+ # @param content_type [String] From html response header
237
+ # @param debug [Boolean] print result to stdout
238
+ # @yield [Hash] each array member in the response (or the entire response, if not iteratable)
239
+ private def iterate_json_response(response:, content_type:, debug: false )
240
+ return 0 if response.nil? # got no responses
241
+
242
+ if content_type =~ /application\/json/
243
+ response_array = JSON.parse(response)
244
+ #If we don't have an Array, turn the response into an Array so we can iterate over this one response.
245
+ response_array = [ response_array ] if ! (response_array.class == Array)
246
+ return 0 if response_array.empty? # got empty array of responses
247
+
248
+ count = 0
249
+ response_array.each do |r|
250
+ yield r if block_given?
251
+ p r if debug
252
+ count += 1
253
+ end
254
+
255
+ return count
256
+ else #just dump the entire response on the caller :)
257
+ yield response if block_given?
258
+ return response.length
259
+ end
260
+ end
261
+ end
262
+ end