bigbluebutton-api-ruby 0.0.11 → 0.1.0.rc1

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 (51) hide show
  1. data/.gitignore +5 -2
  2. data/.rvmrc +1 -1
  3. data/.travis.yml +6 -0
  4. data/CHANGELOG.rdoc +19 -8
  5. data/Gemfile +9 -1
  6. data/Gemfile.lock +62 -9
  7. data/LICENSE +5 -7
  8. data/LICENSE_003 +20 -0
  9. data/README.rdoc +42 -19
  10. data/Rakefile +31 -19
  11. data/bigbluebutton-api-ruby.gemspec +5 -5
  12. data/examples/get_version_example.rb +18 -0
  13. data/examples/join_example.rb +59 -0
  14. data/examples/overall_0.7_example.rb +92 -0
  15. data/examples/prepare.rb +38 -0
  16. data/extras/bigbluebutton_bot.rb +64 -0
  17. data/extras/download_bot_from.txt +1 -0
  18. data/extras/test-presentation.pdf +0 -0
  19. data/features/check_status.feature +45 -0
  20. data/features/config.yml.example +21 -0
  21. data/features/create_meetings.feature +29 -0
  22. data/features/end_meetings.feature +27 -0
  23. data/features/join_meetings.feature +29 -0
  24. data/features/pre_upload_slides.feature +14 -0
  25. data/features/recordings.feature +34 -0
  26. data/features/step_definitions/check_status_steps.rb +119 -0
  27. data/features/step_definitions/common_steps.rb +122 -0
  28. data/features/step_definitions/create_meetings_steps.rb +54 -0
  29. data/features/step_definitions/end_meetings_steps.rb +49 -0
  30. data/features/step_definitions/join_meetings_steps.rb +39 -0
  31. data/features/step_definitions/pre_upload_slides_steps.rb +13 -0
  32. data/features/step_definitions/recordings_steps.rb +38 -0
  33. data/features/support/api_tests/configs.rb +51 -0
  34. data/features/support/env.rb +7 -0
  35. data/features/support/hooks.rb +11 -0
  36. data/lib/bigbluebutton_api.rb +301 -97
  37. data/lib/bigbluebutton_formatter.rb +105 -19
  38. data/lib/bigbluebutton_modules.rb +92 -0
  39. data/lib/hash_to_xml.rb +22 -51
  40. data/spec/bigbluebutton_api_0.8_spec.rb +273 -0
  41. data/spec/bigbluebutton_api_spec.rb +211 -117
  42. data/spec/bigbluebutton_formatter_spec.rb +178 -29
  43. data/spec/bigbluebutton_modules_spec.rb +95 -0
  44. data/spec/data/hash_to_xml_complex.xml +45 -0
  45. data/spec/hash_to_xml_spec.rb +143 -0
  46. data/spec/spec_helper.rb +4 -2
  47. data/spec/support/forgery/forgeries/random_name.rb +7 -0
  48. data/spec/support/forgery/forgeries/url.rb +5 -0
  49. metadata +47 -12
  50. data/test/config.yml.example +0 -9
  51. data/test/test.rb +0 -154
@@ -5,12 +5,25 @@ module BigBlueButton
5
5
  attr_accessor :hash
6
6
 
7
7
  def initialize(hash)
8
- @hash = hash
8
+ @hash = hash || {}
9
9
  end
10
10
 
11
11
  # converts a value in the @hash to boolean
12
12
  def to_boolean(key)
13
- @hash[key] = @hash[key].downcase == "true"
13
+ unless @hash.has_key?(key)
14
+ false
15
+ else
16
+ @hash[key] = @hash[key].downcase == "true"
17
+ end
18
+ end
19
+
20
+ # converts a value in the @hash to int
21
+ def to_int(key)
22
+ unless @hash.has_key?(key)
23
+ 0
24
+ else
25
+ @hash[key] = @hash[key].to_i
26
+ end
14
27
  end
15
28
 
16
29
  # converts a value in the @hash to string
@@ -20,14 +33,51 @@ module BigBlueButton
20
33
 
21
34
  # converts a value in the @hash to DateTime
22
35
  def to_datetime(key)
23
- @hash[key] = @hash[key].downcase == "null" ? nil : DateTime.parse(@hash[key])
36
+ unless @hash.has_key?(key) and @hash[key]
37
+ nil
38
+ else
39
+ # BBB >= 0.8 uses the unix epoch for all time related values
40
+ # older versions use strings
41
+
42
+ # a number but in a String class
43
+ if (@hash[key].class == String && @hash[key].to_i.to_s == @hash[key])
44
+ value = @hash[key].to_i
45
+ else
46
+ value = @hash[key]
47
+ end
48
+
49
+ if value.is_a?(Numeric)
50
+ result = value == 0 ? nil : DateTime.parse(Time.at(value/1000.0).to_s)
51
+ else
52
+ if value.downcase == "null"
53
+ result = nil
54
+ else
55
+ result = DateTime.parse(value)
56
+ end
57
+ end
58
+
59
+ @hash[key] = result
60
+ end
61
+ end
62
+
63
+ # converts a value in the @hash to a symbol
64
+ def to_sym(key)
65
+ unless @hash.has_key?(key)
66
+ ""
67
+ else
68
+ if @hash[key].instance_of?(Symbol)
69
+ @hash[key]
70
+ elsif @hash[key].empty?
71
+ ""
72
+ else
73
+ @hash[key] = @hash[key].downcase.to_sym
74
+ end
75
+ end
24
76
  end
25
77
 
26
78
  # Default formatting for all responses given by a BBB server
27
79
  def default_formatting
28
-
29
- # remove the "response" node
30
- response = Hash[@hash[:response]].inject({}){|h,(k,v)| h[k] = v; h}
80
+ response = @hash
31
81
 
32
82
  # Adjust some values. There will always be a returncode, a message and a messageKey in the hash.
33
83
  response[:returncode] = response[:returncode].downcase == "success" # true instead of "SUCCESS"
@@ -37,25 +87,61 @@ module BigBlueButton
37
87
  @hash = response
38
88
  end
39
89
 
40
- # default formatting for a meeting hash
41
- def format_meeting(meeting)
42
- meeting[:meetingID] = meeting[:meetingID].to_s
43
- meeting[:moderatorPW] = meeting[:moderatorPW].to_s
44
- meeting[:attendeePW] = meeting[:attendeePW].to_s
45
- meeting[:hasBeenForciblyEnded] = meeting[:hasBeenForciblyEnded].downcase == "true"
46
- meeting[:running] = meeting[:running].downcase == "true"
90
+ # Default formatting for a meeting hash
91
+ def self.format_meeting(meeting)
92
+ f = BigBlueButtonFormatter.new(meeting)
93
+ f.to_string(:meetingID)
94
+ f.to_string(:moderatorPW)
95
+ f.to_string(:attendeePW)
96
+ f.to_boolean(:hasBeenForciblyEnded)
97
+ f.to_boolean(:running)
98
+ f.to_int(:createTime) if meeting.has_key?(:createTime)
47
99
  meeting
48
100
  end
49
101
 
50
- # default formatting for an attendee hash
51
- def format_attendee(attendee)
52
- attendee[:userID] = attendee[:userID].to_s
53
- attendee[:role] = attendee[:role].downcase.to_sym
102
+ # Default formatting for an attendee hash
103
+ def self.format_attendee(attendee)
104
+ f = BigBlueButtonFormatter.new(attendee)
105
+ f.to_string(:userID)
106
+ f.to_sym(:role)
54
107
  attendee
55
108
  end
56
109
 
57
- # simplifies the hash making a node e.g. :attendee with an array with all attendees
58
- # TODO: comments with the expected @hash at this point
110
+ # Default formatting for a recording hash
111
+ def self.format_recording(rec)
112
+ f = BigBlueButtonFormatter.new(rec)
113
+ f.to_string(:recordID)
114
+ f.to_string(:meetingID)
115
+ f.to_string(:name)
116
+ f.to_boolean(:published)
117
+ f.to_datetime(:startTime)
118
+ f.to_datetime(:endTime)
119
+ rec
120
+ end
121
+
122
+ # Simplifies the XML-styled hash node 'first'. Its value will then always be an Array.
123
+ #
124
+ # For example, if the current hash is:
125
+ # { :name => "Test", :attendees => { :attendee => [ { :name => "attendee1" }, { :name => "attendee2" } ] } }
126
+ #
127
+ # Calling:
128
+ # flatten_objects(:attendees, :attendee)
129
+ #
130
+ # The hash will become:
131
+ # { :name => "Test", :attendees => [ { :name => "attendee1" }, { :name => "attendee2" } ] }
132
+ #
133
+ # Other examples:
134
+ #
135
+ # Hash:
136
+ # { :name => "Test", :attendees => {} }
137
+ # Result:
138
+ # { :name => "Test", :attendees => [] }
139
+ #
140
+ # Hash:
141
+ # { :name => "Test", :attendees => { :attendee => { :name => "attendee1" } } }
142
+ # Result:
143
+ # { :name => "Test", :attendees => [ { :name => "attendee1" } ] }
144
+ #
59
145
  def flatten_objects(first, second)
60
146
  if @hash[first].empty?
61
147
  collection = []
@@ -0,0 +1,92 @@
1
+ require "base64"
2
+
3
+ module BigBlueButton
4
+
5
+ # An object to store the modules configuration to be passed in
6
+ # BigBlueButtonApi#create_meeting().
7
+ #
8
+ # === Usage example:
9
+ #
10
+ # modules = BigBlueButton::BigBlueButtonModules.new
11
+ #
12
+ # # adds presentations by URL
13
+ # modules.add_presentation(:url, "http://www.samplepdf.com/sample.pdf")
14
+ # modules.add_presentation(:url, "http://www.samplepdf.com/sample2.pdf")
15
+ #
16
+ # # adds presentations from a local file
17
+ # # the file will be opened and encoded in base64
18
+ # modules.add_presentation(:file, "presentations/class01.ppt")
19
+ #
20
+ # # adds a base64 encoded presentation
21
+ # modules.add_presentation(:base64, "JVBERi0xLjQKJ....[clipped here]....0CiUlRU9GCg==", "first-class.pdf")
22
+ #
23
+ class BigBlueButtonModules
24
+
25
+ attr_accessor :presentation_urls
26
+ attr_accessor :presentation_files
27
+ attr_accessor :presentation_base64s
28
+
29
+ def initialize
30
+ @presentation_urls = []
31
+ @presentation_files = []
32
+ @presentation_base64s = []
33
+ end
34
+
35
+ def add_presentation(type, value, name=nil)
36
+ case type
37
+ when :url
38
+ @presentation_urls.push(value)
39
+ when :file
40
+ @presentation_files.push(value)
41
+ when :base64
42
+ @presentation_base64s.push([name, value])
43
+ end
44
+ end
45
+
46
+ def to_xml
47
+ unless has_presentations?
48
+ ""
49
+ else
50
+ xml = xml_header
51
+ xml << presentations_to_xml
52
+ xml << xml_footer
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def has_presentations?
59
+ !@presentation_urls.empty? or
60
+ !@presentation_files.empty? or
61
+ !@presentation_base64s.empty?
62
+ end
63
+
64
+ def xml_header
65
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?><modules>"
66
+ end
67
+
68
+ def xml_footer
69
+ "</modules>"
70
+ end
71
+
72
+ def presentations_to_xml
73
+ xml = "<module name=\"presentation\">"
74
+ @presentation_urls.each { |url| xml << "<document url=\"#{url}\" />" }
75
+ @presentation_base64s.each do |name, data|
76
+ xml << "<document name=\"#{name}\">"
77
+ xml << data
78
+ xml << "</document>"
79
+ end
80
+ @presentation_files.each do |filename|
81
+ xml << "<document name=\"#{File.basename(filename)}\">"
82
+ File.open(filename, "r") do |file|
83
+ xml << Base64.encode64(file.read)
84
+ end
85
+ xml << "</document>"
86
+ end
87
+ xml << "</module>"
88
+ end
89
+
90
+ end
91
+
92
+ end
data/lib/hash_to_xml.rb CHANGED
@@ -1,62 +1,33 @@
1
- # Code from: https://gist.github.com/335286
2
- # USAGE: Hash.from_xml:(YOUR_XML_STRING)
3
- # modified from http://stackoverflow.com/questions/1230741/convert-a-nokogiri-document-to-a-ruby-hash/1231297#1231297
1
+ require 'xmlsimple'
4
2
 
5
3
  class Hash
6
4
  class << self
7
- def from_xml(xml_io)
5
+ def from_xml(xml_io)
8
6
  begin
9
- result = Nokogiri::XML(xml_io)
10
- return { result.root.name.to_sym => xml_node_to_hash(result.root)}
7
+ # we'll not use 'KeyToSymbol' because it doesn't symbolize the keys for node attributes
8
+ opts = { 'ForceArray' => false, 'ForceContent' => false } #
9
+ hash = XmlSimple.xml_in(xml_io, opts)
10
+ return symbolize_keys(hash)
11
11
  rescue Exception => e
12
12
  raise BigBlueButton::BigBlueButtonException.new("Impossible to convert XML to hash. Error: #{e.message}")
13
13
  end
14
- end
15
-
16
- def xml_node_to_hash(node)
17
- # If we are at the root of the document, start the hash
18
- if node.element?
19
- result_hash = {}
20
- if node.attributes != {}
21
- result_hash[:attributes] = {}
22
- node.attributes.keys.each do |key|
23
- result_hash[:attributes][node.attributes[key].name.to_sym] = prepare(node.attributes[key].value)
24
- end
25
- end
26
- if node.children.size > 0
27
- node.children.each do |child|
28
- result = xml_node_to_hash(child)
29
-
30
- if child.name == "text"
31
- unless child.next_sibling || child.previous_sibling
32
- return prepare(result)
33
- end
34
- elsif result_hash[child.name.to_sym]
35
- if result_hash[child.name.to_sym].is_a?(Object::Array)
36
- result_hash[child.name.to_sym] << prepare(result)
37
- else
38
- result_hash[child.name.to_sym] = [result_hash[child.name.to_sym]] << prepare(result)
39
- end
40
- else
41
- result_hash[child.name.to_sym] = prepare(result)
42
- end
43
- end
44
-
45
- return result_hash
46
- else
47
- return result_hash
48
- end
49
- else
50
- return prepare(node.content.to_s)
51
- end
52
- end
14
+ end
53
15
 
54
- def prepare(data)
55
- (data.class == String && data.to_i.to_s == data) ? data.to_i : data
16
+ def symbolize_keys(arg)
17
+ case arg
18
+ when Array
19
+ arg.map { |elem| symbolize_keys elem }
20
+ when Hash
21
+ Hash[
22
+ arg.map { |key, value|
23
+ k = key.is_a?(String) ? key.to_sym : key
24
+ v = symbolize_keys value
25
+ [k,v]
26
+ }]
27
+ else
28
+ arg
29
+ end
56
30
  end
57
- end
58
-
59
- def to_struct(struct_name)
60
- Struct.new(struct_name,*keys).new(*values)
31
+
61
32
  end
62
33
  end
@@ -0,0 +1,273 @@
1
+ require 'spec_helper'
2
+
3
+ # Tests for BBB API version 0.8
4
+ describe BigBlueButton::BigBlueButtonApi do
5
+
6
+ # default variables and API object for all tests
7
+ let(:url) { "http://server.com" }
8
+ let(:salt) { "1234567890abcdefghijkl" }
9
+ let(:version) { "0.8" }
10
+ let(:debug) { false }
11
+ let(:api) { BigBlueButton::BigBlueButtonApi.new(url, salt, version, debug) }
12
+
13
+ describe "#create_meeting" do
14
+
15
+ context "without modules" do
16
+ let(:req_params) {
17
+ { :name => "name", :meetingID => "meeting-id", :moderatorPW => "mp", :attendeePW => "ap",
18
+ :welcome => "Welcome!", :dialNumber => 12345678, :logoutURL => "http://example.com",
19
+ :maxParticipants => 25, :voiceBridge => 12345, :record => "true", :duration => 20,
20
+ :meta_1 => "meta1", :meta_2 => "meta2" }
21
+ }
22
+ let(:req_response) {
23
+ { :meetingID => 123, :moderatorPW => 111, :attendeePW => 222, :hasBeenForciblyEnded => "FALSE", :createTime => "123123123" }
24
+ }
25
+ let(:final_response) {
26
+ { :meetingID => "123", :moderatorPW => "111", :attendeePW => "222", :hasBeenForciblyEnded => false, :createTime => 123123123 }
27
+ }
28
+
29
+ before { api.should_receive(:send_api_request).with(:create, req_params).and_return(req_response) }
30
+ subject {
31
+ options = { :moderatorPW => "mp", :attendeePW => "ap", :welcome => "Welcome!", :dialNumber => 12345678,
32
+ :logoutURL => "http://example.com", :maxParticipants => 25, :voiceBridge => 12345, :record => true,
33
+ :duration => 20, :meta_1 => "meta1", :meta_2 => "meta2" }
34
+ api.create_meeting("name", "meeting-id", options)
35
+ }
36
+ it { subject.should == final_response }
37
+ end
38
+
39
+ context "with modules" do
40
+ let(:req_params) {
41
+ { :name => "name", :meetingID => "meeting-id", :moderatorPW => "mp", :attendeePW => "ap" }
42
+ }
43
+ let(:req_response) {
44
+ { :meetingID => 123, :moderatorPW => 111, :attendeePW => 222, :hasBeenForciblyEnded => "FALSE", :createTime => "123123123" }
45
+ }
46
+ let(:final_response) {
47
+ { :meetingID => "123", :moderatorPW => "111", :attendeePW => "222", :hasBeenForciblyEnded => false, :createTime => 123123123 }
48
+ }
49
+ let(:modules) {
50
+ m = BigBlueButton::BigBlueButtonModules.new
51
+ m.add_presentation(:url, "http://www.samplepdf.com/sample.pdf")
52
+ m.add_presentation(:url, "http://www.samplepdf.com/sample2.pdf")
53
+ m.add_presentation(:base64, "JVBERi0xLjQKJ....[clipped here]....0CiUlRU9GCg==", "first-class.pdf")
54
+ m
55
+ }
56
+
57
+ before {
58
+ api.should_receive(:send_api_request).with(:create, req_params, modules.to_xml).
59
+ and_return(req_response)
60
+ }
61
+ subject {
62
+ options = { :moderatorPW => "mp", :attendeePW => "ap" }
63
+ api.create_meeting("name", "meeting-id", options, modules)
64
+ }
65
+ it { subject.should == final_response }
66
+ end
67
+ end
68
+
69
+ describe "#join_meeting_url" do
70
+ let(:params) {
71
+ { :meetingID => "meeting-id", :password => "pw", :fullName => "Name",
72
+ :userID => "id123", :webVoiceConf => 12345678, :createTime => 9876543 }
73
+ }
74
+
75
+ before { api.should_receive(:get_url).with(:join, params).and_return("test-url") }
76
+ it {
77
+ options = { :userID => "id123", :webVoiceConf => 12345678, :createTime => 9876543 }
78
+ api.join_meeting_url("meeting-id", "Name", "pw", options).should == "test-url"
79
+ }
80
+ end
81
+
82
+ describe "#join_meeting" do
83
+ let(:params) {
84
+ { :meetingID => "meeting-id", :password => "pw", :fullName => "Name",
85
+ :userID => "id123", :webVoiceConf => 12345678, :createTime => 9876543 }
86
+ }
87
+
88
+ before { api.should_receive(:send_api_request).with(:join, params).and_return("join-return") }
89
+ it {
90
+ options = { :userID => "id123", :webVoiceConf => 12345678, :createTime => 9876543 }
91
+ api.join_meeting("meeting-id", "Name", "pw", options).should == "join-return"
92
+ }
93
+ end
94
+
95
+ describe "#get_recordings" do
96
+ let(:recording1) { { :recordID => "id1", :meetindID => "meeting-id" } } # simplified "recording" node in the response
97
+ let(:recording2) { { :recordID => "id2", :meetindID => "meeting-id" } }
98
+ let(:response) {
99
+ { :returncode => true, :recordings => { :recording => [ recording1, recording2 ] }, :messageKey => "mkey", :message => "m" }
100
+ }
101
+ let(:flattened_response) {
102
+ { :returncode => true, :recordings => [ recording1, recording2 ], :messageKey => "mkey", :message => "m" }
103
+ } # hash *after* the flatten_objects call
104
+
105
+ context "only supported for >= 0.8" do
106
+ let(:api) { BigBlueButton::BigBlueButtonApi.new(url, salt, "0.7", debug) }
107
+ it { expect { api.get_recordings }.to raise_error(BigBlueButton::BigBlueButtonException) }
108
+ end
109
+
110
+ context "discards invalid options" do
111
+ let(:req_params) { { :meetingID => "meeting-id" } }
112
+ before { api.should_receive(:send_api_request).with(:getRecordings, req_params).and_return(response) }
113
+ it { api.get_recordings({ :meetingID => "meeting-id", :invalidParam1 => "1" }) }
114
+ end
115
+
116
+ context "without meeting ID" do
117
+ before { api.should_receive(:send_api_request).with(:getRecordings, {}).and_return(response) }
118
+ it { api.get_recordings.should == response }
119
+ end
120
+
121
+ context "with one meeting ID" do
122
+ context "in an array" do
123
+ let(:options) { { :meetingID => ["meeting-id"] } }
124
+ let(:req_params) { { :meetingID => "meeting-id" } }
125
+ before { api.should_receive(:send_api_request).with(:getRecordings, req_params).and_return(response) }
126
+ it { api.get_recordings(options).should == response }
127
+ end
128
+
129
+ context "in a string" do
130
+ let(:options) { { :meetingID => "meeting-id" } }
131
+ let(:req_params) { { :meetingID => "meeting-id" } }
132
+ before { api.should_receive(:send_api_request).with(:getRecordings, req_params).and_return(response) }
133
+ it { api.get_recordings(options).should == response }
134
+ end
135
+ end
136
+
137
+ context "with several meeting IDs" do
138
+ context "in an array" do
139
+ let(:options) { { :meetingID => ["meeting-id-1", "meeting-id-2"] } }
140
+ let(:req_params) { { :meetingID => "meeting-id-1,meeting-id-2" } }
141
+ before { api.should_receive(:send_api_request).with(:getRecordings, req_params).and_return(response) }
142
+ it { api.get_recordings(options).should == response }
143
+ end
144
+
145
+ context "in a string" do
146
+ let(:options) { { :meetingID => "meeting-id-1,meeting-id-2" } }
147
+ let(:req_params) { { :meetingID => "meeting-id-1,meeting-id-2" } }
148
+ before { api.should_receive(:send_api_request).with(:getRecordings, req_params).and_return(response) }
149
+ it { api.get_recordings(options).should == response }
150
+ end
151
+ end
152
+
153
+ context "formats the response" do
154
+ before {
155
+ api.should_receive(:send_api_request).with(:getRecordings, anything).and_return(flattened_response)
156
+ formatter_mock = mock(BigBlueButton::BigBlueButtonFormatter)
157
+ formatter_mock.should_receive(:flatten_objects).with(:recordings, :recording)
158
+ BigBlueButton::BigBlueButtonFormatter.should_receive(:format_recording).with(recording1)
159
+ BigBlueButton::BigBlueButtonFormatter.should_receive(:format_recording).with(recording2)
160
+ BigBlueButton::BigBlueButtonFormatter.should_receive(:new).and_return(formatter_mock)
161
+ }
162
+ it { api.get_recordings }
163
+ end
164
+ end
165
+
166
+ describe "#publish_recordings" do
167
+ context "only supported for >= 0.8" do
168
+ let(:api) { BigBlueButton::BigBlueButtonApi.new(url, salt, "0.7", debug) }
169
+ it { expect { api.publish_recordings("id", true) }.to raise_error(BigBlueButton::BigBlueButtonException) }
170
+ end
171
+
172
+ context "publish is converted to string" do
173
+ let(:recordIDs) { "any" }
174
+ let(:req_params) { { :publish => "false", :recordID => "any" } }
175
+ before { api.should_receive(:send_api_request).with(:publishRecordings, req_params) }
176
+ it { api.publish_recordings(recordIDs, false) }
177
+ end
178
+
179
+ context "with one recording ID" do
180
+ context "in an array" do
181
+ let(:recordIDs) { ["id-1"] }
182
+ let(:req_params) { { :publish => "true", :recordID => "id-1" } }
183
+ before { api.should_receive(:send_api_request).with(:publishRecordings, req_params) }
184
+ it { api.publish_recordings(recordIDs, true) }
185
+ end
186
+
187
+ context "in a string" do
188
+ let(:recordIDs) { "id-1" }
189
+ let(:req_params) { { :publish => "true", :recordID => "id-1" } }
190
+ before { api.should_receive(:send_api_request).with(:publishRecordings, req_params) }
191
+ it { api.publish_recordings(recordIDs, true) }
192
+ end
193
+ end
194
+
195
+ context "with several recording IDs" do
196
+ context "in an array" do
197
+ let(:recordIDs) { ["id-1", "id-2"] }
198
+ let(:req_params) { { :publish => "true", :recordID => "id-1,id-2" } }
199
+ before { api.should_receive(:send_api_request).with(:publishRecordings, req_params) }
200
+ it { api.publish_recordings(recordIDs, true) }
201
+ end
202
+
203
+ context "in a string" do
204
+ let(:recordIDs) { "id-1,id-2,id-3" }
205
+ let(:req_params) { { :publish => "true", :recordID => "id-1,id-2,id-3" } }
206
+ before { api.should_receive(:send_api_request).with(:publishRecordings, req_params) }
207
+ it { api.publish_recordings(recordIDs, true) }
208
+ end
209
+ end
210
+ end
211
+
212
+ describe "#delete_recordings" do
213
+ context "only supported for >= 0.8" do
214
+ let(:api) { BigBlueButton::BigBlueButtonApi.new(url, salt, "0.7", debug) }
215
+ it { expect { api.delete_recordings("id") }.to raise_error(BigBlueButton::BigBlueButtonException) }
216
+ end
217
+
218
+ context "with one recording ID" do
219
+ context "in an array" do
220
+ let(:recordIDs) { ["id-1"] }
221
+ let(:req_params) { { :recordID => "id-1" } }
222
+ before { api.should_receive(:send_api_request).with(:deleteRecordings, req_params) }
223
+ it { api.delete_recordings(recordIDs) }
224
+ end
225
+
226
+ context "in a string" do
227
+ let(:recordIDs) { "id-1" }
228
+ let(:req_params) { { :recordID => "id-1" } }
229
+ before { api.should_receive(:send_api_request).with(:deleteRecordings, req_params) }
230
+ it { api.delete_recordings(recordIDs) }
231
+ end
232
+ end
233
+
234
+ context "with several recording IDs" do
235
+ context "in an array" do
236
+ let(:recordIDs) { ["id-1", "id-2"] }
237
+ let(:req_params) { { :recordID => "id-1,id-2" } }
238
+ before { api.should_receive(:send_api_request).with(:deleteRecordings, req_params) }
239
+ it { api.delete_recordings(recordIDs) }
240
+ end
241
+
242
+ context "in a string" do
243
+ let(:recordIDs) { "id-1,id-2,id-3" }
244
+ let(:req_params) { { :recordID => "id-1,id-2,id-3" } }
245
+ before { api.should_receive(:send_api_request).with(:deleteRecordings, req_params) }
246
+ it { api.delete_recordings(recordIDs) }
247
+ end
248
+ end
249
+ end
250
+
251
+ describe "#get_meeting_info" do
252
+ let(:params) { { :meetingID => "meeting-id", :password => "password" } }
253
+
254
+ # new values were added in the response in 0.8 (we'll only test these values):
255
+ # meetingName, participantCount, maxUsers, voiceBridge, recording, metadata
256
+ let(:response) {
257
+ { :meetingName => 123, :maxUsers => "100", :voiceBridge => "12341234",
258
+ :createTime => "123123123", :attendees => { :attendee => [ ] },
259
+ :messageKey => "mkey", :message => "m", :recording => "false", :meta_1 => "abc", :meta_2 => "2" }
260
+ }
261
+
262
+ before { api.should_receive(:send_api_request).with(:getMeetingInfo, params).and_return(response) }
263
+ subject { api.get_meeting_info("meeting-id", "password") }
264
+ it { subject[:meetingName].should == "123" }
265
+ it { subject[:maxUsers].should == 100 }
266
+ it { subject[:voiceBridge].should == 12341234 }
267
+ it { subject[:createTime].should == 123123123 }
268
+ it { subject[:recording].should == false }
269
+ it { subject[:meta_1].should == "abc" }
270
+ it { subject[:meta_2].should == "2" }
271
+ end
272
+
273
+ end