bigbluebutton_rails 2.0.0 → 2.1.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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -0
  3. data/Gemfile.lock +5 -5
  4. data/app/controllers/bigbluebutton/rooms_controller.rb +0 -5
  5. data/app/controllers/bigbluebutton/servers_controller.rb +1 -1
  6. data/app/models/bigbluebutton_meeting.rb +2 -2
  7. data/app/models/bigbluebutton_recording.rb +16 -12
  8. data/app/models/bigbluebutton_room.rb +109 -42
  9. data/app/models/bigbluebutton_server.rb +10 -9
  10. data/app/views/bigbluebutton/servers/_form.html.erb +2 -2
  11. data/app/views/bigbluebutton/servers/index.html.erb +1 -1
  12. data/app/views/bigbluebutton/servers/show.html.erb +2 -2
  13. data/app/workers/bigbluebutton_meeting_updater.rb +7 -14
  14. data/bigbluebutton_rails.gemspec +1 -1
  15. data/config/locales/en.yml +1 -1
  16. data/config/locales/pt-br.yml +1 -1
  17. data/lib/bigbluebutton_rails.rb +17 -10
  18. data/lib/bigbluebutton_rails/background_tasks.rb +9 -5
  19. data/lib/bigbluebutton_rails/version.rb +1 -1
  20. data/lib/generators/bigbluebutton_rails/templates/migration.rb +6 -2
  21. data/lib/generators/bigbluebutton_rails/templates/migration_2_1_0.rb +21 -0
  22. data/spec/controllers/bigbluebutton/rooms_controller_spec.rb +1 -13
  23. data/spec/controllers/bigbluebutton/servers_controller_spec.rb +2 -2
  24. data/spec/factories/bigbluebutton_meeting.rb +2 -0
  25. data/spec/factories/bigbluebutton_metadata.rb +1 -1
  26. data/spec/factories/bigbluebutton_room.rb +1 -0
  27. data/spec/factories/bigbluebutton_server.rb +1 -1
  28. data/spec/lib/bigbluebutton_rails/background_tasks_spec.rb +106 -15
  29. data/spec/models/bigbluebutton_meeting_db_spec.rb +9 -4
  30. data/spec/models/bigbluebutton_meeting_spec.rb +2 -2
  31. data/spec/models/bigbluebutton_recording_spec.rb +19 -4
  32. data/spec/models/bigbluebutton_room_options_spec.rb +1 -1
  33. data/spec/models/bigbluebutton_room_spec.rb +396 -97
  34. data/spec/models/bigbluebutton_server_db_spec.rb +1 -1
  35. data/spec/models/bigbluebutton_server_spec.rb +38 -16
  36. data/spec/rails_app/db/seeds.rb +0 -1
  37. data/spec/rails_app/features/config.yml.example +2 -4
  38. data/spec/rails_app/features/step_definitions/activity_monitor_servers_step.rb +2 -4
  39. data/spec/rails_app/features/step_definitions/common_steps.rb +1 -2
  40. data/spec/rails_app/features/step_definitions/create_servers_steps.rb +2 -2
  41. data/spec/rails_app/features/step_definitions/destroy_servers_steps.rb +1 -2
  42. data/spec/rails_app/features/support/factories/bigbluebutton_server_integration.rb +1 -1
  43. data/spec/rails_app/features/support/templates.rb +5 -5
  44. data/spec/rails_app/lib/tasks/db/populate.rake +1 -1
  45. data/spec/workers/bigbluebutton_meeting_updater_spec.rb +86 -5
  46. metadata +5 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c9687e5b7cb9d7a46841c69500d2e9cc5362be38
4
- data.tar.gz: 914f67a881910033c18550e2dc239c056ac12ca9
3
+ metadata.gz: a7aa314ce4ce2cd5647e00de7c1507a570cd2943
4
+ data.tar.gz: e79e43b6313f3f001d77c2e86fdaf1af2e196e26
5
5
  SHA512:
6
- metadata.gz: 47dc457d18c9fed76fe02fb491eeaeaab33114af0e953a2b0da256296bd3eeb8a79c7640f995a1a1ac080d78dab14889305f6c29590e6bdbe1153a70ea0c9d59
7
- data.tar.gz: 07b8fae4cc3b53ba89403dcd15f1c9486e5f5d13af88b87473c6d6a46199a9ae47400c51a4eb1a908f8059647190066778ed5c8b7637063f3f931b9ee2325bb8
6
+ metadata.gz: 6cc93453645452f995ce330a496cf00c3e60841709cf0345e62d0a365caf8c692f057f4226dc579ff493330d46cc4e2f8585b3b6a2867b88c2762c82cc34e29c
7
+ data.tar.gz: 923713967e60d3f4120590061fc266a4d296a605ecbdb94d4188a4856b83b83b8a1277407fda41f00396532bb51792264186ba8caef697dcfd45765b9acb2893
data/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Change Log
2
2
 
3
+
4
+ ## [2.1.0] - 2016-07-22
5
+
6
+ * [#98] Improved how meeting records are created and ended. Now they are more reliable and
7
+ will work even if the resque workers are not running.
8
+ * [#132] Fixed recordings being set as unavailable when making requests to a subset of the
9
+ recordings (when using filters in `getRecordings`).
10
+ * [#133] Added option for applications to pass custom metadata when a meeting is being
11
+ created without having to create these metadata in the database.
12
+ * Renamed the attributes `BigbluebuttonServer#salt` to `BigbluebuttonServer#secret`.
13
+
14
+
15
+ ------------------------------------
16
+
17
+ All tickets below use references to IDs in our old issue tracking system.
18
+ To find them, search for their description or ID in the new issue tracker.
19
+
20
+ ------------------------------------
21
+
22
+
3
23
  ## [2.0.0] - 2016-04-07
4
24
 
5
25
  To learn how to migrate to 2.0.0 see:
@@ -246,6 +266,7 @@ https://github.com/mconf/bigbluebutton_rails/wiki/Migrate-to-1.3.0
246
266
  * Controller to access servers and rooms
247
267
  * rooms_controller interacts with a BBB server using bigbluebutton-api-ruby
248
268
 
269
+ [2.1.0]: https://github.com/mconf/bigbluebutton_rails/compare/v2.0.0...v2.1.0
249
270
  [2.0.0]: https://github.com/mconf/bigbluebutton_rails/compare/v1.4.0...v2.0.0
250
271
  [1.4.0]: https://github.com/mconf/bigbluebutton_rails/compare/v1.3.0...v1.4.0
251
272
  [1.3.0]: https://github.com/mconf/bigbluebutton_rails/compare/v1.2.0...v1.3.0
data/Gemfile.lock CHANGED
@@ -7,8 +7,8 @@ GIT
7
7
  PATH
8
8
  remote: .
9
9
  specs:
10
- bigbluebutton_rails (2.0.0)
11
- bigbluebutton-api-ruby (~> 1.4.0)
10
+ bigbluebutton_rails (2.1.0)
11
+ bigbluebutton-api-ruby (~> 1.6)
12
12
  browser (~> 0.8.0)
13
13
  rails (>= 4.0.0)
14
14
  resque (~> 1.25.1)
@@ -46,8 +46,8 @@ GEM
46
46
  addressable (2.3.6)
47
47
  arel (5.0.1.20140414130214)
48
48
  awesome_print (1.2.0)
49
- bigbluebutton-api-ruby (1.4.0)
50
- xml-simple (>= 1.1.1)
49
+ bigbluebutton-api-ruby (1.6.0)
50
+ xml-simple (~> 1.1)
51
51
  browser (0.8.0)
52
52
  builder (3.2.2)
53
53
  capybara (2.2.1)
@@ -139,7 +139,7 @@ GEM
139
139
  mono_logger (1.1.0)
140
140
  multi_json (1.10.1)
141
141
  multi_test (0.1.1)
142
- mysql2 (0.3.16)
142
+ mysql2 (0.3.18)
143
143
  net-http-digest_auth (1.4)
144
144
  net-http-persistent (2.9.4)
145
145
  nokogiri (1.6.2.1)
@@ -367,11 +367,6 @@ class Bigbluebutton::RoomsController < ApplicationController
367
367
  url.gsub!(/^[^:]*:\/\//i, "bigbluebutton://")
368
368
  end
369
369
 
370
- # enqueue an update in the meetings for later on
371
- # note: this is the only update that is not in the model, but has to be here
372
- # because the model doesn't know when a user joined a room
373
- Resque.enqueue(::BigbluebuttonMeetingUpdater, @room.id, 15.seconds)
374
-
375
370
  redirect_to url
376
371
  else
377
372
  flash[:error] = t('bigbluebutton_rails.rooms.errors.join.not_running')
@@ -197,7 +197,7 @@ class Bigbluebutton::ServersController < ApplicationController
197
197
  end
198
198
 
199
199
  def server_allowed_params
200
- [ :name, :url, :salt, :param ]
200
+ [ :name, :url, :secret, :param ]
201
201
  end
202
202
 
203
203
  end
@@ -13,8 +13,8 @@ class BigbluebuttonMeeting < ActiveRecord::Base
13
13
 
14
14
  validates :meetingid, :presence => true, :length => { :minimum => 1, :maximum => 100 }
15
15
 
16
- validates :start_time, :presence => true
17
- validates :start_time, :uniqueness => { :scope => :room_id }
16
+ validates :create_time, :presence => true
17
+ validates :create_time, :uniqueness => { :scope => :room_id }
18
18
 
19
19
  # Whether the meeting was created by the `user` or not.
20
20
  def created_by?(user)
@@ -41,7 +41,7 @@ class BigbluebuttonRecording < ActiveRecord::Base
41
41
  # were fetched.
42
42
  #
43
43
  # TODO: catch exceptions on creating/updating recordings
44
- def self.sync(server, recordings)
44
+ def self.sync(server, recordings, full_sync=false)
45
45
  recordings.each do |rec|
46
46
  rec_obj = BigbluebuttonRecording.find_by_recordid(rec[:recordID])
47
47
  rec_data = adapt_recording_hash(rec)
@@ -58,17 +58,21 @@ class BigbluebuttonRecording < ActiveRecord::Base
58
58
  end
59
59
  end
60
60
 
61
- # set as unavailable the recordings that are not in 'recordings'
62
- recordIDs = recordings.map{ |rec| rec[:recordID] }
63
- if recordIDs.length <= 0 # empty response
64
- BigbluebuttonRecording.
65
- where(available: true, server: server).
66
- update_all(available: false)
67
- else
68
- BigbluebuttonRecording.
69
- where(available: true, server: server).
70
- where.not(recordid: recordIDs).
71
- update_all(available: false)
61
+ # set as unavailable the recordings that are not in 'recordings', but
62
+ # only in a full synchronization process, which means that the recordings
63
+ # in `recordings` are *all* available in `server`, not a subset.
64
+ if full_sync
65
+ recordIDs = recordings.map{ |rec| rec[:recordID] }
66
+ if recordIDs.length <= 0 # empty response
67
+ BigbluebuttonRecording.
68
+ where(available: true, server: server).
69
+ update_all(available: false)
70
+ else
71
+ BigbluebuttonRecording.
72
+ where(available: true, server: server).
73
+ where.not(recordid: recordIDs).
74
+ update_all(available: false)
75
+ end
72
76
  end
73
77
  end
74
78
 
@@ -107,23 +107,38 @@ class BigbluebuttonRoom < ActiveRecord::Base
107
107
  def fetch_meeting_info
108
108
  require_server :get_meeting_info
109
109
 
110
- response = self.server.api.get_meeting_info(self.meetingid, self.moderator_api_password)
111
-
112
- @participant_count = response[:participantCount]
113
- @moderator_count = response[:moderatorCount]
114
- @running = response[:running]
115
- @has_been_forcibly_ended = response[:hasBeenForciblyEnded]
116
- @start_time = response[:startTime]
117
- @end_time = response[:endTime]
118
- @attendees = []
119
- response[:attendees].each do |att|
120
- attendee = BigbluebuttonAttendee.new
121
- attendee.from_hash(att)
122
- @attendees << attendee
123
- end
110
+ begin
111
+ response = self.server.api.get_meeting_info(self.meetingid, self.moderator_api_password)
112
+
113
+ @participant_count = response[:participantCount]
114
+ @moderator_count = response[:moderatorCount]
115
+ @running = response[:running]
116
+ @has_been_forcibly_ended = response[:hasBeenForciblyEnded]
117
+ @start_time = response[:startTime]
118
+ @end_time = response[:endTime]
119
+ @attendees = []
120
+ if response[:attendees].present?
121
+ response[:attendees].each do |att|
122
+ attendee = BigbluebuttonAttendee.new
123
+ attendee.from_hash(att)
124
+ @attendees << attendee
125
+ end
126
+ end
124
127
 
125
- # a 'shortcut' to update meetings since we have all information we need
126
- update_current_meeting(response[:metadata])
128
+ # a 'shortcut' to update meetings since we have all information we need
129
+ # if we got here, it means the meeting is still in the server, so it's not ended
130
+ self.update_attributes(create_time: response[:createTime]) unless self.new_record?
131
+ self.update_current_meeting_record(response[:metadata], true)
132
+
133
+ rescue BigBlueButton::BigBlueButtonException => e
134
+ # note: we could catch only the 'notFound' error, but there are complications, so
135
+ # it's better to end the meeting prematurely and open it again if needed than to
136
+ # not end it at all (e.g. in case the server stops responding)
137
+ Rails.logger.info "BigbluebuttonRoom: detected that a meeting ended in the room #{self.meetingid} after the error #{e.inspect}"
138
+
139
+ self.update_attributes(create_time: nil) unless self.new_record?
140
+ self.finish_meetings
141
+ end
127
142
 
128
143
  response
129
144
  end
@@ -143,8 +158,8 @@ class BigbluebuttonRoom < ActiveRecord::Base
143
158
  require_server :end
144
159
  response = self.server.api.end_meeting(self.meetingid, self.moderator_api_password)
145
160
 
146
- # enqueue an update in the meetings for later on
147
- Resque.enqueue(::BigbluebuttonMeetingUpdater, self.id, 15.seconds)
161
+ # enqueue an update in the meeting to end it faster
162
+ Resque.enqueue(::BigbluebuttonMeetingUpdater, self.id)
148
163
 
149
164
  response
150
165
  end
@@ -178,7 +193,17 @@ class BigbluebuttonRoom < ActiveRecord::Base
178
193
  self.moderator_api_password = response[:moderatorPW]
179
194
  self.create_time = response[:createTime]
180
195
  self.voice_bridge = response[:voiceBridge] if response.has_key?(:voiceBridge)
181
- self.save unless self.new_record?
196
+
197
+ unless self.new_record?
198
+ self.save
199
+
200
+ # creates the meeting object since the create was successful
201
+ create_meeting_record(response[:metadata])
202
+
203
+ # enqueue an update in the meeting with a small delay we assume to be
204
+ # enough for the user to fully join the meeting
205
+ Resque.enqueue(::BigbluebuttonMeetingUpdater, self.id, 10.seconds)
206
+ end
182
207
  end
183
208
 
184
209
  response
@@ -290,23 +315,24 @@ class BigbluebuttonRoom < ActiveRecord::Base
290
315
 
291
316
  # Returns the current meeting running on this room, if any.
292
317
  def get_current_meeting
293
- unless self.start_time.nil?
294
- BigbluebuttonMeeting.find_by_room_id_and_start_time(self.id, self.start_time.utc)
318
+ unless self.create_time.nil?
319
+ BigbluebuttonMeeting.find_by(room_id: self.id, create_time: self.create_time)
295
320
  else
296
321
  nil
297
322
  end
298
323
  end
299
324
 
300
325
  # Updates the current meeting associated with this room
301
- def update_current_meeting(metadata=nil)
302
- unless self.start_time.nil?
326
+ def update_current_meeting_record(metadata=nil, force_not_ended=false)
327
+ unless self.create_time.nil?
303
328
  attrs = {
304
- :server => self.server,
305
- :meetingid => self.meetingid,
306
- :name => self.name,
307
- :recorded => self.record_meeting,
308
- :running => self.running
329
+ :running => self.running,
330
+ :start_time => self.start_time.try(:utc)
309
331
  }
332
+ # note: it's important to update the 'ended' attr so the meeting is
333
+ # reopened in case it was mistakenly considered as ended
334
+ attrs[:ended] = false if force_not_ended
335
+
310
336
  unless metadata.nil?
311
337
  begin
312
338
  attrs[:creator_id] = metadata[BigbluebuttonRails.metadata_user_id].to_i
@@ -318,25 +344,60 @@ class BigbluebuttonRoom < ActiveRecord::Base
318
344
  end
319
345
 
320
346
  meeting = self.get_current_meeting
321
- if !meeting.nil?
322
- meeting.update_attributes(attrs)
347
+ meeting.update_attributes(attrs) if meeting.present?
348
+ end
349
+ end
323
350
 
324
- # only create a new meeting if it is running
325
- elsif self.running
326
- attrs.merge!({ :room => self, :start_time => self.start_time.utc })
327
- meeting = BigbluebuttonMeeting.create(attrs)
351
+ def create_meeting_record(metadata=nil)
352
+ unless get_current_meeting.present?
353
+ if self.create_time.present?
354
+
355
+ # to make sure there's no other meeting related to this room that
356
+ # has not yet been set as ended
357
+ self.finish_meetings
358
+
359
+ attrs = {
360
+ room: self,
361
+ server: self.server,
362
+ server_url: self.server.url,
363
+ server_secret: self.server.secret,
364
+ meetingid: self.meetingid,
365
+ name: self.name,
366
+ recorded: self.record_meeting,
367
+ create_time: self.create_time,
368
+ running: self.running,
369
+ ended: false,
370
+ start_time: self.start_time.try(:utc)
371
+ }
372
+ unless metadata.nil?
373
+ begin
374
+ attrs[:creator_id] = metadata[BigbluebuttonRails.metadata_user_id].to_i
375
+ attrs[:creator_name] = metadata[BigbluebuttonRails.metadata_user_name]
376
+ rescue
377
+ attrs[:creator_id] = nil
378
+ attrs[:creator_name] = nil
379
+ end
380
+ end
381
+ BigbluebuttonMeeting.create(attrs)
328
382
 
383
+ Rails.logger.error "Did not create a current meeting because there was no create_time on room #{self.meetingid}"
384
+ else
385
+ Rails.logger.error "Did not create a current meeting because there was no create_time on room #{self.meetingid}"
329
386
  end
330
- else
331
- # TODO: not enough information to find the meeting, do what?
332
387
  end
333
388
  end
334
389
 
335
390
  # Sets all meetings related to this room as not running
336
391
  def finish_meetings
337
- BigbluebuttonMeeting.where(running: true)
392
+ BigbluebuttonMeeting.where(ended: false)
393
+ .where(room_id: self.id)
394
+ .update_all(running: false, ended: true)
395
+
396
+ # in case there are inconsistent meetings marked as running
397
+ # but that already ended
398
+ BigbluebuttonMeeting.where(running: true, ended: true)
338
399
  .where(room_id: self.id)
339
- .update_all(running: false)
400
+ .update_all(running: false, ended: true)
340
401
  end
341
402
 
342
403
  # Gets a 'configToken' to use when joining the room.
@@ -503,9 +564,6 @@ class BigbluebuttonRoom < ActiveRecord::Base
503
564
  self.server.api.request_headers = @request_headers # we need the client's IP
504
565
  response = self.server.api.create_meeting(self.name, self.meetingid, opts)
505
566
 
506
- # enqueue an update in the meetings to start now
507
- Resque.enqueue(::BigbluebuttonMeetingUpdater, self.id)
508
-
509
567
  response
510
568
  end
511
569
 
@@ -540,9 +598,18 @@ class BigbluebuttonRoom < ActiveRecord::Base
540
598
  end
541
599
 
542
600
  def get_metadata_for_create
543
- self.metadata.inject({}) { |result, meta|
601
+ metadata = self.metadata.inject({}) { |result, meta|
544
602
  result["meta_#{meta.name}"] = meta.content; result
545
603
  }
604
+
605
+ dynamic_metadata = self.try(BigbluebuttonRails.dynamic_metadata_method)
606
+ unless dynamic_metadata.blank?
607
+ metadata = self.dynamic_metadata.inject(metadata) { |result, meta|
608
+ result["meta_#{meta[0]}"] = meta[1]; result
609
+ }
610
+ end
611
+
612
+ metadata
546
613
  end
547
614
 
548
615
  private
@@ -42,7 +42,7 @@ class BigbluebuttonServer < ActiveRecord::Base
42
42
  :format => { :with => /\A[a-zA-Z\d_]+[a-zA-Z\d_-]*[a-zA-Z\d_]+\z/,
43
43
  :message => I18n.t('bigbluebutton_rails.servers.errors.param_format') }
44
44
 
45
- validates :salt,
45
+ validates :secret,
46
46
  :presence => true,
47
47
  :length => { :minimum => 1, :maximum => 500 }
48
48
 
@@ -75,7 +75,7 @@ class BigbluebuttonServer < ActiveRecord::Base
75
75
 
76
76
  version = self.version
77
77
  version = set_api_version_from_server if version.blank?
78
- @api = BigBlueButton::BigBlueButtonApi.new(self.url, self.salt, version.to_s, false)
78
+ @api = BigBlueButton::BigBlueButtonApi.new(self.url, self.secret, version.to_s, false)
79
79
  end
80
80
 
81
81
  # Fetches the meetings currently created in the server (running or not).
@@ -101,7 +101,7 @@ class BigbluebuttonServer < ActiveRecord::Base
101
101
  :moderator_api_password => attr[:moderatorPW])
102
102
  end
103
103
  room.running = attr[:running]
104
- room.update_current_meeting
104
+ room.update_current_meeting_record
105
105
 
106
106
  @meetings << room
107
107
  end
@@ -141,11 +141,12 @@ class BigbluebuttonServer < ActiveRecord::Base
141
141
  # metadata values.
142
142
  #
143
143
  # Triggers API call: <tt>getRecordings</tt>.
144
- def fetch_recordings(filter={})
144
+ def fetch_recordings(filter=nil, full_sync=false)
145
+ filter ||= {}
145
146
  logger.info "Fetching recordings for the server #{self.inspect} with filter: #{filter.inspect}"
146
147
  recordings = self.api.get_recordings(filter)
147
148
  if recordings and recordings[:recordings]
148
- BigbluebuttonRecording.sync(self, recordings[:recordings])
149
+ BigbluebuttonRecording.sync(self, recordings[:recordings], full_sync)
149
150
  end
150
151
  end
151
152
 
@@ -156,7 +157,7 @@ class BigbluebuttonServer < ActiveRecord::Base
156
157
  def set_api_version_from_server
157
158
  begin
158
159
  # creating the object with version=nil makes the gem fetch the version from the server
159
- api = BigBlueButton::BigBlueButtonApi.new(self.url, self.salt, nil, false)
160
+ api = BigBlueButton::BigBlueButtonApi.new(self.url, self.secret, nil, false)
160
161
  self.version = api.version
161
162
  rescue BigBlueButton::BigBlueButtonException
162
163
  # we just ignore errors in case the server is not responding
@@ -187,16 +188,16 @@ class BigbluebuttonServer < ActiveRecord::Base
187
188
 
188
189
  # Checks if we have to update the server version or not and do it if needed.
189
190
  # If the user only changes the version, we assume he's trying to force an API version.
190
- # If the user changes url/salt and the version, we also assume that he wants
191
+ # If the user changes url/secret and the version, we also assume that he wants
191
192
  # to force the API version
192
193
  def check_for_version_update
193
- if [:url, :salt, :version].any? { |k| self.changes.key?(k) }
194
+ if [:url, :secret, :version].any? { |k| self.changes.key?(k) }
194
195
  self.set_api_version_from_server
195
196
  end
196
197
  end
197
198
 
198
199
  def check_for_config_update
199
- if [:url, :salt, :version].any?{ |k| self.changes.key?(k) }
200
+ if [:url, :secret, :version].any?{ |k| self.changes.key?(k) }
200
201
  self.update_config
201
202
  end
202
203
  end
@@ -23,8 +23,8 @@
23
23
  <%= f.text_field :url %>
24
24
  </div>
25
25
  <div class="field">
26
- <%= f.label :salt %><br />
27
- <%= f.text_field :salt %>
26
+ <%= f.label :secret %><br />
27
+ <%= f.text_field :secret %>
28
28
  </div>
29
29
  <div class="field">
30
30
  <%= f.label :version %><br />