connfu-client 0.1
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.
- data/.rspec +3 -0
- data/.rvmrc +2 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +120 -0
- data/LICENSE.txt +661 -0
- data/README.rdoc +398 -0
- data/Rakefile +38 -0
- data/bin/.DS_Store +0 -0
- data/bin/connfu-client +94 -0
- data/connfu-client.gemspec +41 -0
- data/examples/conference/application.rb +68 -0
- data/examples/conference/conference.rb +33 -0
- data/examples/conference/conference_app.rb +25 -0
- data/examples/conference/connfu.log +5 -0
- data/examples/conference/wall.rb +11 -0
- data/examples/provisioning/app/get.rb +29 -0
- data/examples/provisioning/channels/get.rb +34 -0
- data/examples/provisioning/rss/create.rb +28 -0
- data/examples/provisioning/rss/delete.rb +27 -0
- data/examples/provisioning/rss/get.rb +32 -0
- data/examples/provisioning/rss/put.rb +29 -0
- data/examples/provisioning/setup.rb +2 -0
- data/examples/provisioning/twitter/create.rb +31 -0
- data/examples/provisioning/twitter/delete.rb +27 -0
- data/examples/provisioning/twitter/get.rb +32 -0
- data/examples/provisioning/twitter/put.rb +29 -0
- data/examples/provisioning/voice/create.rb +26 -0
- data/examples/provisioning/voice/delete.rb +27 -0
- data/examples/provisioning/voice/get.rb +36 -0
- data/examples/provisioning/voice/phones/create.rb +26 -0
- data/examples/provisioning/voice/phones/delete.rb +28 -0
- data/examples/provisioning/voice/phones/get.rb +38 -0
- data/examples/provisioning/voice/put.rb +38 -0
- data/examples/provisioning/voice/whitelist/create.rb +26 -0
- data/examples/provisioning/voice/whitelist/delete.rb +27 -0
- data/examples/provisioning/voice/whitelist/get.rb +36 -0
- data/examples/provisioning/voice/whitelist/put.rb +27 -0
- data/lib/connfu.rb +134 -0
- data/lib/connfu/cli/generator.rb +71 -0
- data/lib/connfu/connfu_logger.rb +88 -0
- data/lib/connfu/connfu_message_formatter.rb +134 -0
- data/lib/connfu/connfu_stream.rb +182 -0
- data/lib/connfu/dispatcher.rb +164 -0
- data/lib/connfu/dsl.rb +84 -0
- data/lib/connfu/events.rb +32 -0
- data/lib/connfu/listener.rb +85 -0
- data/lib/connfu/listener_channel.rb +100 -0
- data/lib/connfu/message.rb +74 -0
- data/lib/connfu/provisioning.rb +12 -0
- data/lib/connfu/provisioning/application.rb +374 -0
- data/lib/connfu/provisioning/base.rb +95 -0
- data/lib/connfu/provisioning/channel.rb +79 -0
- data/lib/connfu/provisioning/phone.rb +55 -0
- data/lib/connfu/provisioning/rss.rb +21 -0
- data/lib/connfu/provisioning/twitter.rb +28 -0
- data/lib/connfu/provisioning/voice.rb +89 -0
- data/lib/connfu/provisioning/whitelist.rb +62 -0
- data/lib/connfu/version.rb +6 -0
- data/lib/rdoc/generator/template/connfu/_context.rhtml +209 -0
- data/lib/rdoc/generator/template/connfu/_head.rhtml +7 -0
- data/lib/rdoc/generator/template/connfu/class.rhtml +38 -0
- data/lib/rdoc/generator/template/connfu/file.rhtml +36 -0
- data/lib/rdoc/generator/template/connfu/index.rhtml +13 -0
- data/lib/rdoc/generator/template/connfu/resources/apple-touch-icon.png +0 -0
- data/lib/rdoc/generator/template/connfu/resources/css/github.css +129 -0
- data/lib/rdoc/generator/template/connfu/resources/css/main.css +339 -0
- data/lib/rdoc/generator/template/connfu/resources/css/panel.css +389 -0
- data/lib/rdoc/generator/template/connfu/resources/css/reset.css +53 -0
- data/lib/rdoc/generator/template/connfu/resources/favicon.ico +0 -0
- data/lib/rdoc/generator/template/connfu/resources/i/arrows.png +0 -0
- data/lib/rdoc/generator/template/connfu/resources/i/results_bg.png +0 -0
- data/lib/rdoc/generator/template/connfu/resources/i/tree_bg.png +0 -0
- data/lib/rdoc/generator/template/connfu/resources/js/highlight.pack.js +1 -0
- data/lib/rdoc/generator/template/connfu/resources/js/jquery-1.3.2.min.js +19 -0
- data/lib/rdoc/generator/template/connfu/resources/js/jquery-effect.js +593 -0
- data/lib/rdoc/generator/template/connfu/resources/js/main.js +20 -0
- data/lib/rdoc/generator/template/connfu/resources/js/searchdoc.js +628 -0
- data/lib/rdoc/generator/template/connfu/resources/panel/index.html +72 -0
- data/lib/rdoc/generator/template/connfu/se_index.rhtml +8 -0
- data/spec/connfu_message_formatter_spec.rb +88 -0
- data/spec/connfu_spec.rb +51 -0
- data/spec/connfu_stream_spec.rb +84 -0
- data/spec/dispatcher_spec.rb +227 -0
- data/spec/dsl_spec.rb +159 -0
- data/spec/listener_channel_spec.rb +130 -0
- data/spec/listener_spec.rb +67 -0
- data/spec/provisioning/application_spec.rb +47 -0
- data/spec/provisioning/channel_shared_examples.rb +52 -0
- data/spec/provisioning/channel_spec.rb +13 -0
- data/spec/provisioning/phone_spec.rb +88 -0
- data/spec/provisioning/voice_spec.rb +138 -0
- data/spec/provisioning_spec.rb +500 -0
- data/spec/spec_helper.rb +51 -0
- metadata +298 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
require 'rest_client'
|
|
2
|
+
|
|
3
|
+
module Connfu
|
|
4
|
+
module Provisioning
|
|
5
|
+
|
|
6
|
+
##
|
|
7
|
+
# This class is the responsible of any HTTP request to connFu endpoint
|
|
8
|
+
#
|
|
9
|
+
class Base
|
|
10
|
+
|
|
11
|
+
# valid api_key that authenticates the application
|
|
12
|
+
attr_accessor :api_key
|
|
13
|
+
|
|
14
|
+
# Connfu endpoint (host:port)
|
|
15
|
+
attr_accessor :endpoint
|
|
16
|
+
|
|
17
|
+
##
|
|
18
|
+
# Initializer
|
|
19
|
+
# ==== Parameters
|
|
20
|
+
# * +api_key+ valid api_key that authenticates the application
|
|
21
|
+
# * +endpoint+ Connfu endpoint (host:port)
|
|
22
|
+
#
|
|
23
|
+
def initialize(api_key, endpoint = nil)
|
|
24
|
+
@api_key = api_key
|
|
25
|
+
@endpoint = endpoint.nil? ? Base.endpoint : endpoint # if no endpoint retrieved, try to use the class one
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
##
|
|
29
|
+
# HTTP GET request
|
|
30
|
+
#
|
|
31
|
+
def get(path, params = {}, headers = {})
|
|
32
|
+
headers.merge!(base_headers).merge!({:Accept => "application/json"})
|
|
33
|
+
RestClient.get("#{@endpoint}/#{path}?".concat(params.collect { |k, v| "#{k}=#{v.to_s}" }.join("&")), headers)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
##
|
|
37
|
+
# HTTP POST request
|
|
38
|
+
#
|
|
39
|
+
def post(path, body = {}, headers = {})
|
|
40
|
+
headers.merge!(base_headers).merge!({:content_type => :json, :Accept => "application/json"})
|
|
41
|
+
RestClient.post("#{@endpoint}/#{path}", ActiveSupport::JSON.encode(body), headers) { |response, request, result|
|
|
42
|
+
case response.code
|
|
43
|
+
when 200..201
|
|
44
|
+
# If there is a :location header, return it
|
|
45
|
+
if response.headers.has_key?(:location)
|
|
46
|
+
return response.headers[:location]
|
|
47
|
+
end
|
|
48
|
+
# else, do the normal stuff
|
|
49
|
+
if block_given?
|
|
50
|
+
response.return!(request, result, &Proc.new)
|
|
51
|
+
else
|
|
52
|
+
response.return!(request, result)
|
|
53
|
+
end
|
|
54
|
+
else
|
|
55
|
+
if block_given?
|
|
56
|
+
response.return!(request, result, &Proc.new)
|
|
57
|
+
else
|
|
58
|
+
response.return!(request, result)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
}
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
##
|
|
65
|
+
# HTTP PUT request
|
|
66
|
+
#
|
|
67
|
+
def put(path, body = {}, headers = {})
|
|
68
|
+
headers.merge!(base_headers).merge!({:content_type => :json, :Accept => "application/json"})
|
|
69
|
+
RestClient.put("#{@endpoint}/#{path}", ActiveSupport::JSON.encode(body), headers)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
##
|
|
73
|
+
# HTTP DELETE request
|
|
74
|
+
#
|
|
75
|
+
def delete(path, params = {}, headers = {})
|
|
76
|
+
headers.merge!(base_headers).merge!({:content_type => :json, :Accept => "application/json"})
|
|
77
|
+
RestClient.delete("#{@endpoint}/#{path}?".concat(params.collect { |k, v| "#{k}=#{v.to_s}" }.join("&")), headers)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
class << self
|
|
81
|
+
# Enable to configure just once the endpoint
|
|
82
|
+
attr_accessor :endpoint
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
|
|
87
|
+
##
|
|
88
|
+
# Required HTTP headers to be sent in each request
|
|
89
|
+
def base_headers
|
|
90
|
+
{:AUTH_TOKEN => "#{@api_key}", :REQUEST_ID => "#{@api_key[0..10]}#{Time.now.to_i.to_s}"}
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
|
|
2
|
+
module Connfu
|
|
3
|
+
module Provisioning
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
# Channel class models a connFu application channel. Its the superclass of Twitter and Voice and any other
|
|
7
|
+
# forthcoming connFu channel
|
|
8
|
+
class Channel
|
|
9
|
+
|
|
10
|
+
# created at timestamp
|
|
11
|
+
attr_accessor :created_at
|
|
12
|
+
|
|
13
|
+
# updated at timestamp
|
|
14
|
+
attr_accessor :updated_at
|
|
15
|
+
|
|
16
|
+
# channel unique identifier
|
|
17
|
+
attr_accessor :uid
|
|
18
|
+
|
|
19
|
+
# channel type
|
|
20
|
+
attr_accessor :type
|
|
21
|
+
|
|
22
|
+
# Creates a Channel instance using a Hash values
|
|
23
|
+
# It creates an instance variable per each hash key
|
|
24
|
+
def initialize(params)
|
|
25
|
+
self.type = self.class.to_s.downcase
|
|
26
|
+
params.each_pair { |key, value|
|
|
27
|
+
self.instance_variable_set("@#{key}", value)
|
|
28
|
+
}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Creates a hash with the instance info
|
|
32
|
+
def to_hash
|
|
33
|
+
{"uid" => uid}
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Print object using metaprogramming. This method is used by any child class
|
|
37
|
+
def to_s
|
|
38
|
+
value = []
|
|
39
|
+
self.instance_variables.each { |var|
|
|
40
|
+
value << "#{var[1..-1]}: #{self.instance_variable_get(var)}"
|
|
41
|
+
}
|
|
42
|
+
self.class.name + "{\n" + value.join("\t\n").to_s + "\n}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class << self
|
|
46
|
+
|
|
47
|
+
##
|
|
48
|
+
#
|
|
49
|
+
# Creates a Channel instance (or a Channel child class instance) object or an Array using a Hash values
|
|
50
|
+
#
|
|
51
|
+
# ==== Parameters
|
|
52
|
+
#
|
|
53
|
+
# * +data+ - hash containing channel information retrieved using the connFu API
|
|
54
|
+
def unmarshal(data)
|
|
55
|
+
|
|
56
|
+
# Helper to get the channel class using the type attribute (we are
|
|
57
|
+
# retrieving all the channels) or the client class (we are retrieving
|
|
58
|
+
# specific a channel type)
|
|
59
|
+
create_channel = lambda { |channel|
|
|
60
|
+
if channel.has_key?("type") # get the class from type attribute (get all channels)
|
|
61
|
+
type = channel["type"].capitalize
|
|
62
|
+
Connfu::Provisioning.const_get(type).new(channel)
|
|
63
|
+
else # get the class from class
|
|
64
|
+
self.new(channel)
|
|
65
|
+
end
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if data.is_a?(Array) # more than one element
|
|
69
|
+
data.map { |channel| create_channel.call(channel) }
|
|
70
|
+
else # one element
|
|
71
|
+
create_channel.call(data)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module Connfu
|
|
2
|
+
|
|
3
|
+
module Provisioning
|
|
4
|
+
|
|
5
|
+
#
|
|
6
|
+
# connFu Phone (belongs to a Voice channel)
|
|
7
|
+
#
|
|
8
|
+
class Phone
|
|
9
|
+
|
|
10
|
+
# specific country where the phone is allocated
|
|
11
|
+
attr_accessor :country
|
|
12
|
+
|
|
13
|
+
# phone number
|
|
14
|
+
attr_accessor :phone_number
|
|
15
|
+
|
|
16
|
+
# voice channel unique identifier
|
|
17
|
+
attr_reader :voice
|
|
18
|
+
|
|
19
|
+
# @param voice voice channel identifier
|
|
20
|
+
# @param phone_number
|
|
21
|
+
# @param country
|
|
22
|
+
def initialize(voice, phone_number, country = "")
|
|
23
|
+
@voice = voice
|
|
24
|
+
@phone_number = phone_number
|
|
25
|
+
@country = country
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Hash way to retrieve attributes
|
|
29
|
+
def [](value)
|
|
30
|
+
self.respond_to?(value.to_sym) ? self.send(value.to_sym) : nil
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def to_hash
|
|
34
|
+
{"country" => country, "phone_number" => phone_number}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def to_s
|
|
38
|
+
"#{self.class.to_s}: #{to_hash}"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
#
|
|
42
|
+
# Creates a Phone object using the raw data from the provisioning API
|
|
43
|
+
# @param voice channel unique identifier
|
|
44
|
+
# @param data Hash containing the raw data
|
|
45
|
+
def self.unmarshal(voice, data)
|
|
46
|
+
if data.is_a?(Array)
|
|
47
|
+
data.map{|item| Phone.new(voice, item["phone_number"], item["country"])}
|
|
48
|
+
else
|
|
49
|
+
Phone.new(voice, data["phone_number"], data["country"])
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Connfu
|
|
2
|
+
module Provisioning
|
|
3
|
+
|
|
4
|
+
# This class models s connFu RSS channel
|
|
5
|
+
class Rss < Channel
|
|
6
|
+
|
|
7
|
+
# RSS URI
|
|
8
|
+
attr_accessor :uri
|
|
9
|
+
|
|
10
|
+
def initialize(params)
|
|
11
|
+
super(params)
|
|
12
|
+
self.type = "rss"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def to_hash
|
|
16
|
+
{"uid" => uid, "type" => type, "uri" => uri}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
|
|
2
|
+
module Connfu
|
|
3
|
+
module Provisioning
|
|
4
|
+
|
|
5
|
+
#
|
|
6
|
+
# This class models a connFu Twitter channel
|
|
7
|
+
#
|
|
8
|
+
class Twitter < Channel
|
|
9
|
+
|
|
10
|
+
# Twitter accounts associated to that Twitter channel
|
|
11
|
+
attr_accessor :accounts
|
|
12
|
+
|
|
13
|
+
# string that filters the tweets to retrieve only the desired hashtag
|
|
14
|
+
attr_accessor :filter
|
|
15
|
+
|
|
16
|
+
def initialize(params)
|
|
17
|
+
super(params)
|
|
18
|
+
self.type = "twitter"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Creates a hash with the Twitter instance info
|
|
22
|
+
def to_hash
|
|
23
|
+
{"uid" => uid, "type" => type, "accounts" => accounts, "filter" => filter}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
require 'connfu/provisioning/whitelist'
|
|
2
|
+
|
|
3
|
+
module Connfu
|
|
4
|
+
|
|
5
|
+
module Provisioning
|
|
6
|
+
|
|
7
|
+
##
|
|
8
|
+
# This class models a connFu Voice channel
|
|
9
|
+
#
|
|
10
|
+
class Voice < Channel
|
|
11
|
+
|
|
12
|
+
class Privacy
|
|
13
|
+
WHITELIST = "whitelisted"
|
|
14
|
+
PUBLIC = "public"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Voice channel attributes that could be updated
|
|
18
|
+
UPDATE_ATTRIBUTES = ["topic", "welcome_message", "rejected_message", "privacy"]
|
|
19
|
+
|
|
20
|
+
_values = UPDATE_ATTRIBUTES.dup
|
|
21
|
+
_values.each { |value|
|
|
22
|
+
UPDATE_ATTRIBUTES << value.to_sym
|
|
23
|
+
}
|
|
24
|
+
UPDATE_ATTRIBUTES.freeze
|
|
25
|
+
UPDATE_ATTRIBUTES.each { |value| value.freeze }
|
|
26
|
+
|
|
27
|
+
# current topic
|
|
28
|
+
attr_accessor :topic
|
|
29
|
+
|
|
30
|
+
# welcome message for valid users while joining the conference
|
|
31
|
+
attr_accessor :welcome_message
|
|
32
|
+
|
|
33
|
+
# rejected message for invalid users while trying to join the conference
|
|
34
|
+
attr_accessor :rejected_message
|
|
35
|
+
|
|
36
|
+
# Identifies if the conference is open to any phone number or users must
|
|
37
|
+
# be whitelisted to join the conference
|
|
38
|
+
attr_accessor :privacy
|
|
39
|
+
|
|
40
|
+
def initialize(params)
|
|
41
|
+
super(params)
|
|
42
|
+
self.type = "voice"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def to_hash
|
|
46
|
+
{"uid" => uid, "type" => type, "phones" => phones.map(&:to_hash)}
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# access the Voice channel Whitelist
|
|
50
|
+
def whitelist
|
|
51
|
+
Whitelist.new(@name)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Retrieves the phone numbers
|
|
55
|
+
def phone_number
|
|
56
|
+
values = phones.collect{|phone| phone[:phone_number]}
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def phones
|
|
60
|
+
@phones||=[]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def phones=(_phones)
|
|
64
|
+
@phones=_phones
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def <<(phone)
|
|
68
|
+
phones << phone
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
class << self
|
|
72
|
+
|
|
73
|
+
# Creates a Voice object or an Array using a Hash values
|
|
74
|
+
def unmarshal(data)
|
|
75
|
+
obj = super(data)
|
|
76
|
+
if obj.is_a?(Array) # more than one element
|
|
77
|
+
obj.each { |voice|
|
|
78
|
+
voice.phones = voice.phones.map { |phone| Phone.new(voice.uid, phone["phone_number"], phone["country"]) }
|
|
79
|
+
}
|
|
80
|
+
else # one element
|
|
81
|
+
obj.phones = obj.phones.map { |phone| Phone.new(obj.uid, phone["phone_number"], phone["country"]) }
|
|
82
|
+
obj
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module Connfu
|
|
2
|
+
|
|
3
|
+
module Provisioning
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
# This class defines a whitelist user (whitelist item)
|
|
7
|
+
WhitelistUser = Struct.new(:name, :phone)
|
|
8
|
+
|
|
9
|
+
##
|
|
10
|
+
# This class models a conference whitelist
|
|
11
|
+
class Whitelist
|
|
12
|
+
|
|
13
|
+
# WhitelistUser array
|
|
14
|
+
attr_accessor :users
|
|
15
|
+
|
|
16
|
+
# Conference phone
|
|
17
|
+
attr_reader :voice
|
|
18
|
+
|
|
19
|
+
def initialize(voice, users = [])
|
|
20
|
+
@voice = voice
|
|
21
|
+
@users = users
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Iterator based on users array
|
|
25
|
+
def each
|
|
26
|
+
users.each{|user|
|
|
27
|
+
yield user
|
|
28
|
+
}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def to_s
|
|
32
|
+
value = []
|
|
33
|
+
self.instance_variables.each { |var|
|
|
34
|
+
value << "#{var}: #{self.instance_variable_get(var)}"
|
|
35
|
+
}
|
|
36
|
+
value.join("\n").to_s
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
##
|
|
40
|
+
# Creates a Whitelist object using the raw data from the provisioning API
|
|
41
|
+
# ==== Parameters
|
|
42
|
+
# * +voice+ voice channel unique identifier
|
|
43
|
+
# * +data+ raw data retrieved using the connFu API
|
|
44
|
+
def self.unmarshal(voice, data)
|
|
45
|
+
|
|
46
|
+
if data.is_a?(Array)
|
|
47
|
+
numbers = []
|
|
48
|
+
data.each { |number|
|
|
49
|
+
numbers << WhitelistUser.new(*number.values)
|
|
50
|
+
|
|
51
|
+
}
|
|
52
|
+
users = numbers
|
|
53
|
+
else
|
|
54
|
+
users = [WhitelistUser.new(*data.values)]
|
|
55
|
+
end
|
|
56
|
+
Whitelist.new(voice, users)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
|
62
|
+
end
|