sipwizard 0.0.1 → 0.1.0

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.
Files changed (62) hide show
  1. data/.gitignore +1 -0
  2. data/Gemfile +9 -3
  3. data/Guardfile +6 -5
  4. data/lib/sipwizard.rb +3 -0
  5. data/lib/sipwizard/account.rb +101 -0
  6. data/lib/sipwizard/binding.rb +40 -0
  7. data/lib/sipwizard/cdr.rb +59 -0
  8. data/lib/sipwizard/connection.rb +31 -7
  9. data/lib/sipwizard/customer.rb +81 -0
  10. data/lib/sipwizard/dial_plan.rb +91 -0
  11. data/lib/sipwizard/provider.rb +99 -0
  12. data/lib/sipwizard/provider_binding.rb +53 -0
  13. data/lib/sipwizard/rate.rb +81 -0
  14. data/lib/sipwizard/relation.rb +27 -0
  15. data/lib/sipwizard/version.rb +1 -1
  16. data/sipwizard.gemspec +6 -4
  17. data/spec/lib/sipwizard/account_spec.rb +80 -0
  18. data/spec/lib/sipwizard/binding_spec.rb +22 -0
  19. data/spec/lib/sipwizard/cdr_spec.rb +21 -0
  20. data/spec/lib/sipwizard/configuration_spec.rb +1 -1
  21. data/spec/lib/sipwizard/connection_spec.rb +19 -25
  22. data/spec/lib/sipwizard/customer_spec.rb +80 -0
  23. data/spec/lib/sipwizard/dial_plan_spec.rb +95 -0
  24. data/spec/lib/sipwizard/provider_binding_spec.rb +22 -0
  25. data/spec/lib/sipwizard/provider_spec.rb +107 -0
  26. data/spec/lib/sipwizard/rate_spec.rb +83 -0
  27. data/spec/lib/sipwizard_spec.rb +1 -1
  28. data/spec/spec.yml.sample +7 -0
  29. data/spec/spec_helper.rb +32 -9
  30. data/spec/vcr/sipsorcery/cdr/count.yml +70 -0
  31. data/spec/vcr/sipsorcery/cdr/get.yml +38 -0
  32. data/spec/vcr/sipsorcery/customeraccount/add.yml +73 -0
  33. data/spec/vcr/sipsorcery/customeraccount/count.yml +36 -0
  34. data/spec/vcr/sipsorcery/customeraccount/delete.yml +36 -0
  35. data/spec/vcr/sipsorcery/customeraccount/get.yml +36 -0
  36. data/spec/vcr/sipsorcery/customeraccount/update.yml +38 -0
  37. data/spec/vcr/sipsorcery/dialplan/add.yml +75 -0
  38. data/spec/vcr/sipsorcery/dialplan/copy.yml +36 -0
  39. data/spec/vcr/sipsorcery/dialplan/count.yml +36 -0
  40. data/spec/vcr/sipsorcery/dialplan/delete.yml +36 -0
  41. data/spec/vcr/sipsorcery/dialplan/get.yml +37 -0
  42. data/spec/vcr/sipsorcery/dialplan/update.yml +39 -0
  43. data/spec/vcr/sipsorcery/rate/add.yml +73 -0
  44. data/spec/vcr/sipsorcery/rate/count.yml +36 -0
  45. data/spec/vcr/sipsorcery/rate/delete.yml +36 -0
  46. data/spec/vcr/sipsorcery/rate/get.yml +36 -0
  47. data/spec/vcr/sipsorcery/rate/update.yml +38 -0
  48. data/spec/vcr/sipsorcery/sipaccount/add.yml +74 -0
  49. data/spec/vcr/sipsorcery/sipaccount/count.yml +36 -0
  50. data/spec/vcr/sipsorcery/sipaccount/delete.yml +69 -0
  51. data/spec/vcr/sipsorcery/sipaccount/get.yml +36 -0
  52. data/spec/vcr/sipsorcery/sipaccount/update.yml +37 -0
  53. data/spec/vcr/sipsorcery/sipaccountbinding/count.yml +36 -0
  54. data/spec/vcr/sipsorcery/sipaccountbinding/get.yml +36 -0
  55. data/spec/vcr/sipsorcery/sipprovider/add.yml +74 -0
  56. data/spec/vcr/sipsorcery/sipprovider/count.yml +36 -0
  57. data/spec/vcr/sipsorcery/sipprovider/delete.yml +36 -0
  58. data/spec/vcr/sipsorcery/sipprovider/get.yml +36 -0
  59. data/spec/vcr/sipsorcery/sipprovider/update.yml +38 -0
  60. data/spec/vcr/sipsorcery/sipproviderbinding/count.yml +36 -0
  61. data/spec/vcr/sipsorcery/sipproviderbinding/get.yml +69 -0
  62. metadata +129 -6
data/.gitignore CHANGED
@@ -3,6 +3,7 @@
3
3
  .bundle
4
4
  .config
5
5
  .yardoc
6
+ spec/*.yml
6
7
  Gemfile.lock
7
8
  InstalledFiles
8
9
  _yardoc
data/Gemfile CHANGED
@@ -3,12 +3,18 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in sipwizard.gemspec
4
4
 
5
5
  group :test do
6
- gem 'minitest', '~> 4.7.5'
6
+ gem 'rspec'
7
7
  gem 'guard'
8
- gem 'guard-minitest'
8
+ gem 'guard-rspec'
9
+ gem 'vcr'
10
+ gem 'spork'
11
+ end
12
+
13
+ group :test, :development do
9
14
  gem 'pry'
10
15
  gem 'pry-debugger'
11
- gem 'turn'
16
+ gem 'pry-rescue'
17
+ gem 'pry-stack_explorer'
12
18
  end
13
19
 
14
20
  gemspec
data/Guardfile CHANGED
@@ -1,9 +1,10 @@
1
1
  # A sample Guardfile
2
2
  # More info at https://github.com/guard/guard#readme
3
3
 
4
- guard :minitest do
5
- # with Minitest::Spec
6
- watch(%r{^spec/(.*)_spec\.rb})
7
- watch(%r{^lib/(.+)\.rb}) { |m| "spec/lib/#{m[1]}_spec.rb" }
8
- watch(%r{^spec/spec_helper\.rb}) { 'spec' }
4
+
5
+ guard :rspec do
6
+ watch(%r{^spec/.+_spec\.rb$})
7
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
8
+ watch('spec/spec_helper.rb') { "spec" }
9
9
  end
10
+
@@ -1,6 +1,9 @@
1
+ require 'rack'
2
+ require 'hashie'
1
3
  Dir[File.dirname(__FILE__) + '/sipwizard/*.rb'].each{ |file| require file }
2
4
 
3
5
  module Sipwizard
6
+ HTTP_STATUS_CODES = Rack::Utils::HTTP_STATUS_CODES.invert
4
7
  extend self
5
8
 
6
9
  attr_accessor :config
@@ -0,0 +1,101 @@
1
+ require 'active_support/core_ext/string/inflections'
2
+
3
+ module Sipwizard
4
+ class Account < Hashie::Trash
5
+ API_PATH_MAP ={
6
+ count: 'sipaccount/count',
7
+ find: 'sipaccount/get',
8
+ create: 'sipaccount/add',
9
+ update: 'sipaccount/update',
10
+ delete: 'sipaccount/delete'
11
+ }
12
+
13
+ string_to_bool = ->(string) { string == "true" }
14
+
15
+ property :id, from: :ID
16
+ property :domain, from: :SIPDomain
17
+ property :username, from: :SIPUsername, required: true
18
+ property :password, from: :SIPPassword,required: true
19
+ property :account_code, from: :AccountCode
20
+ property :avatar_url, from: :AvatarURL
21
+ property :description, from: :Description
22
+ property :dont_mangle_enabled, from: :DontMangleEnabled, transform_with: ->(b) { string_to_bool.call(b) }
23
+ property :ip_address_acl, from: :IPAddressACL
24
+ property :in_dial_plan_name, from: :InDialPlanName
25
+ property :is_incoming_only, from: :IsIncomingOnly, transform_with: ->(b) { string_to_bool.call(b) }
26
+ property :is_switch_board_enabled, from: :IsSwitchboardEnabled, transform_with: ->(b) { string_to_bool.call(b) }
27
+ property :is_user_disabled, from: :IsUserDisabled, transform_with: ->(b) { string_to_bool.call(b) }
28
+ property :network_id, from: :NetworkID
29
+ property :out_dial_plan_name, from: :OutDialPlanName
30
+ property :send_nat_keep_alives, from: :SendNATKeepAlives, transform_with: ->(b) { string_to_bool.call(b) }
31
+
32
+ alias :dont_mangle? :dont_mangle_enabled
33
+ alias :incoming_only? :is_incoming_only
34
+ alias :switch_board_enabled? :is_switch_board_enabled
35
+ alias :user_disabled? :is_user_disabled
36
+ alias :send_nat_keep_alives? :send_nat_keep_alives
37
+
38
+ def self.build_for_request(h)
39
+ account = self.new(h)
40
+ account = Hash[account.map{ |k,v| ["#{k}".camelize, v] }]
41
+ account['ID'] = account.delete('Id')
42
+ account['SIPDomain'] = account.delete('Domain')
43
+ account['SIPUsername'] = account.delete('Username')
44
+ account['SIPPassword'] = account.delete('Password')
45
+ account['IPAddressACL'] = account.delete('IpAddressAcl')
46
+ account['AvatarURL'] = account.delete('AvatarUrl')
47
+ account['NetworkID'] = account.delete('NetworkId')
48
+ account['SendNATKeepAlives'] = account.delete('SendNatKeepAlives')
49
+
50
+ account.delete_if{ |_,v| v.nil? } #delete all the keys for which we dont have value
51
+ end
52
+
53
+ def self.count(params={})
54
+ response = Connection.new.get(API_PATH_MAP[:count], params)
55
+
56
+ response['Success'] ? response['Result'] : -1
57
+ end
58
+
59
+ def self.where(params)
60
+ Relation.new.where(params)
61
+ end
62
+
63
+ def self.find(id)
64
+ relation = self.where({ ID: id }).count(1)
65
+ result = Connection.new.get(API_PATH_MAP[:find], relation.relation)
66
+
67
+ return nil unless result['Success']
68
+
69
+ self.new(result['Result'][0])
70
+ end
71
+
72
+ def self.create(params)
73
+ payload = self.build_for_request(params)
74
+ result = Connection.new.post(API_PATH_MAP[:create], payload)
75
+
76
+ raise ArgumentError.new(result["Error"]) unless result['Success']
77
+
78
+ result['Result'] #ID
79
+ end
80
+
81
+ def self.delete(id)
82
+ result = Connection.new.get(API_PATH_MAP[:delete], {id: id})
83
+
84
+ raise ArgumentError.new(result["Error"]) unless result['Success']
85
+
86
+ result['Result'] #true | false
87
+ end
88
+
89
+ def save
90
+ payload = Account.build_for_request(self.to_hash)
91
+ result = Connection.new.post(API_PATH_MAP[:update], payload)
92
+ raise ArgumentError.new(result["Error"]) unless result['Success']
93
+
94
+ result['Result'] #ID
95
+ end
96
+
97
+ def delete
98
+ Account.delete(self.id)
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,40 @@
1
+ module Sipwizard
2
+ class Binding < Hashie::Trash
3
+ API_PATH_MAP={
4
+ count: 'sipaccountbinding/count',
5
+ find: 'sipaccountbinding/get'
6
+ }
7
+
8
+ property :id, from: :ID
9
+ property :contact_udi, from: :ContactURI
10
+ property :expiry, from: :Expiry
11
+ property :expiry_time, from: :ExpiryTime
12
+ property :last_update, from: :LastUpdate
13
+ property :mangled_contact_uri, from: :MangledContactURI
14
+ property :proxy_sip_socket, from: :ProxySIPSocket
15
+ property :registrat_sip_socket, from: :RegistrarSIPSocket
16
+ property :remote_sip_socket, from: :RemoteSIPSocket
17
+ property :account_id, from: :SIPAccountID
18
+ property :account_name, from: :SIPAccountName
19
+ property :user_agent, from: :UserAgent
20
+
21
+ def self.count
22
+ response = Connection.new.get(API_PATH_MAP[:count])
23
+
24
+ response['Success'] ? response['Result'] : -1
25
+ end
26
+
27
+ def self.where(params)
28
+ Relation.new.where(params)
29
+ end
30
+
31
+ def self.find(id)
32
+ relation = self.where({ ID: id }).count(1)
33
+ result = Connection.new.get(API_PATH_MAP[:find], relation.relation)
34
+
35
+ return nil unless result['Success']
36
+
37
+ self.new(result['Result'][0])
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,59 @@
1
+ module Sipwizard
2
+ class Cdr < Hashie::Trash
3
+ API_PATH_MAP={
4
+ count: 'cdr/count',
5
+ find: 'cdr/get'
6
+ }
7
+
8
+ property :account_code, from: :AccountCode
9
+ property :answered_reason, from: :AnsweredReason
10
+ property :answered_status, from: :AnsweredStatus
11
+ property :answered_time, from: :AnsweredTime
12
+ property :balance, from: :Balance
13
+ property :bridge_id, from: :BridgeId
14
+ property :call_direction, from: :CallDirection
15
+ property :call_id, from: :CallId
16
+ property :cost, from: :Cost
17
+ property :created, from: :Created
18
+ property :dial_plan_context_id, from: :DialPlanContextID
19
+ property :dst, from: :Dst
20
+ property :dst_host, from: :DstHost
21
+ property :dst_uri, from: :DstURI
22
+ property :duration, from: :Duration
23
+ property :from_header, from: :FromHeader
24
+ property :from_name, from: :FromName
25
+ property :from_user, from: :FromUser
26
+ property :hungup_reason, from: :HungupReason
27
+ property :hungup_time, from: :HungupTime
28
+ property :id, from: :ID
29
+ property :in_progress_reason, from: :InProgressReason
30
+ property :in_progress_status, from: :InProgressStatus
31
+ property :in_progress_time, from: :InProgressTime
32
+ property :increment_seconds, from: :IncrementSeconds
33
+ property :inserted, from: :Inserted
34
+ property :local_socket, from: :LocalSocket
35
+ property :rate, from: :Rate
36
+ property :remote_socket, from: :RemoteSocket
37
+ property :ring_duration, from: :RingDuration
38
+ property :setup_cost, from: :SetupCost
39
+
40
+ def self.count
41
+ response = Connection.new.get(API_PATH_MAP[:count])
42
+
43
+ response['Success'] ? response['Result'] : -1
44
+ end
45
+
46
+ def self.where(params)
47
+ Relation.new.where(params)
48
+ end
49
+
50
+ def self.find(id)
51
+ relation = self.where({ ID: id }).count(1)
52
+ result = Connection.new.get(API_PATH_MAP[:find], relation.relation)
53
+
54
+ return nil unless result['Success']
55
+
56
+ self.new(result['Result'][0])
57
+ end
58
+ end
59
+ end
@@ -3,27 +3,51 @@ require 'faraday_middleware'
3
3
 
4
4
  module Sipwizard
5
5
  class Connection
6
- API_PATH = 'https://www.sipsorcery.com/rest/v0.1/provisioning.svc'
6
+ BASE_REST_API= "https://www.sipsorcery.com/rest/v0.1"
7
+ API_PATHS ={
8
+ provisioning: "#{BASE_REST_API}/provisioning.svc",
9
+ accounting: "#{BASE_REST_API}/accounting.svc",
10
+ }
7
11
 
8
12
  attr_accessor :faraday_connection
9
13
 
10
- def initialize(faraday_adapter=Faraday.default_adapter)
11
- @faraday_connection = Faraday.new do |faraday|
14
+ def initialize(options={})
15
+ faraday_adapter = options.fetch(:adapter){ Faraday.default_adapter }
16
+ api_type = options.fetch(:api_type){ :provisioning }
17
+ @faraday_connection = Faraday.new(API_PATHS[api_type]) do |faraday|
12
18
  faraday.request :url_encoded #for post/put params
19
+
13
20
  faraday.response :logger
21
+ faraday.response :raise_error
14
22
  faraday.response :json, content_type: /\bjson\z/
23
+
15
24
  faraday.adapter faraday_adapter
16
25
  end
17
26
 
18
27
  @faraday_connection.headers['apikey'] = Sipwizard.config.api_key
19
28
  end
20
29
 
21
- def self.uri_for_path(path)
22
- "#{API_PATH}#{path}"
23
- end
24
30
 
31
+ # Public make a get request to the api
32
+ #
33
+ # path - The path of the api
34
+ # params - The query parameters (default: {}):
35
+ #
36
+ # Examples
37
+ #
38
+ # get('cdr/count')
39
+ #
40
+ # get('cdr/count', { where: 'FromName="John Doe"'})
41
+ #
42
+ # Returns Faraday::Response
25
43
  def get(path, params={})
26
- self.faraday_connection.get(Connection.uri_for_path(path), params)
44
+ self.faraday_connection.get(path, params).body
45
+ end
46
+
47
+ def post(path, params)
48
+ self.faraday_connection.headers['Content-Type'] ='application/json; charset=utf-8'
49
+ payload = params.to_json
50
+ self.faraday_connection.post(path, payload).body
27
51
  end
28
52
  end
29
53
  end
@@ -0,0 +1,81 @@
1
+ module Sipwizard
2
+ class Customer < Hashie::Trash
3
+ API_PATH_MAP={
4
+ count: 'customeraccount/count',
5
+ create: 'customeraccount/add',
6
+ find: 'customeraccount/get',
7
+ update: 'customeraccount/update',
8
+ delete: 'customeraccount/delete'
9
+ }
10
+
11
+ property :id, from: :ID
12
+ property :account_code, from: :AccountCode
13
+ property :credit, from: :Credit
14
+ property :account_name, from: :AccountName
15
+ property :account_number, from: :AccountNumber
16
+ property :pin, from: :PIN
17
+ property :inserted, from: :Inserted
18
+
19
+ def self.count(params={})
20
+ response = connection.get(API_PATH_MAP[:count], params)
21
+
22
+ response['Success'] ? response['Result'] : -1
23
+ end
24
+
25
+ def self.build_for_request(h)
26
+ customer = self.new(h)
27
+ customer = Hash[customer.map{ |k,v| ["#{k}".camelize, v] }]
28
+ customer['ID'] = customer.delete('Id')
29
+ customer['PIN'] = customer.delete('Pin')
30
+
31
+ customer.delete_if{ |_,v| v.nil? } #delete all the keys for which we dont have value
32
+ end
33
+
34
+ def self.create(params)
35
+ payload = self.build_for_request(params)
36
+ result = connection.post(API_PATH_MAP[:create], payload)
37
+
38
+ raise ArgumentError.new(result["Error"]) unless result['Success']
39
+
40
+ result['Result'] #ID
41
+ end
42
+
43
+ def self.where(params)
44
+ Relation.new.where(params)
45
+ end
46
+
47
+ def self.find(id)
48
+ relation = self.where({ ID: id }).count(1)
49
+ result = connection.get(API_PATH_MAP[:find], relation.relation)
50
+
51
+ return nil unless result['Success']
52
+
53
+ self.new(result['Result'][0])
54
+ end
55
+
56
+ def save
57
+ payload = Customer.build_for_request(self.to_hash)
58
+ result = Connection.new(api_type: :accounting).post(API_PATH_MAP[:update], payload)
59
+ raise ArgumentError.new(result["Error"]) unless result['Success']
60
+
61
+ result['Result'] #ID
62
+ end
63
+
64
+ def self.delete(id)
65
+ result = connection.get(API_PATH_MAP[:delete], {id: id})
66
+
67
+ raise ArgumentError.new(result["Error"]) unless result['Success']
68
+
69
+ result['Result'] #true | false
70
+ end
71
+
72
+ def delete
73
+ Customer.delete(self.id)
74
+ end
75
+ private
76
+
77
+ def self.connection
78
+ Connection.new(api_type: :accounting)
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,91 @@
1
+ module Sipwizard
2
+ class DialPlan < Hashie::Trash
3
+ API_PATH_MAP= {
4
+ count: 'dialplan/count',
5
+ find: 'dialplan/get',
6
+ create: 'dialplan/add',
7
+ delete: 'dialplan/delete',
8
+ update: 'dialplan/update',
9
+ copy: 'dialplan/copy'
10
+ }
11
+
12
+ string_to_bool = ->(string) { string == "true" }
13
+
14
+ property :id, from: :ID
15
+ property :dial_plan_name, from: :DialPlanName
16
+ property :trace_email_address, from: :TraceEmailAddress
17
+ property :dial_plan_script, from: :DialPlanScript
18
+ property :script_type_description, from: :ScriptTypeDescription
19
+ property :accept_non_invite, from: :AcceptNonInvite, transform_with: ->(b) { string_to_bool.call(b) }
20
+
21
+ alias :accept_non_invite? :accept_non_invite
22
+
23
+ def self.build_for_request(h)
24
+ dial_plan = self.new(h)
25
+ dial_plan = Hash[dial_plan.map{ |k,v| ["#{k}".camelize, v] }]
26
+ dial_plan['ID'] = dial_plan.delete('Id')
27
+
28
+ dial_plan.delete_if{ |_,v| v.nil? } #delete all the keys for which we dont have value
29
+ end
30
+
31
+ def self.count(params={})
32
+ response = Connection.new.get(API_PATH_MAP[:count], params)
33
+
34
+ response['Success'] ? response['Result'] : -1
35
+ end
36
+
37
+ def self.where(params)
38
+ Relation.new.where(params)
39
+ end
40
+
41
+ def self.find(id)
42
+ relation = self.where({ ID: id }).count(1)
43
+ result = Connection.new.get(API_PATH_MAP[:find], relation.relation)
44
+
45
+ return nil unless result['Success']
46
+
47
+ self.new(result['Result'][0])
48
+ end
49
+
50
+ def self.create(params)
51
+ payload = self.build_for_request(params)
52
+ result = Connection.new.post(API_PATH_MAP[:create], payload)
53
+
54
+ raise ArgumentError.new(result["Error"]) unless result['Success']
55
+
56
+ result['Result'] #ID
57
+ end
58
+
59
+ def self.delete(id)
60
+ result = Connection.new.get(API_PATH_MAP[:delete], {id: id})
61
+
62
+ raise ArgumentError.new(result["Error"]) unless result['Success']
63
+
64
+ result['Result'] #true | false
65
+ end
66
+
67
+ def self.copy(id)
68
+ result = Connection.new.get(API_PATH_MAP[:copy], {id: id})
69
+
70
+ raise ArgumentError.new(result["Error"]) unless result['Success']
71
+
72
+ result['Result'] #true | false
73
+ end
74
+
75
+ def save
76
+ payload = DialPlan.build_for_request(self.to_hash)
77
+ result = Connection.new.post(API_PATH_MAP[:update], payload)
78
+ raise ArgumentError.new(result["Error"]) unless result['Success']
79
+
80
+ result['Result'] #ID
81
+ end
82
+
83
+ def delete
84
+ DialPlan.delete(self.id)
85
+ end
86
+
87
+ def copy
88
+ DialPlan.copy(self.id)
89
+ end
90
+ end
91
+ end