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.
@@ -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
@@ -0,0 +1,5 @@
1
+ module Sdk4me
2
+ class Client
3
+ VERSION = '1.1.2'
4
+ end
5
+ 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: []