bigbluebutton-api-ruby 1.3.0 → 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -1
- data/.rspec +1 -0
- data/.ruby-version +1 -1
- data/.travis.yml +7 -3
- data/CHANGELOG.md +197 -0
- data/Dockerfile +13 -0
- data/Gemfile +2 -2
- data/Gemfile.lock +26 -13
- data/LICENSE +1 -1
- data/README.md +96 -0
- data/Rakefile +8 -4
- data/bigbluebutton-api-ruby.gemspec +19 -12
- data/docker-compose.yml +10 -0
- data/examples/get_version_example.rb +1 -3
- data/examples/join_example.rb +0 -1
- data/examples/prepare.rb +1 -1
- data/features/config.yml.example +5 -9
- data/features/step_definitions/common_steps.rb +3 -4
- data/lib/bigbluebutton_api.rb +111 -32
- data/lib/bigbluebutton_config_layout.rb +3 -1
- data/lib/bigbluebutton_config_xml.rb +8 -5
- data/lib/bigbluebutton_exception.rb +1 -1
- data/lib/bigbluebutton_formatter.rb +4 -2
- data/lib/bigbluebutton_hash_to_xml.rb +3 -1
- data/spec/bigbluebutton_api_0.81_spec.rb +2 -3
- data/spec/bigbluebutton_api_0.9_spec.rb +32 -0
- data/spec/bigbluebutton_api_spec.rb +665 -599
- data/spec/bigbluebutton_config_xml_spec.rb +30 -4
- data/spec/bigbluebutton_formatter_spec.rb +36 -7
- metadata +113 -35
- data/CHANGELOG.rdoc +0 -90
- data/README.rdoc +0 -62
data/lib/bigbluebutton_api.rb
CHANGED
@@ -9,10 +9,11 @@ require 'bigbluebutton_formatter'
|
|
9
9
|
require 'bigbluebutton_modules'
|
10
10
|
require 'bigbluebutton_config_xml'
|
11
11
|
require 'bigbluebutton_config_layout'
|
12
|
+
require 'logger'
|
12
13
|
|
13
14
|
module BigBlueButton
|
14
15
|
|
15
|
-
# This class provides access to the BigBlueButton API. For more details see README.
|
16
|
+
# This class provides access to the BigBlueButton API. For more details see README.
|
16
17
|
#
|
17
18
|
# Sample usage of the API is as follows:
|
18
19
|
# 1. Create a meeting with create_meeting;
|
@@ -44,14 +45,14 @@ module BigBlueButton
|
|
44
45
|
# URL to a BigBlueButton server (e.g. http://demo.bigbluebutton.org/bigbluebutton/api)
|
45
46
|
attr_accessor :url
|
46
47
|
|
47
|
-
#
|
48
|
-
attr_accessor :
|
48
|
+
# Shared secret for this server
|
49
|
+
attr_accessor :secret
|
49
50
|
|
50
51
|
# API version e.g. 0.81
|
51
52
|
attr_accessor :version
|
52
53
|
|
53
|
-
#
|
54
|
-
attr_accessor :
|
54
|
+
# logger to log reponses and infos
|
55
|
+
attr_accessor :logger
|
55
56
|
|
56
57
|
# Maximum wait time for HTTP requests (secs)
|
57
58
|
attr_accessor :timeout
|
@@ -65,22 +66,27 @@ module BigBlueButton
|
|
65
66
|
|
66
67
|
# Initializes an instance
|
67
68
|
# url:: URL to a BigBlueButton server (e.g. http://demo.bigbluebutton.org/bigbluebutton/api)
|
68
|
-
#
|
69
|
+
# secret:: Shared secret for this server
|
69
70
|
# version:: API version e.g. 0.81
|
70
|
-
def initialize(url,
|
71
|
-
@supported_versions = ['0.8', '0.81']
|
71
|
+
def initialize(url, secret, version=nil, logger=nil)
|
72
|
+
@supported_versions = ['0.8', '0.81', '0.9', '1.0']
|
72
73
|
@url = url
|
73
|
-
@
|
74
|
-
@debug = debug
|
74
|
+
@secret = secret
|
75
75
|
@timeout = 10 # default timeout for api requests
|
76
76
|
@request_headers = {} # http headers sent in all requests
|
77
|
-
|
78
|
-
|
77
|
+
@logger = logger
|
78
|
+
if logger.nil?
|
79
|
+
@logger = Logger.new(STDOUT)
|
80
|
+
@logger.level = Logger::INFO
|
81
|
+
end
|
82
|
+
|
83
|
+
version = nil if version && version.strip.empty?
|
84
|
+
@version = nearest_version(version || get_api_version)
|
79
85
|
unless @supported_versions.include?(@version)
|
80
|
-
|
86
|
+
@logger.warn("BigBlueButtonAPI: detected unsupported version, using the closest one that is supported (#{@version})")
|
81
87
|
end
|
82
88
|
|
83
|
-
|
89
|
+
@logger.debug("BigBlueButtonAPI: Using version #{@version}")
|
84
90
|
end
|
85
91
|
|
86
92
|
# Creates a new meeting. Returns the hash with the response or throws BigBlueButtonException
|
@@ -225,7 +231,8 @@ module BigBlueButton
|
|
225
231
|
# in this hash and they will be added to the API call.
|
226
232
|
def join_meeting_url(meeting_id, user_name, password, options={})
|
227
233
|
params = { :meetingID => meeting_id, :password => password, :fullName => user_name }.merge(options)
|
228
|
-
get_url(:join, params)
|
234
|
+
url, data = get_url(:join, params)
|
235
|
+
url
|
229
236
|
end
|
230
237
|
|
231
238
|
# Returns a hash object containing the information of a meeting.
|
@@ -459,6 +466,10 @@ module BigBlueButton
|
|
459
466
|
options[:meetingID] = options[:meetingID].join(",") if options[:meetingID].instance_of?(Array)
|
460
467
|
end
|
461
468
|
|
469
|
+
if options.has_key?(:state)
|
470
|
+
options[:state] = options[:state].join(",") if options[:state].instance_of?(Array)
|
471
|
+
end
|
472
|
+
|
462
473
|
response = send_api_request(:getRecordings, options)
|
463
474
|
|
464
475
|
formatter = BigBlueButtonFormatter.new(response)
|
@@ -467,6 +478,30 @@ module BigBlueButton
|
|
467
478
|
response
|
468
479
|
end
|
469
480
|
|
481
|
+
# Available since BBB v1.1
|
482
|
+
# Update metadata (or other attributes depending on the API implementation) for a given recordID (or set of record IDs).
|
483
|
+
# recordIDs (string, Array):: ID or IDs of the target recordings.
|
484
|
+
# Any of the following values are accepted:
|
485
|
+
# "id1"
|
486
|
+
# "id1,id2,id3"
|
487
|
+
# ["id1"]
|
488
|
+
# ["id1", "id2", "id3"]
|
489
|
+
# meta (String):: Pass one or more metadata values to be update (format is the same as in create call)
|
490
|
+
# options (Hash):: Hash with additional parameters. This method doesn't accept additional
|
491
|
+
# parameters, but if you have a custom API with more parameters, you
|
492
|
+
# can simply pass them in this hash and they will be added to the API call.
|
493
|
+
#
|
494
|
+
# === Example responses
|
495
|
+
#
|
496
|
+
# { :returncode => success, :updated => true }
|
497
|
+
#
|
498
|
+
def update_recordings(recordIDs, meta=nil, options={})
|
499
|
+
recordIDs = recordIDs.join(",") if recordIDs.instance_of?(Array) # ["id1", "id2"] becomes "id1,id2"
|
500
|
+
params = { :recordID => recordIDs, :meta => meta }.merge(options)
|
501
|
+
send_api_request(:updateRecordings, params)
|
502
|
+
end
|
503
|
+
|
504
|
+
|
470
505
|
# Publish and unpublish recordings for a given recordID (or set of record IDs).
|
471
506
|
# recordIDs (string, Array):: ID or IDs of the target recordings.
|
472
507
|
# Any of the following values are accepted:
|
@@ -598,10 +633,15 @@ module BigBlueButton
|
|
598
633
|
response[:returncode]
|
599
634
|
end
|
600
635
|
|
636
|
+
def check_url
|
637
|
+
url, data = get_url(:check)
|
638
|
+
url
|
639
|
+
end
|
640
|
+
|
601
641
|
# API's are equal if all the following attributes are equal.
|
602
642
|
def ==(other)
|
603
643
|
r = true
|
604
|
-
[:url, :supported_versions, :
|
644
|
+
[:url, :supported_versions, :secret, :version, :logger].each do |param|
|
605
645
|
r = r && self.send(param) == other.send(param)
|
606
646
|
end
|
607
647
|
r
|
@@ -622,11 +662,12 @@ module BigBlueButton
|
|
622
662
|
# params (Hash):: The parameters to be passed in the URL
|
623
663
|
def get_url(method, params={})
|
624
664
|
if method == :index
|
625
|
-
return @url
|
665
|
+
return @url, nil
|
666
|
+
elsif method == :check
|
667
|
+
baseurl = URI.join(@url, "/").to_s
|
668
|
+
return "#{baseurl}check", nil
|
626
669
|
end
|
627
670
|
|
628
|
-
url = "#{@url}/#{method}?"
|
629
|
-
|
630
671
|
# stringify and escape all params
|
631
672
|
params.delete_if { |k, v| v.nil? } unless params.nil?
|
632
673
|
# some API calls require the params to be sorted
|
@@ -634,16 +675,22 @@ module BigBlueButton
|
|
634
675
|
params = params.inject({}){ |memo,(k,v)| memo[k.to_sym] = v; memo }
|
635
676
|
params = Hash[params.sort]
|
636
677
|
params_string = ""
|
637
|
-
params_string = params.map{ |k,v| "#{k}=" +
|
678
|
+
params_string = params.map{ |k,v| "#{k}=" + URI.encode_www_form_component(v.to_s) unless k.nil? || v.nil? }.join("&")
|
638
679
|
|
639
680
|
# checksum calc
|
640
|
-
checksum_param = params_string + @
|
681
|
+
checksum_param = params_string + @secret
|
641
682
|
checksum_param = method.to_s + checksum_param
|
642
683
|
checksum = Digest::SHA1.hexdigest(checksum_param)
|
643
684
|
|
644
|
-
|
645
|
-
|
646
|
-
|
685
|
+
if method == :setConfigXML
|
686
|
+
params_string = "checksum=#{checksum}&#{params_string}"
|
687
|
+
return "#{@url}/#{method}", params_string
|
688
|
+
else
|
689
|
+
url = "#{@url}/#{method}?"
|
690
|
+
url += "#{params_string}&" unless params_string.empty?
|
691
|
+
url += "checksum=#{checksum}"
|
692
|
+
return url, nil
|
693
|
+
end
|
647
694
|
end
|
648
695
|
|
649
696
|
# Performs an API call.
|
@@ -660,7 +707,9 @@ module BigBlueButton
|
|
660
707
|
# raw (boolean):: If true, returns the data as it was received. Will not parse it into a Hash,
|
661
708
|
# check for errors or throw exceptions.
|
662
709
|
def send_api_request(method, params={}, data=nil, raw=false)
|
663
|
-
|
710
|
+
# if the method returns a body, use it as the data in the post request
|
711
|
+
url, body = get_url(method, params)
|
712
|
+
data = body if body
|
664
713
|
|
665
714
|
@http_response = send_request(url, data)
|
666
715
|
return {} if @http_response.body.empty?
|
@@ -699,29 +748,59 @@ module BigBlueButton
|
|
699
748
|
# Otherwise uses GET
|
700
749
|
def send_request(url, data=nil)
|
701
750
|
begin
|
702
|
-
|
751
|
+
@logger.debug("BigBlueButtonAPI: URL request = #{url}")
|
703
752
|
url_parsed = URI.parse(url)
|
704
753
|
http = Net::HTTP.new(url_parsed.host, url_parsed.port)
|
705
754
|
http.open_timeout = @timeout
|
706
755
|
http.read_timeout = @timeout
|
756
|
+
http.use_ssl = true if url_parsed.scheme.downcase == 'https'
|
757
|
+
|
707
758
|
if data.nil?
|
708
759
|
response = http.get(url_parsed.request_uri, @request_headers)
|
709
760
|
else
|
710
|
-
|
711
|
-
opts = { 'Content-Type' => '
|
761
|
+
@logger.debug("BigBlueButtonAPI: Sending as a POST request with data.size = #{data.size}")
|
762
|
+
opts = { 'Content-Type' => 'application/xml' }.merge @request_headers
|
712
763
|
response = http.post(url_parsed.request_uri, data, opts)
|
713
764
|
end
|
714
|
-
|
765
|
+
@logger.info("BigBlueButtonAPI: request=#{url} response_status=#{response.class.name} response_code=#{response.code} message_key=#{response.message}")
|
766
|
+
@logger.debug("BigBlueButtonAPI: URL response = #{response.body}")
|
715
767
|
|
716
|
-
rescue
|
717
|
-
|
768
|
+
rescue Timeout::Error => error
|
769
|
+
exception = BigBlueButtonException.new("Timeout error. Your server is probably down: \"#{@url}\". Error: #{error}")
|
770
|
+
exception.key = 'TimeoutError'
|
771
|
+
raise exception
|
718
772
|
|
719
773
|
rescue Exception => error
|
720
|
-
|
774
|
+
exception = BigBlueButtonException.new("Connection error. Your URL is probably incorrect: \"#{@url}\". Error: #{error}")
|
775
|
+
exception.key = 'IncorrectUrlError'
|
776
|
+
raise exception
|
721
777
|
end
|
722
778
|
|
723
779
|
response
|
724
780
|
end
|
725
781
|
|
782
|
+
def nearest_version(target)
|
783
|
+
version = target
|
784
|
+
|
785
|
+
# 0.81 in BBB is actually < than 0.9, but not when comparing here
|
786
|
+
# so normalize x.xx versions to x.x.x
|
787
|
+
match = version.match(/(\d)\.(\d)(\d)/)
|
788
|
+
version = "#{match[1]}.#{match[2]}.#{match[3]}" if match
|
789
|
+
|
790
|
+
# we don't allow older versions than the one supported, use an old version of the gem for that
|
791
|
+
if Gem::Version.new(version) < Gem::Version.new(@supported_versions[0])
|
792
|
+
exception = BigBlueButtonException.new("BigBlueButton error: Invalid API version #{version}. Supported versions: #{@supported_versions.join(', ')}")
|
793
|
+
exception.key = 'APIVersionError'
|
794
|
+
raise exception
|
795
|
+
|
796
|
+
# allow newer versions by using the newest one we support
|
797
|
+
elsif Gem::Version.new(version) > Gem::Version.new(@supported_versions.last)
|
798
|
+
@supported_versions.last
|
799
|
+
|
800
|
+
else
|
801
|
+
target
|
802
|
+
end
|
803
|
+
end
|
804
|
+
|
726
805
|
end
|
727
806
|
end
|
@@ -29,7 +29,9 @@ module BigBlueButton
|
|
29
29
|
begin
|
30
30
|
@xml = XmlSimple.xml_in(xml, opts)
|
31
31
|
rescue Exception => e
|
32
|
-
|
32
|
+
exception = BigBlueButton::BigBlueButtonException.new("Error parsing the layouts XML. Error: #{e.message}")
|
33
|
+
exception.key = 'XMLParsingError'
|
34
|
+
raise exception
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
@@ -25,15 +25,17 @@ module BigBlueButton
|
|
25
25
|
attr_accessor :xml
|
26
26
|
|
27
27
|
def initialize(xml)
|
28
|
-
@
|
28
|
+
@original_string = nil
|
29
29
|
@xml = nil
|
30
30
|
unless xml.nil?
|
31
31
|
opts = { 'ForceArray' => false, 'KeepRoot' => true }
|
32
32
|
begin
|
33
33
|
@xml = XmlSimple.xml_in(xml, opts)
|
34
|
-
@
|
34
|
+
@original_string = self.as_string.clone
|
35
35
|
rescue Exception => e
|
36
|
-
|
36
|
+
exception = BigBlueButton::BigBlueButtonException.new("Error parsing the config XML. Error: #{e.message}")
|
37
|
+
exception.key = 'XMLParsingError'
|
38
|
+
raise exception
|
37
39
|
end
|
38
40
|
end
|
39
41
|
end
|
@@ -60,7 +62,8 @@ module BigBlueButton
|
|
60
62
|
if tag
|
61
63
|
attr = find_attribute(tag, attr_name)
|
62
64
|
if attr
|
63
|
-
|
65
|
+
# saves always as string
|
66
|
+
tag[attr_name] = value.is_a?(String) ? value : value.to_s
|
64
67
|
else
|
65
68
|
nil
|
66
69
|
end
|
@@ -75,7 +78,7 @@ module BigBlueButton
|
|
75
78
|
|
76
79
|
def is_modified?
|
77
80
|
@xml and
|
78
|
-
|
81
|
+
self.as_string != @original_string
|
79
82
|
end
|
80
83
|
|
81
84
|
protected
|
@@ -22,7 +22,7 @@ module BigBlueButton
|
|
22
22
|
unless @hash.has_key?(key)
|
23
23
|
0
|
24
24
|
else
|
25
|
-
@hash[key] = @hash[key].to_i
|
25
|
+
@hash[key] = @hash[key].to_i rescue 0
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -49,7 +49,9 @@ module BigBlueButton
|
|
49
49
|
if value.is_a?(Numeric)
|
50
50
|
result = value == 0 ? nil : DateTime.parse(Time.at(value/1000.0).to_s)
|
51
51
|
else
|
52
|
-
if value.
|
52
|
+
if (value.is_a?(Hash) || value.is_a?(Array)) && value.empty?
|
53
|
+
result = nil
|
54
|
+
elsif value.is_a?(String) && (value.empty? || value.downcase == 'null')
|
53
55
|
result = nil
|
54
56
|
else
|
55
57
|
# note: just in case the value comes as a string in the format: "Thu Sep 01 17:51:42 UTC 2011"
|
@@ -10,7 +10,9 @@ module BigBlueButton
|
|
10
10
|
hash = XmlSimple.xml_in(xml_io, opts)
|
11
11
|
return symbolize_keys(hash)
|
12
12
|
rescue Exception => e
|
13
|
-
|
13
|
+
exception = BigBlueButtonException.new("Impossible to convert XML to hash. Error: #{e.message}")
|
14
|
+
exception.key = 'XMLConversionError'
|
15
|
+
raise exception
|
14
16
|
end
|
15
17
|
end
|
16
18
|
|
@@ -5,10 +5,9 @@ describe BigBlueButton::BigBlueButtonApi do
|
|
5
5
|
|
6
6
|
# default variables and API object for all tests
|
7
7
|
let(:url) { "http://server.com" }
|
8
|
-
let(:
|
8
|
+
let(:secret) { "1234567890abcdefghijkl" }
|
9
9
|
let(:version) { "0.81" }
|
10
|
-
let(:
|
11
|
-
let(:api) { BigBlueButton::BigBlueButtonApi.new(url, salt, version, debug) }
|
10
|
+
let(:api) { BigBlueButton::BigBlueButtonApi.new(url, secret, version) }
|
12
11
|
|
13
12
|
describe "#get_default_config_xml" do
|
14
13
|
let(:response) { "<response><returncode>1</returncode></response>" }
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# Tests for BBB API version 0.81
|
4
|
+
describe BigBlueButton::BigBlueButtonApi do
|
5
|
+
|
6
|
+
# default variables and API object for all tests
|
7
|
+
let(:url) { "http://server.com" }
|
8
|
+
let(:secret) { "1234567890abcdefghijkl" }
|
9
|
+
let(:version) { "0.9" }
|
10
|
+
let(:api) { BigBlueButton::BigBlueButtonApi.new(url, secret, version) }
|
11
|
+
|
12
|
+
describe "#create_meeting" do
|
13
|
+
context "accepts the new parameters" do
|
14
|
+
let(:req_params) {
|
15
|
+
{ :name => "name", :meetingID => "meeting-id",
|
16
|
+
:moderatorOnlyMessage => "my-msg", :autoStartRecording => "false",
|
17
|
+
:allowStartStopRecording => "true"
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
before { api.should_receive(:send_api_request).with(:create, req_params) }
|
22
|
+
it {
|
23
|
+
options = {
|
24
|
+
:moderatorOnlyMessage => "my-msg",
|
25
|
+
:autoStartRecording => "false",
|
26
|
+
:allowStartStopRecording => "true"
|
27
|
+
}
|
28
|
+
api.create_meeting("name", "meeting-id", options)
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|