4me-sdk 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/4me-sdk.gemspec +40 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +74 -0
- data/LICENSE +21 -0
- data/README.md +324 -0
- data/lib/sdk4me.rb +37 -0
- data/lib/sdk4me/ca-bundle.crt +3910 -0
- data/lib/sdk4me/client.rb +342 -0
- data/lib/sdk4me/client/attachments.rb +109 -0
- data/lib/sdk4me/client/multipart.rb +75 -0
- data/lib/sdk4me/client/response.rb +119 -0
- data/lib/sdk4me/client/version.rb +5 -0
- metadata +169 -0
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'mime/types'
|
3
|
+
|
4
|
+
# Takes a hash of string and file parameters and returns a string of text
|
5
|
+
# formatted to be sent as a multipart form post.
|
6
|
+
#
|
7
|
+
# Author:: Cody Brimhall <mailto:cbrimhall@ucdavis.edu>
|
8
|
+
# Created:: 22 Feb 2008
|
9
|
+
module Sdk4me
|
10
|
+
module Multipart
|
11
|
+
VERSION = "1.0.0" unless const_defined?(:VERSION)
|
12
|
+
|
13
|
+
# Formats a given hash as a multipart form post
|
14
|
+
# If a hash value responds to :string or :read messages, then it is
|
15
|
+
# interpreted as a file and processed accordingly; otherwise, it is assumed
|
16
|
+
# to be a string
|
17
|
+
class Post
|
18
|
+
# We have to pretend like we're a web browser...
|
19
|
+
USERAGENT = "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/523.10.6 (KHTML, like Gecko) Version/3.0.4 Safari/523.10.6" unless const_defined?(:USERAGENT)
|
20
|
+
BOUNDARY = '0123456789ABLEWASIEREISAWELBA9876543210' unless const_defined?(:BOUNDARY)
|
21
|
+
CONTENT_TYPE = "multipart/form-data; boundary=#{ BOUNDARY }" unless const_defined?(:CONTENT_TYPE)
|
22
|
+
HEADER = { 'Content-Type' => CONTENT_TYPE, 'User-Agent' => USERAGENT } unless const_defined?(:HEADER)
|
23
|
+
|
24
|
+
def self.prepare_query(params)
|
25
|
+
fp = []
|
26
|
+
|
27
|
+
params.each do |k, v|
|
28
|
+
if v.respond_to?(:path) && v.respond_to?(:read)
|
29
|
+
fp.push(FileParam.new(k, v.path, v.read))
|
30
|
+
else
|
31
|
+
fp.push(StringParam.new(k, v))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Assemble the request body using the special multipart format
|
36
|
+
query = fp.map{ |p| "--#{BOUNDARY}\r\n#{p.to_multipart}" }.join + "--#{BOUNDARY}--"
|
37
|
+
return query, HEADER
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# Formats a basic string key/value pair for inclusion with a multipart post
|
44
|
+
class StringParam
|
45
|
+
attr_accessor :k, :v
|
46
|
+
|
47
|
+
def initialize(k, v)
|
48
|
+
@k = k
|
49
|
+
@v = v
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_multipart
|
53
|
+
return %(Content-Disposition: form-data; name="#{CGI::escape(k.to_s)}"\r\n\r\n#{v}\r\n)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Formats the contents of a file or string for inclusion with a multipart
|
58
|
+
# form post
|
59
|
+
class FileParam
|
60
|
+
attr_accessor :k, :filename, :content
|
61
|
+
|
62
|
+
def initialize(k, filename, content)
|
63
|
+
@k = k
|
64
|
+
@filename = filename
|
65
|
+
@content = content
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_multipart
|
69
|
+
# If we can tell the possible mime-type from the filename, use the first in the list; otherwise, use "application/octet-stream"
|
70
|
+
mime_type = MIME::Types.type_for(filename)[0] || MIME::Types["application/octet-stream"][0]
|
71
|
+
return %(Content-Disposition: form-data; name="#{CGI::escape(k.to_s)}"; filename="#{filename}"\r\nContent-Type: #{ mime_type.simplified }\r\n\r\n#{ content }\r\n)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module Sdk4me
|
2
|
+
class Response
|
3
|
+
def initialize(request, response)
|
4
|
+
@request = request
|
5
|
+
@response = response
|
6
|
+
end
|
7
|
+
|
8
|
+
def request
|
9
|
+
@request
|
10
|
+
end
|
11
|
+
|
12
|
+
def response
|
13
|
+
@response
|
14
|
+
end
|
15
|
+
alias_method :raw, :response
|
16
|
+
|
17
|
+
def body
|
18
|
+
@response.body
|
19
|
+
end
|
20
|
+
|
21
|
+
# The JSON value, if single resource is queried this is a Hash, if multiple resources where queried it is an Array
|
22
|
+
# If the response is not +valid?+ it is a Hash with 'message' and optionally 'errors'
|
23
|
+
def json
|
24
|
+
return @json if defined?(@json)
|
25
|
+
# no content, no JSON
|
26
|
+
if @response.code.to_s == '204'
|
27
|
+
data = {}
|
28
|
+
elsif @response.body.blank?
|
29
|
+
# no body, no json
|
30
|
+
data = {message: @response.message.blank? ? 'empty body' : @response.message.strip}
|
31
|
+
end
|
32
|
+
begin
|
33
|
+
data ||= JSON.parse(@response.body)
|
34
|
+
rescue ::Exception => e
|
35
|
+
data = { message: "Invalid JSON - #{e.message} for:\n#{@response.body}" }
|
36
|
+
end
|
37
|
+
# indifferent access to hashes
|
38
|
+
data = data.is_a?(Array) ? data.map(&:with_indifferent_access) : data.with_indifferent_access
|
39
|
+
# empty OK response is not seen as an error
|
40
|
+
data = {} if data.is_a?(Hash) && data.size == 1 && data[:message] == 'OK'
|
41
|
+
# prepend HTTP response code to message
|
42
|
+
data[:message] = "#{response.code}: #{data[:message]}" unless @response.is_a?(Net::HTTPSuccess)
|
43
|
+
@json = data
|
44
|
+
end
|
45
|
+
|
46
|
+
# the error message in case the response is not +valid?+
|
47
|
+
def message
|
48
|
+
@message ||= json.is_a?(Hash) ? json[:message] : nil
|
49
|
+
end
|
50
|
+
|
51
|
+
# +true+ if the server did not respond at all
|
52
|
+
def empty?
|
53
|
+
@response.body.blank?
|
54
|
+
end
|
55
|
+
|
56
|
+
# +true+ if no 'message' is given (and the JSON could be parsed)
|
57
|
+
def valid?
|
58
|
+
message.nil?
|
59
|
+
end
|
60
|
+
alias_method :success?, :valid?
|
61
|
+
|
62
|
+
# retrieve a value from the resource
|
63
|
+
# if the JSON value is an Array a array with the value for each resource will be given
|
64
|
+
# @param keys: a single key or a key-path separated by comma
|
65
|
+
def[](*keys)
|
66
|
+
values = json.is_a?(Array) ? json : [json]
|
67
|
+
keys.each { |key| values = values.map{ |value| value.is_a?(Hash) ? value[key] : nil} }
|
68
|
+
json.is_a?(Array) ? values : values.first
|
69
|
+
end
|
70
|
+
|
71
|
+
# The nr of resources found
|
72
|
+
def size
|
73
|
+
@size ||= message ? 0 : json.is_a?(Array) ? json.size : 1
|
74
|
+
end
|
75
|
+
alias :count :size
|
76
|
+
|
77
|
+
# pagination - per page
|
78
|
+
def per_page
|
79
|
+
@per_page ||= @response.header['X-Pagination-Per-Page'].to_i
|
80
|
+
end
|
81
|
+
|
82
|
+
# pagination - current page
|
83
|
+
def current_page
|
84
|
+
@current_page ||= @response.header['X-Pagination-Current-Page'].to_i
|
85
|
+
end
|
86
|
+
|
87
|
+
# pagination - total pages
|
88
|
+
def total_pages
|
89
|
+
@total_pages ||= @response.header['X-Pagination-Total-Pages'].to_i
|
90
|
+
end
|
91
|
+
|
92
|
+
# pagination - total entries
|
93
|
+
def total_entries
|
94
|
+
@total_entries ||= @response.header['X-Pagination-Total-Entries'].to_i
|
95
|
+
end
|
96
|
+
|
97
|
+
# pagination urls (full paths with server) - relations :first, :prev, :next, :last
|
98
|
+
# Link: <https://api.4me.com/v1/requests?page=1&per_page=25>; rel="first", <https://api.4me.com/v1/requests?page=2&per_page=25>; rel="prev", etc.
|
99
|
+
def pagination_link(relation)
|
100
|
+
# split on ',' select the [url] in '<[url]>; rel="[relation]"', compact to all url's found (at most one) and take the first
|
101
|
+
(@pagination_links ||= {})[relation] ||= @response.header['Link'] && @response.header['Link'].split(/,\s*<?/).map{ |link| link[/^\s*<?(.*?)>?;\s*rel="#{relation.to_s}"\s*$/, 1] }.compact.first
|
102
|
+
end
|
103
|
+
|
104
|
+
# pagination urls (relative paths without server) - relations :first, :prev, :next, :last
|
105
|
+
def pagination_relative_link(relation)
|
106
|
+
(@pagination_relative_links ||= {})[relation] ||= pagination_link(relation) && pagination_link(relation)[/^https?:\/\/[^\/]*(.*)/, 1]
|
107
|
+
end
|
108
|
+
|
109
|
+
# +true+ if the response is invalid because of throttling
|
110
|
+
def throttled?
|
111
|
+
!!(@response.code.to_s == '429' || (message && message =~ /Too Many Requests/))
|
112
|
+
end
|
113
|
+
|
114
|
+
def to_s
|
115
|
+
valid? ? json.to_s : message
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
metadata
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: 4me-sdk
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- 4me
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-11-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: gem_config
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.3'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4.2'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: mime-types
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '12'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '12'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.3'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.3'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: webmock
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '2'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '2'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: simplecov
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: SDK for accessing the 4me
|
126
|
+
email: developers@4me.com
|
127
|
+
executables: []
|
128
|
+
extensions: []
|
129
|
+
extra_rdoc_files: []
|
130
|
+
files:
|
131
|
+
- 4me-sdk.gemspec
|
132
|
+
- Gemfile
|
133
|
+
- Gemfile.lock
|
134
|
+
- LICENSE
|
135
|
+
- README.md
|
136
|
+
- lib/sdk4me.rb
|
137
|
+
- lib/sdk4me/ca-bundle.crt
|
138
|
+
- lib/sdk4me/client.rb
|
139
|
+
- lib/sdk4me/client/attachments.rb
|
140
|
+
- lib/sdk4me/client/multipart.rb
|
141
|
+
- lib/sdk4me/client/response.rb
|
142
|
+
- lib/sdk4me/client/version.rb
|
143
|
+
homepage: https://github.com/code4me/4me-sdk-ruby
|
144
|
+
licenses:
|
145
|
+
- MIT
|
146
|
+
metadata: {}
|
147
|
+
post_install_message:
|
148
|
+
rdoc_options:
|
149
|
+
- "--charset=UTF-8"
|
150
|
+
require_paths:
|
151
|
+
- lib
|
152
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
153
|
+
requirements:
|
154
|
+
- - ">="
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: 2.0.0
|
157
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
158
|
+
requirements:
|
159
|
+
- - ">="
|
160
|
+
- !ruby/object:Gem::Version
|
161
|
+
version: '0'
|
162
|
+
requirements: []
|
163
|
+
rubyforge_project:
|
164
|
+
rubygems_version: 2.6.14
|
165
|
+
signing_key:
|
166
|
+
specification_version: 4
|
167
|
+
summary: The official 4me SDK for Ruby. Provides easy access to the APIs found at
|
168
|
+
https://developer.4me.com
|
169
|
+
test_files: []
|