sipwizard 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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