bigbluebutton_rails 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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 />