bigbluebutton_rails 2.2.0 → 2.3.0

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 (86) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -3
  3. data/CHANGELOG.md +34 -0
  4. data/Dockerfile +23 -0
  5. data/Gemfile +3 -0
  6. data/Gemfile.lock +14 -5
  7. data/README.md +42 -59
  8. data/Rakefile +6 -3
  9. data/app/controllers/bigbluebutton/api/rooms_controller.rb +117 -0
  10. data/app/controllers/bigbluebutton/playback_types_controller.rb +0 -3
  11. data/app/controllers/bigbluebutton/recordings_controller.rb +37 -23
  12. data/app/controllers/bigbluebutton/rooms_controller.rb +6 -31
  13. data/app/controllers/bigbluebutton/servers_controller.rb +0 -14
  14. data/app/helpers/bigbluebutton_rails_helper.rb +4 -0
  15. data/app/models/bigbluebutton_attendee.rb +21 -0
  16. data/app/models/bigbluebutton_meeting.rb +5 -0
  17. data/app/models/bigbluebutton_playback_format.rb +3 -2
  18. data/app/models/bigbluebutton_recording.rb +164 -68
  19. data/app/models/bigbluebutton_room.rb +148 -59
  20. data/app/models/bigbluebutton_server.rb +1 -1
  21. data/app/views/bigbluebutton/api/error.rabl +10 -0
  22. data/app/views/bigbluebutton/api/rooms/index.rabl +45 -0
  23. data/app/views/bigbluebutton/api/rooms/join.rabl +6 -0
  24. data/app/views/bigbluebutton/api/rooms/running.rabl +10 -0
  25. data/app/views/bigbluebutton/recordings/play.html.erb +1 -0
  26. data/app/views/bigbluebutton/servers/_activity_list.html.erb +5 -5
  27. data/app/workers/{bigbluebutton_finish_meetings.rb → bigbluebutton_finish_meetings_worker.rb} +2 -2
  28. data/app/workers/{bigbluebutton_meeting_updater.rb → bigbluebutton_meeting_updater_worker.rb} +3 -3
  29. data/app/workers/bigbluebutton_recordings_for_room_worker.rb +27 -0
  30. data/app/workers/{bigbluebutton_update_recordings.rb → bigbluebutton_update_recordings_worker.rb} +2 -2
  31. data/app/workers/{bigbluebutton_update_server_configs.rb → bigbluebutton_update_server_configs_worker.rb} +3 -3
  32. data/bigbluebutton_rails.gemspec +1 -0
  33. data/config/locales/en.yml +21 -0
  34. data/config/locales/pt-br.yml +1 -0
  35. data/config/resque/resque.rake +7 -1
  36. data/config/resque/workers_schedule.yml +3 -3
  37. data/docker-compose.yml +68 -0
  38. data/dumb-init_1.2.0 +0 -0
  39. data/lib/bigbluebutton_rails.rb +1 -2
  40. data/lib/bigbluebutton_rails/api_controller_methods.rb +138 -0
  41. data/lib/bigbluebutton_rails/configuration.rb +33 -4
  42. data/lib/bigbluebutton_rails/controller_methods.rb +0 -31
  43. data/lib/bigbluebutton_rails/exceptions.rb +17 -0
  44. data/lib/bigbluebutton_rails/rails/routes.rb +14 -0
  45. data/lib/bigbluebutton_rails/version.rb +1 -1
  46. data/lib/generators/bigbluebutton_rails/templates/migration.rb +17 -3
  47. data/lib/generators/bigbluebutton_rails/templates/migration_2_2_0.rb +1 -1
  48. data/lib/generators/bigbluebutton_rails/templates/migration_2_2_0_b.rb +106 -0
  49. data/lib/generators/bigbluebutton_rails/templates/migration_2_3_0.rb +22 -0
  50. data/lib/tasks/bigbluebutton_rails/meetings.rake +1 -1
  51. data/spec/controllers/bigbluebutton/api/rooms_controller_spec.rb +498 -0
  52. data/spec/controllers/bigbluebutton/recordings_controller_spec.rb +84 -0
  53. data/spec/controllers/bigbluebutton/rooms_controller_exception_handling_spec.rb +2 -2
  54. data/spec/controllers/bigbluebutton/rooms_controller_spec.rb +24 -22
  55. data/spec/controllers/bigbluebutton/servers_controller_spec.rb +9 -0
  56. data/spec/factories/bigbluebutton_attendee.rb +7 -0
  57. data/spec/factories/bigbluebutton_meeting.rb +0 -1
  58. data/spec/factories/bigbluebutton_playback_type.rb +1 -0
  59. data/spec/factories/bigbluebutton_recording.rb +2 -4
  60. data/spec/helpers/bigbluebutton_rails_helper_spec.rb +10 -2
  61. data/spec/lib/bigbluebutton_rails/background_tasks_spec.rb +1 -0
  62. data/spec/lib/tasks/meetings_rake_spec.rb +1 -1
  63. data/spec/models/bigbluebutton_attendee_spec.rb +44 -0
  64. data/spec/models/bigbluebutton_meeting_db_spec.rb +0 -1
  65. data/spec/models/bigbluebutton_meeting_spec.rb +1 -0
  66. data/spec/models/bigbluebutton_playback_format_spec.rb +2 -0
  67. data/spec/models/bigbluebutton_playback_type_db_spec.rb +1 -0
  68. data/spec/models/bigbluebutton_recording_db_spec.rb +2 -2
  69. data/spec/models/bigbluebutton_recording_spec.rb +404 -72
  70. data/spec/models/bigbluebutton_room_spec.rb +435 -148
  71. data/spec/rails_app/config/database.yml.example +10 -11
  72. data/spec/rails_app/config/initializers/resque.rb +33 -0
  73. data/spec/rails_app/config/routes.rb +2 -0
  74. data/spec/rails_app/lib/tasks/db/populate.rake +73 -55
  75. data/spec/support/mocked_server.rb +1 -1
  76. data/spec/workers/{bigbluebutton_finish_meetings_spec.rb → bigbluebutton_finish_meetings_worker_spec.rb} +3 -3
  77. data/spec/workers/{bigbluebutton_meeting_updater_spec.rb → bigbluebutton_meeting_updater_worker_spec.rb} +8 -7
  78. data/spec/workers/bigbluebutton_recordings_for_room_worker_spec.rb +49 -0
  79. data/spec/workers/{bigbluebutton_update_recordings_spec.rb → bigbluebutton_update_recordings_worker_spec.rb} +3 -3
  80. data/spec/workers/{bigbluebutton_update_server_configs_spec.rb → bigbluebutton_update_server_configs_worker_spec.rb} +4 -4
  81. metadata +42 -14
  82. data/lib/classes/bigbluebutton_attendee.rb +0 -21
  83. data/spec/classes/bigbluebutton_attendee_spec.rb +0 -76
  84. data/spec/controllers/bigbluebutton/recordings_controller_json_responses_spec.rb +0 -111
  85. data/spec/controllers/bigbluebutton/rooms_controller_json_responses_spec.rb +0 -203
  86. data/spec/controllers/bigbluebutton/servers_controller_json_responses_spec.rb +0 -162
@@ -273,6 +273,90 @@ describe Bigbluebutton::RecordingsController do
273
273
  before(:each) { get :play, :id => recording.to_param, :type => format.format_type }
274
274
  it { should assign_to(:recording).with(other_recording) }
275
275
  end
276
+
277
+ context "authenticates" do
278
+ let!(:format) { FactoryGirl.create(:bigbluebutton_playback_format, :recording => recording) }
279
+
280
+ before { @previous = BigbluebuttonRails.configuration.playback_url_authentication }
281
+ after { BigbluebuttonRails.configuration.playback_url_authentication = @previous }
282
+
283
+ context "if authentication is enabled" do
284
+ before {
285
+ BigbluebuttonRails.configuration.playback_url_authentication = true
286
+ controller.should_receive(:bigbluebutton_user).and_return('fake-user')
287
+ BigbluebuttonRecording.any_instance.should_receive(:token_url)
288
+ .with('fake-user', request.remote_ip, format)
289
+ .and_return('tokenized-url')
290
+ }
291
+ before(:each) { get :play, :id => recording.to_param, :type => format.format_type }
292
+ it { should respond_with(:redirect) }
293
+ it { should redirect_to 'tokenized-url' }
294
+ it { should assign_to(:playback_url).with('tokenized-url') }
295
+ end
296
+
297
+ context "if authentication is not enabled" do
298
+ before {
299
+ BigbluebuttonRails.configuration.playback_url_authentication = false
300
+ BigbluebuttonRecording.any_instance.should_not_receive(:token_url)
301
+ }
302
+ before(:each) { get :play, :id => recording.to_param, :type => format.format_type }
303
+ it { should respond_with(:redirect) }
304
+ it { should redirect_to format.url }
305
+ it { should assign_to(:playback_url).with(format.url) }
306
+ end
307
+ end
308
+
309
+ context "uses an iframe" do
310
+ let!(:format) { FactoryGirl.create(:bigbluebutton_playback_format, :recording => recording) }
311
+
312
+ before { @previous = BigbluebuttonRails.configuration.playback_iframe }
313
+ after { BigbluebuttonRails.configuration.playback_iframe = @previous }
314
+
315
+ context "if the iframe option is on" do
316
+ before { BigbluebuttonRails.configuration.playback_iframe = true }
317
+
318
+ context "and it is downloadable" do
319
+ before {
320
+ format.playback_type.update_attributes(downloadable: true)
321
+ get :play, :id => recording.to_param, :type => format.format_type
322
+ }
323
+ it { should respond_with(:redirect) }
324
+ it { should redirect_to format.url }
325
+ end
326
+
327
+ context "and it is not downloadable" do
328
+ before {
329
+ format.playback_type.update_attributes(downloadable: false)
330
+ get :play, :id => recording.to_param, :type => format.format_type
331
+ }
332
+ it { should respond_with(:success) }
333
+ it { should render_template(:play) }
334
+ it { should_not render_with_layout }
335
+ end
336
+ end
337
+
338
+ context "if the iframe option is off" do
339
+ before { BigbluebuttonRails.configuration.playback_iframe = false }
340
+
341
+ context "and it is downloadable" do
342
+ before {
343
+ format.playback_type.update_attributes(downloadable: true)
344
+ get :play, :id => recording.to_param, :type => format.format_type
345
+ }
346
+ it { should respond_with(:redirect) }
347
+ it { should redirect_to format.url }
348
+ end
349
+
350
+ context "and it is not downloadable" do
351
+ before {
352
+ format.playback_type.update_attributes(downloadable: false)
353
+ get :play, :id => recording.to_param, :type => format.format_type
354
+ }
355
+ it { should respond_with(:redirect) }
356
+ it { should redirect_to format.url }
357
+ end
358
+ end
359
+ end
276
360
  end
277
361
 
278
362
  # these actions are essentially the same
@@ -10,7 +10,7 @@ describe Bigbluebutton::RoomsController do
10
10
  let(:http_referer) { bigbluebutton_server_path(mocked_server) }
11
11
  let(:room) { FactoryGirl.create(:bigbluebutton_room) }
12
12
  before {
13
- BigbluebuttonRoom.stub(:find_by_param) { room }
13
+ BigbluebuttonRoom.stub(:find_by) { room }
14
14
  BigbluebuttonRoom.stub(:find) { room }
15
15
  mock_server_and_api
16
16
  request.env["HTTP_REFERER"] = http_referer
@@ -69,7 +69,7 @@ describe Bigbluebutton::RoomsController do
69
69
  before {
70
70
  controller.should_receive(:bigbluebutton_role).with(room).and_return(:moderator)
71
71
  room.stub(:select_server).and_return(mocked_server)
72
- BigbluebuttonRoom.stub(:find_by_param).and_return(room)
72
+ BigbluebuttonRoom.stub(:find_by).and_return(room)
73
73
  }
74
74
 
75
75
  it "catches exception on the first is_meeting_running" do
@@ -307,7 +307,7 @@ describe Bigbluebutton::RoomsController do
307
307
  it {
308
308
  # we just check that the rails method 'permit' is being called on the hash with the
309
309
  # correct parameters
310
- BigbluebuttonRoom.stub(:find_by_param).and_return(room)
310
+ BigbluebuttonRoom.stub(:find_by).and_return(room)
311
311
  room.stub(:update_attributes).and_return(true)
312
312
  attrs.stub(:permit).and_return(attrs)
313
313
  controller.stub(:params).and_return(params)
@@ -476,7 +476,7 @@ describe Bigbluebutton::RoomsController do
476
476
  context "if params[:id] doesn't exists" do
477
477
  let(:message) { I18n.t('bigbluebutton_rails.rooms.errors.join.wrong_params') }
478
478
  before(:each) {
479
- BigbluebuttonRoom.stub(:find_by_param).and_return(nil)
479
+ BigbluebuttonRoom.stub(:find_by).and_return(nil)
480
480
  send(method, :join, :id => "inexistent-room-id", :user => user_hash)
481
481
  }
482
482
  it { should assign_to(:room).with(nil) }
@@ -801,6 +801,15 @@ describe Bigbluebutton::RoomsController do
801
801
  it { should set_the_flash.to(I18n.t('bigbluebutton_rails.rooms.notice.fetch_recordings.success')) }
802
802
  end
803
803
 
804
+ context "responds to :json" do
805
+ before(:each) {
806
+ mocked_server.should_receive(:fetch_recordings).with(filter)
807
+ post :fetch_recordings, :id => room.to_param, :format => :json
808
+ }
809
+ it { should respond_with(:success) }
810
+ it { should respond_with_content_type('application/json') }
811
+ end
812
+
804
813
  context "on BigBlueButtonException" do
805
814
  let(:bbb_error_msg) { SecureRandom.hex(250) }
806
815
  let(:bbb_error) { BigBlueButton::BigBlueButtonException.new(bbb_error_msg) }
@@ -930,7 +939,7 @@ describe Bigbluebutton::RoomsController do
930
939
  # uses any action that triggers this before filter
931
940
  context "when @room is valid" do
932
941
  before {
933
- BigbluebuttonRoom.stub(:find_by_param).and_return(room)
942
+ BigbluebuttonRoom.stub(:find_by).and_return(room)
934
943
  room.should_receive(:fetch_is_running?).and_return(false)
935
944
  }
936
945
  it {
@@ -969,28 +978,22 @@ describe Bigbluebutton::RoomsController do
969
978
  request.env["HTTP_REFERER"] = http_referer
970
979
  controller.stub(:bigbluebutton_user).and_return(user)
971
980
  controller.stub(:bigbluebutton_role).and_return(:attendee)
972
- BigbluebuttonRoom.stub(:find_by_param).and_return(room)
981
+ BigbluebuttonRoom.stub(:find_by).and_return(room)
973
982
  controller.send(:find_room)
974
983
  }
975
984
 
976
985
  context "when the user has permission to create the meeting" do
977
-
978
- context "in the standard case" do
979
- before {
980
- room.should_receive(:fetch_is_running?).at_least(:once).and_return(false)
981
- controller.stub(:bigbluebutton_can_create?).with(room, :attendee)
982
- .and_return(true)
983
- controller.stub(:bigbluebutton_create_options).with(room)
984
- .and_return({ custom: true })
985
- room.should_receive(:create_meeting)
986
- .with(user, controller.request, { custom: true }).and_return(true)
987
- room.should_receive(:fetch_new_token).and_return(nil)
988
- room.should_receive(:join_url).and_return("http://test.com/join/url/")
989
- }
990
- before(:each) { get :join, :id => room.to_param }
991
- it { should respond_with(:redirect) }
992
- it { should redirect_to("http://test.com/join/url/") }
993
- end
986
+ before {
987
+ room.should_receive(:fetch_is_running?).at_least(:once).and_return(false)
988
+ controller.stub(:bigbluebutton_can_create?).with(room, :attendee).and_return(true)
989
+ room.should_receive(:create_meeting)
990
+ .with(user, controller.request).and_return(true)
991
+ room.should_receive(:fetch_new_token).and_return(nil)
992
+ room.should_receive(:join_url).and_return("http://test.com/join/url/")
993
+ }
994
+ before(:each) { get :join, :id => room.to_param }
995
+ it { should respond_with(:redirect) }
996
+ it { should redirect_to("http://test.com/join/url/") }
994
997
  end
995
998
 
996
999
  context "when the user doesn't have permission to create the meeting" do
@@ -1194,7 +1197,6 @@ describe Bigbluebutton::RoomsController do
1194
1197
  context "doesn't break if a guest user has permission to create a meeting" do
1195
1198
  before {
1196
1199
  room.stub(:fetch_is_running?).and_return(false)
1197
- controller.stub(:bigbluebutton_create_options).and_return({ custom: true })
1198
1200
  controller.stub(:bigbluebutton_can_create?).and_return(true)
1199
1201
  room.stub(:create_meeting).and_return(true)
1200
1202
  controller.stub(:bigbluebutton_user).and_return(nil)
@@ -469,6 +469,15 @@ describe Bigbluebutton::ServersController do
469
469
  it { should set_the_flash.to(I18n.t('bigbluebutton_rails.servers.notice.fetch_recordings.success')) }
470
470
  end
471
471
 
472
+ context "responds to :json" do
473
+ before(:each) {
474
+ server.should_receive(:fetch_recordings).with({})
475
+ post :fetch_recordings, :id => server.to_param, :format => :json
476
+ }
477
+ it { should respond_with(:success) }
478
+ it { should respond_with_content_type('application/json') }
479
+ end
480
+
472
481
  context "on failure" do
473
482
  let(:bbb_error_msg) { SecureRandom.hex(250) }
474
483
  let(:bbb_error) { BigBlueButton::BigBlueButtonException.new(bbb_error_msg) }
@@ -0,0 +1,7 @@
1
+ FactoryGirl.define do
2
+ factory :bigbluebutton_attendee do |a|
3
+ a.sequence(:user_id) { |n| "userid-#{n}" }
4
+ a.sequence(:user_name) { |n| "User Full Name #{n}" }
5
+ a.association :meeting, :factory => :bigbluebutton_meeting
6
+ end
7
+ end
@@ -6,7 +6,6 @@ FactoryGirl.define do
6
6
  m.recorded false
7
7
  m.running false
8
8
  m.ended false
9
- m.start_time { Time.at(Time.now.to_i + rand(999999)) }
10
9
  m.create_time { Time.now.to_i + rand(999999) }
11
10
  # m.creator_id
12
11
  # m.creator_name
@@ -3,5 +3,6 @@ FactoryGirl.define do
3
3
  pbt.sequence(:identifier) { |n| "#{Forgery(:name).first_name.downcase}-#{n}" }
4
4
  pbt.visible true
5
5
  pbt.default false
6
+ pbt.downloadable false
6
7
  end
7
8
  end
@@ -6,8 +6,8 @@ FactoryGirl.define do
6
6
  r.meetingid { "meeting" + SecureRandom.hex(8) }
7
7
  r.sequence(:name) { |n| "Rec #{n}" }
8
8
  r.published true
9
- r.start_time { Time.now - rand(5).hours }
10
- r.end_time { Time.now + rand(5).hours }
9
+ r.start_time { Time.now.to_i - rand(5).hours }
10
+ r.end_time { Time.now.to_i + rand(5).hours }
11
11
  # TODO: should contain the meeting's start_time at the end
12
12
  r.sequence(:recordid) { |n| "rec#{n}-#{SecureRandom.uuid}-#{DateTime.now.to_i}" }
13
13
  r.size { rand((20*1024**2)..(500*1024**2)) } # size ranging from 20Mb to 500Mb
@@ -17,8 +17,6 @@ FactoryGirl.define do
17
17
  after(:create) do |r|
18
18
  r.updated_at = r.updated_at.change(:usec => 0)
19
19
  r.created_at = r.created_at.change(:usec => 0)
20
- r.start_time = r.start_time.change(:usec => 0)
21
- r.end_time = r.end_time.change(:usec => 0)
22
20
  end
23
21
  end
24
22
  end
@@ -14,6 +14,14 @@ describe BigbluebuttonRailsHelper do
14
14
  it("uses UTF-8") { should match /choe=UTF-8/ }
15
15
  end
16
16
 
17
- end
18
-
17
+ describe "#api_typeof" do
18
+ it { api_type_of(FactoryGirl.create(:bigbluebutton_room)).should eql('room') }
19
+ it { api_type_of(FactoryGirl.create(:bigbluebutton_server)).should eql('server') }
20
+ it { api_type_of(FactoryGirl.create(:bigbluebutton_recording)).should eql('recording') }
19
21
 
22
+ context "for a new class" do
23
+ class MyUserClass; end
24
+ it { api_type_of(MyUserClass.new).should eql('my-user-class') }
25
+ end
26
+ end
27
+ end
@@ -4,6 +4,7 @@ describe BigbluebuttonRails::BackgroundTasks do
4
4
 
5
5
  describe ".finish_meetings" do
6
6
  let!(:api) { double(BigBlueButton::BigBlueButtonApi) }
7
+ let!(:server) { FactoryGirl.create(:bigbluebutton_server) }
7
8
 
8
9
  context "set meetings that ended as not running and ended" do
9
10
  let(:room) { FactoryGirl.create(:bigbluebutton_room) }
@@ -15,4 +15,4 @@ describe "bigbluebutton_rails:meetings:finish" do
15
15
  subject.invoke
16
16
  BigbluebuttonRails::BackgroundTasks.should have_received(:finish_meetings)
17
17
  end
18
- end
18
+ end
@@ -0,0 +1,44 @@
1
+ # coding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe BigbluebuttonAttendee do
5
+ it "loaded correctly" do
6
+ BigbluebuttonAttendee.new.should be_a_kind_of(ActiveRecord::Base)
7
+ end
8
+
9
+ before { FactoryGirl.create(:bigbluebutton_attendee) }
10
+
11
+ context "gets params from hash" do
12
+ let(:hash) { {:userID=>"user_id", :fullName=>"House M.D.", :role=>"MODERATOR"} }
13
+ let(:attendee) { BigbluebuttonAttendee.new }
14
+
15
+ it "standard case" do
16
+ attendee.from_hash(hash)
17
+ attendee.user_id.should == "user_id"
18
+ attendee.user_name.should == "House M.D."
19
+ attendee.role.should == :moderator
20
+ end
21
+
22
+ it "converts user_id to string" do
23
+ hash[:userID] = 123
24
+ attendee.from_hash(hash)
25
+ attendee.user_id.should == "123"
26
+ end
27
+
28
+ it "role is not case sensitive" do
29
+ hash[:role] = "mODErAtOR"
30
+ attendee.from_hash(hash)
31
+ attendee.role.should == :moderator
32
+ end
33
+
34
+ it "any role other than 'moderator' is attendee" do
35
+ hash[:role] = "VIEWER"
36
+ attendee.from_hash(hash)
37
+ attendee.role.should == :attendee
38
+
39
+ hash[:role] = "whatever"
40
+ attendee.from_hash(hash)
41
+ attendee.role.should == :attendee
42
+ end
43
+ end
44
+ end
@@ -7,7 +7,6 @@ describe BigbluebuttonMeeting do
7
7
  it { should have_db_column(:room_id).of_type(:integer) }
8
8
  it { should have_db_column(:meetingid).of_type(:string) }
9
9
  it { should have_db_column(:name).of_type(:string) }
10
- it { should have_db_column(:start_time).of_type(:datetime) }
11
10
  it { should have_db_column(:running).of_type(:boolean) }
12
11
  it { should have_db_column(:recorded).of_type(:boolean) }
13
12
  it { should have_db_column(:creator_id).of_type(:integer) }
@@ -19,6 +19,7 @@ describe BigbluebuttonMeeting do
19
19
  it { should validate_presence_of(:create_time) }
20
20
  it { should validate_uniqueness_of(:create_time).scoped_to(:room_id) }
21
21
 
22
+
22
23
  describe "#created_by?" do
23
24
  let(:target) { FactoryGirl.create(:bigbluebutton_meeting) }
24
25
 
@@ -22,6 +22,8 @@ describe BigbluebuttonPlaybackFormat do
22
22
  it { should delegate_method(:default).to(:playback_type) }
23
23
  it { should delegate_method(:default?).to(:playback_type) }
24
24
  it { should delegate_method(:description).to(:playback_type) }
25
+ it { should delegate_method(:downloadable).to(:playback_type) }
26
+ it { should delegate_method(:downloadable?).to(:playback_type) }
25
27
 
26
28
  context "allows nil for delegates to playback_type" do
27
29
  let(:target) { FactoryGirl.create(:bigbluebutton_playback_format, playback_type: nil) }
@@ -9,6 +9,7 @@ describe BigbluebuttonPlaybackType do
9
9
  it { should have_db_column(:default).of_type(:boolean) }
10
10
  it { should have_db_column(:created_at).of_type(:datetime) }
11
11
  it { should have_db_column(:updated_at).of_type(:datetime) }
12
+ it { should have_db_column(:downloadable).of_type(:boolean) }
12
13
  end
13
14
 
14
15
  end
@@ -10,8 +10,8 @@ describe BigbluebuttonRecording do
10
10
  it { should have_db_column(:meetingid).of_type(:string) }
11
11
  it { should have_db_column(:name).of_type(:string) }
12
12
  it { should have_db_column(:published).of_type(:boolean) }
13
- it { should have_db_column(:start_time).of_type(:datetime) }
14
- it { should have_db_column(:end_time).of_type(:datetime) }
13
+ it { should have_db_column(:start_time).of_type(:integer) }
14
+ it { should have_db_column(:end_time).of_type(:integer) }
15
15
  it { should have_db_column(:available).of_type(:boolean) }
16
16
  it { should have_db_column(:description).of_type(:string) }
17
17
  it { should have_db_column(:created_at).of_type(:datetime) }
@@ -48,6 +48,43 @@ describe BigbluebuttonRecording do
48
48
  }
49
49
  end
50
50
 
51
+ describe "#get_token" do
52
+ it { should respond_to(:get_token) }
53
+
54
+ let!(:recording) { FactoryGirl.create(:bigbluebutton_recording) }
55
+ let!(:type_default) { FactoryGirl.create(:bigbluebutton_playback_type, default: true) }
56
+ let!(:server) { FactoryGirl.create(:bigbluebutton_server) }
57
+ let(:user) { FactoryGirl.build(:user) }
58
+ let(:user_ip) { "10.0.0.1" }
59
+ let(:api) { double(BigBlueButton::BigBlueButtonApi) }
60
+
61
+ before do
62
+ BigbluebuttonServer.any_instance.stub(:api).and_return(api)
63
+ api.stub(:send_api_request).and_return({:returncode=>true, :token=>"RECORDING_TOKEN", :messageKey=>"", :message=>""})
64
+ end
65
+
66
+ it { recording.get_token(user, user_ip).should include("RECORDING_TOKEN") }
67
+ end
68
+
69
+ describe "#token_url" do
70
+ it { should respond_to(:token_url) }
71
+
72
+ let!(:recording) { FactoryGirl.create(:bigbluebutton_recording) }
73
+ let!(:type_default) { FactoryGirl.create(:bigbluebutton_playback_type, default: true) }
74
+ let!(:server) { FactoryGirl.create(:bigbluebutton_server) }
75
+ let(:user) { FactoryGirl.build(:user) }
76
+ let(:user_ip) { "10.0.0.1" }
77
+ let!(:format) { FactoryGirl.create(:bigbluebutton_playback_format, recording: recording, playback_type: type_default) }
78
+ let(:api) { double(BigBlueButton::BigBlueButtonApi) }
79
+
80
+ before do
81
+ BigbluebuttonServer.any_instance.stub(:api).and_return(api)
82
+ api.stub(:send_api_request).and_return({:returncode=>true, :token=>"RECORDING_TOKEN", :messageKey=>"", :message=>""})
83
+ end
84
+
85
+ it { recording.token_url(user, user_ip, format).should include("?token=RECORDING_TOKEN") }
86
+ end
87
+
51
88
  describe "#default_playback_format" do
52
89
  let!(:recording) { FactoryGirl.create(:bigbluebutton_recording) }
53
90
  let!(:type_default) { FactoryGirl.create(:bigbluebutton_playback_type, default: true) }
@@ -66,6 +103,26 @@ describe BigbluebuttonRecording do
66
103
  end
67
104
  end
68
105
 
106
+ describe "#delete_from_server" do
107
+ let!(:recording) { FactoryGirl.create(:bigbluebutton_recording) }
108
+
109
+ context "when there's a server associated" do
110
+ let!(:server) { FactoryGirl.create(:bigbluebutton_server) }
111
+ before {
112
+ recording.update_attributes(server: server)
113
+ server.should_receive(:send_delete_recordings).with(recording.recordid).and_return('response')
114
+ }
115
+ it { recording.delete_from_server!.should eql('response') }
116
+ end
117
+
118
+ context "when there's no server associated" do
119
+ before {
120
+ recording.update_attributes(server: nil)
121
+ }
122
+ it { recording.delete_from_server!.should be(false) }
123
+ end
124
+ end
125
+
69
126
  describe ".overall_average_length" do
70
127
  context "when there's no recording" do
71
128
  it { BigbluebuttonRecording.overall_average_length.should eql(0) }
@@ -98,36 +155,221 @@ describe BigbluebuttonRecording do
98
155
  end
99
156
  end
100
157
 
158
+ describe ".recording_changed?" do
159
+ let!(:data) {
160
+ {
161
+ recordid: "recording-1",
162
+ meetingid: "meetingid-1",
163
+ name: "Evening Class1",
164
+ published: true,
165
+ start_time: DateTime.now,
166
+ end_time: DateTime.now + 2.hours,
167
+ size: "100",
168
+ metadata: {
169
+ course: "Fundamentals of JAVA",
170
+ description: "List of recordings",
171
+ activity: "Evening Class1"
172
+ },
173
+ playback: { format:
174
+ [
175
+ { type: "slides",
176
+ url: "http://test-install.blindsidenetworks.com/playback/slides/playback.html?meetingId=125468758b24fa27551e7a065849dda3ce65dd32-1329872486268",
177
+ length: 64
178
+ },
179
+ { type: "presentation",
180
+ url: "http://test-install.blindsidenetworks.com/presentation/slides/playback.html?meetingId=125468758b24fa27551e7a065849dda3ce65dd32-1329872486268",
181
+ length: 64
182
+ }
183
+ ]
184
+ }
185
+ }
186
+ }
187
+ let!(:recording) {
188
+ attrs = {
189
+ recordid: data[:recordid],
190
+ meetingid: data[:meetingid],
191
+ name: data[:name],
192
+ published: data[:published],
193
+ start_time: data[:start_time],
194
+ end_time: data[:end_time],
195
+ size: data[:size]
196
+ }
197
+ r = FactoryGirl.create(:bigbluebutton_recording, attrs)
198
+ data[:metadata].each do |k, v|
199
+ BigbluebuttonMetadata.create(owner: r, name: k, content: v)
200
+ end
201
+ data[:playback][:format].each do |format|
202
+ type = BigbluebuttonPlaybackType.create(visible: true, identifier: format[:type])
203
+ BigbluebuttonPlaybackFormat.create(recording: r, url: format[:url], length: format[:length], playback_type: type)
204
+ end
205
+ r
206
+ }
207
+
208
+ it "returns false when they didn't changed" do
209
+ BigbluebuttonRecording.recording_changed?(recording, data).should be(false)
210
+ end
211
+
212
+ context "returns true when an attribute changed" do
213
+ it "in the data" do
214
+ data[:published] = !data[:published]
215
+ BigbluebuttonRecording.recording_changed?(recording, data).should be(true)
216
+ end
217
+
218
+ it "in the database" do
219
+ recording.update(published: !recording.published)
220
+ BigbluebuttonRecording.recording_changed?(recording, data).should be(true)
221
+ end
222
+ end
223
+
224
+ context "returns true when a metadata" do
225
+ context "changed" do
226
+ it "in the data" do
227
+ data[:metadata][:course] = data[:metadata][:course] + "-changed"
228
+ BigbluebuttonRecording.recording_changed?(recording, data).should be(true)
229
+ end
230
+
231
+ it "in the database" do
232
+ recording.metadata.first.update(content: recording.metadata.first.content + "-changed")
233
+ BigbluebuttonRecording.recording_changed?(recording, data).should be(true)
234
+ end
235
+ end
236
+
237
+ context "was added" do
238
+ it "in the data" do
239
+ data[:metadata][:new_one] = "anything"
240
+ BigbluebuttonRecording.recording_changed?(recording, data).should be(true)
241
+ end
242
+
243
+ it "in the database" do
244
+ BigbluebuttonMetadata.create(owner: recording, name: "new", content: "anything")
245
+ BigbluebuttonRecording.recording_changed?(recording, data).should be(true)
246
+ end
247
+ end
248
+
249
+ context "was removed" do
250
+ it "in the data" do
251
+ data[:metadata].delete(:course)
252
+ BigbluebuttonRecording.recording_changed?(recording, data).should be(true)
253
+ end
254
+
255
+ it "in the database" do
256
+ recording.metadata.first.destroy
257
+ BigbluebuttonRecording.recording_changed?(recording, data).should be(true)
258
+ end
259
+ end
260
+ end
261
+
262
+ context "returns true when a playback format" do
263
+ context "changed" do
264
+ it "in the data" do
265
+ data[:playback][:format][0][:url] = data[:playback][:format][0][:url] + "/changed"
266
+ BigbluebuttonRecording.recording_changed?(recording, data).should be(true)
267
+ end
268
+
269
+ it "in the database" do
270
+ recording.playback_formats.first.update(url: recording.playback_formats.first.url + "/changed")
271
+ BigbluebuttonRecording.recording_changed?(recording, data).should be(true)
272
+ end
273
+ end
274
+
275
+ context "was added" do
276
+ it "in the data" do
277
+ data[:playback][:format] << {
278
+ type: "new-format",
279
+ url: "http://anything.here",
280
+ length: 64
281
+ }
282
+ BigbluebuttonRecording.recording_changed?(recording, data).should be(true)
283
+ end
284
+
285
+ it "in the database" do
286
+ type = BigbluebuttonPlaybackType.create(visible: true, identifier: "new-format-db")
287
+ BigbluebuttonPlaybackFormat.create(recording: recording, url: "anything", length: 12, playback_type: type)
288
+ BigbluebuttonRecording.recording_changed?(recording, data).should be(true)
289
+ end
290
+ end
291
+
292
+ context "was removed" do
293
+ it "in the data" do
294
+ data[:playback][:format] = data[:playback][:format].drop(1)
295
+ BigbluebuttonRecording.recording_changed?(recording, data).should be(true)
296
+ end
297
+
298
+ it "in the database" do
299
+ recording.playback_formats.first.destroy
300
+ BigbluebuttonRecording.recording_changed?(recording, data).should be(true)
301
+ end
302
+ end
303
+ end
304
+
305
+ context "ignores ignored keys" do
306
+ it "in the data" do
307
+ data[:random] = "anything"
308
+ BigbluebuttonRecording.recording_changed?(recording, data).should be(false)
309
+ end
310
+
311
+ it "in the database" do
312
+ recording.available = !recording.available
313
+ BigbluebuttonRecording.recording_changed?(recording, data).should be(false)
314
+ end
315
+ end
316
+
317
+ it "ignores the ordering of the elements in the inputs" do
318
+ data[:playback][:format] = data[:playback][:format].reverse
319
+ BigbluebuttonRecording.recording_changed?(recording, data).should be(false)
320
+ end
321
+
322
+ context "works when there are no formats" do
323
+ it "in the data" do
324
+ data[:playback].delete(:format)
325
+ BigbluebuttonRecording.recording_changed?(recording, data).should be(true)
326
+ end
327
+
328
+ it "in the database" do
329
+ BigbluebuttonPlaybackFormat.delete_all
330
+ BigbluebuttonRecording.recording_changed?(recording, data).should be(true)
331
+ end
332
+ end
333
+
334
+ context "works when there is no metadata" do
335
+ it "in the data" do
336
+ data.delete(:metadata)
337
+ BigbluebuttonRecording.recording_changed?(recording, data).should be(true)
338
+ end
339
+
340
+ it "in the database" do
341
+ BigbluebuttonMetadata.delete_all
342
+ BigbluebuttonRecording.recording_changed?(recording, data).should be(true)
343
+ end
344
+ end
345
+ end
346
+
101
347
  describe ".sync" do
102
348
  let(:data) {
103
- [
104
- {
105
- :recordID => "recording-1",
106
- :meetingID => "meetingid-1",
107
- :name => "Evening Class1",
108
- :published => true,
109
- :startTime => DateTime.now,
110
- :endTime => DateTime.now + 2.hours,
111
- :size => 100,
112
- :metadata => {
113
- :course => "Fundamentals of JAVA",
114
- :description => "List of recordings",
115
- :activity => "Evening Class1"
116
- },
117
- :playback => { :format =>
118
- [
119
- { :type => "slides",
120
- :url => "http://test-install.blindsidenetworks.com/playback/slides/playback.html?meetingId=125468758b24fa27551e7a065849dda3ce65dd32-1329872486268",
121
- :length => 64
122
- },
123
- { :type => "presentation",
124
- :url => "http://test-install.blindsidenetworks.com/presentation/slides/playback.html?meetingId=125468758b24fa27551e7a065849dda3ce65dd32-1329872486268",
125
- :length => 64
126
- }
127
- ]
128
- }
129
- }
130
- ]
349
+ [{
350
+ recordID: "recording-1",
351
+ meetingID: "meetingid-1",
352
+ name: "Evening Class1",
353
+ published: true,
354
+ startTime: DateTime.now,
355
+ endTime: DateTime.now + 2.hours,
356
+ size: 100,
357
+ metadata: {
358
+ course: "Fundamentals of JAVA",
359
+ description: "List of recordings",
360
+ activity: "Evening Class1"
361
+ },
362
+ playback: { format:
363
+ [{ type: "slides",
364
+ url: "http://test-install.blindsidenetworks.com/playback/slides/playback.html?meetingId=125468758b24fa27551e7a065849dda3ce65dd32-1329872486268",
365
+ length: 64
366
+ },
367
+ { type: "presentation",
368
+ url: "http://test-install.blindsidenetworks.com/presentation/slides/playback.html?meetingId=125468758b24fa27551e7a065849dda3ce65dd32-1329872486268",
369
+ length: 64
370
+ }]
371
+ }
372
+ }]
131
373
  }
132
374
  let(:new_server) { FactoryGirl.create(:bigbluebutton_server) }
133
375
  before {
@@ -144,8 +386,8 @@ describe BigbluebuttonRecording do
144
386
  it { @recording.meetingid.should == data[0][:meetingID] }
145
387
  it { @recording.name.should == data[0][:name] }
146
388
  it { @recording.published.should == data[0][:published] }
147
- it { @recording.end_time.utc.to_i.should == data[0][:endTime].utc.to_i }
148
- it { @recording.start_time.utc.to_i.should == data[0][:startTime].utc.to_i }
389
+ it { @recording.end_time.to_i.should == data[0][:endTime].to_i }
390
+ it { @recording.start_time.to_i.should == data[0][:startTime].to_i }
149
391
  it { @recording.server.should == new_server }
150
392
  it { @recording.room.should == @room }
151
393
  it { @recording.available.should == true }
@@ -176,8 +418,8 @@ describe BigbluebuttonRecording do
176
418
  it { @recording.meetingid.should == data[0][:meetingID] }
177
419
  it { @recording.name.should == data[0][:name] }
178
420
  it { @recording.published.should == data[0][:published] }
179
- it { @recording.end_time.utc.to_i.should == data[0][:endTime].utc.to_i }
180
- it { @recording.start_time.utc.to_i.should == data[0][:startTime].utc.to_i }
421
+ it { @recording.end_time.to_i.should == data[0][:endTime].to_i }
422
+ it { @recording.start_time.to_i.should == data[0][:startTime].to_i }
181
423
  it { @recording.server.should == new_server }
182
424
  it { @recording.room.should == @room }
183
425
  it { @recording.available.should == true }
@@ -293,6 +535,40 @@ describe BigbluebuttonRecording do
293
535
  it { BigbluebuttonMetadata.count.should == 3 }
294
536
  it { BigbluebuttonPlaybackFormat.count.should == 2 }
295
537
  end
538
+
539
+ context "when there are unused playback types on the database" do
540
+ before {
541
+ FactoryGirl.create(:bigbluebutton_playback_type, :identifier => "to-be-removed")
542
+ FactoryGirl.create(:bigbluebutton_playback_type, :identifier => "another")
543
+ BigbluebuttonRecording.sync(new_server, data)
544
+ }
545
+ it { BigbluebuttonPlaybackType.count.should == 2 }
546
+ it { BigbluebuttonPlaybackType.find_by(identifier: "slides").should_not be_nil }
547
+ it { BigbluebuttonPlaybackType.find_by(identifier: "presentation").should_not be_nil }
548
+ end
549
+
550
+ it "doesn't update if the recording didn't change" do
551
+ # once to create the recording
552
+ now = DateTime.now
553
+ expected = now - 1.month
554
+ Timecop.freeze(expected)
555
+ rec_data = data.clone
556
+
557
+ BigbluebuttonRecording.sync(new_server, rec_data)
558
+
559
+ # set an expected updated_at
560
+ rec = BigbluebuttonRecording.first
561
+ puts "before #{rec.updated_at} (#{DateTime.now})"
562
+ # rec.send(:write_attribute, :updated_at, expected)
563
+
564
+ # shouldn't change it
565
+ Timecop.freeze(now)
566
+ BigbluebuttonRecording.sync(new_server, rec_data)
567
+ puts "after #{rec.reload.updated_at} (#{DateTime.now})"
568
+ rec.reload.updated_at.to_i.should eql(expected.to_i)
569
+
570
+ Timecop.return
571
+ end
296
572
  end
297
573
 
298
574
  describe ".update_recording" do
@@ -309,6 +585,7 @@ describe BigbluebuttonRecording do
309
585
  :end_time => attrs[:end_time],
310
586
  :size => attrs[:size],
311
587
  :metadata => { :any => "any" },
588
+ :recordingUsers => { :user => [{ :externalUserID => 1 }, { :externalUserID => 2 }] },
312
589
  :playback => { :format => [ { :type => "any1" }, { :type => "any2" } ] }
313
590
  }
314
591
  }
@@ -325,11 +602,12 @@ describe BigbluebuttonRecording do
325
602
  it { recording.meetingid.should == attrs[:meetingid] }
326
603
  it { recording.name.should == attrs[:name] }
327
604
  it { recording.published.should == !old_attrs[:published] }
328
- it { recording.end_time.utc.to_i.should == attrs[:end_time].utc.to_i }
329
- it { recording.start_time.utc.to_i.should == attrs[:start_time].utc.to_i }
605
+ it { recording.end_time.to_i.should == attrs[:end_time].to_i }
606
+ it { recording.start_time.to_i.should == attrs[:start_time].to_i }
330
607
  it { recording.size.should == attrs[:size] }
331
608
  it { recording.server.should == new_server }
332
609
  it { recording.room.should == @room }
610
+ it { recording.recording_users.should eql([1, 2]) }
333
611
  end
334
612
 
335
613
  context "works if the recording returned has no :size attribute" do
@@ -340,11 +618,19 @@ describe BigbluebuttonRecording do
340
618
  }
341
619
  it { recording.size.should == 0 }
342
620
  end
621
+
622
+ context "works if the recording returned has no :recordingUsers attribute" do
623
+ before {
624
+ data.delete(:recordingUsers)
625
+ BigbluebuttonRecording.send(:update_recording, new_server, recording, data)
626
+ }
627
+ it { recording.recording_users.should == [] }
628
+ end
343
629
  end
344
630
 
345
631
  describe ".create_recording" do
346
- let(:meeting_start_time) { DateTime.now }
347
- let(:recordid) { "#{SecureRandom.uuid}-#{meeting_start_time.to_i}" }
632
+ let(:meeting_create_time) { DateTime.now.utc.to_i }
633
+ let(:recordid) { "#{SecureRandom.uuid}-#{meeting_create_time.to_i}" }
348
634
  let(:attrs) { FactoryGirl.attributes_for(:bigbluebutton_recording) }
349
635
  let(:data) {
350
636
  {
@@ -352,9 +638,10 @@ describe BigbluebuttonRecording do
352
638
  :meetingid => attrs[:meetingid],
353
639
  :name => attrs[:name],
354
640
  :published => attrs[:published],
355
- :start_time => attrs[:start_time],
641
+ :start_time => meeting_create_time,
356
642
  :end_time => attrs[:end_time],
357
643
  :metadata => { :any => "any" },
644
+ :recordingUsers => { :user => [{ :externalUserID => 3 }, { :externalUserID => 4 }] },
358
645
  :playback => { :format => [ { :type => "any1" }, { :type => "any2" } ] }
359
646
  }
360
647
  }
@@ -362,7 +649,7 @@ describe BigbluebuttonRecording do
362
649
 
363
650
  before {
364
651
  @room = FactoryGirl.create(:bigbluebutton_room, :meetingid => attrs[:meetingid])
365
- @meeting = FactoryGirl.create(:bigbluebutton_meeting, :room => @room, :start_time => meeting_start_time.utc)
652
+ @meeting = FactoryGirl.create(:bigbluebutton_meeting, :room => @room, :create_time => meeting_create_time, :meetingid => attrs[:meetingid])
366
653
 
367
654
  BigbluebuttonRecording.should_receive(:sync_additional_data)
368
655
  .with(anything, data)
@@ -373,15 +660,16 @@ describe BigbluebuttonRecording do
373
660
  it("sets meetingid") { @recording.meetingid.should == attrs[:meetingid] }
374
661
  it("sets name") { @recording.name.should == attrs[:name] }
375
662
  it("sets published") { @recording.published.should == attrs[:published] }
376
- it("sets end_time") { @recording.end_time.utc.to_i.should == attrs[:end_time].utc.to_i }
377
- it("sets start_time") { @recording.start_time.utc.to_i.should == attrs[:start_time].utc.to_i }
663
+ it("sets end_time") { @recording.end_time.to_i.should == attrs[:end_time].to_i }
664
+ it("sets start_time") { @recording.start_time.to_i.should == meeting_create_time }
378
665
  it("sets server") { @recording.server.should == new_server }
379
666
  it("sets room") { @recording.room.should == @room }
380
667
  it("sets meeting") { @recording.meeting.should == @meeting }
381
668
  it("sets description") {
382
- time = data[:start_time].utc.to_formatted_s(:long)
669
+ time = Time.at(data[:start_time]).utc.to_formatted_s(:long)
383
670
  @recording.description.should == I18n.t('bigbluebutton_rails.recordings.default.description', :time => time)
384
671
  }
672
+ it("sets recording_users") { @recording.recording_users.should eql([3, 4]) }
385
673
  end
386
674
 
387
675
  describe ".adapt_recording_hash" do
@@ -407,6 +695,30 @@ describe BigbluebuttonRecording do
407
695
  it { should eq(after) }
408
696
  end
409
697
 
698
+ describe ".adapt_recording_users" do
699
+ context "with one user" do
700
+ let(:original) {
701
+ { :user => { :externalUserID => 1 } }
702
+ }
703
+ let(:expected) { [1] }
704
+ it { BigbluebuttonRecording.send(:adapt_recording_users, original).should eql(expected) }
705
+ end
706
+
707
+ context "with several users" do
708
+ let(:original) {
709
+ { :user => [{ :externalUserID => 2 }, { :externalUserID => 1 }, { :externalUserID => 15 }] }
710
+ }
711
+ let(:expected) { [2, 1, 15] }
712
+ it { BigbluebuttonRecording.send(:adapt_recording_users, original).should eql(expected) }
713
+ end
714
+
715
+ [nil, []].each do |arg|
716
+ context "returns nil if the argument is #{arg.inspect}" do
717
+ it { BigbluebuttonRecording.send(:adapt_recording_users, arg).should be_nil }
718
+ end
719
+ end
720
+ end
721
+
410
722
  describe ".sync_additional_data" do
411
723
  let(:attrs) { FactoryGirl.attributes_for(:bigbluebutton_recording) }
412
724
  let(:recording) { FactoryGirl.create(:bigbluebutton_recording) }
@@ -520,14 +832,29 @@ describe BigbluebuttonRecording do
520
832
  }
521
833
 
522
834
  context "and it's not in the database yet" do
523
- before {
524
- BigbluebuttonRecording.send(:sync_playback_formats, recording, data)
525
- }
526
- it { BigbluebuttonPlaybackFormat.count.should == 1 }
527
- it { BigbluebuttonPlaybackFormat.where(:recording_id => recording.id).count.should == 1 }
528
- it { BigbluebuttonPlaybackFormat.where(:recording_id => recording.id).last.url.should == "url1" }
529
- it { BigbluebuttonPlaybackFormat.where(:recording_id => recording.id).last.length.should == 1 }
530
- it { BigbluebuttonPlaybackFormat.where(:recording_id => recording.id).last.visible.should be(true) }
835
+ context "if it is not a downloadable format" do
836
+ before {
837
+ BigbluebuttonRecording.send(:sync_playback_formats, recording, data)
838
+ }
839
+ it { BigbluebuttonPlaybackFormat.count.should == 1 }
840
+ it { BigbluebuttonPlaybackFormat.where(:recording_id => recording.id).count.should == 1 }
841
+ it { BigbluebuttonPlaybackFormat.where(:recording_id => recording.id).last.url.should == "url1" }
842
+ it { BigbluebuttonPlaybackFormat.where(:recording_id => recording.id).last.length.should == 1 }
843
+ it { BigbluebuttonPlaybackFormat.where(:recording_id => recording.id).last.visible.should be(true) }
844
+ end
845
+
846
+ context "if it is a downloadable format" do
847
+ after {
848
+ @previous = BigbluebuttonRails.configuration.downloadable_playback_types
849
+ }
850
+ before {
851
+ BigbluebuttonRails.configuration.downloadable_playback_types = ['any1']
852
+ BigbluebuttonRecording.send(:sync_playback_formats, recording, data)
853
+ BigbluebuttonRails.configuration.downloadable_playback_types = @previous
854
+ }
855
+ it { BigbluebuttonPlaybackFormat.count.should == 1 }
856
+ it { BigbluebuttonPlaybackFormat.where(:recording_id => recording.id).last.downloadable.should be(true) }
857
+ end
531
858
  end
532
859
 
533
860
  context "and it's already in the database" do
@@ -584,17 +911,31 @@ describe BigbluebuttonRecording do
584
911
 
585
912
  BigbluebuttonRecording.send(:sync_playback_formats, recording, data)
586
913
  }
587
- it { BigbluebuttonPlaybackType.count.should == 3 }
588
914
  it { BigbluebuttonPlaybackFormat.count.should == 3 }
589
- it { BigbluebuttonPlaybackFormat.where(:recording_id => recording.id).count.should == 3 }
590
- it { BigbluebuttonPlaybackFormat.where(:recording_id => recording.id, :playback_type_id => playback_type.id).first.url.should == "url1" }
591
- it { BigbluebuttonPlaybackFormat.where(:recording_id => recording.id, :playback_type_id => playback_type.id).first.length.should == 1 }
592
- it { BigbluebuttonPlaybackFormat.where(:recording_id => recording.id, :playback_type_id => playback_type.id).first.visible.should be(true) }
593
- it { BigbluebuttonPlaybackFormat.where(:recording_id => recording.id, :playback_type_id => playback_type_hidden.id).first.url.should == "url2" }
594
- it { BigbluebuttonPlaybackFormat.where(:recording_id => recording.id, :playback_type_id => playback_type_hidden.id).first.length.should == 2 }
595
- it { BigbluebuttonPlaybackFormat.where(:recording_id => recording.id, :playback_type_id => playback_type_hidden.id).first.visible.should be(false) }
596
- it { BigbluebuttonPlaybackFormat.where(:recording_id => recording.id, :playback_type_id => BigbluebuttonPlaybackType.last.id).first.url.should == "url3" }
597
- it { BigbluebuttonPlaybackFormat.where(:recording_id => recording.id, :playback_type_id => BigbluebuttonPlaybackType.last.id).first.length.should == 3 }
915
+ it { BigbluebuttonPlaybackFormat.where(recording_id: recording.id).count.should == 3 }
916
+ it {
917
+ q = BigbluebuttonPlaybackFormat.where(recording_id: recording.id, playback_type_id: playback_type.id, url: "url1")
918
+ q.size.should == 1
919
+ f = q.first
920
+ f.should_not be_nil
921
+ f.length.should == 1
922
+ f.visible.should be(true)
923
+ }
924
+ it {
925
+ q = BigbluebuttonPlaybackFormat.where(recording_id: recording.id, playback_type_id: playback_type_hidden.id, url: "url2")
926
+ q.size.should == 1
927
+ f = q.first
928
+ f.should_not be_nil
929
+ f.length.should == 2
930
+ f.visible.should be(false)
931
+ }
932
+ it {
933
+ q = BigbluebuttonPlaybackFormat.where(recording_id: recording.id, playback_type_id: BigbluebuttonPlaybackType.last.id, url: "url3")
934
+ q.size.should == 1
935
+ f = q.first
936
+ f.should_not be_nil
937
+ f.length.should == 3
938
+ }
598
939
  end
599
940
 
600
941
  context "ignores formats with blank type" do
@@ -637,16 +978,6 @@ describe BigbluebuttonRecording do
637
978
  it { BigbluebuttonPlaybackType.last.identifier.should == "any1" }
638
979
  it { BigbluebuttonPlaybackType.last.playback_formats.should include(BigbluebuttonPlaybackFormat.last) }
639
980
  end
640
-
641
- context "when there are unused playback types on the database" do
642
- before {
643
- FactoryGirl.create(:bigbluebutton_playback_type, :identifier => "any2")
644
- FactoryGirl.create(:bigbluebutton_playback_type, :identifier => "any3")
645
- BigbluebuttonRecording.send(:sync_playback_formats, recording, data)
646
- }
647
- it { BigbluebuttonPlaybackType.count.should == 1 }
648
- it { BigbluebuttonPlaybackType.last.identifier.should == "any1" }
649
- end
650
981
  end
651
982
  end
652
983
 
@@ -702,9 +1033,10 @@ describe BigbluebuttonRecording do
702
1033
  end
703
1034
 
704
1035
  context "if found a start time in recordid" do
705
- let(:meeting_start_time) { DateTime.now }
1036
+ let(:meeting_create_time) { DateTime.now.to_i }
1037
+ let(:meetingid_rand) { SecureRandom.uuid }
706
1038
  let(:recording) {
707
- FactoryGirl.create(:bigbluebutton_recording, :recordid => "#{SecureRandom.uuid}-#{meeting_start_time.to_i}")
1039
+ FactoryGirl.create(:bigbluebutton_recording, :recordid => "#{SecureRandom.uuid}-#{meeting_create_time}", :start_time => meeting_create_time, :meetingid => "#{meetingid_rand}-#{meeting_create_time}")
708
1040
  }
709
1041
 
710
1042
  context "when there's no associated meeting" do
@@ -714,7 +1046,7 @@ describe BigbluebuttonRecording do
714
1046
 
715
1047
  context "when there's one associated meeting" do
716
1048
  before {
717
- @meeting = FactoryGirl.create(:bigbluebutton_meeting, :room => recording.room, :start_time => meeting_start_time)
1049
+ @meeting = FactoryGirl.create(:bigbluebutton_meeting, :room => recording.room, :create_time => meeting_create_time, :meetingid => "#{meetingid_rand}-#{meeting_create_time}")
718
1050
  }
719
1051
  subject { BigbluebuttonRecording.send(:find_matching_meeting, recording) }
720
1052
  it { subject.should eq(@meeting) }