diff --git a/__tests__/Api/Address.unit.rb b/__tests__/Api/Address.unit.rb index 4a53448..ee3540b 100755 --- a/__tests__/Api/Address.unit.rb +++ b/__tests__/Api/Address.unit.rb @@ -35,7 +35,7 @@ addressApiMock = double("ApiClient") addressApi = AddressesApi.new(addressApiMock) addressEditable = AddressEditable.new - fakeAddress = UsAddress.new + fakeAddress = Address.new fakeAddress.id = "adr_fakeid" allow(addressApi).to receive(:create) { fakeAddress } @@ -62,7 +62,7 @@ it "retrieves an address" do addressApiMock = double("ApiClient") addressApi = AddressesApi.new(addressApiMock) - fakeAddress = UsAddress.new + fakeAddress = Address.new fakeAddress.id = "adr_fakeid" allow(addressApi).to receive(:get) { fakeAddress } @@ -91,7 +91,7 @@ addressApiMock = double("ApiClient") addressApi = AddressesApi.new(addressApiMock) addressEditable = AddressEditable.new - fakeAddresses = Array.new(2) { UsAddress.new } + fakeAddresses = Array.new(2) { Address.new } fakeAddresses[0].id = "adr_fakeid" allow(addressApi).to receive(:list) { fakeAddresses } @@ -106,7 +106,7 @@ addressApiMock = double("ApiClient") addressApi = AddressesApi.new(addressApiMock) addressEditable = AddressEditable.new - fakeAddresses = Array.new(2) { UsAddress.new } + fakeAddresses = Array.new(2) { Address.new } fakeAddresses[0].id = "adr_fakeid" allow(addressApi).to receive(:list) { fakeAddresses } @@ -121,7 +121,7 @@ addressApiMock = double("ApiClient") addressApi = AddressesApi.new(addressApiMock) addressEditable = AddressEditable.new - fakeAddresses = Array.new(2) { UsAddress.new } + fakeAddresses = Array.new(2) { Address.new } fakeAddresses[0].id = "adr_fakeid" allow(addressApi).to receive(:list) { fakeAddresses } @@ -136,7 +136,7 @@ addressApiMock = double("ApiClient") addressApi = AddressesApi.new(addressApiMock) addressEditable = AddressEditable.new - fakeAddresses = Array.new(2) { UsAddress.new } + fakeAddresses = Array.new(2) { Address.new } fakeAddresses[0].id = "adr_fakeid" allow(addressApi).to receive(:list) { fakeAddresses } @@ -151,7 +151,7 @@ addressApiMock = double("ApiClient") addressApi = AddressesApi.new(addressApiMock) addressEditable = AddressEditable.new - fakeAddresses = Array.new(2) { UsAddress.new } + fakeAddresses = Array.new(2) { Address.new } dateFilter = { gt: "2020-01-01", lt: "2020-01-31T12" }; fakeAddresses[0].id = "adr_fakeid" @@ -167,7 +167,7 @@ addressApiMock = double("ApiClient") addressApi = AddressesApi.new(addressApiMock) addressEditable = AddressEditable.new - fakeAddresses = Array.new(2) { UsAddress.new } + fakeAddresses = Array.new(2) { Address.new } metadata = { fakeMetadata: "fakemetadata" } fakeAddresses[0].id = "adr_fakeid" diff --git a/__tests__/Integration/Address.spec.rb b/__tests__/Integration/Address.spec.rb index e2e8527..c73d345 100755 --- a/__tests__/Integration/Address.spec.rb +++ b/__tests__/Integration/Address.spec.rb @@ -147,13 +147,13 @@ end it "lists addresses with after param" do - response = @addressApi.list(limit: 2) + response = @addressApi.list() responseAfter = @addressApi.list(after: response.getNextPageToken()) expect(responseAfter.data.length()).to be > 0 end it "lists addresses with before param" do - response = @addressApi.list(limit: 2) + response = @addressApi.list() responseAfter = @addressApi.list(before: response.getNextPageToken()) expect(responseAfter.data.length()).to be > 0 end @@ -197,4 +197,4 @@ expect(response.deleted).to eq(true) end end - end + end \ No newline at end of file diff --git a/__tests__/Integration/Check.spec.rb b/__tests__/Integration/Check.spec.rb index 457930f..aa35e7d 100755 --- a/__tests__/Integration/Check.spec.rb +++ b/__tests__/Integration/Check.spec.rb @@ -236,7 +236,7 @@ expect(response.data[0].id).not_to eq(first_chk_id) - uri = URI.parse(response.previous_url) + uri = URI.parse(response.next_url) params = CGI.parse(uri.query) response = @checkApi.list({ :"limit" => 2, :"before" => params["before"][0] }) diff --git a/__tests__/Integration/Letter.spec.rb b/__tests__/Integration/Letter.spec.rb index 3b31da5..88c32a3 100755 --- a/__tests__/Integration/Letter.spec.rb +++ b/__tests__/Integration/Letter.spec.rb @@ -178,7 +178,7 @@ expect(response.data[0].id).not_to eq(first_ltr_id) - uri = URI.parse(response.previous_url) + uri = URI.parse(response.next_url) params = CGI.parse(uri.query) response = @letterApi.list({ :"limit" => 2, :"before" => params["before"][0] }) diff --git a/__tests__/Integration/Template.spec.rb b/__tests__/Integration/Template.spec.rb index 2d1fda1..964d12e 100755 --- a/__tests__/Integration/Template.spec.rb +++ b/__tests__/Integration/Template.spec.rb @@ -98,8 +98,7 @@ templateWritable3 = TemplateWritable.new({ description: "Ruby Integration Test", - html: "Updated HTML for Ruby Integration Test", - metadata: { name: "Harry" } + html: "Updated HTML for Ruby Integration Test" }) response1 = @templateApi.create(templateWritable1) @@ -124,7 +123,7 @@ expect(response.data[0].id).not_to eq(first_tmpl_id) - uri = URI.parse(response.previous_url) + uri = URI.parse(response.next_url) params = CGI.parse(uri.query) response = @templateApi.list({ :"limit" => 2, :"before" => params["before"][0] }) diff --git a/__tests__/Integration/UsAutocompletion.spec.rb b/__tests__/Integration/UsAutocompletion.spec.rb index 064e1cd..9ca6da3 100755 --- a/__tests__/Integration/UsAutocompletion.spec.rb +++ b/__tests__/Integration/UsAutocompletion.spec.rb @@ -24,6 +24,7 @@ it "Autocompletes US address (with test key)" do autocompletedAddr = @usAutocompletionApi.autocomplete(@validAddress) + puts autocompletedAddr.suggestions[0].primary_line expect(autocompletedAddr.suggestions[0].primary_line).to eq("1 TELEGRAPH HILL BLVD") end diff --git a/docs/Address.md b/docs/Address.md index 31f05c8..0142fff 100755 --- a/docs/Address.md +++ b/docs/Address.md @@ -14,8 +14,8 @@ | **address_line1** | **String** | | [optional] | | **address_line2** | **String** | | [optional] | | **address_city** | **String** | | [optional] | -| **address_state** | **String** | 2 letter state short-name code for US address or must be no longer than 200 characters for non-US address. | [optional] | -| **address_zip** | **String** | Must follow the ZIP format of `12345` or ZIP+4 format of `12345-1234` for US address or must be no longer than 40 characters for non-US address. | [optional] | +| **address_state** | **String** | 2 letter state short-name code | [optional] | +| **address_zip** | **String** | Must follow the ZIP format of `12345` or ZIP+4 format of `12345-1234`. | [optional] | | **address_country** | [**CountryExtendedExpanded**](CountryExtendedExpanded.md) | | [optional] | | **object** | **String** | | [optional][default to 'address'] | | **date_created** | **Time** | A timestamp in ISO 8601 format of the date the resource was created. | [optional] | @@ -28,7 +28,7 @@ ```ruby require 'lob' -instance = Lob::Address.build( +instance = Lob::Address.new( id: null, description: null, name: null, diff --git a/docs/IntlAddress.md b/docs/IntlAddress.md index 5052ff3..344e474 100755 --- a/docs/IntlAddress.md +++ b/docs/IntlAddress.md @@ -14,8 +14,8 @@ | **address_line1** | **String** | | [optional] | | **address_line2** | **String** | | [optional] | | **address_city** | **String** | | [optional] | -| **address_state** | **String** | Must be no longer than 200 characters. | [optional] | -| **address_zip** | **String** | Must be no longer than 40 characters. | [optional] | +| **address_state** | **String** | 2 letter state short-name code | [optional] | +| **address_zip** | **String** | Must have a maximum of 12 characters | [optional] | | **address_country** | [**CountryExtendedExpandedNoUs**](CountryExtendedExpandedNoUs.md) | | [optional] | | **object** | **String** | | [optional][default to 'address'] | | **date_created** | **Time** | A timestamp in ISO 8601 format of the date the resource was created. | [optional] | diff --git a/lib/lob.rb b/lib/lob.rb index 75fe745..2505201 100755 --- a/lib/lob.rb +++ b/lib/lob.rb @@ -65,7 +65,6 @@ require 'lob/models/cmp_use_type' require 'lob/models/country_extended' require 'lob/models/country_extended_expanded' -require 'lob/models/country_extended_expanded_no_us' require 'lob/models/creative_patch' require 'lob/models/creative_response' require 'lob/models/creative_writable' @@ -82,7 +81,6 @@ require 'lob/models/http_validation_error' require 'lob/models/identity_validation' require 'lob/models/inline_object' -require 'lob/models/intl_address' require 'lob/models/intl_autocompletions' require 'lob/models/intl_autocompletions_writable' require 'lob/models/intl_components' @@ -163,7 +161,6 @@ require 'lob/models/upload_updatable' require 'lob/models/upload_writable' require 'lob/models/uploads_metadata' -require 'lob/models/us_address' require 'lob/models/us_autocompletions' require 'lob/models/us_autocompletions_writable' require 'lob/models/us_components' diff --git a/lib/lob/models/address.rb b/lib/lob/models/address.rb index 8296fcd..2f07124 100755 --- a/lib/lob/models/address.rb +++ b/lib/lob/models/address.rb @@ -14,92 +14,603 @@ require 'time' module Lob - module Address - class << self - # List of class defined in oneOf (OpenAPI v3) - def openapi_one_of - [ - :'IntlAddress', - :'UsAddress' - ] - end - - # Builds the object - # @param [Mixed] Data to be matched against the list of oneOf items - # @return [Object] Returns the model or the data itself - def build(data) - # Go through the list of oneOf items and attempt to identify the appropriate one. - # Note: - # - We do not attempt to check whether exactly one item matches. - # - No advanced validation of types in some cases (e.g. "x: { type: string }" will happily match { x: 123 }) - # due to the way the deserialization is made in the base_object template (it just casts without verifying). - # - TODO: scalar values are de facto behaving as if they were nullable. - # - TODO: logging when debugging is set. - openapi_one_of.each do |klass| - begin - next if klass == :AnyType # "nullable: true" - typed_data = find_and_cast_into_type(klass, data) - return typed_data if typed_data - rescue # rescue all errors so we keep iterating even if the current item lookup raises + class Address + # Unique identifier prefixed with `adr_`. + attr_accessor :id + + # An internal description that identifies this resource. Must be no longer than 255 characters. + attr_accessor :description + + # name associated with address + attr_accessor :name + + # Either `name` or `company` is required, you may also add both. + attr_accessor :company + + # Must be no longer than 40 characters. + attr_accessor :phone + + # Must be no longer than 100 characters. + attr_accessor :email + + # Use metadata to store custom information for tagging and labeling back to your internal systems. Must be an object with up to 20 key-value pairs. Keys must be at most 40 characters and values must be at most 500 characters. Neither can contain the characters `\"` and `\\`. i.e. '{\"customer_id\" : \"NEWYORK2015\"}' Nested objects are not supported. See [Metadata](#section/Metadata) for more information. + attr_accessor :metadata + + attr_accessor :address_line1 + + attr_accessor :address_line2 + + attr_accessor :address_city + + # 2 letter state short-name code + attr_accessor :address_state + + # Must follow the ZIP format of `12345` or ZIP+4 format of `12345-1234`. + attr_accessor :address_zip + + attr_accessor :address_country + + attr_accessor :object + + # A timestamp in ISO 8601 format of the date the resource was created. + attr_accessor :date_created + + # A timestamp in ISO 8601 format of the date the resource was last modified. + attr_accessor :date_modified + + # Only returned if the resource has been successfully deleted. + attr_accessor :deleted + + # Only returned for accounts on certain Print & Mail Editions. Value is `true` if the address was altered because the recipient filed for a National Change of Address (NCOA), `false` if the NCOA check was run but no altered address was found, and `null` if the NCOA check was not run. The NCOA check does not happen for non-US addresses, for non-deliverable US addresses, or for addresses created before the NCOA feature was added to your account. + attr_accessor :recipient_moved + + class EnumAttributeValidator + attr_reader :datatype + attr_reader :allowable_values + + def initialize(datatype, allowable_values) + @allowable_values = allowable_values.map do |value| + case datatype.to_s + when /Integer/i + value.to_i + when /Float/i + value.to_f + else + value end end + end - openapi_one_of.include?(:AnyType) ? data : nil - end - - private - - SchemaMismatchError = Class.new(StandardError) - - # Note: 'File' is missing here because in the regular case we get the data _after_ a call to JSON.parse. - def find_and_cast_into_type(klass, data) - return if data.nil? - - case klass.to_s - when 'Boolean' - return data if data.instance_of?(TrueClass) || data.instance_of?(FalseClass) - when 'Float' - return data if data.instance_of?(Float) - when 'Integer' - return data if data.instance_of?(Integer) - when 'Time' - return Time.parse(data) - when 'Date' - return Date.parse(data) - when 'String' - return data if data.instance_of?(String) - when 'Object' # "type: object" - return data if data.instance_of?(Hash) - when /\AArray<(?.+)>\z/ # "type: array" - if data.instance_of?(Array) - sub_type = Regexp.last_match[:sub_type] - return data.map { |item| find_and_cast_into_type(sub_type, item) } - end - when /\AHash.+)>\z/ # "type: object" with "additionalProperties: { ... }" - if data.instance_of?(Hash) && data.keys.all? { |k| k.instance_of?(Symbol) || k.instance_of?(String) } - sub_type = Regexp.last_match[:sub_type] - return data.each_with_object({}) { |(k, v), hsh| hsh[k] = find_and_cast_into_type(sub_type, v) } + def valid?(value) + !value || allowable_values.include?(value) + end + end + + # Attribute mapping from ruby-style variable name to JSON key. + def self.attribute_map + { + :'id' => :'id', + :'description' => :'description', + :'name' => :'name', + :'company' => :'company', + :'phone' => :'phone', + :'email' => :'email', + :'metadata' => :'metadata', + :'address_line1' => :'address_line1', + :'address_line2' => :'address_line2', + :'address_city' => :'address_city', + :'address_state' => :'address_state', + :'address_zip' => :'address_zip', + :'address_country' => :'address_country', + :'object' => :'object', + :'date_created' => :'date_created', + :'date_modified' => :'date_modified', + :'deleted' => :'deleted', + :'recipient_moved' => :'recipient_moved' + } + end + + # Returns all the JSON keys this model knows about + def self.acceptable_attributes + attribute_map.values + end + + # Attribute type mapping. + def self.openapi_types + { + :'id' => :'String', + :'description' => :'String', + :'name' => :'String', + :'company' => :'String', + :'phone' => :'String', + :'email' => :'String', + :'metadata' => :'Hash', + :'address_line1' => :'String', + :'address_line2' => :'String', + :'address_city' => :'String', + :'address_state' => :'String', + :'address_zip' => :'String', + :'address_country' => :'CountryExtendedExpanded', + :'object' => :'String', + :'date_created' => :'Time', + :'date_modified' => :'Time', + :'deleted' => :'Boolean', + :'recipient_moved' => :'Boolean' + } + end + + # List of attributes with nullable: true + def self.openapi_nullable + Set.new([ + :'description', + :'name', + :'company', + :'phone', + :'email', + :'address_line2', + :'recipient_moved' + ]) + end + + # Initializes the object + # @param [Hash] attributes Model attributes in the form of hash + def initialize(attributes = {}) + if (!attributes.is_a?(Hash)) + fail ArgumentError, "The input argument (attributes) must be a hash in `Lob::Address` initialize method" + end + + # check to see if the attribute exists and convert string to symbol for hash key + attributes = attributes.each_with_object({}) { |(k, v), h| + if (!self.class.attribute_map.key?(k.to_sym)) + fail ArgumentError, "`#{k}` is not a valid attribute in `Lob::Address`. Please check the name to make sure it's valid. List of attributes: " + self.class.attribute_map.keys.inspect + end + h[k.to_sym] = v + } + + if attributes.key?(:'id') + self.id = attributes[:'id'] + end + + if attributes.key?(:'description') + self.description = attributes[:'description'] + end + + if attributes.key?(:'name') + self.name = attributes[:'name'] + end + + if attributes.key?(:'company') + self.company = attributes[:'company'] + end + + if attributes.key?(:'phone') + self.phone = attributes[:'phone'] + end + + if attributes.key?(:'email') + self.email = attributes[:'email'] + end + + if attributes.key?(:'metadata') + if (value = attributes[:'metadata']).is_a?(Hash) + self.metadata = value + end + end + + if attributes.key?(:'address_line1') + self.address_line1 = attributes[:'address_line1'] + end + + if attributes.key?(:'address_line2') + self.address_line2 = attributes[:'address_line2'] + end + + if attributes.key?(:'address_city') + self.address_city = attributes[:'address_city'] + end + + if attributes.key?(:'address_state') + self.address_state = attributes[:'address_state'] + end + + if attributes.key?(:'address_zip') + self.address_zip = attributes[:'address_zip'] + end + + if attributes.key?(:'address_country') + self.address_country = attributes[:'address_country'] + end + + if attributes.key?(:'object') + self.object = attributes[:'object'] + else + self.object = 'address' + end + + if attributes.key?(:'date_created') + self.date_created = attributes[:'date_created'] + end + + if attributes.key?(:'date_modified') + self.date_modified = attributes[:'date_modified'] + end + + if attributes.key?(:'deleted') + self.deleted = attributes[:'deleted'] + end + + if attributes.key?(:'recipient_moved') + self.recipient_moved = attributes[:'recipient_moved'] + end + end + + # Show invalid properties with the reasons. Usually used together with valid? + # @return Array for valid properties with the reasons + def list_invalid_properties + invalid_properties = Array.new + pattern = Regexp.new(/^adr_[a-zA-Z0-9]+$/) + if !@id.nil? && @id !~ pattern + invalid_properties.push("invalid value for \"id\", must conform to the pattern #{pattern}.") + end + + if !@description.nil? && @description.to_s.length > 255 + invalid_properties.push('invalid value for "description", the character length must be smaller than or equal to 255.') + end + + if !@name.nil? && @name.to_s.length > 40 + invalid_properties.push('invalid value for "name", the character length must be smaller than or equal to 40.') + end + + if !@company.nil? && @company.to_s.length > 40 + invalid_properties.push('invalid value for "company", the character length must be smaller than or equal to 40.') + end + + if !@phone.nil? && @phone.to_s.length > 40 + invalid_properties.push('invalid value for "phone", the character length must be smaller than or equal to 40.') + end + + if !@email.nil? && @email.to_s.length > 100 + invalid_properties.push('invalid value for "email", the character length must be smaller than or equal to 100.') + end + + if !@address_line1.nil? && @address_line1.to_s.length > 64 + invalid_properties.push('invalid value for "address_line1", the character length must be smaller than or equal to 64.') + end + + if !@address_line2.nil? && @address_line2.to_s.length > 64 + invalid_properties.push('invalid value for "address_line2", the character length must be smaller than or equal to 64.') + end + + if !@address_city.nil? && @address_city.to_s.length > 200 + invalid_properties.push('invalid value for "address_city", the character length must be smaller than or equal to 200.') + end + + pattern = Regexp.new(/^[a-zA-Z]{2}$/) + if !@address_state.nil? && @address_state !~ pattern + invalid_properties.push("invalid value for \"address_state\", must conform to the pattern #{pattern}.") + end + + pattern = Regexp.new(/^\d{5}(-\d{4})?$/) + if !@address_zip.nil? && @address_zip !~ pattern + invalid_properties.push("invalid value for \"address_zip\", must conform to the pattern #{pattern}.") + end + + invalid_properties + end + + # Check to see if the all the properties in the model are valid + # @return true if the model is valid + def valid? + return false if !@id.nil? && @id !~ Regexp.new(/^adr_[a-zA-Z0-9]+$/) + return false if !@description.nil? && @description.to_s.length > 255 + return false if !@name.nil? && @name.to_s.length > 40 + return false if !@company.nil? && @company.to_s.length > 40 + return false if !@phone.nil? && @phone.to_s.length > 40 + return false if !@email.nil? && @email.to_s.length > 100 + return false if !@address_line1.nil? && @address_line1.to_s.length > 64 + return false if !@address_line2.nil? && @address_line2.to_s.length > 64 + return false if !@address_city.nil? && @address_city.to_s.length > 200 + return false if !@address_state.nil? && @address_state !~ Regexp.new(/^[a-zA-Z]{2}$/) + return false if !@address_zip.nil? && @address_zip !~ Regexp.new(/^\d{5}(-\d{4})?$/) + object_validator = EnumAttributeValidator.new('String', ["address"]) + return false unless object_validator.valid?(@object) + true + end + + # Custom attribute writer method with validation + # @param [Object] id Value to be assigned + def id=(id) + pattern = Regexp.new(/^adr_[a-zA-Z0-9]+$/) + if !id.nil? && id !~ pattern + fail ArgumentError, "invalid value for \"id\", must conform to the pattern #{pattern}." + end + + @id = id + end + + # Custom attribute writer method with validation + # @param [Object] description Value to be assigned + def description=(description) + if !description.nil? && description.to_s.length > 255 + fail ArgumentError, 'invalid value for "description", the character length must be smaller than or equal to 255.' + end + + @description = description + end + + # Custom attribute writer method with validation + # @param [Object] name Value to be assigned + def name=(name) + if !name.nil? && name.to_s.length > 40 + fail ArgumentError, 'invalid value for "name", the character length must be smaller than or equal to 40.' + end + + @name = name + end + + # Custom attribute writer method with validation + # @param [Object] company Value to be assigned + def company=(company) + if !company.nil? && company.to_s.length > 40 + fail ArgumentError, 'invalid value for "company", the character length must be smaller than or equal to 40.' + end + + @company = company + end + + # Custom attribute writer method with validation + # @param [Object] phone Value to be assigned + def phone=(phone) + if !phone.nil? && phone.to_s.length > 40 + fail ArgumentError, 'invalid value for "phone", the character length must be smaller than or equal to 40.' + end + + @phone = phone + end + + # Custom attribute writer method with validation + # @param [Object] email Value to be assigned + def email=(email) + if !email.nil? && email.to_s.length > 100 + fail ArgumentError, 'invalid value for "email", the character length must be smaller than or equal to 100.' + end + + @email = email + end + + # Custom attribute writer method with validation + # @param [Object] metadata Value to be assigned + def metadata=(metadata) + @metadata = metadata + end + + # Custom attribute writer method with validation + # @param [Object] address_line1 Value to be assigned + def address_line1=(address_line1) + if !address_line1.nil? && address_line1.to_s.length > 64 + fail ArgumentError, 'invalid value for "address_line1", the character length must be smaller than or equal to 64.' + end + + @address_line1 = address_line1 + end + + # Custom attribute writer method with validation + # @param [Object] address_line2 Value to be assigned + def address_line2=(address_line2) + if !address_line2.nil? && address_line2.to_s.length > 64 + fail ArgumentError, 'invalid value for "address_line2", the character length must be smaller than or equal to 64.' + end + + @address_line2 = address_line2 + end + + # Custom attribute writer method with validation + # @param [Object] address_city Value to be assigned + def address_city=(address_city) + if !address_city.nil? && address_city.to_s.length > 200 + fail ArgumentError, 'invalid value for "address_city", the character length must be smaller than or equal to 200.' + end + + @address_city = address_city + end + + # Custom attribute writer method with validation + # @param [Object] address_state Value to be assigned + def address_state=(address_state) + pattern = Regexp.new(/^[a-zA-Z]{2}$/) + if !address_state.nil? && address_state !~ pattern + fail ArgumentError, "invalid value for \"address_state\", must conform to the pattern #{pattern}." + end + + @address_state = address_state + end + + # Custom attribute writer method with validation + # @param [Object] address_zip Value to be assigned + def address_zip=(address_zip) + pattern = Regexp.new(/^\d{5}(-\d{4})?$/) + if !address_zip.nil? && address_zip !~ pattern + fail ArgumentError, "invalid value for \"address_zip\", must conform to the pattern #{pattern}." + end + + @address_zip = address_zip + end + + # Custom attribute writer method checking allowed values (enum). + # @param [Object] object Object to be assigned + def object=(object) + validator = EnumAttributeValidator.new('String', ["address"]) + unless validator.valid?(object) + fail ArgumentError, "invalid value for \"object\", must be one of #{validator.allowable_values}." + end + @object = object + end + + # Checks equality by comparing each attribute. + # @param [Object] Object to be compared + def ==(o) + return true if self.equal?(o) + self.class == o.class && + id == o.id && + description == o.description && + name == o.name && + company == o.company && + phone == o.phone && + email == o.email && + metadata == o.metadata && + address_line1 == o.address_line1 && + address_line2 == o.address_line2 && + address_city == o.address_city && + address_state == o.address_state && + address_zip == o.address_zip && + address_country == o.address_country && + object == o.object && + date_created == o.date_created && + date_modified == o.date_modified && + deleted == o.deleted && + recipient_moved == o.recipient_moved + end + + # @see the `==` method + # @param [Object] Object to be compared + def eql?(o) + self == o + end + + # Calculates hash code according to all attributes. + # @return [Integer] Hash code + def hash + [id, description, name, company, phone, email, metadata, address_line1, address_line2, address_city, address_state, address_zip, address_country, object, date_created, date_modified, deleted, recipient_moved].hash + end + + + # Builds the object from hash + # @param [Hash] attributes Model attributes in the form of hash + # @return [Object] Returns the model itself + def self.build_from_hash(attributes) + new.build_from_hash(attributes) + end + + # Builds the object from hash + # @param [Hash] attributes Model attributes in the form of hash + # @return [Object] Returns the model itself + def build_from_hash(attributes) + return nil unless attributes.is_a?(Hash) + attributes = attributes.transform_keys(&:to_sym) + self.class.openapi_types.each_pair do |key, type| + if attributes[self.class.attribute_map[key]].nil? && self.class.openapi_nullable.include?(key) + self.send("#{key}=", nil) # // guardrails-disable-line + elsif type =~ /\AArray<(.*)>/i + # check to ensure the input is an array given that the attribute + # is documented as an array but the input is not + if attributes[self.class.attribute_map[key]].is_a?(Array) + self.send("#{key}=", attributes[self.class.attribute_map[key]].map { |v| _deserialize($1, v) }) # // guardrails-disable-line end - else # model - const = Lob.const_get(klass) - if const - if const.respond_to?(:openapi_one_of) # nested oneOf model - model = const.build(data) - return model if model - else - # raise if data contains keys that are not known to the model - raise unless (data.keys - const.acceptable_attributes).empty? - model = const.build_from_hash(data) - return model if model && model.valid? + elsif !attributes[self.class.attribute_map[key]].nil? && type.kind_of?(Array) + for base_type in type do + res = _deserialize(base_type, attributes[self.class.attribute_map[key]]) + if !res.nil? + self.send("#{key}=", res) # // guardrails-disable-line + break end end + elsif !attributes[self.class.attribute_map[key]].nil? + self.send("#{key}=", _deserialize(type, attributes[self.class.attribute_map[key]])) # // guardrails-disable-line + end + end + + self + end + + # Deserializes the data based on type + # @param string type Data type + # @param string value Value to be deserialized + # @return [Object] Deserialized data + def _deserialize(type, value) + case type.to_sym + when :Time + Time.parse(value) + when :Date + Date.parse(value) + when :String + value.to_s + when :Integer + value.to_i + when :Float + value.to_f + when :Boolean + if value.to_s =~ /\A(true|t|yes|y|1)\z/i + true + else + false + end + when :Object + # generic object (usually a Hash), return directly + value + when /\AArray<(?.+)>\z/ + inner_type = Regexp.last_match[:inner_type] + value.map { |v| _deserialize(inner_type, v) } + when /\AHash<(?.+?), (?.+)>\z/ + k_type = Regexp.last_match[:k_type] + v_type = Regexp.last_match[:v_type] + {}.tap do |hash| + value.each do |k, v| + hash[_deserialize(k_type, k)] = _deserialize(v_type, v) + end + end + else # model + # models (e.g. Pet) or oneOf + klass = Lob.const_get(type) + klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass.build_from_hash(value) + end + end + + # Returns the string representation of the object + # @return [String] String presentation of the object + def to_s + to_hash.to_s + end + + # to_body is an alias to to_hash (backward compatibility) + # @return [Hash] Returns the object in the form of hash + def to_body + to_hash + end + + # Returns the object in the form of hash + # @return [Hash] Returns the object in the form of hash + def to_hash + hash = {} + self.class.attribute_map.each_pair do |attr, param| + value = self.send(attr) # // guardrails-disable-line + if value.nil? + is_nullable = self.class.openapi_nullable.include?(attr) + next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}")) end - raise # if no match by now, raise - rescue - raise SchemaMismatchError, "#{data} doesn't match the #{klass} type" + hash[param] = _to_hash(value) end + hash end + + # Outputs non-array value in the form of hash + # For object, use to_hash. Otherwise, just return the value + # @param [Object] value Any valid value + # @return [Hash] Returns the value in the form of hash + def _to_hash(value) + if value.is_a?(Array) + value.compact.map { |v| _to_hash(v) } + elsif value.is_a?(Hash) + {}.tap do |hash| + value.each { |k, v| hash[k] = _to_hash(v) } + end + elsif value.respond_to? :to_hash + value.to_hash + else + value + end + end + end end diff --git a/lib/lob/models/intl_address.rb b/lib/lob/models/intl_address.rb index cf833fd..c997c30 100755 --- a/lib/lob/models/intl_address.rb +++ b/lib/lob/models/intl_address.rb @@ -42,10 +42,10 @@ class IntlAddress attr_accessor :address_city - # Must be no longer than 200 characters. + # 2 letter state short-name code attr_accessor :address_state - # Must be no longer than 40 characters. + # Must have a maximum of 12 characters attr_accessor :address_zip attr_accessor :address_country @@ -294,12 +294,13 @@ def list_invalid_properties invalid_properties.push('invalid value for "address_city", the character length must be smaller than or equal to 200.') end - if !@address_state.nil? && @address_state.to_s.length > 200 - invalid_properties.push('invalid value for "address_state", the character length must be smaller than or equal to 200.') + pattern = Regexp.new(/^[a-zA-Z]{2}$/) + if !@address_state.nil? && @address_state !~ pattern + invalid_properties.push("invalid value for \"address_state\", must conform to the pattern #{pattern}.") end - if !@address_zip.nil? && @address_zip.to_s.length > 40 - invalid_properties.push('invalid value for "address_zip", the character length must be smaller than or equal to 40.') + if !@address_zip.nil? && @address_zip.to_s.length > 12 + invalid_properties.push('invalid value for "address_zip", the character length must be smaller than or equal to 12.') end invalid_properties @@ -317,8 +318,8 @@ def valid? return false if !@address_line1.nil? && @address_line1.to_s.length > 64 return false if !@address_line2.nil? && @address_line2.to_s.length > 64 return false if !@address_city.nil? && @address_city.to_s.length > 200 - return false if !@address_state.nil? && @address_state.to_s.length > 200 - return false if !@address_zip.nil? && @address_zip.to_s.length > 40 + return false if !@address_state.nil? && @address_state !~ Regexp.new(/^[a-zA-Z]{2}$/) + return false if !@address_zip.nil? && @address_zip.to_s.length > 12 object_validator = EnumAttributeValidator.new('String', ["address"]) return false unless object_validator.valid?(@object) true @@ -424,8 +425,9 @@ def address_city=(address_city) # Custom attribute writer method with validation # @param [Object] address_state Value to be assigned def address_state=(address_state) - if !address_state.nil? && address_state.to_s.length > 200 - fail ArgumentError, 'invalid value for "address_state", the character length must be smaller than or equal to 200.' + pattern = Regexp.new(/^[a-zA-Z]{2}$/) + if !address_state.nil? && address_state !~ pattern + fail ArgumentError, "invalid value for \"address_state\", must conform to the pattern #{pattern}." end @address_state = address_state @@ -434,8 +436,8 @@ def address_state=(address_state) # Custom attribute writer method with validation # @param [Object] address_zip Value to be assigned def address_zip=(address_zip) - if !address_zip.nil? && address_zip.to_s.length > 40 - fail ArgumentError, 'invalid value for "address_zip", the character length must be smaller than or equal to 40.' + if !address_zip.nil? && address_zip.to_s.length > 12 + fail ArgumentError, 'invalid value for "address_zip", the character length must be smaller than or equal to 12.' end @address_zip = address_zip diff --git a/lib/openapi_client.rb b/lib/openapi_client.rb new file mode 100755 index 0000000..8ad7846 --- /dev/null +++ b/lib/openapi_client.rb @@ -0,0 +1,212 @@ +=begin +#Lob + +#The Lob API is organized around REST. Our API is designed to have predictable, resource-oriented URLs and uses HTTP response codes to indicate any API errors.

Looking for our [previous documentation](https://lob.github.io/legacy-docs/)? + +The version of the OpenAPI document: 1.3.0 +Contact: lob-openapi@lob.com +Generated by: https://openapi-generator.tech +OpenAPI Generator version: 5.2.1 + +=end + +# Common files +require 'openapi_client/api_client' +require 'openapi_client/api_error' +require 'openapi_client/version' +require 'openapi_client/configuration' + +# Models +require 'lob/models/address' +require 'lob/models/address_deletion' +require 'lob/models/address_domestic' +require 'lob/models/address_domestic_expanded' +require 'lob/models/address_editable' +require 'lob/models/address_list' +require 'lob/models/bank_account' +require 'lob/models/bank_account_deletion' +require 'lob/models/bank_account_list' +require 'lob/models/bank_account_verify' +require 'lob/models/bank_account_writable' +require 'lob/models/bank_type_enum' +require 'lob/models/billing_group' +require 'lob/models/billing_group_editable' +require 'lob/models/billing_group_list' +require 'lob/models/buckslip' +require 'lob/models/buckslip_deletion' +require 'lob/models/buckslip_editable' +require 'lob/models/buckslip_order' +require 'lob/models/buckslip_order_editable' +require 'lob/models/buckslip_orders_list' +require 'lob/models/buckslip_updatable' +require 'lob/models/buckslips_list' +require 'lob/models/bulk_error' +require 'lob/models/bulk_error_properties' +require 'lob/models/campaign' +require 'lob/models/campaign_creative' +require 'lob/models/campaign_deletion' +require 'lob/models/campaign_updatable' +require 'lob/models/campaign_writable' +require 'lob/models/campaigns_list' +require 'lob/models/card' +require 'lob/models/card_deletion' +require 'lob/models/card_editable' +require 'lob/models/card_list' +require 'lob/models/card_order' +require 'lob/models/card_order_editable' +require 'lob/models/card_order_list' +require 'lob/models/card_updatable' +require 'lob/models/check' +require 'lob/models/check_deletion' +require 'lob/models/check_editable' +require 'lob/models/check_list' +require 'lob/models/chk_use_type' +require 'lob/models/cmp_schedule_type' +require 'lob/models/cmp_use_type' +require 'lob/models/country_extended' +require 'lob/models/country_extended_expanded' +require 'lob/models/creative_patch' +require 'lob/models/creative_response' +require 'lob/models/creative_writable' +require 'lob/models/custom_envelope_returned' +require 'lob/models/deliverability_analysis' +require 'lob/models/dpv_footnote' +require 'lob/models/engine_html' +require 'lob/models/event_type' +require 'lob/models/events' +require 'lob/models/export' +require 'lob/models/export_model' +require 'lob/models/geocode_addresses' +require 'lob/models/geocode_components' +require 'lob/models/http_validation_error' +require 'lob/models/identity_validation' +require 'lob/models/inline_object' +require 'lob/models/intl_autocompletions' +require 'lob/models/intl_autocompletions_writable' +require 'lob/models/intl_components' +require 'lob/models/intl_suggestions' +require 'lob/models/intl_verification' +require 'lob/models/intl_verification_or_error' +require 'lob/models/intl_verification_writable' +require 'lob/models/intl_verifications' +require 'lob/models/intl_verifications_payload' +require 'lob/models/letter' +require 'lob/models/letter_custom_envelope' +require 'lob/models/letter_deletion' +require 'lob/models/letter_details_returned' +require 'lob/models/letter_details_writable' +require 'lob/models/letter_editable' +require 'lob/models/letter_list' +require 'lob/models/lob_confidence_score' +require 'lob/models/lob_error' +require 'lob/models/location' +require 'lob/models/location_analysis' +require 'lob/models/ltr_use_type' +require 'lob/models/mail_type' +require 'lob/models/multi_line_address' +require 'lob/models/multiple_components' +require 'lob/models/multiple_components_intl' +require 'lob/models/multiple_components_list' +require 'lob/models/optional_address_column_mapping' +require 'lob/models/placeholder_model' +require 'lob/models/postcard' +require 'lob/models/postcard_deletion' +require 'lob/models/postcard_details_returned' +require 'lob/models/postcard_details_writable' +require 'lob/models/postcard_editable' +require 'lob/models/postcard_list' +require 'lob/models/postcard_size' +require 'lob/models/psc_use_type' +require 'lob/models/qr_code' +require 'lob/models/required_address_column_mapping' +require 'lob/models/return_envelope' +require 'lob/models/reverse_geocode' +require 'lob/models/self_mailer' +require 'lob/models/self_mailer_deletion' +require 'lob/models/self_mailer_editable' +require 'lob/models/self_mailer_list' +require 'lob/models/self_mailer_size' +require 'lob/models/sfm_use_type' +require 'lob/models/sort_by' +require 'lob/models/sort_by1' +require 'lob/models/sort_by2' +require 'lob/models/sort_by3' +require 'lob/models/sort_by_date_modified' +require 'lob/models/suggestions' +require 'lob/models/template' +require 'lob/models/template_deletion' +require 'lob/models/template_list' +require 'lob/models/template_update' +require 'lob/models/template_version' +require 'lob/models/template_version_deletion' +require 'lob/models/template_version_list' +require 'lob/models/template_version_updatable' +require 'lob/models/template_version_writable' +require 'lob/models/template_writable' +require 'lob/models/thumbnail' +require 'lob/models/tracking_event_certified' +require 'lob/models/tracking_event_details' +require 'lob/models/tracking_event_normal' +require 'lob/models/upload' +require 'lob/models/upload_create_export' +require 'lob/models/upload_file' +require 'lob/models/upload_state' +require 'lob/models/upload_updatable' +require 'lob/models/upload_writable' +require 'lob/models/uploads_metadata' +require 'lob/models/us_autocompletions' +require 'lob/models/us_autocompletions_writable' +require 'lob/models/us_components' +require 'lob/models/us_verification' +require 'lob/models/us_verification_or_error' +require 'lob/models/us_verifications' +require 'lob/models/us_verifications_writable' +require 'lob/models/validation_error' +require 'lob/models/zip' +require 'lob/models/zip_code_type' +require 'lob/models/zip_editable' +require 'lob/models/zip_lookup_city' + +# APIs +require 'lob/api/addresses_api' +require 'lob/api/bank_accounts_api' +require 'lob/api/billing_groups_api' +require 'lob/api/buckslip_orders_api' +require 'lob/api/buckslips_api' +require 'lob/api/campaigns_api' +require 'lob/api/card_orders_api' +require 'lob/api/cards_api' +require 'lob/api/checks_api' +require 'lob/api/creatives_api' +require 'lob/api/default_api' +require 'lob/api/identity_validation_api' +require 'lob/api/intl_autocompletions_api' +require 'lob/api/intl_verifications_api' +require 'lob/api/letters_api' +require 'lob/api/postcards_api' +require 'lob/api/reverse_geocode_lookups_api' +require 'lob/api/self_mailers_api' +require 'lob/api/template_versions_api' +require 'lob/api/templates_api' +require 'lob/api/uploads_api' +require 'lob/api/us_autocompletions_api' +require 'lob/api/us_verifications_api' +require 'lob/api/zip_lookups_api' + +module OpenapiClient + class << self + # Customize default settings for the SDK using block. + # OpenapiClient.configure do |config| + # config.username = "xxx" + # config.password = "xxx" + # end + # If no block given, return the default Configuration object. + def configure + if block_given? + yield(Configuration.default) + else + Configuration.default + end + end + end +end diff --git a/lib/openapi_client/api_client.rb b/lib/openapi_client/api_client.rb new file mode 100755 index 0000000..dc99931 --- /dev/null +++ b/lib/openapi_client/api_client.rb @@ -0,0 +1,392 @@ +=begin +#Lob + +#The Lob API is organized around REST. Our API is designed to have predictable, resource-oriented URLs and uses HTTP response codes to indicate any API errors.

Looking for our [previous documentation](https://lob.github.io/legacy-docs/)? + +The version of the OpenAPI document: 1.3.0 +Contact: lob-openapi@lob.com +Generated by: https://openapi-generator.tech +OpenAPI Generator version: 5.2.1 + +=end + +require 'date' +require 'json' +require 'logger' +require 'tempfile' +require 'time' +require 'typhoeus' + +module Lob + class ApiClient + # The Configuration object holding settings to be used in the API client. + attr_accessor :config + + # Defines the headers to be used in HTTP requests of all API calls by default. + # + # @return [Hash] + attr_accessor :default_headers + + # Initializes the ApiClient + # @option config [Configuration] Configuration for initializing the object, default to Configuration.default + def initialize(config = Configuration.default) + @config = config + @user_agent = "OpenAPI-Generator/#{VERSION}/ruby" + @default_headers = { + 'Content-Type' => 'application/json', + 'User-Agent' => @user_agent + } + end + + def self.default + @@default ||= ApiClient.new + end + + # Call an API with given options. + # + # @return [Array<(Object, Integer, Hash)>] an array of 3 elements: + # the data deserialized from response body (could be nil), response status code and response headers. + def call_api(http_method, path, opts = {}) + request = build_request(http_method, path, opts) + response = request.run + + if @config.debugging + @config.logger.debug "HTTP response body ~BEGIN~\n#{response.body}\n~END~\n" + end + + unless response.success? + if response.timed_out? + fail ApiError.new('Connection timed out') + elsif response.code == 0 + # Errors from libcurl will be made visible here + fail ApiError.new(:code => 0, + :message => response.return_message) + else + fail ApiError.new(:code => response.code, + :response_headers => response.headers, + :response_body => response.body), + response.status_message + end + end + + if opts[:return_type] + data = deserialize(response, opts[:return_type]) + else + data = nil + end + return data, response.code, response.headers + end + + # Builds the HTTP request + # + # @param [String] http_method HTTP method/verb (e.g. POST) + # @param [String] path URL path (e.g. /account/new) + # @option opts [Hash] :header_params Header parameters + # @option opts [Hash] :query_params Query parameters + # @option opts [Hash] :form_params Query parameters + # @option opts [Object] :body HTTP body (JSON/XML) + # @return [Typhoeus::Request] A Typhoeus Request + def build_request(http_method, path, opts = {}) + url = build_request_url(path, opts) + http_method = http_method.to_sym.downcase + + header_params = @default_headers.merge(opts[:header_params] || {}) + query_params = opts[:query_params] || {} + form_params = opts[:form_params] || {} + follow_location = opts[:follow_location] || true + + update_params_for_auth! header_params, query_params, opts[:auth_names] + + # set ssl_verifyhosts option based on @config.verify_ssl_host (true/false) + _verify_ssl_host = @config.verify_ssl_host ? 2 : 0 + + req_opts = { + :method => http_method, + :headers => header_params, + :params => query_params, + :params_encoding => @config.params_encoding, + :timeout => @config.timeout, + :ssl_verifypeer => @config.verify_ssl, + :ssl_verifyhost => _verify_ssl_host, + :sslcert => @config.cert_file, + :sslkey => @config.key_file, + :verbose => @config.debugging, + :followlocation => follow_location + } + + # set custom cert, if provided + req_opts[:cainfo] = @config.ssl_ca_cert if @config.ssl_ca_cert + + if [:post, :patch, :put, :delete].include?(http_method) + req_body = build_request_body(header_params, form_params, opts[:body]) + req_opts.update :body => req_body + if @config.debugging + @config.logger.debug "HTTP request body param ~BEGIN~\n#{req_body}\n~END~\n" + end + end + + request = Typhoeus::Request.new(url, req_opts) + download_file(request) if opts[:return_type] == 'File' + request + end + + # Builds the HTTP request body + # + # @param [Hash] header_params Header parameters + # @param [Hash] form_params Query parameters + # @param [Object] body HTTP body (JSON/XML) + # @return [String] HTTP body data in the form of string + def build_request_body(header_params, form_params, body) + # http form + if header_params['Content-Type'] == 'application/x-www-form-urlencoded' || + header_params['Content-Type'] == 'multipart/form-data' + data = {} + form_params.each do |key, value| + case value + when ::File, ::Array, nil + # let typhoeus handle File, Array and nil parameters + data[key] = value + else + data[key] = value.to_s + end + end + elsif body + data = body.is_a?(String) ? body : body.to_json + else + data = nil + end + data + end + + # Save response body into a file in (the defined) temporary folder, using the filename + # from the "Content-Disposition" header if provided, otherwise a random filename. + # The response body is written to the file in chunks in order to handle files which + # size is larger than maximum Ruby String or even larger than the maximum memory a Ruby + # process can use. + # + # @see Configuration#temp_folder_path + def download_file(request) + tempfile = nil + encoding = nil + request.on_headers do |response| + content_disposition = response.headers['Content-Disposition'] + if content_disposition && content_disposition =~ /filename=/i + filename = content_disposition[/filename=['"]?([^'"\s]+)['"]?/, 1] + prefix = sanitize_filename(filename) + else + prefix = 'download-' + end + prefix = prefix + '-' unless prefix.end_with?('-') + encoding = response.body.encoding + tempfile = Tempfile.open(prefix, @config.temp_folder_path, encoding: encoding) + @tempfile = tempfile + end + request.on_body do |chunk| + chunk.force_encoding(encoding) + tempfile.write(chunk) + end + request.on_complete do |response| + if tempfile + tempfile.close + @config.logger.info "Temp file written to #{tempfile.path}, please copy the file to a proper folder "\ + "with e.g. `FileUtils.cp(tempfile.path, '/new/file/path')` otherwise the temp file "\ + "will be deleted automatically with GC. It's also recommended to delete the temp file "\ + "explicitly with `tempfile.delete`" + end + end + end + + # Check if the given MIME is a JSON MIME. + # JSON MIME examples: + # application/json + # application/json; charset=UTF8 + # APPLICATION/JSON + # */* + # @param [String] mime MIME + # @return [Boolean] True if the MIME is application/json + def json_mime?(mime) + (mime == '*/*') || !(mime =~ /Application\/.*json(?!p)(;.*)?/i).nil? + end + + # Deserialize the response to the given return type. + # + # @param [Response] response HTTP response + # @param [String] return_type some examples: "User", "Array", "Hash" + def deserialize(response, return_type) + body = response.body + + # handle file downloading - return the File instance processed in request callbacks + # note that response body is empty when the file is written in chunks in request on_body callback + return @tempfile if return_type == 'File' + + return nil if body.nil? || body.empty? + + # return response body directly for String return type + return body if return_type == 'String' + + # ensuring a default content type + content_type = response.headers['Content-Type'] || 'application/json' + + fail "Content-Type is not supported: #{content_type}" unless json_mime?(content_type) + + begin + data = JSON.parse("[#{body}]", :symbolize_names => true)[0] + rescue JSON::ParserError => e + if %w(String Date Time).include?(return_type) + data = body + else + raise e + end + end + + convert_to_type data, return_type + end + + # Convert data to the given return type. + # @param [Object] data Data to be converted + # @param [String] return_type Return type + # @return [Mixed] Data in a particular type + def convert_to_type(data, return_type) + return nil if data.nil? + case return_type + when 'String' + data.to_s + when 'Integer' + data.to_i + when 'Float' + data.to_f + when 'Boolean' + data == true + when 'Time' + # parse date time (expecting ISO 8601 format) + Time.parse data + when 'Date' + # parse date time (expecting ISO 8601 format) + Date.parse data + when 'Object' + # generic object (usually a Hash), return directly + data + when /\AArray<(.+)>\z/ + # e.g. Array + sub_type = $1 + data.map { |item| convert_to_type(item, sub_type) } + when /\AHash\\z/ + # e.g. Hash + sub_type = $1 + {}.tap do |hash| + data.each { |k, v| hash[k] = convert_to_type(v, sub_type) } + end + else + # models (e.g. Pet) or oneOf + klass = Lob.const_get(return_type) + klass.respond_to?(:openapi_one_of) ? klass.build(data) : klass.build_from_hash(data) + end + end + + # Sanitize filename by removing path. + # e.g. ../../sun.gif becomes sun.gif + # + # @param [String] filename the filename to be sanitized + # @return [String] the sanitized filename + def sanitize_filename(filename) + filename.gsub(/.*[\/\\]/, '') + end + + def build_request_url(path, opts = {}) + # Add leading and trailing slashes to path + path = "/#{path}".gsub(/\/+/, '/') + @config.base_url(opts[:operation]) + path + end + + # Update header and query params based on authentication settings. + # + # @param [Hash] header_params Header parameters + # @param [Hash] query_params Query parameters + # @param [String] auth_names Authentication scheme name + def update_params_for_auth!(header_params, query_params, auth_names) + Array(auth_names).each do |auth_name| + auth_setting = @config.auth_settings[auth_name] + next unless auth_setting + case auth_setting[:in] + when 'header' then header_params[auth_setting[:key]] = auth_setting[:value] + when 'query' then query_params[auth_setting[:key]] = auth_setting[:value] + else fail ArgumentError, 'Authentication token must be in `query` or `header`' + end + end + end + + # Sets user agent in HTTP header + # + # @param [String] user_agent User agent (e.g. openapi-generator/ruby/1.0.0) + def user_agent=(user_agent) + @user_agent = user_agent + @default_headers['User-Agent'] = @user_agent + end + + # Return Accept header based on an array of accepts provided. + # @param [Array] accepts array for Accept + # @return [String] the Accept header (e.g. application/json) + def select_header_accept(accepts) + return nil if accepts.nil? || accepts.empty? + # use JSON when present, otherwise use all of the provided + json_accept = accepts.find { |s| json_mime?(s) } + json_accept || accepts.join(',') + end + + # Return Content-Type header based on an array of content types provided. + # @param [Array] content_types array for Content-Type + # @return [String] the Content-Type header (e.g. application/json) + def select_header_content_type(content_types) + # return nil by default + return if content_types.nil? || content_types.empty? + # use JSON when present, otherwise use the first one + json_content_type = content_types.find { |s| json_mime?(s) } + json_content_type || content_types.first + end + + # Convert object (array, hash, object, etc) to JSON string. + # @param [Object] model object to be converted into JSON string + # @return [String] JSON string representation of the object + def object_to_http_body(model) + return model if model.nil? || model.is_a?(String) + local_body = nil + if model.is_a?(Array) + local_body = model.map { |m| object_to_hash(m) } + else + local_body = object_to_hash(model) + end + local_body.to_json + end + + # Convert object(non-array) to hash. + # @param [Object] obj object to be converted into JSON string + # @return [String] JSON string representation of the object + def object_to_hash(obj) + if obj.respond_to?(:to_hash) + obj.to_hash + else + obj + end + end + + # Build parameter value according to the given collection format. + # @param [String] collection_format one of :csv, :ssv, :tsv, :pipes and :multi + def build_collection_param(param, collection_format) + case collection_format + when :csv + param.join(',') + when :ssv + param.join(' ') + when :tsv + param.join("\t") + when :pipes + param.join('|') + when :multi + # return the array directly as typhoeus will handle it as expected + param + else + fail "unknown collection format: #{collection_format.inspect}" + end + end + end +end diff --git a/lib/openapi_client/api_error.rb b/lib/openapi_client/api_error.rb new file mode 100755 index 0000000..adab133 --- /dev/null +++ b/lib/openapi_client/api_error.rb @@ -0,0 +1,57 @@ +=begin +#Lob + +#The Lob API is organized around REST. Our API is designed to have predictable, resource-oriented URLs and uses HTTP response codes to indicate any API errors.

Looking for our [previous documentation](https://lob.github.io/legacy-docs/)? + +The version of the OpenAPI document: 1.3.0 +Contact: lob-openapi@lob.com +Generated by: https://openapi-generator.tech +OpenAPI Generator version: 5.2.1 + +=end + +module Lob + class ApiError < StandardError + attr_reader :code, :response_headers, :response_body + + # Usage examples: + # ApiError.new + # ApiError.new("message") + # ApiError.new(:code => 500, :response_headers => {}, :response_body => "") + # ApiError.new(:code => 404, :message => "Not Found") + def initialize(arg = nil) + if arg.is_a? Hash + if arg.key?(:message) || arg.key?('message') + super(arg[:message] || arg['message']) + else + super arg + end + + arg.each do |k, v| + instance_variable_set "@#{k}", v + end + else + super arg + end + end + + # Override to_s to display a friendly error message + def to_s + message + end + + def message + if @message.nil? + msg = "Error message: the server returns an error" + else + msg = @message + end + + msg += "\nHTTP status code: #{code}" if code + msg += "\nResponse headers: #{response_headers}" if response_headers + msg += "\nResponse body: #{response_body}" if response_body + + msg + end + end +end diff --git a/lib/openapi_client/configuration.rb b/lib/openapi_client/configuration.rb new file mode 100755 index 0000000..7e6a4b8 --- /dev/null +++ b/lib/openapi_client/configuration.rb @@ -0,0 +1,279 @@ +=begin +#Lob + +#The Lob API is organized around REST. Our API is designed to have predictable, resource-oriented URLs and uses HTTP response codes to indicate any API errors.

Looking for our [previous documentation](https://lob.github.io/legacy-docs/)? + +The version of the OpenAPI document: 1.3.0 +Contact: lob-openapi@lob.com +Generated by: https://openapi-generator.tech +OpenAPI Generator version: 5.2.1 + +=end + +module Lob + class Configuration + # Defines url scheme + attr_accessor :scheme + + # Defines url host + attr_accessor :host + + # Defines url base path + attr_accessor :base_path + + # Define server configuration index + attr_accessor :server_index + + # Define server operation configuration index + attr_accessor :server_operation_index + + # Default server variables + attr_accessor :server_variables + + # Default server operation variables + attr_accessor :server_operation_variables + + # Defines API keys used with API Key authentications. + # + # @return [Hash] key: parameter name, value: parameter value (API key) + # + # @example parameter name is "api_key", API key is "xxx" (e.g. "api_key=xxx" in query string) + # config.api_key['api_key'] = 'xxx' + attr_accessor :api_key + + # Defines API key prefixes used with API Key authentications. + # + # @return [Hash] key: parameter name, value: API key prefix + # + # @example parameter name is "Authorization", API key prefix is "Token" (e.g. "Authorization: Token xxx" in headers) + # config.api_key_prefix['api_key'] = 'Token' + attr_accessor :api_key_prefix + + # Defines the username used with HTTP basic authentication. + # + # @return [String] + attr_accessor :username + + # Defines the password used with HTTP basic authentication. + # + # @return [String] + attr_accessor :password + + # Defines the access token (Bearer) used with OAuth2. + attr_accessor :access_token + + # Set this to enable/disable debugging. When enabled (set to true), HTTP request/response + # details will be logged with `logger.debug` (see the `logger` attribute). + # Default to false. + # + # @return [true, false] + attr_accessor :debugging + + # Defines the logger used for debugging. + # Default to `Rails.logger` (when in Rails) or logging to STDOUT. + # + # @return [#debug] + attr_accessor :logger + + # Defines the temporary folder to store downloaded files + # (for API endpoints that have file response). + # Default to use `Tempfile`. + # + # @return [String] + attr_accessor :temp_folder_path + + # The time limit for HTTP request in seconds. + # Default to 0 (never times out). + attr_accessor :timeout + + # Set this to false to skip client side validation in the operation. + # Default to true. + # @return [true, false] + attr_accessor :client_side_validation + + ### TLS/SSL setting + # Set this to false to skip verifying SSL certificate when calling API from https server. + # Default to true. + # + # @note Do NOT set it to false in production code, otherwise you would face multiple types of cryptographic attacks. + # + # @return [true, false] + attr_accessor :verify_ssl + + ### TLS/SSL setting + # Set this to false to skip verifying SSL host name + # Default to true. + # + # @note Do NOT set it to false in production code, otherwise you would face multiple types of cryptographic attacks. + # + # @return [true, false] + attr_accessor :verify_ssl_host + + ### TLS/SSL setting + # Set this to customize the certificate file to verify the peer. + # + # @return [String] the path to the certificate file + # + # @see The `cainfo` option of Typhoeus, `--cert` option of libcurl. Related source code: + # https://github.com/typhoeus/typhoeus/blob/master/lib/typhoeus/easy_factory.rb#L145 + attr_accessor :ssl_ca_cert + + ### TLS/SSL setting + # Client certificate file (for client certificate) + attr_accessor :cert_file + + ### TLS/SSL setting + # Client private key file (for client certificate) + attr_accessor :key_file + + # Set this to customize parameters encoding of array parameter with multi collectionFormat. + # Default to nil. + # + # @see The params_encoding option of Ethon. Related source code: + # https://github.com/typhoeus/ethon/blob/master/lib/ethon/easy/queryable.rb#L96 + attr_accessor :params_encoding + + + attr_accessor :inject_format + + attr_accessor :force_ending_format + + def initialize + @scheme = 'https' + @host = 'api.lob.com' + @base_path = '/v1' + @server_index = 0 + @server_operation_index = {} + @server_variables = {} + @server_operation_variables = {} + @api_key = {} + @api_key_prefix = {} + @client_side_validation = true + @verify_ssl = true + @verify_ssl_host = true + @cert_file = nil + @key_file = nil + @timeout = 0 + @params_encoding = nil + @debugging = false + @inject_format = false + @force_ending_format = false + @logger = defined?(Rails) ? Rails.logger : Logger.new(STDOUT) + + yield(self) if block_given? + end + + # The default Configuration object. + def self.default + @@default ||= Configuration.new + end + + def configure + yield(self) if block_given? + end + + def scheme=(scheme) + # remove :// from scheme + @scheme = scheme.sub(/:\/\//, '') + end + + def host=(host) + # remove http(s):// and anything after a slash + @host = host.sub(/https?:\/\//, '').split('/').first + end + + def base_path=(base_path) + # Add leading and trailing slashes to base_path + @base_path = "/#{base_path}".gsub(/\/+/, '/') + @base_path = '' if @base_path == '/' + end + + # Returns base URL for specified operation based on server settings + def base_url(operation = nil) + index = server_operation_index.fetch(operation, server_index) + return "#{scheme}://#{[host, base_path].join('/').gsub(/\/+/, '/')}".sub(/\/+\z/, '') if index == nil + + server_url(index, server_operation_variables.fetch(operation, server_variables), operation_server_settings[operation]) + end + + # Gets API key (with prefix if set). + # @param [String] param_name the parameter name of API key auth + def api_key_with_prefix(param_name, param_alias = nil) + key = @api_key[param_name] + key = @api_key.fetch(param_alias, key) unless param_alias.nil? + if @api_key_prefix[param_name] + "#{@api_key_prefix[param_name]} #{key}" + else + key + end + end + + # Gets Basic Auth token string + def basic_auth_token + 'Basic ' + ["#{username}:#{password}"].pack('m').delete("\r\n") + end + + # Returns Auth Settings hash for api client. + def auth_settings + { + 'basicAuth' => + { + type: 'basic', + in: 'header', + key: 'Authorization', + value: basic_auth_token + }, + } + end + + # Returns an array of Server setting + def server_settings + [ + { + url: "https://api.lob.com/v1", + description: "production", + } + ] + end + + def operation_server_settings + { + } + end + + # Returns URL based on server settings + # + # @param index array index of the server settings + # @param variables hash of variable and the corresponding value + def server_url(index, variables = {}, servers = nil) + servers = server_settings if servers == nil + + # check array index out of bound + if (index < 0 || index >= servers.size) + fail ArgumentError, "Invalid index #{index} when selecting the server. Must be less than #{servers.size}" + end + + server = servers[index] + url = server[:url] + + return url unless server.key? :variables + + # go through variable and assign a value + server[:variables].each do |name, variable| + if variables.key?(name) + if (!server[:variables][name].key?(:enum_values) || server[:variables][name][:enum_values].include?(variables[name])) + url.gsub! "{" + name.to_s + "}", variables[name] + else + fail ArgumentError, "The variable `#{name}` in the server URL has invalid value #{variables[name]}. Must be #{server[:variables][name][:enum_values]}." + end + else + # use default value + url.gsub! "{" + name.to_s + "}", server[:variables][name][:default_value] + end + end + + url + end + + end +end diff --git a/lib/openapi_client/version.rb b/lib/openapi_client/version.rb new file mode 100755 index 0000000..6cefc34 --- /dev/null +++ b/lib/openapi_client/version.rb @@ -0,0 +1,15 @@ +=begin +#Lob + +#The Lob API is organized around REST. Our API is designed to have predictable, resource-oriented URLs and uses HTTP response codes to indicate any API errors.

Looking for our [previous documentation](https://lob.github.io/legacy-docs/)? + +The version of the OpenAPI document: 1.3.0 +Contact: lob-openapi@lob.com +Generated by: https://openapi-generator.tech +OpenAPI Generator version: 5.2.1 + +=end + +module Lob + VERSION = '7.0.0' +end