Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ jobs:
fail-fast: false
matrix:
include:
- ruby: 2.6
- ruby: 2.7
- ruby: 3
- ruby: 3.1
- ruby: 3.2
- ruby: 3.3
- ruby: 3.4
runs-on: ubuntu-latest
name: RSpec suite with Ruby ${{ matrix.ruby }}
env:
Expand Down
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ gemspec

# When updating the following gems, run `earthly +dev` in the case you're using
# Docker to develop this gem.
gem 'dry-struct'
gem 'dry-types'
gem 'ffaker'
gem 'rake'
gem 'rspec'
Expand Down
136 changes: 85 additions & 51 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,89 +2,123 @@ PATH
remote: .
specs:
sms_factor (0.2.2)
dry-struct (~> 1.6)
dry-types (~> 1.7)
nokogiri (~> 1.13, < 1.14)
rest-client (~> 2.0.2, >= 2.0.2)

GEM
remote: https://rubygems.org/
specs:
addressable (2.8.4)
public_suffix (>= 2.0.2, < 6.0)
ast (2.4.2)
crack (0.4.5)
addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0)
ast (2.4.3)
base64 (0.3.0)
bigdecimal (3.2.2)
concurrent-ruby (1.3.5)
crack (1.0.0)
bigdecimal
rexml
diff-lcs (1.5.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
diff-lcs (1.6.2)
domain_name (0.6.20240107)
dry-core (1.0.0)
concurrent-ruby (~> 1.0)
zeitwerk (~> 2.6)
dry-inflector (1.1.0)
dry-logic (1.5.0)
concurrent-ruby (~> 1.0)
dry-core (~> 1.0, < 2)
zeitwerk (~> 2.6)
dry-struct (1.6.0)
dry-core (~> 1.0, < 2)
dry-types (>= 1.7, < 2)
ice_nine (~> 0.11)
zeitwerk (~> 2.6)
dry-types (1.7.1)
concurrent-ruby (~> 1.0)
dry-core (~> 1.0)
dry-inflector (~> 1.0)
dry-logic (~> 1.4)
zeitwerk (~> 2.6)
ffaker (2.21.0)
hashdiff (1.0.1)
http-cookie (1.0.5)
hashdiff (1.2.0)
http-cookie (1.0.8)
domain_name (~> 0.5)
json (2.6.3)
mime-types (3.4.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2023.0218.1)
ice_nine (0.11.2)
json (2.12.2)
language_server-protocol (3.17.0.5)
lint_roller (1.1.0)
logger (1.7.0)
mime-types (3.7.0)
logger
mime-types-data (~> 3.2025, >= 3.2025.0507)
mime-types-data (3.2025.0701)
netrc (0.11.0)
nokogiri (1.13.10-x86_64-linux)
racc (~> 1.4)
parallel (1.22.1)
parser (3.2.2.0)
parallel (1.27.0)
parser (3.3.8.0)
ast (~> 2.4.1)
public_suffix (5.0.1)
racc (1.6.2)
racc
prism (1.4.0)
public_suffix (5.1.1)
racc (1.8.1)
rainbow (3.1.1)
rake (13.0.6)
regexp_parser (2.7.0)
rake (13.3.0)
regexp_parser (2.10.0)
rest-client (2.0.2)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
rexml (3.2.5)
rspec (3.12.0)
rspec-core (~> 3.12.0)
rspec-expectations (~> 3.12.0)
rspec-mocks (~> 3.12.0)
rspec-core (3.12.1)
rspec-support (~> 3.12.0)
rspec-expectations (3.12.2)
rexml (3.4.1)
rspec (3.13.1)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
rspec-core (3.13.5)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.5)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-mocks (3.12.5)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.5)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-support (3.12.0)
rubocop (1.49.0)
rspec-support (~> 3.13.0)
rspec-support (3.13.4)
rubocop (1.77.0)
json (~> 2.3)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
parallel (~> 1.10)
parser (>= 3.2.0.0)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.28.0, < 2.0)
regexp_parser (>= 2.9.3, < 3.0)
rubocop-ast (>= 1.45.1, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.28.0)
parser (>= 3.2.1.0)
rubocop-capybara (2.17.1)
rubocop (~> 1.41)
rubocop-rspec (2.19.0)
rubocop (~> 1.33)
rubocop-capybara (~> 2.17)
unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.45.1)
parser (>= 3.3.7.2)
prism (~> 1.4)
rubocop-rspec (3.6.0)
lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1)
ruby-progressbar (1.13.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.8.2)
unicode-display_width (2.4.2)
vcr (6.1.0)
webmock (3.18.1)
unicode-display_width (3.1.4)
unicode-emoji (~> 4.0, >= 4.0.4)
unicode-emoji (4.0.4)
vcr (6.3.1)
base64
webmock (3.25.1)
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
zeitwerk (2.6.18)

PLATFORMS
ruby

DEPENDENCIES
dry-struct
dry-types
ffaker
rake
rspec
Expand All @@ -95,4 +129,4 @@ DEPENDENCIES
webmock

BUNDLED WITH
2.1.4
2.3.26
2 changes: 2 additions & 0 deletions docker-compose-earthly.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
version: '3'

name: sms_factor

services:
# docker-compose run --rm gem [rspec [path to spec file]]
gem:
Expand Down
27 changes: 13 additions & 14 deletions lib/sms_factor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def deliver(delay: :now, check: false, api_key: nil)
RestClient.post(
sms_factor_url(check),
{ data: build_deliver_data_from(delay).to_json },
sms_factor_api_headers(api_key)
SmsFactor::Headers.api_headers(api_key)
)
)
end
Expand All @@ -65,26 +65,25 @@ def build_deliver_data_from(delay)
data
end

def sms_factor_api_headers(api_key = null)
headers = {
accept: :json,
verify_ssl: false
}

if SmsFactor::Init.configuration.api_auth?
headers[:Authorization] = "Bearer #{api_key || SmsFactor::Init.configuration.api_key}"
end

headers
end

def sms_factor_url(check)
url = "#{SmsFactor::Init.configuration.api_url}/send"
url += '/simulate' if check
url
end
end

# core utils
require 'sms_factor/configuration'
require 'sms_factor/errors'
require 'sms_factor/headers'
require 'sms_factor/init'
require 'sms_factor/response_factory'
require 'sms_factor/types'

# responses
require 'sms_factor/sms_response'
Dir[File.expand_path('sms_factor/responses/**/*.rb', __dir__)].sort.each { |f| require f }

# services
require 'sms_factor/sub_account'
require 'sms_factor/token'
24 changes: 24 additions & 0 deletions lib/sms_factor/errors.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

class SmsFactor
class ApiError < StandardError
attr_reader :status, :message, :details

def initialize(status, message, details)
@status = status
@message = "#{message}: #{details}"
super("[API error #{status}] #{message}: #{details}")
end
end

class AuthError < ApiError; end
class XmlError < ApiError; end
class NotEnoughCreditsError < ApiError; end
class DateError < ApiError; end
class ResourceNotFoundError < ApiError; end
class JsonError < ApiError; end
class DataError < ApiError; end
class ModerationError < ApiError; end
class InvalidTokenIdError < ApiError; end
class UnknownApiError < ApiError; end
end
19 changes: 19 additions & 0 deletions lib/sms_factor/headers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

class SmsFactor
module Headers
def self.api_headers(api_key = nil)
headers = {
accept: :json,
content_type: :json,
verify_ssl: false
}

if SmsFactor::Init.configuration.api_auth?
headers[:Authorization] = "Bearer #{api_key || SmsFactor::Init.configuration.api_key}"
end

headers
end
end
end
31 changes: 31 additions & 0 deletions lib/sms_factor/response_factory.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# frozen_string_literal: true

class SmsFactor
class ResponseFactory
ERROR_CLASSES = {
-1 => SmsFactor::AuthError,
-2 => SmsFactor::XmlError,
-3 => SmsFactor::NotEnoughCreditsError,
-4 => SmsFactor::DateError,
-5 => SmsFactor::ResourceNotFoundError,
-6 => SmsFactor::JsonError,
-7 => SmsFactor::DataError,
-8 => SmsFactor::ModerationError,
-10 => SmsFactor::InvalidTokenIdError
}.freeze

def self.build(response, klass)
parsed = JSON.parse(response.body, symbolize_names: true)

unless parsed[:status] == 1
raise error_class(parsed[:status]).new(parsed[:status], parsed[:message], parsed[:details])
end

klass.new(parsed)
end

def self.error_class(status)
ERROR_CLASSES[status] || SmsFactor::UnknownApiError
end
end
end
14 changes: 14 additions & 0 deletions lib/sms_factor/responses/balance_response.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# frozen_string_literal: true

require 'sms_factor/responses/base_response'

class SmsFactor
module Responses
class BalanceResponse < BaseResponse
attribute :credits, SmsFactor::Types::Coercible::Integer
attribute :postpaid, SmsFactor::Types::Coercible::Integer
attribute :postpaid_limit, SmsFactor::Types::Strict::Bool | SmsFactor::Types::Coercible::Integer
attribute :unlimited, SmsFactor::Types::Strict::Bool
end
end
end
20 changes: 20 additions & 0 deletions lib/sms_factor/responses/base_response.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

require 'dry-struct'
require 'sms_factor/types'
require 'sms_factor/errors'

class SmsFactor
module Responses
class BaseResponse < Dry::Struct
transform_keys { |k| k.to_s.gsub('-', '_').to_sym }

attribute :status, SmsFactor::Types::Strict::Integer
attribute :message, SmsFactor::Types::Strict::String

def success?
status == 1
end
end
end
end
12 changes: 12 additions & 0 deletions lib/sms_factor/responses/create_sub_account_response.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

require 'sms_factor/responses/base_response'

class SmsFactor
module Responses
class CreateSubAccountResponse < BaseResponse
attribute :id, SmsFactor::Types::Coercible::Integer
attribute :active, SmsFactor::Types::Coercible::Integer
end
end
end
13 changes: 13 additions & 0 deletions lib/sms_factor/responses/create_token_response.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

require 'sms_factor/responses/base_response'

class SmsFactor
module Responses
class CreateTokenResponse < BaseResponse
attribute :token, SmsFactor::Types::Strict::String
attribute :token_id, SmsFactor::Types::Strict::String
attribute :allowed_ips, SmsFactor::Types::Array.of(SmsFactor::Types::Strict::String).optional
end
end
end
Loading
Loading