Skip to content

Commit

Permalink
Allow all methods to receive custom parameters
Browse files Browse the repository at this point in the history
Useful for development or for custom versions of the API. With this, all the
methods that generate URLs accept an optional hash with parameters that will
be added to the URL as they are passed, without restriction or validation.

refs #476
  • Loading branch information
daronco committed Jan 11, 2014
1 parent 03d7b7f commit c405b12
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 59 deletions.
52 changes: 38 additions & 14 deletions lib/bigbluebutton_api.rb
Expand Up @@ -179,6 +179,9 @@ def create_meeting(meeting_name, meeting_id, options={}, modules=nil)
# Ends an existing meeting. Throws BigBlueButtonException on failure.
# meeting_id (string):: Unique identifier for the meeting
# moderator_password (string):: Moderator password
# options (Hash):: Hash with additional parameters. This method doesn't accept additional
# parameters, but if you have a custom API with more parameters, you
# can simply pass them in this hash and they will be added to the API call.
#
# === Return examples (for 0.81)
#
Expand All @@ -190,15 +193,20 @@ def create_meeting(meeting_name, meeting_id, options={}, modules=nil)
# :message => "A request to end the meeting was sent. Please wait a few seconds, and then use the getMeetingInfo or isMeetingRunning API calls to verify that it was ended."
# }
#
def end_meeting(meeting_id, moderator_password)
send_api_request(:end, { :meetingID => meeting_id, :password => moderator_password } )
def end_meeting(meeting_id, moderator_password, options={})
params = { :meetingID => meeting_id, :password => moderator_password }.merge(options)
send_api_request(:end, params)
end

# Returns whether the meeting is running or not. A meeting is only running after at least
# one participant has joined. Returns true or false.
# meeting_id (string):: Unique identifier for the meeting
def is_meeting_running?(meeting_id)
hash = send_api_request(:isMeetingRunning, { :meetingID => meeting_id } )
# meeting_id (string):: Unique identifier for the meeting
# options (Hash):: Hash with additional parameters. This method doesn't accept additional
# parameters, but if you have a custom API with more parameters, you
# can simply pass them in this hash and they will be added to the API call.
def is_meeting_running?(meeting_id, options={})
params = { :meetingID => meeting_id }.merge(options)
hash = send_api_request(:isMeetingRunning, params)
BigBlueButtonFormatter.new(hash).to_boolean(:running)
end

Expand Down Expand Up @@ -240,6 +248,9 @@ def join_meeting(meeting_id, user_name, password, options={})
#
# meeting_id (string):: Unique identifier for the meeting
# password (string):: Moderator password for this meeting
# options (Hash):: Hash with additional parameters. This method doesn't accept additional
# parameters, but if you have a custom API with more parameters, you
# can simply pass them in this hash and they will be added to the API call.
#
# === Example responses for 0.81
#
Expand Down Expand Up @@ -300,8 +311,9 @@ def join_meeting(meeting_id, user_name, password, options={})
# :message => ""
# }
#
def get_meeting_info(meeting_id, password)
response = send_api_request(:getMeetingInfo, { :meetingID => meeting_id, :password => password } )
def get_meeting_info(meeting_id, password, options={})
params = { :meetingID => meeting_id, :password => password }.merge(options)
response = send_api_request(:getMeetingInfo, params)

formatter = BigBlueButtonFormatter.new(response)
formatter.flatten_objects(:attendees, :attendee)
Expand All @@ -328,6 +340,10 @@ def get_meeting_info(meeting_id, password)
# Returns a hash object with information about all the meetings currently created in the
# server, either they are running or not.
#
# options (Hash):: Hash with additional parameters. This method doesn't accept additional
# parameters, but if you have a custom API with more parameters, you
# can simply pass them in this hash and they will be added to the API call.
#
# === Example responses for 0.81
#
# Server with one or more meetings:
Expand Down Expand Up @@ -373,8 +389,8 @@ def get_meeting_info(meeting_id, password)
# :message => "no meetings were found on this server"
# }
#
def get_meetings
response = send_api_request(:getMeetings)
def get_meetings(options={})
response = send_api_request(:getMeetings, options)

formatter = BigBlueButtonFormatter.new(response)
formatter.flatten_objects(:meetings, :meeting)
Expand Down Expand Up @@ -474,15 +490,19 @@ def get_recordings(options={})
# "id1,id2,id3"
# ["id1"]
# ["id1", "id2", "id3"]
# publish (boolean):: Whether to publish or unpublish the recording(s)
# publish (boolean):: Whether to publish or unpublish the recording(s)
# options (Hash):: Hash with additional parameters. This method doesn't accept additional
# parameters, but if you have a custom API with more parameters, you
# can simply pass them in this hash and they will be added to the API call.
#
# === Example responses
#
# { :returncode => true, :published => true }
#
def publish_recordings(recordIDs, publish)
def publish_recordings(recordIDs, publish, options={})
recordIDs = recordIDs.join(",") if recordIDs.instance_of?(Array) # ["id1", "id2"] becomes "id1,id2"
send_api_request(:publishRecordings, { :recordID => recordIDs, :publish => publish.to_s })
params = { :recordID => recordIDs, :publish => publish.to_s }.merge(options)
send_api_request(:publishRecordings, params)
end

# Delete one or more recordings for a given recordID (or set of record IDs).
Expand All @@ -492,14 +512,18 @@ def publish_recordings(recordIDs, publish)
# "id1,id2,id3"
# ["id1"]
# ["id1", "id2", "id3"]
# options (Hash):: Hash with additional parameters. This method doesn't accept additional
# parameters, but if you have a custom API with more parameters, you
# can simply pass them in this hash and they will be added to the API call.
#
# === Example responses
#
# { :returncode => true, :deleted => true }
#
def delete_recordings(recordIDs)
def delete_recordings(recordIDs, options={})
recordIDs = recordIDs.join(",") if recordIDs.instance_of?(Array) # ["id1", "id2"] becomes "id1,id2"
send_api_request(:deleteRecordings, { :recordID => recordIDs })
params = { :recordID => recordIDs }.merge(options)
send_api_request(:deleteRecordings, params)
end


Expand Down
2 changes: 1 addition & 1 deletion lib/bigbluebutton_formatter.rb
Expand Up @@ -169,7 +169,7 @@ def self.format_recording(rec)
# { :name => "Test", :attendees => [ { :name => "attendee1" } ] }
#
def flatten_objects(first, second)
if @hash[first].empty?
if !@hash[first] or @hash[first].empty?
collection = []
else
node = @hash[first][second]
Expand Down
164 changes: 120 additions & 44 deletions spec/bigbluebutton_api_spec.rb
Expand Up @@ -146,11 +146,26 @@
describe "#end_meeting" do
let(:meeting_id) { "meeting-id" }
let(:moderator_password) { "password" }
let(:params) { { :meetingID => meeting_id, :password => moderator_password } }
let(:response) { "anything" }

before { api.should_receive(:send_api_request).with(:end, params).and_return(response) }
it { api.end_meeting(meeting_id, moderator_password).should == response }
context "standard case" do
let(:params) { { :meetingID => meeting_id, :password => moderator_password } }
let(:response) { "anything" }

before { api.should_receive(:send_api_request).with(:end, params).and_return(response) }
it { api.end_meeting(meeting_id, moderator_password).should == response }
end

context "accepts non standard options" do
let(:params_in) {
{ :anything1 => "anything-1", :anything2 => 2 }
}
let(:params_out) {
{ :meetingID => meeting_id, :password => moderator_password,
:anything1 => "anything-1", :anything2 => 2 }
}
before { api.should_receive(:send_api_request).with(:end, params_out) }
it { api.end_meeting(meeting_id, moderator_password, params_in) }
end
end

describe "#is_meeting_running?" do
Expand All @@ -168,6 +183,17 @@
before { api.should_receive(:send_api_request).with(:isMeetingRunning, params).and_return(response) }
it { api.is_meeting_running?(meeting_id).should == false }
end

context "accepts non standard options" do
let(:params_in) {
{ :anything1 => "anything-1", :anything2 => 2 }
}
let(:params_out) {
{ :meetingID => meeting_id, :anything1 => "anything-1", :anything2 => 2 }
}
before { api.should_receive(:send_api_request).with(:isMeetingRunning, params_out) }
it { api.is_meeting_running?(meeting_id, params_in) }
end
end

describe "#join_meeting_url" do
Expand Down Expand Up @@ -221,52 +247,77 @@
describe "#get_meeting_info" do
let(:meeting_id) { "meeting-id" }
let(:password) { "password" }
let(:params) { { :meetingID => meeting_id, :password => password } }

let(:attendee1) { { :userID => 123, :fullName => "Dexter Morgan", :role => "MODERATOR" } }
let(:attendee2) { { :userID => "id2", :fullName => "Cameron", :role => "VIEWER" } }
let(:response) {
{ :meetingID => 123, :moderatorPW => 111, :attendeePW => 222, :hasBeenForciblyEnded => "FALSE",
:running => "TRUE", :startTime => "Thu Sep 01 17:51:42 UTC 2011", :endTime => "null",
:returncode => true, :attendees => { :attendee => [ attendee1, attendee2 ] },
:messageKey => "mkey", :message => "m", :participantCount => "50", :moderatorCount => "3",
:meetingName => "meeting-name", :maxUsers => "100", :voiceBridge => "12341234", :createTime => "123123123",
:recording => "false", :meta_1 => "abc", :meta_2 => "2" }
} # hash after the send_api_request call, before the formatting

let(:expected_attendee1) { { :userID => "123", :fullName => "Dexter Morgan", :role => :moderator } }
let(:expected_attendee2) { { :userID => "id2", :fullName => "Cameron", :role => :viewer } }
let(:final_response) {
{ :meetingID => "123", :moderatorPW => "111", :attendeePW => "222", :hasBeenForciblyEnded => false,
:running => true, :startTime => DateTime.parse("Thu Sep 01 17:51:42 UTC 2011"), :endTime => nil,
:returncode => true, :attendees => [ expected_attendee1, expected_attendee2 ],
:messageKey => "mkey", :message => "m", :participantCount => 50, :moderatorCount => 3,
:meetingName => "meeting-name", :maxUsers => 100, :voiceBridge => 12341234, :createTime => 123123123,
:recording => false, :meta_1 => "abc", :meta_2 => "2" }
} # expected return hash after all the formatting

# ps: not mocking the formatter here because it's easier to just check the results (final_response)
before { api.should_receive(:send_api_request).with(:getMeetingInfo, params).and_return(response) }
it { api.get_meeting_info(meeting_id, password).should == final_response }
context "standard case" do
let(:params) { { :meetingID => meeting_id, :password => password } }

let(:attendee1) { { :userID => 123, :fullName => "Dexter Morgan", :role => "MODERATOR" } }
let(:attendee2) { { :userID => "id2", :fullName => "Cameron", :role => "VIEWER" } }
let(:response) {
{ :meetingID => 123, :moderatorPW => 111, :attendeePW => 222, :hasBeenForciblyEnded => "FALSE",
:running => "TRUE", :startTime => "Thu Sep 01 17:51:42 UTC 2011", :endTime => "null",
:returncode => true, :attendees => { :attendee => [ attendee1, attendee2 ] },
:messageKey => "mkey", :message => "m", :participantCount => "50", :moderatorCount => "3",
:meetingName => "meeting-name", :maxUsers => "100", :voiceBridge => "12341234", :createTime => "123123123",
:recording => "false", :meta_1 => "abc", :meta_2 => "2" }
} # hash after the send_api_request call, before the formatting

let(:expected_attendee1) { { :userID => "123", :fullName => "Dexter Morgan", :role => :moderator } }
let(:expected_attendee2) { { :userID => "id2", :fullName => "Cameron", :role => :viewer } }
let(:final_response) {
{ :meetingID => "123", :moderatorPW => "111", :attendeePW => "222", :hasBeenForciblyEnded => false,
:running => true, :startTime => DateTime.parse("Thu Sep 01 17:51:42 UTC 2011"), :endTime => nil,
:returncode => true, :attendees => [ expected_attendee1, expected_attendee2 ],
:messageKey => "mkey", :message => "m", :participantCount => 50, :moderatorCount => 3,
:meetingName => "meeting-name", :maxUsers => 100, :voiceBridge => 12341234, :createTime => 123123123,
:recording => false, :meta_1 => "abc", :meta_2 => "2" }
} # expected return hash after all the formatting

# ps: not mocking the formatter here because it's easier to just check the results (final_response)
before { api.should_receive(:send_api_request).with(:getMeetingInfo, params).and_return(response) }
it { api.get_meeting_info(meeting_id, password).should == final_response }
end

context "accepts non standard options" do
let(:params_in) {
{ :anything1 => "anything-1", :anything2 => 2 }
}
let(:params_out) {
{ :meetingID => meeting_id, :password => password,
:anything1 => "anything-1", :anything2 => 2 }
}
before { api.should_receive(:send_api_request).with(:getMeetingInfo, params_out).and_return({}) }
it { api.get_meeting_info(meeting_id, password, params_in) }
end
end

describe "#get_meetings" do
let(:meeting_hash1) { { :meetingID => "Demo Meeting", :attendeePW => "ap", :moderatorPW => "mp", :hasBeenForciblyEnded => false, :running => true } }
let(:meeting_hash2) { { :meetingID => "Ended Meeting", :attendeePW => "pass", :moderatorPW => "pass", :hasBeenForciblyEnded => true, :running => false } }
let(:flattened_response) {
{ :returncode => true, :meetings => [ meeting_hash1, meeting_hash2 ], :messageKey => "mkey", :message => "m" }
} # hash *after* the flatten_objects call
context "standard case" do
let(:meeting_hash1) { { :meetingID => "Demo Meeting", :attendeePW => "ap", :moderatorPW => "mp", :hasBeenForciblyEnded => false, :running => true } }
let(:meeting_hash2) { { :meetingID => "Ended Meeting", :attendeePW => "pass", :moderatorPW => "pass", :hasBeenForciblyEnded => true, :running => false } }
let(:flattened_response) {
{ :returncode => true, :meetings => [ meeting_hash1, meeting_hash2 ], :messageKey => "mkey", :message => "m" }
} # hash *after* the flatten_objects call

before {
api.should_receive(:send_api_request).with(:getMeetings).
before {
api.should_receive(:send_api_request).with(:getMeetings, {}).
and_return(flattened_response)
formatter_mock = mock(BigBlueButton::BigBlueButtonFormatter)
formatter_mock.should_receive(:flatten_objects).with(:meetings, :meeting)
BigBlueButton::BigBlueButtonFormatter.should_receive(:new).and_return(formatter_mock)
BigBlueButton::BigBlueButtonFormatter.should_receive(:format_meeting).with(meeting_hash1)
BigBlueButton::BigBlueButtonFormatter.should_receive(:format_meeting).with(meeting_hash2)
}
it { api.get_meetings }
formatter_mock = mock(BigBlueButton::BigBlueButtonFormatter)
formatter_mock.should_receive(:flatten_objects).with(:meetings, :meeting)
BigBlueButton::BigBlueButtonFormatter.should_receive(:new).and_return(formatter_mock)
BigBlueButton::BigBlueButtonFormatter.should_receive(:format_meeting).with(meeting_hash1)
BigBlueButton::BigBlueButtonFormatter.should_receive(:format_meeting).with(meeting_hash2)
}
it { api.get_meetings }
end

context "accepts non standard options" do
let(:params) {
{ :anything1 => "anything-1", :anything2 => 2 }
}
before { api.should_receive(:send_api_request).with(:getMeetings, params).and_return({}) }
it { api.get_meetings(params) }
end
end

describe "#get_api_version" do
Expand Down Expand Up @@ -639,6 +690,19 @@
it { api.publish_recordings(recordIDs, true) }
end
end

context "accepts non standard options" do
let(:recordIDs) { ["id-1"] }
let(:params_in) {
{ :anything1 => "anything-1", :anything2 => 2 }
}
let(:params_out) {
{ :publish => "true", :recordID => "id-1",
:anything1 => "anything-1", :anything2 => 2 }
}
before { api.should_receive(:send_api_request).with(:publishRecordings, params_out) }
it { api.publish_recordings(recordIDs, true, params_in) }
end
end

describe "#delete_recordings" do
Expand Down Expand Up @@ -674,6 +738,18 @@
it { api.delete_recordings(recordIDs) }
end
end

context "accepts non standard options" do
let(:recordIDs) { ["id-1"] }
let(:params_in) {
{ :anything1 => "anything-1", :anything2 => 2 }
}
let(:params_out) {
{ :recordID => "id-1", :anything1 => "anything-1", :anything2 => 2 }
}
before { api.should_receive(:send_api_request).with(:deleteRecordings, params_out) }
it { api.delete_recordings(recordIDs, params_in) }
end
end

end
7 changes: 7 additions & 0 deletions spec/bigbluebutton_formatter_spec.rb
Expand Up @@ -297,6 +297,13 @@
it { subject.should == { :objects => [] } }
end

context "when the target key doesn't exist in the hash" do
let(:hash) { { } }
before { formatter.hash = hash }
subject { formatter.flatten_objects(:objects, :object) }
it { subject.should == { :objects => [] } } # adds the one the doesn't exist
end

context "when there's only one object in the list" do
let(:object_hash) { { :id => 1 } }
let(:hash) { { :objects => { :object => object_hash } } }
Expand Down

0 comments on commit c405b12

Please sign in to comment.