bigbluebutton_rails 1.3.0 → 1.4.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/.rspec +2 -2
- data/.ruby-version +1 -1
- data/CHANGELOG.rdoc +31 -6
- data/Gemfile +13 -3
- data/Gemfile.lock +88 -42
- data/README.rdoc +84 -15
- data/Rakefile +22 -25
- data/{TODO_08 → TODO.rdoc} +6 -2
- data/app/assets/images/badges/apple_store_en.png +0 -0
- data/app/assets/images/badges/apple_store_pt-br.png +0 -0
- data/app/assets/images/badges/google_play_en.png +0 -0
- data/app/assets/images/badges/google_play_pt-br.png +0 -0
- data/app/controllers/bigbluebutton/recordings_controller.rb +25 -10
- data/app/controllers/bigbluebutton/rooms_controller.rb +158 -141
- data/app/controllers/bigbluebutton/servers_controller.rb +25 -12
- data/app/helpers/bigbluebutton_rails_helper.rb +20 -0
- data/app/models/bigbluebutton_meeting.rb +28 -0
- data/app/models/bigbluebutton_metadata.rb +2 -2
- data/app/models/bigbluebutton_playback_format.rb +2 -2
- data/app/models/bigbluebutton_recording.rb +29 -4
- data/app/models/bigbluebutton_room.rb +153 -22
- data/app/models/bigbluebutton_room_options.rb +46 -0
- data/app/models/bigbluebutton_server.rb +4 -2
- data/app/views/bigbluebutton/recordings/_form.html.erb +4 -0
- data/app/views/bigbluebutton/recordings/_recordings.html.erb +1 -0
- data/app/views/bigbluebutton/recordings/show.html.erb +5 -0
- data/app/views/bigbluebutton/rooms/join_mobile.html.erb +29 -5
- data/app/workers/bigbluebutton_meeting_updater.rb +31 -0
- data/bigbluebutton_rails.gemspec +5 -1
- data/config/locales/en.yml +6 -5
- data/config/schedule.rb +4 -0
- data/lib/bigbluebutton_rails/controller_methods.rb +29 -10
- data/lib/bigbluebutton_rails/internal_controller_methods.rb +56 -0
- data/lib/bigbluebutton_rails/rails/routes.rb +1 -5
- data/lib/bigbluebutton_rails/version.rb +1 -1
- data/lib/bigbluebutton_rails.rb +11 -0
- data/lib/generators/bigbluebutton_rails/templates/migration.rb +28 -0
- data/lib/generators/bigbluebutton_rails/templates/migration_1_4_0.rb +37 -0
- data/lib/tasks/bigbluebutton_rails/meetings.rake +22 -0
- data/lib/tasks/bigbluebutton_rails/recordings.rake +2 -1
- data/spec/classes/bigbluebutton_attendee_spec.rb +1 -1
- data/spec/controllers/bigbluebutton/recordings_controller_json_responses_spec.rb +10 -9
- data/spec/controllers/bigbluebutton/recordings_controller_spec.rb +103 -16
- data/spec/controllers/bigbluebutton/rooms_controller_exception_handling_spec.rb +15 -5
- data/spec/controllers/bigbluebutton/rooms_controller_json_responses_spec.rb +17 -12
- data/spec/controllers/bigbluebutton/rooms_controller_spec.rb +485 -432
- data/spec/controllers/bigbluebutton/servers_controller_json_responses_spec.rb +20 -13
- data/spec/controllers/bigbluebutton/servers_controller_spec.rb +174 -16
- data/spec/factories/bigbluebutton_meeting.rb +13 -0
- data/spec/factories/bigbluebutton_recording.rb +4 -2
- data/spec/factories/bigbluebutton_room.rb +5 -1
- data/spec/factories/bigbluebutton_room_options.rb +6 -0
- data/spec/generators/install_generator_spec.rb +1 -1
- data/spec/generators/views_generator_spec.rb +0 -1
- data/spec/lib/tasks/meetings_rake_spec.rb +5 -0
- data/spec/lib/tasks/recordings_rake_spec.rb +5 -0
- data/spec/models/bigbluebutton_meeting_db_spec.rb +24 -0
- data/spec/models/bigbluebutton_meeting_spec.rb +52 -0
- data/spec/models/bigbluebutton_metadata_db_spec.rb +2 -0
- data/spec/models/bigbluebutton_metadata_spec.rb +18 -22
- data/spec/models/bigbluebutton_playback_format_db_spec.rb +2 -0
- data/spec/models/bigbluebutton_playback_format_spec.rb +0 -4
- data/spec/models/bigbluebutton_recording_db_spec.rb +3 -0
- data/spec/models/bigbluebutton_recording_spec.rb +69 -16
- data/spec/models/bigbluebutton_room_db_spec.rb +2 -0
- data/spec/models/bigbluebutton_room_options_db_spec.rb +16 -0
- data/spec/models/bigbluebutton_room_options_spec.rb +206 -0
- data/spec/models/bigbluebutton_room_spec.rb +420 -80
- data/spec/models/bigbluebutton_server_db_spec.rb +2 -0
- data/spec/models/bigbluebutton_server_spec.rb +22 -24
- data/spec/rails_app/config/application.rb +3 -0
- data/spec/rails_app/config/database.yml.example +28 -0
- data/spec/rails_app/config/environments/test.rb +1 -1
- data/spec/rails_app/db/seeds.rb +1 -0
- data/spec/rails_app/features/step_definitions/activity_monitor_servers_step.rb +0 -2
- data/spec/rails_app/features/step_definitions/common_steps.rb +6 -0
- data/spec/rails_app/features/step_definitions/join_rooms_steps.rb +0 -6
- data/spec/rails_app/features/support/locales.rb +4 -2
- data/spec/rails_app/features/support/paths.rb +0 -2
- data/spec/rails_app/features/support/templates.rb +2 -17
- data/spec/rails_app/lib/tasks/db/populate.rake +2 -0
- data/spec/rails_app/lib/tasks/resque.rake +3 -0
- data/spec/routing/bigbluebutton/custom_controllers_routing_spec.rb +1 -10
- data/spec/routing/bigbluebutton/rooms_only_routing_spec.rb +1 -9
- data/spec/routing/bigbluebutton/rooms_routing_spec.rb +3 -31
- data/spec/spec_helper.rb +40 -24
- data/spec/support/matchers/array_with_key.rb +7 -0
- data/spec/support/matchers/array_without_key.rb +7 -0
- data/spec/support/matchers/delegate_matcher.rb +62 -0
- data/spec/support/matchers/respond_with_content_type.rb +8 -0
- data/spec/support/matchers/shoulda/assign_to_matcher.rb +131 -0
- data/spec/support/mocked_server.rb +2 -2
- data/spec/support/models/user.rb +11 -0
- data/spec/workers/bigbluebutton_meeting_updater_spec.rb +9 -0
- metadata +86 -16
- data/app/views/bigbluebutton/rooms/external.html.erb +0 -25
- data/spec/rails_app/config/database.yml +0 -25
- data/spec/rails_app/features/join_external_rooms.feature +0 -61
@@ -1,4 +1,5 @@
|
|
1
1
|
class Bigbluebutton::ServersController < ApplicationController
|
2
|
+
include BigbluebuttonRails::InternalControllerMethods
|
2
3
|
|
3
4
|
respond_to :html
|
4
5
|
respond_to :json, :only => [:index, :show, :new, :create, :update, :destroy, :activity, :rooms]
|
@@ -57,17 +58,17 @@ class Bigbluebutton::ServersController < ApplicationController
|
|
57
58
|
end
|
58
59
|
|
59
60
|
def create
|
60
|
-
@server = BigbluebuttonServer.new(
|
61
|
+
@server = BigbluebuttonServer.new(server_params)
|
61
62
|
|
62
63
|
respond_with @server do |format|
|
63
64
|
if @server.save
|
64
65
|
format.html {
|
65
66
|
message = t('bigbluebutton_rails.servers.notice.create.success')
|
66
|
-
|
67
|
+
redirect_to_using_params @server, :notice => message
|
67
68
|
}
|
68
69
|
format.json { render :json => @server, :status => :created }
|
69
70
|
else
|
70
|
-
format.html {
|
71
|
+
format.html { redirect_to_params_or_render :new }
|
71
72
|
format.json { render :json => @server.errors.full_messages, :status => :unprocessable_entity }
|
72
73
|
end
|
73
74
|
end
|
@@ -75,14 +76,14 @@ class Bigbluebutton::ServersController < ApplicationController
|
|
75
76
|
|
76
77
|
def update
|
77
78
|
respond_with @server do |format|
|
78
|
-
if @server.update_attributes(
|
79
|
+
if @server.update_attributes(server_params)
|
79
80
|
format.html {
|
80
81
|
message = t('bigbluebutton_rails.servers.notice.update.success')
|
81
|
-
|
82
|
+
redirect_to_using_params @server, :notice => message
|
82
83
|
}
|
83
|
-
format.json {
|
84
|
+
format.json { render :json => true, :status => :ok }
|
84
85
|
else
|
85
|
-
format.html {
|
86
|
+
format.html { redirect_to_params_or_render :edit }
|
86
87
|
format.json { render :json => @server.errors.full_messages, :status => :unprocessable_entity }
|
87
88
|
end
|
88
89
|
end
|
@@ -93,8 +94,8 @@ class Bigbluebutton::ServersController < ApplicationController
|
|
93
94
|
@server.destroy
|
94
95
|
|
95
96
|
respond_with do |format|
|
96
|
-
format.html {
|
97
|
-
format.json {
|
97
|
+
format.html { redirect_to_using_params bigbluebutton_servers_url }
|
98
|
+
format.json { render :json => true, :status => :ok }
|
98
99
|
end
|
99
100
|
end
|
100
101
|
|
@@ -146,7 +147,7 @@ class Bigbluebutton::ServersController < ApplicationController
|
|
146
147
|
if error
|
147
148
|
render :json => { :message => message }, :status => :error
|
148
149
|
else
|
149
|
-
|
150
|
+
render :json => true, :status => :ok
|
150
151
|
end
|
151
152
|
}
|
152
153
|
end
|
@@ -168,7 +169,7 @@ class Bigbluebutton::ServersController < ApplicationController
|
|
168
169
|
else
|
169
170
|
message = t('bigbluebutton_rails.servers.notice.unpublish_recordings.success')
|
170
171
|
end
|
171
|
-
|
172
|
+
redirect_to_using_params recordings_bigbluebutton_server_path(@server), :notice => message
|
172
173
|
}
|
173
174
|
format.json { render :json => message }
|
174
175
|
end
|
@@ -176,11 +177,23 @@ class Bigbluebutton::ServersController < ApplicationController
|
|
176
177
|
respond_with do |format|
|
177
178
|
format.html {
|
178
179
|
flash[:error] = e.to_s[0..200]
|
179
|
-
|
180
|
+
redirect_to_using_params recordings_bigbluebutton_server_path(@server)
|
180
181
|
}
|
181
182
|
format.json { render :json => e.to_s, :status => :error }
|
182
183
|
end
|
183
184
|
end
|
184
185
|
end
|
185
186
|
|
187
|
+
def server_params
|
188
|
+
unless params[:bigbluebutton_server].nil?
|
189
|
+
params[:bigbluebutton_server].permit(*server_allowed_params)
|
190
|
+
else
|
191
|
+
[]
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def server_allowed_params
|
196
|
+
[ :name, :url, :version, :salt, :param ]
|
197
|
+
end
|
198
|
+
|
186
199
|
end
|
@@ -21,4 +21,24 @@ module BigbluebuttonRailsHelper
|
|
21
21
|
room
|
22
22
|
end
|
23
23
|
|
24
|
+
# Link to download the Android application from Google Play.
|
25
|
+
def mobile_google_play_link
|
26
|
+
"https://play.google.com/store/apps/details?id=air.com.mconf.mconfmobile"
|
27
|
+
end
|
28
|
+
|
29
|
+
# Google Play image to show together with the link to download the Android client.
|
30
|
+
def mobile_google_play_image
|
31
|
+
"badges/google_play_#{I18n.locale}.png"
|
32
|
+
end
|
33
|
+
|
34
|
+
# Link to download the iOS application from Apple Store.
|
35
|
+
def mobile_apple_store_link
|
36
|
+
"https://itunes.apple.com/us/app/mconf-mobile/id864391260"
|
37
|
+
end
|
38
|
+
|
39
|
+
# Apple Store image to show together with the link to download the iOS client.
|
40
|
+
def mobile_apple_store_image
|
41
|
+
"badges/apple_store_#{I18n.locale}.png"
|
42
|
+
end
|
43
|
+
|
24
44
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class BigbluebuttonMeeting < ActiveRecord::Base
|
2
|
+
include ActiveModel::ForbiddenAttributesProtection
|
3
|
+
|
4
|
+
belongs_to :server, :class_name => 'BigbluebuttonServer'
|
5
|
+
belongs_to :room, :class_name => 'BigbluebuttonRoom'
|
6
|
+
|
7
|
+
has_one :recording,
|
8
|
+
:class_name => 'BigbluebuttonRecording',
|
9
|
+
:foreign_key => 'meeting_id',
|
10
|
+
:dependent => :nullify
|
11
|
+
|
12
|
+
validates :room, :presence => true
|
13
|
+
|
14
|
+
validates :meetingid, :presence => true, :length => { :minimum => 1, :maximum => 100 }
|
15
|
+
|
16
|
+
validates :start_time, :presence => true
|
17
|
+
validates :start_time, :uniqueness => { :scope => :room_id }
|
18
|
+
|
19
|
+
# Whether the meeting was created by the `user` or not.
|
20
|
+
def created_by?(user)
|
21
|
+
unless user.nil?
|
22
|
+
userid = user.send(BigbluebuttonRails.user_attr_id)
|
23
|
+
self.creator_id == userid
|
24
|
+
else
|
25
|
+
false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,4 +1,6 @@
|
|
1
1
|
class BigbluebuttonMetadata < ActiveRecord::Base
|
2
|
+
include ActiveModel::ForbiddenAttributesProtection
|
3
|
+
|
2
4
|
belongs_to :owner, :polymorphic => true, :inverse_of => :metadata
|
3
5
|
|
4
6
|
validates :owner_id, :presence => true
|
@@ -13,8 +15,6 @@ class BigbluebuttonMetadata < ActiveRecord::Base
|
|
13
15
|
:uniqueness => { :scope => [:owner_id, :owner_type] }
|
14
16
|
validate :exclusion_of_name_in_reserved_metadata_keys
|
15
17
|
|
16
|
-
attr_accessible :name, :content
|
17
|
-
|
18
18
|
# metadata keys are only invalid when the metadata belongs to a room,
|
19
19
|
# metadata that will be used in a 'create' call
|
20
20
|
# TODO: a better solution for rails >= 3.1
|
@@ -1,9 +1,9 @@
|
|
1
1
|
class BigbluebuttonPlaybackFormat < ActiveRecord::Base
|
2
|
+
include ActiveModel::ForbiddenAttributesProtection
|
3
|
+
|
2
4
|
belongs_to :recording, :class_name => 'BigbluebuttonRecording'
|
3
5
|
|
4
6
|
validates :recording_id, :presence => true
|
5
7
|
|
6
8
|
validates :format_type, :presence => true
|
7
|
-
|
8
|
-
attr_accessible :recording_id, :format_type, :url, :length
|
9
9
|
end
|
@@ -1,6 +1,9 @@
|
|
1
1
|
class BigbluebuttonRecording < ActiveRecord::Base
|
2
|
+
include ActiveModel::ForbiddenAttributesProtection
|
3
|
+
|
2
4
|
belongs_to :server, :class_name => 'BigbluebuttonServer'
|
3
5
|
belongs_to :room, :class_name => 'BigbluebuttonRoom'
|
6
|
+
belongs_to :meeting, :class_name => 'BigbluebuttonMeeting'
|
4
7
|
|
5
8
|
validates :server, :presence => true
|
6
9
|
|
@@ -8,9 +11,6 @@ class BigbluebuttonRecording < ActiveRecord::Base
|
|
8
11
|
:presence => true,
|
9
12
|
:uniqueness => true
|
10
13
|
|
11
|
-
attr_accessible :recordid, :meetingid, :name, :published, :start_time,
|
12
|
-
:end_time, :available
|
13
|
-
|
14
14
|
has_many :metadata,
|
15
15
|
:class_name => 'BigbluebuttonMetadata',
|
16
16
|
:as => :owner,
|
@@ -69,7 +69,8 @@ class BigbluebuttonRecording < ActiveRecord::Base
|
|
69
69
|
|
70
70
|
protected
|
71
71
|
|
72
|
-
# Adapt keys in 'hash' from bigbluebutton-api-ruby's
|
72
|
+
# Adapt keys in 'hash' from bigbluebutton-api-ruby's (the way they are returned by
|
73
|
+
# BigBlueButton's API) format to ours (more rails-like).
|
73
74
|
def self.adapt_recording_hash(hash)
|
74
75
|
new_hash = hash.clone
|
75
76
|
mappings = {
|
@@ -104,6 +105,8 @@ class BigbluebuttonRecording < ActiveRecord::Base
|
|
104
105
|
recording.available = true
|
105
106
|
recording.room = BigbluebuttonRails.match_room_recording(data)
|
106
107
|
recording.server = server
|
108
|
+
recording.description = I18n.t('bigbluebutton_rails.recordings.default.description', :time => recording.start_time.utc.to_formatted_s(:long))
|
109
|
+
recording.meeting = BigbluebuttonRecording.find_matching_meeting(recording)
|
107
110
|
recording.save!
|
108
111
|
|
109
112
|
sync_additional_data(recording, data)
|
@@ -188,4 +191,26 @@ class BigbluebuttonRecording < ActiveRecord::Base
|
|
188
191
|
end
|
189
192
|
end
|
190
193
|
|
194
|
+
# Finds the BigbluebuttonMeeting that generated this recording. The meeting is searched using
|
195
|
+
# the room associated with this recording and the create time of the meeting, taken from
|
196
|
+
# the recording's ID.
|
197
|
+
def self.find_matching_meeting(recording)
|
198
|
+
meeting = nil
|
199
|
+
|
200
|
+
unless recording.nil? or recording.room.nil?
|
201
|
+
|
202
|
+
# recordid is something like: 'dd2816950ce2f1e0a928c1a5b8d5b526e9b3e32c-1381978014526'
|
203
|
+
# the create time of the meeting is the timestamp at the end
|
204
|
+
start_time = recording.recordid.match(/-(\d*)$/)
|
205
|
+
unless start_time.nil?
|
206
|
+
start_time = start_time[1]
|
207
|
+
start_time = Time.at(start_time.to_i).to_datetime.utc
|
208
|
+
meeting = BigbluebuttonMeeting.where(:room_id => recording.room.id, :start_time => start_time).last
|
209
|
+
logger.info "Recording: meeting found for the recording #{recording.inspect}: #{meeting.inspect}"
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
meeting
|
214
|
+
end
|
215
|
+
|
191
216
|
end
|
@@ -1,4 +1,6 @@
|
|
1
1
|
class BigbluebuttonRoom < ActiveRecord::Base
|
2
|
+
include ActiveModel::ForbiddenAttributesProtection
|
3
|
+
|
2
4
|
belongs_to :server, :class_name => 'BigbluebuttonServer'
|
3
5
|
belongs_to :owner, :polymorphic => true
|
4
6
|
|
@@ -13,6 +15,18 @@ class BigbluebuttonRoom < ActiveRecord::Base
|
|
13
15
|
:dependent => :destroy,
|
14
16
|
:inverse_of => :owner
|
15
17
|
|
18
|
+
has_one :room_options,
|
19
|
+
:class_name => 'BigbluebuttonRoomOptions',
|
20
|
+
:foreign_key => 'room_id',
|
21
|
+
:autosave => true,
|
22
|
+
:dependent => :destroy
|
23
|
+
|
24
|
+
delegate :default_layout, :default_layout=, :to => :room_options
|
25
|
+
delegate :presenter_share_only, :presenter_share_only=, :to => :room_options
|
26
|
+
delegate :auto_start_video, :auto_start_video=, :to => :room_options
|
27
|
+
delegate :auto_start_audio, :auto_start_audio=, :to => :room_options
|
28
|
+
delegate :get_available_layouts, :to => :room_options
|
29
|
+
|
16
30
|
accepts_nested_attributes_for :metadata,
|
17
31
|
:allow_destroy => true,
|
18
32
|
:reject_if => :all_blank
|
@@ -45,16 +59,12 @@ class BigbluebuttonRoom < ActiveRecord::Base
|
|
45
59
|
validates :attendee_password, :presence => true, :if => :private?
|
46
60
|
validates :moderator_password, :presence => true, :if => :private?
|
47
61
|
|
48
|
-
attr_accessible :name, :server_id, :meetingid, :attendee_password, :moderator_password,
|
49
|
-
:welcome_msg, :owner, :server, :private, :logout_url, :dial_number,
|
50
|
-
:voice_bridge, :max_participants, :owner_id, :owner_type,
|
51
|
-
:external, :param, :record, :duration, :metadata_attributes
|
52
|
-
|
53
62
|
# Note: these params need to be fetched from the server before being accessed
|
54
63
|
attr_accessor :running, :participant_count, :moderator_count, :attendees,
|
55
64
|
:has_been_forcibly_ended, :start_time, :end_time
|
56
65
|
|
57
66
|
after_initialize :init
|
67
|
+
after_create :create_room_options
|
58
68
|
before_validation :set_param
|
59
69
|
before_validation :set_passwords
|
60
70
|
|
@@ -66,6 +76,13 @@ class BigbluebuttonRoom < ActiveRecord::Base
|
|
66
76
|
# Currently used to send the client's IP to the load balancer.
|
67
77
|
attr_accessor :request_headers
|
68
78
|
|
79
|
+
# In case there's no room_options created yet, build one
|
80
|
+
# (happens usually when an old database is migrated).
|
81
|
+
def room_options_with_initialize
|
82
|
+
room_options_without_initialize || build_room_options
|
83
|
+
end
|
84
|
+
alias_method_chain :room_options, :initialize
|
85
|
+
|
69
86
|
# Convenience method to access the attribute <tt>running</tt>
|
70
87
|
def is_running?
|
71
88
|
@running
|
@@ -105,6 +122,9 @@ class BigbluebuttonRoom < ActiveRecord::Base
|
|
105
122
|
@attendees << attendee
|
106
123
|
end
|
107
124
|
|
125
|
+
# a 'shortcut' to update meetings since we have all information we need
|
126
|
+
update_current_meeting(response[:metadata])
|
127
|
+
|
108
128
|
response
|
109
129
|
end
|
110
130
|
|
@@ -121,12 +141,19 @@ class BigbluebuttonRoom < ActiveRecord::Base
|
|
121
141
|
# Triggers API call: <tt>end</tt>.
|
122
142
|
def send_end
|
123
143
|
require_server
|
124
|
-
self.server.api.end_meeting(self.meetingid, self.moderator_password)
|
144
|
+
response = self.server.api.end_meeting(self.meetingid, self.moderator_password)
|
145
|
+
|
146
|
+
# enqueue an update in the meetings for later on
|
147
|
+
Resque.enqueue(::BigbluebuttonMeetingUpdater, self.id, 15.seconds)
|
148
|
+
|
149
|
+
response
|
125
150
|
end
|
126
151
|
|
127
152
|
# Sends a call to the BBB server to create the meeting.
|
128
|
-
# '
|
129
|
-
# '
|
153
|
+
# 'user' is the object that represents the user that is creating the meeting.
|
154
|
+
# 'user_opts' is a hash of parameters to override the parameters sent in the create
|
155
|
+
# request. Can be passed by the application to enforce some values over the values
|
156
|
+
# that are taken from the database.
|
130
157
|
#
|
131
158
|
# Will trigger 'select_server' to select a server where the meeting
|
132
159
|
# will be created. If a server is selected, the model is saved.
|
@@ -136,14 +163,14 @@ class BigbluebuttonRoom < ActiveRecord::Base
|
|
136
163
|
# * <tt>moderator_password</tt>
|
137
164
|
#
|
138
165
|
# Triggers API call: <tt>create</tt>.
|
139
|
-
def send_create(
|
166
|
+
def send_create(user=nil, user_opts={})
|
140
167
|
# updates the server whenever a meeting will be created and guarantees it has a meetingid
|
141
168
|
self.server = select_server
|
142
169
|
self.meetingid = unique_meetingid() if self.meetingid.nil?
|
143
170
|
self.save unless self.new_record?
|
144
171
|
require_server
|
145
172
|
|
146
|
-
response =
|
173
|
+
response = internal_create_meeting(user, user_opts)
|
147
174
|
unless response.nil?
|
148
175
|
self.attendee_password = response[:attendeePW]
|
149
176
|
self.moderator_password = response[:moderatorPW]
|
@@ -157,19 +184,23 @@ class BigbluebuttonRoom < ActiveRecord::Base
|
|
157
184
|
# username:: Name of the user
|
158
185
|
# role:: Role of the user in this room. Can be <tt>[:moderator, :attendee]</tt>
|
159
186
|
# password:: Password to be use (in case role == nil)
|
187
|
+
# options:: Additional options to use when generating the URL
|
160
188
|
#
|
161
189
|
# Uses the API but does not require a request to the server.
|
162
|
-
def join_url(username, role, password=nil)
|
190
|
+
def join_url(username, role, password=nil, options={})
|
163
191
|
require_server
|
164
192
|
|
165
193
|
case role
|
166
194
|
when :moderator
|
167
|
-
self.server.api.join_meeting_url(self.meetingid, username, self.moderator_password)
|
195
|
+
r = self.server.api.join_meeting_url(self.meetingid, username, self.moderator_password, options)
|
168
196
|
when :attendee
|
169
|
-
self.server.api.join_meeting_url(self.meetingid, username, self.attendee_password)
|
197
|
+
r = self.server.api.join_meeting_url(self.meetingid, username, self.attendee_password, options)
|
170
198
|
else
|
171
|
-
self.server.api.join_meeting_url(self.meetingid, username, password)
|
199
|
+
r = self.server.api.join_meeting_url(self.meetingid, username, password, options)
|
172
200
|
end
|
201
|
+
|
202
|
+
r.strip! unless r.nil?
|
203
|
+
r
|
173
204
|
end
|
174
205
|
|
175
206
|
|
@@ -179,7 +210,7 @@ class BigbluebuttonRoom < ActiveRecord::Base
|
|
179
210
|
# params:: Hash with a key :password
|
180
211
|
def user_role(params)
|
181
212
|
role = nil
|
182
|
-
if params.has_key?(:password)
|
213
|
+
if params && params.has_key?(:password)
|
183
214
|
if self.moderator_password == params[:password]
|
184
215
|
role = :moderator
|
185
216
|
elsif self.attendee_password == params[:password]
|
@@ -216,11 +247,11 @@ class BigbluebuttonRoom < ActiveRecord::Base
|
|
216
247
|
# The create logic.
|
217
248
|
# Will create the meeting in this room unless it is already running.
|
218
249
|
# Returns true if the meeting was created.
|
219
|
-
def create_meeting(
|
250
|
+
def create_meeting(user=nil, request=nil, user_opts={})
|
220
251
|
fetch_is_running?
|
221
252
|
unless is_running?
|
222
253
|
add_domain_to_logout_url(request.protocol, request.host_with_port) unless request.nil?
|
223
|
-
send_create(
|
254
|
+
send_create(user, user_opts)
|
224
255
|
true
|
225
256
|
else
|
226
257
|
false
|
@@ -249,8 +280,97 @@ class BigbluebuttonRoom < ActiveRecord::Base
|
|
249
280
|
"#{SecureRandom.uuid}-#{Time.now.to_i}"
|
250
281
|
end
|
251
282
|
|
283
|
+
# Returns the current meeting running on this room, if any.
|
284
|
+
def get_current_meeting
|
285
|
+
unless self.start_time.nil?
|
286
|
+
BigbluebuttonMeeting.find_by_room_id_and_start_time(self.id, self.start_time.utc)
|
287
|
+
else
|
288
|
+
nil
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
# Updates the current meeting associated with this room
|
293
|
+
def update_current_meeting(metadata=nil)
|
294
|
+
unless self.start_time.nil?
|
295
|
+
attrs = {
|
296
|
+
:server => self.server,
|
297
|
+
:meetingid => self.meetingid,
|
298
|
+
:name => self.name,
|
299
|
+
:record => self.record,
|
300
|
+
:running => self.running
|
301
|
+
}
|
302
|
+
unless metadata.nil?
|
303
|
+
begin
|
304
|
+
attrs[:creator_id] = metadata[BigbluebuttonRails.metadata_user_id].to_i
|
305
|
+
attrs[:creator_name] = metadata[BigbluebuttonRails.metadata_user_name]
|
306
|
+
rescue
|
307
|
+
attrs[:creator_id] = nil
|
308
|
+
attrs[:creator_name] = nil
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
meeting = self.get_current_meeting
|
313
|
+
if !meeting.nil?
|
314
|
+
meeting.update_attributes(attrs)
|
315
|
+
|
316
|
+
# only create a new meeting if it is running
|
317
|
+
elsif self.running
|
318
|
+
attrs.merge!({ :room => self, :start_time => self.start_time.utc })
|
319
|
+
meeting = BigbluebuttonMeeting.create(attrs)
|
320
|
+
|
321
|
+
end
|
322
|
+
else
|
323
|
+
# TODO: not enough information to find the meeting, do what?
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
# Sets all meetings related to this room as not running
|
328
|
+
def finish_meetings
|
329
|
+
BigbluebuttonMeeting.where(:running => true)
|
330
|
+
.find_by_room_id(room_id)
|
331
|
+
.update_attributes(:running => false)
|
332
|
+
end
|
333
|
+
|
334
|
+
# Gets a 'configToken' to use when joining the room.
|
335
|
+
# Returns a string with the token generated or nil if there's no need
|
336
|
+
# for a token (the options set in the room are the default options or there
|
337
|
+
# are no options set in the room) or if an error occurred.
|
338
|
+
#
|
339
|
+
# The entire process consists in these steps:
|
340
|
+
# * Go to the server get the default config.xml;
|
341
|
+
# * Modify the config.xml based on the room options set in the room;
|
342
|
+
# * Go to the server set the new config.xml;
|
343
|
+
# * Get the token identifier and return it.
|
344
|
+
#
|
345
|
+
# Triggers API call: <tt>getDefaultConfigXML</tt>.
|
346
|
+
# Triggers API call: <tt>setConfigXML</tt>.
|
347
|
+
def fetch_new_token
|
348
|
+
if self.room_options.is_modified?
|
349
|
+
|
350
|
+
# get the default XML we will use to create a new one
|
351
|
+
config_xml = self.server.api.get_default_config_xml
|
352
|
+
|
353
|
+
# set the options on the XML
|
354
|
+
# returns true if something was changed
|
355
|
+
config_xml = self.room_options.set_on_config_xml(config_xml)
|
356
|
+
if config_xml
|
357
|
+
|
358
|
+
# get the new token for the room, and return it
|
359
|
+
self.server.api.set_config_xml(self.meetingid, config_xml)
|
360
|
+
else
|
361
|
+
nil
|
362
|
+
end
|
363
|
+
else
|
364
|
+
nil
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
252
368
|
protected
|
253
369
|
|
370
|
+
def create_room_options
|
371
|
+
BigbluebuttonRoomOptions.create(:room => self)
|
372
|
+
end
|
373
|
+
|
254
374
|
# Every room needs a server to be used.
|
255
375
|
# The server of a room can change during the room's lifespan, but
|
256
376
|
# it should not change if the room is running or if it was created
|
@@ -299,7 +419,7 @@ class BigbluebuttonRoom < ActiveRecord::Base
|
|
299
419
|
value
|
300
420
|
end
|
301
421
|
|
302
|
-
def
|
422
|
+
def internal_create_meeting(user=nil, user_opts={})
|
303
423
|
opts = {
|
304
424
|
:record => self.record,
|
305
425
|
:duration => self.duration,
|
@@ -310,14 +430,25 @@ class BigbluebuttonRoom < ActiveRecord::Base
|
|
310
430
|
:logoutURL => self.full_logout_url || self.logout_url,
|
311
431
|
:maxParticipants => self.max_participants,
|
312
432
|
:voiceBridge => self.voice_bridge
|
313
|
-
}.merge(
|
433
|
+
}.merge(user_opts)
|
434
|
+
|
435
|
+
opts.merge!(self.get_metadata_for_create)
|
314
436
|
|
315
437
|
# Add information about the user that is creating the meeting (if any)
|
316
|
-
|
317
|
-
|
438
|
+
unless user.nil?
|
439
|
+
userid = user.send(BigbluebuttonRails.user_attr_id)
|
440
|
+
username = user.send(BigbluebuttonRails.user_attr_name)
|
441
|
+
opts.merge!({ "meta_#{BigbluebuttonRails.metadata_user_id}" => userid })
|
442
|
+
opts.merge!({ "meta_#{BigbluebuttonRails.metadata_user_name}" => username })
|
443
|
+
end
|
318
444
|
|
319
445
|
self.server.api.request_headers = @request_headers # we need the client's IP
|
320
|
-
self.server.api.create_meeting(self.name, self.meetingid, opts)
|
446
|
+
response = self.server.api.create_meeting(self.name, self.meetingid, opts)
|
447
|
+
|
448
|
+
# enqueue an update in the meetings to start now
|
449
|
+
Resque.enqueue(::BigbluebuttonMeetingUpdater, self.id)
|
450
|
+
|
451
|
+
response
|
321
452
|
end
|
322
453
|
|
323
454
|
# Returns the default welcome message to be shown in a conference in case
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'bigbluebutton_api'
|
2
|
+
|
3
|
+
class BigbluebuttonRoomOptions < ActiveRecord::Base
|
4
|
+
include ActiveModel::ForbiddenAttributesProtection
|
5
|
+
|
6
|
+
belongs_to :room, :class_name => 'BigbluebuttonRoom'
|
7
|
+
validates :room_id, :presence => true
|
8
|
+
|
9
|
+
def get_available_layouts
|
10
|
+
["Default", "Video Chat", "Meeting", "Webinar", "Lecture assistant", "Lecture"]
|
11
|
+
end
|
12
|
+
|
13
|
+
# Sets the attributes from the model into the config.xml passed in the arguments.
|
14
|
+
# If anything was modified in the XML, returns the new XML generated as string.
|
15
|
+
# Otherwise returns false.
|
16
|
+
#
|
17
|
+
# xml (string):: The config.xml in which the attributes will be set
|
18
|
+
def set_on_config_xml(xml)
|
19
|
+
config_xml = BigBlueButton::BigBlueButtonConfigXml.new(xml)
|
20
|
+
unless self.default_layout.blank?
|
21
|
+
config_xml.set_attribute("layout", "defaultLayout", self.default_layout, false)
|
22
|
+
end
|
23
|
+
unless self.presenter_share_only.nil?
|
24
|
+
config_xml.set_attribute("VideoconfModule", "presenterShareOnly", self.presenter_share_only, true)
|
25
|
+
config_xml.set_attribute("PhoneModule", "presenterShareOnly", self.presenter_share_only, true)
|
26
|
+
end
|
27
|
+
unless self.auto_start_video.nil?
|
28
|
+
config_xml.set_attribute("VideoconfModule", "autoStart", self.auto_start_video, true)
|
29
|
+
end
|
30
|
+
unless self.auto_start_audio.nil?
|
31
|
+
config_xml.set_attribute("PhoneModule", "autoJoin", self.auto_start_audio, true)
|
32
|
+
end
|
33
|
+
if config_xml.is_modified?
|
34
|
+
config_xml.as_string
|
35
|
+
else
|
36
|
+
false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns true if any of the attributes was set. Is used to check whether the options
|
41
|
+
# have to be sent to the server (setConfigXML) or not.
|
42
|
+
def is_modified?
|
43
|
+
!self.default_layout.nil? || !self.presenter_share_only.nil? || !self.auto_start_audio.nil? ||
|
44
|
+
!self.auto_start_video.nil?
|
45
|
+
end
|
46
|
+
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'bigbluebutton_api'
|
2
2
|
|
3
3
|
class BigbluebuttonServer < ActiveRecord::Base
|
4
|
+
include ActiveModel::ForbiddenAttributesProtection
|
5
|
+
|
4
6
|
has_many :rooms,
|
5
7
|
:class_name => 'BigbluebuttonRoom',
|
6
8
|
:foreign_key => 'server_id',
|
@@ -38,8 +40,6 @@ class BigbluebuttonServer < ActiveRecord::Base
|
|
38
40
|
:presence => true,
|
39
41
|
:inclusion => { :in => ['0.7', '0.8'] }
|
40
42
|
|
41
|
-
attr_accessible :name, :url, :version, :salt, :param
|
42
|
-
|
43
43
|
# Array of <tt>BigbluebuttonMeeting</tt>
|
44
44
|
attr_reader :meetings
|
45
45
|
|
@@ -69,6 +69,7 @@ class BigbluebuttonServer < ActiveRecord::Base
|
|
69
69
|
@meetings = []
|
70
70
|
response[:meetings].each do |attr|
|
71
71
|
room = BigbluebuttonRoom.find_by_server_id_and_meetingid(self.id, attr[:meetingID])
|
72
|
+
# TODO: there might be more attributes returned by the API, review them all
|
72
73
|
if room.nil?
|
73
74
|
room = BigbluebuttonRoom.new(:server => self, :meetingid => attr[:meetingID],
|
74
75
|
:name => attr[:meetingID], :attendee_password => attr[:attendeePW],
|
@@ -78,6 +79,7 @@ class BigbluebuttonServer < ActiveRecord::Base
|
|
78
79
|
:moderator_password => attr[:moderatorPW])
|
79
80
|
end
|
80
81
|
room.running = attr[:running]
|
82
|
+
room.update_current_meeting
|
81
83
|
|
82
84
|
@meetings << room
|
83
85
|
end
|
@@ -46,6 +46,10 @@
|
|
46
46
|
<%= f.label :end_time %><br />
|
47
47
|
<%= f.text_field :end_time %>
|
48
48
|
</div>
|
49
|
+
<div class="field">
|
50
|
+
<%= f.label :description %><br />
|
51
|
+
<%= f.text_field :description %>
|
52
|
+
</div>
|
49
53
|
|
50
54
|
<p>
|
51
55
|
<b><%= BigbluebuttonRecording.human_attribute_name(:metadata) %>:</b>
|
@@ -22,6 +22,7 @@
|
|
22
22
|
<div class="field"><label><%= BigbluebuttonRecording.human_attribute_name(:available) %></label> <%= recording.available %></div>
|
23
23
|
<div class="field"><label><%= BigbluebuttonRecording.human_attribute_name(:start_time) %></label> <%= recording.start_time %></div>
|
24
24
|
<div class="field"><label><%= BigbluebuttonRecording.human_attribute_name(:end_time) %></label> <%= recording.end_time %></div>
|
25
|
+
<div class="field"><label><%= BigbluebuttonRecording.human_attribute_name(:description) %></label> <%= recording.description %></div>
|
25
26
|
<div class="field">
|
26
27
|
<label><%= BigbluebuttonRecording.human_attribute_name(:metadata) %></label>
|
27
28
|
<div>
|
@@ -52,6 +52,11 @@
|
|
52
52
|
<%= @recording.end_time %>
|
53
53
|
</p>
|
54
54
|
|
55
|
+
<p>
|
56
|
+
<b><%= BigbluebuttonRecording.human_attribute_name(:description) %>:</b>
|
57
|
+
<%= @recording.description %>
|
58
|
+
</p>
|
59
|
+
|
55
60
|
<p>
|
56
61
|
<b><%= BigbluebuttonRecording.human_attribute_name(:metadata) %>:</b>
|
57
62
|
<% @recording.metadata.each do |metadata| %>
|