Skip to content

Commit f867c69

Browse files
authored
SWI-8854 Add OAuth (#189)
* add oauth * update generator version * fix test * update oauth logic * update templates * update config * update spec help env vars * template * update tests and wf files * remove 401/403 tests * update tests * update template * stats test * stats test fr this time * update readme * rename expiration
1 parent fd2d794 commit f867c69

File tree

228 files changed

+4044
-10860
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

228 files changed

+4044
-10860
lines changed

.github/workflows/deploy.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ jobs:
1313
BW_ACCOUNT_ID: ${{ secrets.BW_ACCOUNT_ID }}
1414
BW_USERNAME: ${{ secrets.BW_USERNAME }}
1515
BW_PASSWORD: ${{ secrets.BW_PASSWORD }}
16+
BW_CLIENT_ID: ${{ secrets.BW_CLIENT_ID }}
17+
BW_CLIENT_SECRET: ${{ secrets.BW_CLIENT_SECRET }}
1618
BW_USERNAME_FORBIDDEN: ${{ secrets.BW_USERNAME_FORBIDDEN }}
1719
BW_PASSWORD_FORBIDDEN: ${{ secrets.BW_PASSWORD_FORBIDDEN }}
1820
BW_VOICE_APPLICATION_ID: ${{ secrets.BW_VOICE_APPLICATION_ID }}

.github/workflows/test-pr.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ env:
1313
BW_ACCOUNT_ID: ${{ secrets.BW_ACCOUNT_ID }}
1414
BW_USERNAME: ${{ secrets.BW_USERNAME }}
1515
BW_PASSWORD: ${{ secrets.BW_PASSWORD }}
16+
BW_CLIENT_ID: ${{ secrets.BW_CLIENT_ID }}
17+
BW_CLIENT_SECRET: ${{ secrets.BW_CLIENT_SECRET }}
1618
BW_USERNAME_FORBIDDEN: ${{ secrets.BW_USERNAME_FORBIDDEN }}
1719
BW_PASSWORD_FORBIDDEN: ${{ secrets.BW_PASSWORD_FORBIDDEN }}
1820
BW_VOICE_APPLICATION_ID: ${{ secrets.BW_VOICE_APPLICATION_ID }}

.github/workflows/test-smoke.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ concurrency:
1515
env:
1616
BW_USERNAME: ${{ secrets.BW_USERNAME }}
1717
BW_PASSWORD: ${{ secrets.BW_PASSWORD }}
18+
BW_CLIENT_ID: ${{ secrets.BW_CLIENT_ID }}
19+
BW_CLIENT_SECRET: ${{ secrets.BW_CLIENT_SECRET }}
1820
BW_USERNAME_FORBIDDEN: ${{ secrets.BW_USERNAME_FORBIDDEN }}
1921
BW_PASSWORD_FORBIDDEN: ${{ secrets.BW_PASSWORD_FORBIDDEN }}
2022
USER_NUMBER: ${{ secrets.USER_NUMBER }}

.openapi-generator/FILES

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ lib/bandwidth-sdk/api/toll_free_verification_api.rb
204204
lib/bandwidth-sdk/api/transcriptions_api.rb
205205
lib/bandwidth-sdk/api_client.rb
206206
lib/bandwidth-sdk/api_error.rb
207+
lib/bandwidth-sdk/api_model_base.rb
207208
lib/bandwidth-sdk/configuration.rb
208209
lib/bandwidth-sdk/models/account_statistics.rb
209210
lib/bandwidth-sdk/models/additional_denial_reason.rb

.openapi-generator/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
7.8.0
1+
7.17.0

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,16 @@ Bandwidth.configure do |config|
8585
config.password = 'YOUR_PASSWORD'
8686
# Configure faraday connection
8787
config.configure_faraday_connection { |connection| 'YOUR CONNECTION CONFIG PROC' }
88+
89+
# Configure OAuth2 access token for authorization: OAuth2
90+
config.access_token = 'YOUR_ACCESS TOKEN'
91+
# Or use your client ID and client secret to obtain an access token
92+
config.client_id = 'YOUR_CLIENT_ID'
93+
config.client_secret = 'YOUR_CLIENT_SECRET'
94+
# Configure a proc to get access tokens in lieu of the static access_token configuration
95+
config.access_token_getter = -> { 'YOUR TOKEN GETTER PROC' }
96+
# Configure faraday connection
97+
config.configure_faraday_connection { |connection| 'YOUR CONNECTION CONFIG PROC' }
8898
end
8999

90100
api_instance = Bandwidth::CallsApi.new
@@ -345,3 +355,11 @@ Authentication schemes defined for the API:
345355

346356
- **Type**: HTTP basic authentication
347357

358+
### OAuth2
359+
360+
361+
- **Type**: OAuth
362+
- **Flow**: application
363+
- **Authorization URL**:
364+
- **Scopes**: N/A
365+

bandwidth-sdk.gemspec

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88
The version of the OpenAPI document: 1.0.0
99
1010
Generated by: https://openapi-generator.tech
11-
Generator version: 7.8.0
12-
11+
Generator version: 7.17.0
1312
=end
1413

1514
$:.push File.expand_path('../lib', __FILE__)

bandwidth.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ info:
99
version: 1.0.0
1010
security:
1111
- Basic: []
12+
- OAuth2: []
1213
tags:
1314
- name: Messages
1415
- name: Media
@@ -8427,6 +8428,12 @@ components:
84278428
84288429
84298430
- Example: `Authorization: Basic ZGVtbZpwQDU1dzByZA==`
8431+
OAuth2:
8432+
type: oauth2
8433+
flows:
8434+
clientCredentials:
8435+
tokenUrl: https://api.bandwidth.com/api/v1/oauth2/token
8436+
scopes: {}
84308437
callbacks:
84318438
inboundCallback:
84328439
'{inboundCallbackUrl}':

custom_templates/README.mustache

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,10 @@ require '{{{gemName}}}'
9999
# Uncomment the following line to set a prefix for the API key, e.g. 'Bearer' (defaults to nil)
100100
# config.api_key_prefix['{{{name}}}'] = 'Bearer'{{/isApiKey}}{{#isOAuth}}
101101
# Configure OAuth2 access token for authorization: {{{name}}}
102-
config.access_token = 'YOUR ACCESS TOKEN'
102+
config.access_token = 'YOUR_ACCESS TOKEN'
103+
# Or use your client ID and client secret to obtain an access token
104+
config.client_id = 'YOUR_CLIENT_ID'
105+
config.client_secret = 'YOUR_CLIENT_SECRET'
103106
# Configure a proc to get access tokens in lieu of the static access_token configuration
104107
config.access_token_getter = -> { 'YOUR TOKEN GETTER PROC' } {{/isOAuth}}
105108
{{#isFaraday}}
Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
=begin
2+
{{> api_info}}
3+
4+
=end
5+
6+
require 'date'
7+
require 'json'
8+
require 'logger'
9+
require 'tempfile'
10+
require 'time'
11+
{{#isTyphoeus}}
12+
require 'typhoeus'
13+
{{/isTyphoeus}}
14+
{{#isFaraday}}
15+
require 'faraday'
16+
require 'faraday/multipart' if Gem::Version.new(Faraday::VERSION) >= Gem::Version.new('2.0')
17+
require 'marcel'
18+
{{/isFaraday}}
19+
{{#isHttpx}}
20+
require 'httpx'
21+
require 'net/http/status'
22+
{{/isHttpx}}
23+
24+
25+
module {{moduleName}}
26+
class ApiClient
27+
# The Configuration object holding settings to be used in the API client.
28+
attr_accessor :config
29+
30+
# Defines the headers to be used in HTTP requests of all API calls by default.
31+
#
32+
# @return [Hash]
33+
attr_accessor :default_headers
34+
35+
# Initializes the ApiClient
36+
# @option config [Configuration] Configuration for initializing the object, default to Configuration.default
37+
def initialize(config = Configuration.default)
38+
@config = config
39+
@user_agent = "{{{httpUserAgent}}}{{^httpUserAgent}}OpenAPI-Generator/#{VERSION}/ruby{{/httpUserAgent}}"
40+
@default_headers = {
41+
'Content-Type' => 'application/json',
42+
'User-Agent' => @user_agent
43+
}
44+
end
45+
46+
def self.default
47+
@@default ||= ApiClient.new
48+
end
49+
50+
{{#isTyphoeus}}
51+
{{> api_client_typhoeus_partial}}
52+
53+
{{/isTyphoeus}}
54+
{{#isFaraday}}
55+
{{> api_client_faraday_partial}}
56+
57+
{{/isFaraday}}
58+
{{#isHttpx}}
59+
{{> api_client_httpx_partial}}
60+
61+
{{/isHttpx}}
62+
# Check if the given MIME is a JSON MIME.
63+
# JSON MIME examples:
64+
# application/json
65+
# application/json; charset=UTF8
66+
# APPLICATION/JSON
67+
# */*
68+
# @param [String] mime MIME
69+
# @return [Boolean] True if the MIME is application/json
70+
def json_mime?(mime)
71+
(mime == '*/*') || !(mime =~ /^Application\/.*json(?!p)(;.*)?/i).nil?
72+
end
73+
74+
# Deserialize the response to the given return type.
75+
#
76+
# @param [Response] response HTTP response
77+
# @param [String] return_type some examples: "User", "Array<User>", "Hash<String, Integer>"
78+
def deserialize(response, return_type)
79+
body = response.body
80+
return nil if body.nil? || body.empty?
81+
82+
# return response body directly for String return type
83+
return body.to_s if return_type == 'String'
84+
85+
# ensuring a default content type
86+
content_type = response.headers['Content-Type'] || 'application/json'
87+
88+
fail "Content-Type is not supported: #{content_type}" unless json_mime?(content_type)
89+
90+
begin
91+
data = JSON.parse("[#{body}]", :symbolize_names => true)[0]
92+
rescue JSON::ParserError => e
93+
if %w(String Date Time).include?(return_type)
94+
data = body
95+
else
96+
raise e
97+
end
98+
end
99+
100+
convert_to_type data, return_type
101+
end
102+
103+
# Convert data to the given return type.
104+
# @param [Object] data Data to be converted
105+
# @param [String] return_type Return type
106+
# @return [Mixed] Data in a particular type
107+
def convert_to_type(data, return_type)
108+
return nil if data.nil?
109+
case return_type
110+
when 'String'
111+
data.to_s
112+
when 'Integer'
113+
data.to_i
114+
when 'Float'
115+
data.to_f
116+
when 'Boolean'
117+
data == true
118+
when 'Time'
119+
# parse date time (expecting ISO 8601 format)
120+
Time.parse data
121+
when 'Date'
122+
# parse date time (expecting ISO 8601 format)
123+
Date.parse data
124+
when 'Object'
125+
# generic object (usually a Hash), return directly
126+
data
127+
when /\AArray<(.+)>\z/
128+
# e.g. Array<Pet>
129+
sub_type = $1
130+
data.map { |item| convert_to_type(item, sub_type) }
131+
when /\AHash\<String, (.+)\>\z/
132+
# e.g. Hash<String, Integer>
133+
sub_type = $1
134+
{}.tap do |hash|
135+
data.each { |k, v| hash[k] = convert_to_type(v, sub_type) }
136+
end
137+
else
138+
# models (e.g. Pet) or oneOf/anyOf
139+
klass = {{moduleName}}.const_get(return_type)
140+
if klass.respond_to?(:openapi_one_of) || klass.respond_to?(:openapi_any_of)
141+
klass.build(data)
142+
else
143+
klass.build_from_hash(data)
144+
end
145+
end
146+
end
147+
148+
# Sanitize filename by removing path.
149+
# e.g. ../../sun.gif becomes sun.gif
150+
#
151+
# @param [String] filename the filename to be sanitized
152+
# @return [String] the sanitized filename
153+
def sanitize_filename(filename)
154+
filename.split(/[\/\\]/).last
155+
end
156+
157+
def build_request_url(path, opts = {})
158+
# Add leading and trailing slashes to path
159+
path = "/#{path}".gsub(/\/+/, '/')
160+
@config.base_url(opts[:operation]) + path
161+
end
162+
163+
# Update header and query params based on authentication settings.
164+
#
165+
# @param [Hash] header_params Header parameters
166+
# @param [Hash] query_params Query parameters
167+
# @param [String] auth_names Authentication scheme name
168+
def update_params_for_auth!(header_params, query_params, auth_names)
169+
Array(auth_names).each do |auth_name|
170+
auth_setting = @config.auth_settings[auth_name]
171+
next unless auth_setting
172+
case auth_setting[:in]
173+
when 'header' then header_params[auth_setting[:key]] = auth_setting[:value] unless auth_setting[:value].nil?
174+
when 'query' then query_params[auth_setting[:key]] = auth_setting[:value] unless auth_setting[:value].nil?
175+
else fail ArgumentError, 'Authentication token must be in `query` or `header`'
176+
end
177+
end
178+
end
179+
180+
# Sets user agent in HTTP header
181+
#
182+
# @param [String] user_agent User agent (e.g. openapi-generator/ruby/1.0.0)
183+
def user_agent=(user_agent)
184+
@user_agent = user_agent
185+
@default_headers['User-Agent'] = @user_agent
186+
end
187+
188+
# Return Accept header based on an array of accepts provided.
189+
# @param [Array] accepts array for Accept
190+
# @return [String] the Accept header (e.g. application/json)
191+
def select_header_accept(accepts)
192+
return nil if accepts.nil? || accepts.empty?
193+
# use JSON when present, otherwise use all of the provided
194+
json_accept = accepts.find { |s| json_mime?(s) }
195+
json_accept || accepts.join(',')
196+
end
197+
198+
# Return Content-Type header based on an array of content types provided.
199+
# @param [Array] content_types array for Content-Type
200+
# @return [String] the Content-Type header (e.g. application/json)
201+
def select_header_content_type(content_types)
202+
# return nil by default
203+
return if content_types.nil? || content_types.empty?
204+
# use JSON when present, otherwise use the first one
205+
json_content_type = content_types.find { |s| json_mime?(s) }
206+
json_content_type || content_types.first
207+
end
208+
209+
# Convert object (array, hash, object, etc) to JSON string.
210+
# @param [Object] model object to be converted into JSON string
211+
# @return [String] JSON string representation of the object
212+
def object_to_http_body(model)
213+
return model if model.nil? || model.is_a?(String)
214+
local_body = nil
215+
if model.is_a?(Array)
216+
local_body = model.map { |m| object_to_hash(m) }
217+
else
218+
local_body = object_to_hash(model)
219+
end
220+
local_body.to_json
221+
end
222+
223+
# Convert object(non-array) to hash.
224+
# @param [Object] obj object to be converted into JSON string
225+
# @return [String] JSON string representation of the object
226+
def object_to_hash(obj)
227+
if obj.respond_to?(:to_hash)
228+
obj.to_hash
229+
else
230+
obj
231+
end
232+
end
233+
234+
# Build parameter value according to the given collection format.
235+
# @param [String] collection_format one of :csv, :ssv, :tsv, :pipes and :multi
236+
def build_collection_param(param, collection_format)
237+
case collection_format
238+
when :csv
239+
param.join(',')
240+
when :ssv
241+
param.join(' ')
242+
when :tsv
243+
param.join("\t")
244+
when :pipes
245+
param.join('|')
246+
when :multi
247+
# return the array directly as typhoeus will handle it as expected
248+
param
249+
else
250+
fail "unknown collection format: #{collection_format.inspect}"
251+
end
252+
end
253+
end
254+
end

0 commit comments

Comments
 (0)