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.
- checksums.yaml +4 -4
- data/.travis.yml +3 -3
- data/CHANGELOG.md +34 -0
- data/Dockerfile +23 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +14 -5
- data/README.md +42 -59
- data/Rakefile +6 -3
- data/app/controllers/bigbluebutton/api/rooms_controller.rb +117 -0
- data/app/controllers/bigbluebutton/playback_types_controller.rb +0 -3
- data/app/controllers/bigbluebutton/recordings_controller.rb +37 -23
- data/app/controllers/bigbluebutton/rooms_controller.rb +6 -31
- data/app/controllers/bigbluebutton/servers_controller.rb +0 -14
- data/app/helpers/bigbluebutton_rails_helper.rb +4 -0
- data/app/models/bigbluebutton_attendee.rb +21 -0
- data/app/models/bigbluebutton_meeting.rb +5 -0
- data/app/models/bigbluebutton_playback_format.rb +3 -2
- data/app/models/bigbluebutton_recording.rb +164 -68
- data/app/models/bigbluebutton_room.rb +148 -59
- data/app/models/bigbluebutton_server.rb +1 -1
- data/app/views/bigbluebutton/api/error.rabl +10 -0
- data/app/views/bigbluebutton/api/rooms/index.rabl +45 -0
- data/app/views/bigbluebutton/api/rooms/join.rabl +6 -0
- data/app/views/bigbluebutton/api/rooms/running.rabl +10 -0
- data/app/views/bigbluebutton/recordings/play.html.erb +1 -0
- data/app/views/bigbluebutton/servers/_activity_list.html.erb +5 -5
- data/app/workers/{bigbluebutton_finish_meetings.rb → bigbluebutton_finish_meetings_worker.rb} +2 -2
- data/app/workers/{bigbluebutton_meeting_updater.rb → bigbluebutton_meeting_updater_worker.rb} +3 -3
- data/app/workers/bigbluebutton_recordings_for_room_worker.rb +27 -0
- data/app/workers/{bigbluebutton_update_recordings.rb → bigbluebutton_update_recordings_worker.rb} +2 -2
- data/app/workers/{bigbluebutton_update_server_configs.rb → bigbluebutton_update_server_configs_worker.rb} +3 -3
- data/bigbluebutton_rails.gemspec +1 -0
- data/config/locales/en.yml +21 -0
- data/config/locales/pt-br.yml +1 -0
- data/config/resque/resque.rake +7 -1
- data/config/resque/workers_schedule.yml +3 -3
- data/docker-compose.yml +68 -0
- data/dumb-init_1.2.0 +0 -0
- data/lib/bigbluebutton_rails.rb +1 -2
- data/lib/bigbluebutton_rails/api_controller_methods.rb +138 -0
- data/lib/bigbluebutton_rails/configuration.rb +33 -4
- data/lib/bigbluebutton_rails/controller_methods.rb +0 -31
- data/lib/bigbluebutton_rails/exceptions.rb +17 -0
- data/lib/bigbluebutton_rails/rails/routes.rb +14 -0
- data/lib/bigbluebutton_rails/version.rb +1 -1
- data/lib/generators/bigbluebutton_rails/templates/migration.rb +17 -3
- data/lib/generators/bigbluebutton_rails/templates/migration_2_2_0.rb +1 -1
- data/lib/generators/bigbluebutton_rails/templates/migration_2_2_0_b.rb +106 -0
- data/lib/generators/bigbluebutton_rails/templates/migration_2_3_0.rb +22 -0
- data/lib/tasks/bigbluebutton_rails/meetings.rake +1 -1
- data/spec/controllers/bigbluebutton/api/rooms_controller_spec.rb +498 -0
- data/spec/controllers/bigbluebutton/recordings_controller_spec.rb +84 -0
- data/spec/controllers/bigbluebutton/rooms_controller_exception_handling_spec.rb +2 -2
- data/spec/controllers/bigbluebutton/rooms_controller_spec.rb +24 -22
- data/spec/controllers/bigbluebutton/servers_controller_spec.rb +9 -0
- data/spec/factories/bigbluebutton_attendee.rb +7 -0
- data/spec/factories/bigbluebutton_meeting.rb +0 -1
- data/spec/factories/bigbluebutton_playback_type.rb +1 -0
- data/spec/factories/bigbluebutton_recording.rb +2 -4
- data/spec/helpers/bigbluebutton_rails_helper_spec.rb +10 -2
- data/spec/lib/bigbluebutton_rails/background_tasks_spec.rb +1 -0
- data/spec/lib/tasks/meetings_rake_spec.rb +1 -1
- data/spec/models/bigbluebutton_attendee_spec.rb +44 -0
- data/spec/models/bigbluebutton_meeting_db_spec.rb +0 -1
- data/spec/models/bigbluebutton_meeting_spec.rb +1 -0
- data/spec/models/bigbluebutton_playback_format_spec.rb +2 -0
- data/spec/models/bigbluebutton_playback_type_db_spec.rb +1 -0
- data/spec/models/bigbluebutton_recording_db_spec.rb +2 -2
- data/spec/models/bigbluebutton_recording_spec.rb +404 -72
- data/spec/models/bigbluebutton_room_spec.rb +435 -148
- data/spec/rails_app/config/database.yml.example +10 -11
- data/spec/rails_app/config/initializers/resque.rb +33 -0
- data/spec/rails_app/config/routes.rb +2 -0
- data/spec/rails_app/lib/tasks/db/populate.rake +73 -55
- data/spec/support/mocked_server.rb +1 -1
- data/spec/workers/{bigbluebutton_finish_meetings_spec.rb → bigbluebutton_finish_meetings_worker_spec.rb} +3 -3
- data/spec/workers/{bigbluebutton_meeting_updater_spec.rb → bigbluebutton_meeting_updater_worker_spec.rb} +8 -7
- data/spec/workers/bigbluebutton_recordings_for_room_worker_spec.rb +49 -0
- data/spec/workers/{bigbluebutton_update_recordings_spec.rb → bigbluebutton_update_recordings_worker_spec.rb} +3 -3
- data/spec/workers/{bigbluebutton_update_server_configs_spec.rb → bigbluebutton_update_server_configs_worker_spec.rb} +4 -4
- metadata +42 -14
- data/lib/classes/bigbluebutton_attendee.rb +0 -21
- data/spec/classes/bigbluebutton_attendee_spec.rb +0 -76
- data/spec/controllers/bigbluebutton/recordings_controller_json_responses_spec.rb +0 -111
- data/spec/controllers/bigbluebutton/rooms_controller_json_responses_spec.rb +0 -203
- data/spec/controllers/bigbluebutton/servers_controller_json_responses_spec.rb +0 -162
|
@@ -2,7 +2,6 @@ class Bigbluebutton::PlaybackTypesController < ApplicationController
|
|
|
2
2
|
include BigbluebuttonRails::InternalControllerMethods
|
|
3
3
|
|
|
4
4
|
respond_to :html
|
|
5
|
-
respond_to :json
|
|
6
5
|
before_filter :find_playback_type, only: [:update]
|
|
7
6
|
|
|
8
7
|
def update
|
|
@@ -12,13 +11,11 @@ class Bigbluebutton::PlaybackTypesController < ApplicationController
|
|
|
12
11
|
message = t('bigbluebutton_rails.playback_types.notice.update.success')
|
|
13
12
|
redirect_to_using_params request.referer, :notice => message
|
|
14
13
|
}
|
|
15
|
-
format.json { render :json => true, :status => :ok }
|
|
16
14
|
else
|
|
17
15
|
format.html {
|
|
18
16
|
flash[:error] = @playback_type.errors.full_messages.join(", ")
|
|
19
17
|
redirect_to_using_params request.referer
|
|
20
18
|
}
|
|
21
|
-
format.json { render :json => @playback_type.errors.full_messages, :status => :unprocessable_entity }
|
|
22
19
|
end
|
|
23
20
|
end
|
|
24
21
|
end
|
|
@@ -2,11 +2,21 @@ class Bigbluebutton::RecordingsController < ApplicationController
|
|
|
2
2
|
include BigbluebuttonRails::InternalControllerMethods
|
|
3
3
|
|
|
4
4
|
respond_to :html
|
|
5
|
-
respond_to :json, :only => [:index, :show, :update, :destroy, :publish, :unpublish]
|
|
6
5
|
before_filter :find_recording, :except => [:index]
|
|
7
6
|
before_filter :check_for_server, :only => [:publish, :unpublish]
|
|
8
7
|
before_filter :find_playback, :only => [:play]
|
|
9
8
|
|
|
9
|
+
layout :determine_layout
|
|
10
|
+
|
|
11
|
+
def determine_layout
|
|
12
|
+
case params[:action].to_sym
|
|
13
|
+
when :play
|
|
14
|
+
false
|
|
15
|
+
else
|
|
16
|
+
'application'
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
10
20
|
def index
|
|
11
21
|
@recordings ||= BigbluebuttonRecording.all
|
|
12
22
|
respond_with(@recordings)
|
|
@@ -27,10 +37,8 @@ class Bigbluebutton::RecordingsController < ApplicationController
|
|
|
27
37
|
message = t('bigbluebutton_rails.recordings.notice.update.success')
|
|
28
38
|
redirect_to_using_params @recording, :notice => message
|
|
29
39
|
}
|
|
30
|
-
format.json { render :json => true, :status => :ok }
|
|
31
40
|
else
|
|
32
41
|
format.html { redirect_to_params_or_render :edit }
|
|
33
|
-
format.json { render :json => @recording.errors.full_messages, :status => :unprocessable_entity }
|
|
34
42
|
end
|
|
35
43
|
end
|
|
36
44
|
end
|
|
@@ -60,26 +68,29 @@ class Bigbluebutton::RecordingsController < ApplicationController
|
|
|
60
68
|
redirect_to_using_params bigbluebutton_recordings_url, :notice => message
|
|
61
69
|
end
|
|
62
70
|
}
|
|
63
|
-
format.json {
|
|
64
|
-
if error
|
|
65
|
-
render :json => { :message => message }, :status => :error
|
|
66
|
-
else
|
|
67
|
-
render :json => { :message => message }
|
|
68
|
-
end
|
|
69
|
-
}
|
|
70
71
|
end
|
|
71
72
|
end
|
|
72
73
|
|
|
73
74
|
def play
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
if
|
|
77
|
-
|
|
75
|
+
if @recording.present?
|
|
76
|
+
if @playback
|
|
77
|
+
if BigbluebuttonRails.configuration.playback_url_authentication
|
|
78
|
+
uri = @recording.token_url(bigbluebutton_user, request.remote_ip, @playback)
|
|
79
|
+
@playback_url = uri
|
|
78
80
|
else
|
|
79
|
-
|
|
80
|
-
redirect_to_using_params bigbluebutton_recording_url(@recording)
|
|
81
|
+
@playback_url = @playback.url
|
|
81
82
|
end
|
|
82
|
-
|
|
83
|
+
if @playback.downloadable? || !BigbluebuttonRails.configuration.playback_iframe
|
|
84
|
+
redirect_to @playback_url
|
|
85
|
+
end
|
|
86
|
+
# else will render the default 'play' view
|
|
87
|
+
else
|
|
88
|
+
flash[:error] = t('bigbluebutton_rails.recordings.errors.play.no_format')
|
|
89
|
+
redirect_to_using_params bigbluebutton_recording_url(@recording)
|
|
90
|
+
end
|
|
91
|
+
else
|
|
92
|
+
flash[:error] = t('bigbluebutton_rails.recordings.errors.destroyed')
|
|
93
|
+
redirect_to my_home_path
|
|
83
94
|
end
|
|
84
95
|
end
|
|
85
96
|
|
|
@@ -105,7 +116,6 @@ class Bigbluebutton::RecordingsController < ApplicationController
|
|
|
105
116
|
flash[:error] = message
|
|
106
117
|
redirect_to bigbluebutton_recording_path(@recording)
|
|
107
118
|
}
|
|
108
|
-
format.json { render :json => message, :status => :error }
|
|
109
119
|
end
|
|
110
120
|
false
|
|
111
121
|
else
|
|
@@ -126,7 +136,6 @@ class Bigbluebutton::RecordingsController < ApplicationController
|
|
|
126
136
|
format.html {
|
|
127
137
|
redirect_to_using_params bigbluebutton_recording_path(@recording), :notice => message
|
|
128
138
|
}
|
|
129
|
-
format.json { render :json => message }
|
|
130
139
|
end
|
|
131
140
|
rescue BigBlueButton::BigBlueButtonException => e
|
|
132
141
|
respond_with do |format|
|
|
@@ -134,7 +143,6 @@ class Bigbluebutton::RecordingsController < ApplicationController
|
|
|
134
143
|
flash[:error] = e.to_s[0..200]
|
|
135
144
|
redirect_to_using_params bigbluebutton_recording_path(@recording)
|
|
136
145
|
}
|
|
137
|
-
format.json { render :json => e.to_s[0..200], :status => :error }
|
|
138
146
|
end
|
|
139
147
|
end
|
|
140
148
|
end
|
|
@@ -154,11 +162,17 @@ class Bigbluebutton::RecordingsController < ApplicationController
|
|
|
154
162
|
protected
|
|
155
163
|
|
|
156
164
|
def find_playback
|
|
157
|
-
if
|
|
158
|
-
|
|
165
|
+
if @recording.present?
|
|
166
|
+
if params[:type]
|
|
167
|
+
@playback = @recording.playback_formats.where(:playback_type_id => BigbluebuttonPlaybackType.find_by_identifier(params[:type])).first
|
|
168
|
+
else
|
|
169
|
+
@playback = @recording.default_playback_format || @recording.playback_formats.first
|
|
170
|
+
end
|
|
159
171
|
else
|
|
160
|
-
|
|
172
|
+
flash[:error] = t('bigbluebutton_rails.recordings.errors.destroyed')
|
|
173
|
+
redirect_to my_home_path
|
|
161
174
|
end
|
|
175
|
+
|
|
162
176
|
end
|
|
163
177
|
|
|
164
178
|
end
|
|
@@ -14,8 +14,8 @@ class Bigbluebutton::RoomsController < ApplicationController
|
|
|
14
14
|
before_filter :join_check_can_create, :only => :join
|
|
15
15
|
before_filter :join_check_redirect_to_mobile, :only => :join
|
|
16
16
|
|
|
17
|
-
respond_to :html, :
|
|
18
|
-
respond_to :json, :
|
|
17
|
+
respond_to :html, except: :running
|
|
18
|
+
respond_to :json, only: :running
|
|
19
19
|
|
|
20
20
|
def index
|
|
21
21
|
@rooms ||= BigbluebuttonRoom.all
|
|
@@ -50,15 +50,11 @@ class Bigbluebutton::RoomsController < ApplicationController
|
|
|
50
50
|
format.html {
|
|
51
51
|
redirect_to_using_params bigbluebutton_room_path(@room), :notice => message
|
|
52
52
|
}
|
|
53
|
-
format.json {
|
|
54
|
-
render :json => { :message => message }, :status => :created
|
|
55
|
-
}
|
|
56
53
|
else
|
|
57
54
|
format.html {
|
|
58
55
|
message = t('bigbluebutton_rails.rooms.notice.create.failure')
|
|
59
56
|
redirect_to_params_or_render :new, :error => message
|
|
60
57
|
}
|
|
61
|
-
format.json { render :json => @room.errors.full_messages, :status => :unprocessable_entity }
|
|
62
58
|
end
|
|
63
59
|
end
|
|
64
60
|
end
|
|
@@ -70,13 +66,11 @@ class Bigbluebutton::RoomsController < ApplicationController
|
|
|
70
66
|
format.html {
|
|
71
67
|
redirect_to_using_params bigbluebutton_room_path(@room), :notice => message
|
|
72
68
|
}
|
|
73
|
-
format.json { render :json => { :message => message } }
|
|
74
69
|
else
|
|
75
70
|
format.html {
|
|
76
71
|
message = t('bigbluebutton_rails.rooms.notice.update.failure')
|
|
77
72
|
redirect_to_params_or_render :edit, :error => message
|
|
78
73
|
}
|
|
79
|
-
format.json { render :json => @room.errors.full_messages, :status => :unprocessable_entity }
|
|
80
74
|
end
|
|
81
75
|
end
|
|
82
76
|
end
|
|
@@ -100,13 +94,6 @@ class Bigbluebutton::RoomsController < ApplicationController
|
|
|
100
94
|
flash[:error] = message if error
|
|
101
95
|
redirect_to_using_params bigbluebutton_rooms_url
|
|
102
96
|
}
|
|
103
|
-
format.json {
|
|
104
|
-
if error
|
|
105
|
-
render :json => { :message => message }, :status => :error
|
|
106
|
-
else
|
|
107
|
-
render :json => { :message => message }
|
|
108
|
-
end
|
|
109
|
-
}
|
|
110
97
|
end
|
|
111
98
|
end
|
|
112
99
|
|
|
@@ -163,14 +150,12 @@ class Bigbluebutton::RoomsController < ApplicationController
|
|
|
163
150
|
flash[:error] = message
|
|
164
151
|
redirect_to_using_params :back
|
|
165
152
|
}
|
|
166
|
-
format.json { render :json => message, :status => :error }
|
|
167
153
|
end
|
|
168
154
|
else
|
|
169
155
|
respond_with do |format|
|
|
170
156
|
format.html {
|
|
171
157
|
redirect_to_using_params bigbluebutton_room_path(@room), :notice => message
|
|
172
158
|
}
|
|
173
|
-
format.json { render :json => message }
|
|
174
159
|
end
|
|
175
160
|
end
|
|
176
161
|
|
|
@@ -224,7 +209,6 @@ class Bigbluebutton::RoomsController < ApplicationController
|
|
|
224
209
|
message = t('bigbluebutton_rails.rooms.notice.generate_dial_number.success')
|
|
225
210
|
respond_with do |format|
|
|
226
211
|
format.html { redirect_to_using_params :back, notice: message }
|
|
227
|
-
format.json { render json: true, status: :ok }
|
|
228
212
|
end
|
|
229
213
|
else
|
|
230
214
|
message = t('bigbluebutton_rails.rooms.errors.generate_dial_number.not_unique')
|
|
@@ -233,7 +217,6 @@ class Bigbluebutton::RoomsController < ApplicationController
|
|
|
233
217
|
flash[:error] = message
|
|
234
218
|
redirect_to_using_params :back
|
|
235
219
|
}
|
|
236
|
-
format.json { render json: { message: message }, status: :error }
|
|
237
220
|
end
|
|
238
221
|
end
|
|
239
222
|
end
|
|
@@ -241,7 +224,7 @@ class Bigbluebutton::RoomsController < ApplicationController
|
|
|
241
224
|
protected
|
|
242
225
|
|
|
243
226
|
def find_room
|
|
244
|
-
@room ||= BigbluebuttonRoom.
|
|
227
|
+
@room ||= BigbluebuttonRoom.find_by(param: params[:id])
|
|
245
228
|
end
|
|
246
229
|
|
|
247
230
|
def set_request_headers
|
|
@@ -336,8 +319,7 @@ class Bigbluebutton::RoomsController < ApplicationController
|
|
|
336
319
|
# first check if we have to create the room and if the user can do it
|
|
337
320
|
unless @room.fetch_is_running?
|
|
338
321
|
if bigbluebutton_can_create?(@room, role)
|
|
339
|
-
|
|
340
|
-
if @room.create_meeting(bigbluebutton_user, request, user_opts)
|
|
322
|
+
if @room.create_meeting(bigbluebutton_user, request)
|
|
341
323
|
logger.info "Meeting created: id: #{@room.meetingid}, name: #{@room.name}, created_by: #{username}, time: #{Time.now.iso8601}"
|
|
342
324
|
end
|
|
343
325
|
else
|
|
@@ -347,16 +329,9 @@ class Bigbluebutton::RoomsController < ApplicationController
|
|
|
347
329
|
end
|
|
348
330
|
end
|
|
349
331
|
|
|
350
|
-
# gets the token with the configurations for this user/room
|
|
351
|
-
token = @room.fetch_new_token
|
|
352
|
-
options = if token.nil? then {} else { :configToken => token } end
|
|
353
|
-
|
|
354
|
-
# set the create time and the user id, if they exist
|
|
355
|
-
options.merge!({ createTime: @room.create_time }) unless @room.create_time.blank?
|
|
356
|
-
options.merge!({ userID: id }) unless id.blank?
|
|
357
|
-
|
|
358
332
|
# room created and running, try to join it
|
|
359
|
-
url = @room.
|
|
333
|
+
url = @room.parameterized_join_url(username, role, id, {}, bigbluebutton_user)
|
|
334
|
+
|
|
360
335
|
unless url.nil?
|
|
361
336
|
|
|
362
337
|
# change the protocol to join with a mobile device
|
|
@@ -2,7 +2,6 @@ class Bigbluebutton::ServersController < ApplicationController
|
|
|
2
2
|
include BigbluebuttonRails::InternalControllerMethods
|
|
3
3
|
|
|
4
4
|
respond_to :html
|
|
5
|
-
respond_to :json, :only => [:index, :show, :new, :create, :update, :destroy, :activity, :rooms]
|
|
6
5
|
before_filter :find_server, :except => [:index, :new, :create]
|
|
7
6
|
|
|
8
7
|
def index
|
|
@@ -47,14 +46,8 @@ class Bigbluebutton::ServersController < ApplicationController
|
|
|
47
46
|
if error
|
|
48
47
|
flash[:error] = message
|
|
49
48
|
format.html { render :activity }
|
|
50
|
-
format.json {
|
|
51
|
-
array = @server.meetings
|
|
52
|
-
array.insert(0, { :message => message })
|
|
53
|
-
render :json => array, :status => :error
|
|
54
|
-
}
|
|
55
49
|
else
|
|
56
50
|
format.html
|
|
57
|
-
format.json
|
|
58
51
|
end
|
|
59
52
|
end
|
|
60
53
|
end
|
|
@@ -68,10 +61,8 @@ class Bigbluebutton::ServersController < ApplicationController
|
|
|
68
61
|
message = t('bigbluebutton_rails.servers.notice.create.success')
|
|
69
62
|
redirect_to_using_params @server, :notice => message
|
|
70
63
|
}
|
|
71
|
-
format.json { render :json => @server, :status => :created }
|
|
72
64
|
else
|
|
73
65
|
format.html { redirect_to_params_or_render :new }
|
|
74
|
-
format.json { render :json => @server.errors.full_messages, :status => :unprocessable_entity }
|
|
75
66
|
end
|
|
76
67
|
end
|
|
77
68
|
end
|
|
@@ -83,10 +74,8 @@ class Bigbluebutton::ServersController < ApplicationController
|
|
|
83
74
|
message = t('bigbluebutton_rails.servers.notice.update.success')
|
|
84
75
|
redirect_to_using_params @server, :notice => message
|
|
85
76
|
}
|
|
86
|
-
format.json { render :json => true, :status => :ok }
|
|
87
77
|
else
|
|
88
78
|
format.html { redirect_to_params_or_render :edit }
|
|
89
|
-
format.json { render :json => @server.errors.full_messages, :status => :unprocessable_entity }
|
|
90
79
|
end
|
|
91
80
|
end
|
|
92
81
|
end
|
|
@@ -97,7 +86,6 @@ class Bigbluebutton::ServersController < ApplicationController
|
|
|
97
86
|
|
|
98
87
|
respond_with do |format|
|
|
99
88
|
format.html { redirect_to_using_params bigbluebutton_servers_url }
|
|
100
|
-
format.json { render :json => true, :status => :ok }
|
|
101
89
|
end
|
|
102
90
|
end
|
|
103
91
|
|
|
@@ -174,7 +162,6 @@ class Bigbluebutton::ServersController < ApplicationController
|
|
|
174
162
|
end
|
|
175
163
|
redirect_to_using_params recordings_bigbluebutton_server_path(@server), :notice => message
|
|
176
164
|
}
|
|
177
|
-
format.json { render :json => message }
|
|
178
165
|
end
|
|
179
166
|
rescue BigBlueButton::BigBlueButtonException => e
|
|
180
167
|
respond_with do |format|
|
|
@@ -182,7 +169,6 @@ class Bigbluebutton::ServersController < ApplicationController
|
|
|
182
169
|
flash[:error] = e.to_s[0..200]
|
|
183
170
|
redirect_to_using_params recordings_bigbluebutton_server_path(@server)
|
|
184
171
|
}
|
|
185
|
-
format.json { render :json => e.to_s, :status => :error }
|
|
186
172
|
end
|
|
187
173
|
end
|
|
188
174
|
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class BigbluebuttonAttendee < ActiveRecord::Base
|
|
2
|
+
include ActiveModel::ForbiddenAttributesProtection
|
|
3
|
+
|
|
4
|
+
belongs_to :meeting, :class_name => 'BigbluebuttonMeeting',
|
|
5
|
+
:foreign_key => :bigbluebutton_meeting_id
|
|
6
|
+
|
|
7
|
+
validates :bigbluebutton_meeting_id, :presence => true
|
|
8
|
+
|
|
9
|
+
# TODO: no role on getStats yet, but it exists on getMeetings
|
|
10
|
+
attr_accessor :role
|
|
11
|
+
|
|
12
|
+
def duration
|
|
13
|
+
self.left_time - self.join_time
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def from_hash(hash)
|
|
17
|
+
self.user_id = hash[:userID].to_s
|
|
18
|
+
self.user_name = hash[:fullName].to_s
|
|
19
|
+
self.role = hash[:role].to_s.downcase == "moderator" ? :moderator : :attendee
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# coding: utf-8
|
|
1
2
|
class BigbluebuttonMeeting < ActiveRecord::Base
|
|
2
3
|
include ActiveModel::ForbiddenAttributesProtection
|
|
3
4
|
|
|
@@ -8,6 +9,10 @@ class BigbluebuttonMeeting < ActiveRecord::Base
|
|
|
8
9
|
:foreign_key => 'meeting_id',
|
|
9
10
|
:dependent => :nullify
|
|
10
11
|
|
|
12
|
+
has_many :attendees,
|
|
13
|
+
:class_name => 'BigbluebuttonAttendee',
|
|
14
|
+
:dependent => :destroy
|
|
15
|
+
|
|
11
16
|
validates :room, :presence => true
|
|
12
17
|
|
|
13
18
|
validates :meetingid, :presence => true, :length => { :minimum => 1, :maximum => 100 }
|
|
@@ -4,8 +4,9 @@ class BigbluebuttonPlaybackFormat < ActiveRecord::Base
|
|
|
4
4
|
belongs_to :recording, :class_name => 'BigbluebuttonRecording'
|
|
5
5
|
belongs_to :playback_type, :class_name => 'BigbluebuttonPlaybackType'
|
|
6
6
|
|
|
7
|
-
delegate :name, :identifier, :visible, :visible?, :default, :default?,
|
|
8
|
-
|
|
7
|
+
delegate :name, :identifier, :visible, :visible?, :default, :default?,
|
|
8
|
+
:description, :downloadable, :downloadable?,
|
|
9
|
+
to: :playback_type, allow_nil: true
|
|
9
10
|
alias_attribute :format_type, :identifier
|
|
10
11
|
|
|
11
12
|
validates :recording_id, :presence => true
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
class BigbluebuttonRecording < ActiveRecord::Base
|
|
2
2
|
include ActiveModel::ForbiddenAttributesProtection
|
|
3
3
|
|
|
4
|
+
# NOTE: when adding new attributes to recordings, add them to `recording_changed?`
|
|
5
|
+
|
|
4
6
|
belongs_to :server, class_name: 'BigbluebuttonServer'
|
|
5
7
|
belongs_to :room, class_name: 'BigbluebuttonRoom'
|
|
6
8
|
belongs_to :meeting, class_name: 'BigbluebuttonMeeting'
|
|
@@ -23,15 +25,46 @@ class BigbluebuttonRecording < ActiveRecord::Base
|
|
|
23
25
|
|
|
24
26
|
scope :published, -> { where(:published => true) }
|
|
25
27
|
|
|
28
|
+
serialize :recording_users, Array
|
|
29
|
+
|
|
26
30
|
def to_param
|
|
27
31
|
self.recordid
|
|
28
32
|
end
|
|
29
33
|
|
|
34
|
+
def get_token(user, ip)
|
|
35
|
+
server = BigbluebuttonServer.default
|
|
36
|
+
user.present? ? authName = user.username : authName = "anonymous"
|
|
37
|
+
api_token = server.api.send_api_request(:getRecordingToken, { authUser: authName, authAddr: ip, meetingID: self.recordid })
|
|
38
|
+
str_token = api_token[:token]
|
|
39
|
+
str_token
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Passing it on the url
|
|
43
|
+
#
|
|
44
|
+
def token_url(user, ip, playback)
|
|
45
|
+
auth_token = get_token(user, ip)
|
|
46
|
+
if auth_token.present?
|
|
47
|
+
uri = playback.url
|
|
48
|
+
uri += URI.parse(uri).query.blank? ? "?" : "&"
|
|
49
|
+
uri += "token=#{auth_token}"
|
|
50
|
+
uri
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
30
54
|
def default_playback_format
|
|
31
55
|
playback_formats.joins(:playback_type)
|
|
32
56
|
.where("bigbluebutton_playback_types.default = ?", true).first
|
|
33
57
|
end
|
|
34
58
|
|
|
59
|
+
# Remove this recording from the server
|
|
60
|
+
def delete_from_server!
|
|
61
|
+
if self.server.present?
|
|
62
|
+
self.server.send_delete_recordings(self.recordid)
|
|
63
|
+
else
|
|
64
|
+
false
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
35
68
|
# Returns the overall (i.e. for all recordings) average length of recordings in seconds
|
|
36
69
|
# Uses the length of the default playback format
|
|
37
70
|
def self.overall_average_length
|
|
@@ -47,6 +80,56 @@ class BigbluebuttonRecording < ActiveRecord::Base
|
|
|
47
80
|
avg.nil? ? 0 : avg
|
|
48
81
|
end
|
|
49
82
|
|
|
83
|
+
# Compares a recording from the db with data from a getRecordings call.
|
|
84
|
+
# If anything changed in the recording, returns true.
|
|
85
|
+
# We select only the attributes that are saved and turn it all into sorted arrays
|
|
86
|
+
# to compare. If new attributes are stored in recordings, they should be added here.
|
|
87
|
+
#
|
|
88
|
+
# This was created to speed up the full sync of recordings.
|
|
89
|
+
# In the worst case the comparison is wrong and we're updating them all (same as
|
|
90
|
+
# not using this method at all, which is ok).
|
|
91
|
+
def self.recording_changed?(recording, data)
|
|
92
|
+
begin
|
|
93
|
+
# the attributes that are considered in the comparison
|
|
94
|
+
keys = [:end_time, :meetingid, :metadata, :playback, :published, :recordid, :size, :start_time] # rawSize is not stored at the moment
|
|
95
|
+
keys_formats = [:length, :type, :url] # :size, :processingTime are not stored at the moment
|
|
96
|
+
|
|
97
|
+
# the data from getRecordings
|
|
98
|
+
data_clone = data.deep_dup
|
|
99
|
+
data_clone[:size] = data_clone[:size].to_s if data_clone.key?(:size)
|
|
100
|
+
data_clone[:metadata] = data_clone[:metadata].sort if data_clone.key?(:metadata)
|
|
101
|
+
if data_clone.key?(:playback) && data_clone[:playback].key?(:format)
|
|
102
|
+
data_clone[:playback][:format] = [data_clone[:playback][:format]] unless data_clone[:playback][:format].is_a?(Array)
|
|
103
|
+
data_clone[:playback] = data_clone[:playback][:format].map{ |f|
|
|
104
|
+
f.slice(*keys_formats).sort
|
|
105
|
+
}.sort
|
|
106
|
+
else
|
|
107
|
+
data_clone[:playback] = []
|
|
108
|
+
end
|
|
109
|
+
data_clone[:end_time] = data_clone[:end_time].to_i if data_clone.key?(:end_time)
|
|
110
|
+
data_clone[:start_time] = data_clone[:start_time].to_i if data_clone.key?(:start_time)
|
|
111
|
+
data_clone = data_clone.slice(*keys)
|
|
112
|
+
data_sorted = data_clone.sort
|
|
113
|
+
|
|
114
|
+
# the data from the recording in the db
|
|
115
|
+
attrs = recording.attributes.symbolize_keys.slice(*keys)
|
|
116
|
+
attrs[:size] = attrs[:size].to_s if attrs.key?(:size)
|
|
117
|
+
attrs[:metadata] = recording.metadata.pluck(:name, :content).map{ |i| [i[0].to_sym, i[1]] }.sort
|
|
118
|
+
attrs[:playback] = recording.playback_formats.map{ |f|
|
|
119
|
+
r = f.attributes.symbolize_keys.slice(*keys_formats)
|
|
120
|
+
r[:type] = f.format_type
|
|
121
|
+
r.sort
|
|
122
|
+
}.sort
|
|
123
|
+
attrs = attrs.sort
|
|
124
|
+
|
|
125
|
+
# compare
|
|
126
|
+
data_sorted.to_s != attrs.to_s
|
|
127
|
+
rescue StandardError => e
|
|
128
|
+
logger.error "Error comparing recordings: #{e.inspect}"
|
|
129
|
+
true # always update recordings if on error
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
50
133
|
# Syncs the recordings in the db with the array of recordings in 'recordings',
|
|
51
134
|
# as received from BigBlueButtonApi#get_recordings.
|
|
52
135
|
# Will add new recordings that are not in the db yet and update the ones that
|
|
@@ -60,18 +143,24 @@ class BigbluebuttonRecording < ActiveRecord::Base
|
|
|
60
143
|
recordings.each do |rec|
|
|
61
144
|
rec_obj = BigbluebuttonRecording.find_by_recordid(rec[:recordID])
|
|
62
145
|
rec_data = adapt_recording_hash(rec)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
146
|
+
changed = !rec_obj.present? ||
|
|
147
|
+
self.recording_changed?(rec_obj, rec_data)
|
|
148
|
+
|
|
149
|
+
if changed
|
|
150
|
+
BigbluebuttonRecording.transaction do
|
|
151
|
+
if rec_obj
|
|
152
|
+
logger.info "Sync recordings: updating recording #{rec_obj.inspect}"
|
|
153
|
+
logger.debug "Sync recordings: recording data #{rec_data.inspect}"
|
|
154
|
+
self.update_recording(server, rec_obj, rec_data)
|
|
155
|
+
else
|
|
156
|
+
logger.info "Sync recordings: creating recording"
|
|
157
|
+
logger.debug "Sync recordings: recording data #{rec_data.inspect}"
|
|
158
|
+
self.create_recording(server, rec_data)
|
|
159
|
+
end
|
|
72
160
|
end
|
|
73
161
|
end
|
|
74
162
|
end
|
|
163
|
+
cleanup_playback_types
|
|
75
164
|
|
|
76
165
|
# set as unavailable the recordings that are not in 'recordings', but
|
|
77
166
|
# only in a full synchronization process, which means that the recordings
|
|
@@ -107,6 +196,22 @@ class BigbluebuttonRecording < ActiveRecord::Base
|
|
|
107
196
|
new_hash
|
|
108
197
|
end
|
|
109
198
|
|
|
199
|
+
def self.adapt_recording_users(original)
|
|
200
|
+
if original.present? && original.size > 0
|
|
201
|
+
users = original[:user]
|
|
202
|
+
users = [users] unless users.is_a?(Array)
|
|
203
|
+
users = users.map{ |u|
|
|
204
|
+
id = u[:externalUserID]
|
|
205
|
+
begin
|
|
206
|
+
id = Integer(id)
|
|
207
|
+
rescue
|
|
208
|
+
end
|
|
209
|
+
id
|
|
210
|
+
}
|
|
211
|
+
return users
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
110
215
|
# Updates the BigbluebuttonRecording 'recording' with the data in the hash 'data'.
|
|
111
216
|
# The format expected for 'data' follows the format returned by
|
|
112
217
|
# BigBlueButtonApi#get_recordings but with the keys already converted to our format.
|
|
@@ -115,6 +220,7 @@ class BigbluebuttonRecording < ActiveRecord::Base
|
|
|
115
220
|
recording.room = BigbluebuttonRails.configuration.match_room_recording.call(data)
|
|
116
221
|
recording.attributes = data.slice(:meetingid, :name, :published, :start_time, :end_time, :size)
|
|
117
222
|
recording.available = true
|
|
223
|
+
recording.recording_users = adapt_recording_users(data[:recordingUsers])
|
|
118
224
|
recording.save!
|
|
119
225
|
|
|
120
226
|
sync_additional_data(recording, data)
|
|
@@ -129,8 +235,9 @@ class BigbluebuttonRecording < ActiveRecord::Base
|
|
|
129
235
|
recording.available = true
|
|
130
236
|
recording.room = BigbluebuttonRails.configuration.match_room_recording.call(data)
|
|
131
237
|
recording.server = server
|
|
132
|
-
recording.description = I18n.t('bigbluebutton_rails.recordings.default.description', :time => recording.start_time.utc.to_formatted_s(:long))
|
|
238
|
+
recording.description = I18n.t('bigbluebutton_rails.recordings.default.description', :time => Time.at(recording.start_time).utc.to_formatted_s(:long))
|
|
133
239
|
recording.meeting = BigbluebuttonRecording.find_matching_meeting(recording)
|
|
240
|
+
recording.recording_users = adapt_recording_users(data[:recordingUsers])
|
|
134
241
|
recording.save!
|
|
135
242
|
|
|
136
243
|
sync_additional_data(recording, data)
|
|
@@ -154,73 +261,60 @@ class BigbluebuttonRecording < ActiveRecord::Base
|
|
|
154
261
|
# keys are stored as strings in the db
|
|
155
262
|
received_metadata = metadata.clone.stringify_keys
|
|
156
263
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
meta_db.update_attributes({ :content => received_metadata[meta_db.name] })
|
|
163
|
-
received_metadata.delete(meta_db.name)
|
|
164
|
-
|
|
165
|
-
# the metadata is not in the received data, remove from the db
|
|
166
|
-
else
|
|
167
|
-
meta_db.destroy
|
|
168
|
-
end
|
|
169
|
-
end
|
|
264
|
+
# get all metadata for this recording
|
|
265
|
+
# note: it's a little slower than removing all metadata and adding again,
|
|
266
|
+
# but it's cleaner to just update it and the loss of performance is small
|
|
267
|
+
query = { owner_id: recording.id, owner_type: recording.class.to_s }
|
|
268
|
+
metas = BigbluebuttonMetadata.where(query).all
|
|
170
269
|
|
|
171
|
-
#
|
|
270
|
+
# batch insert all metadata
|
|
271
|
+
columns = [ :id, :name, :content, :owner_id, :owner_type ]
|
|
272
|
+
values = []
|
|
172
273
|
received_metadata.each do |name, content|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
:content => content,
|
|
176
|
-
}
|
|
177
|
-
meta = BigbluebuttonMetadata.create(attrs)
|
|
178
|
-
meta.owner = recording
|
|
179
|
-
meta.save!
|
|
274
|
+
id = metas.select{ |m| m.name == name }.first.try(:id)
|
|
275
|
+
values << [ id, name, content, recording.id, recording.class.to_s ]
|
|
180
276
|
end
|
|
277
|
+
BigbluebuttonMetadata.import! columns, values, validate: true,
|
|
278
|
+
on_duplicate_key_update: [:name, :content]
|
|
279
|
+
|
|
280
|
+
# delete all that doesn't exist anymore
|
|
281
|
+
BigbluebuttonMetadata.where(query).where.not(name: received_metadata.keys).delete_all
|
|
181
282
|
end
|
|
182
283
|
|
|
183
284
|
# Syncs the playback formats objects of 'recording' with the data in 'formats'.
|
|
184
285
|
# The format expected for 'formats' follows the format returned by
|
|
185
286
|
# BigBlueButtonApi#get_recordings but with the keys already converted to our format.
|
|
186
287
|
def self.sync_playback_formats(recording, formats)
|
|
187
|
-
formats_copy = formats.clone
|
|
188
288
|
|
|
189
|
-
# make it an array if it's a hash with a single format
|
|
289
|
+
# clone and make it an array if it's a hash with a single format
|
|
290
|
+
formats_copy = formats.clone
|
|
190
291
|
formats_copy = [formats_copy] if formats_copy.is_a?(Hash)
|
|
191
292
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
# the format exists in the hash, update it in the db
|
|
198
|
-
if format
|
|
199
|
-
format_db.update_attributes({ url: format[:url], length: format[:length] })
|
|
200
|
-
formats_copy.delete(format)
|
|
201
|
-
|
|
202
|
-
# the format is not in the hash, remove from the db
|
|
203
|
-
else
|
|
204
|
-
format_db.destroy
|
|
205
|
-
end
|
|
206
|
-
end
|
|
293
|
+
# remove all formats for this recording
|
|
294
|
+
# note: easier than updating the formats because they don't have a clear key
|
|
295
|
+
# to match by
|
|
296
|
+
BigbluebuttonPlaybackFormat.where(recording_id: recording.id).delete_all
|
|
207
297
|
|
|
208
|
-
#
|
|
298
|
+
# batch insert all playback formats
|
|
299
|
+
columns = [ :recording_id, :url, :length , :playback_type_id ]
|
|
300
|
+
values = []
|
|
209
301
|
formats_copy.each do |format|
|
|
210
302
|
unless format[:type].blank?
|
|
211
|
-
playback_type = BigbluebuttonPlaybackType.
|
|
303
|
+
playback_type = BigbluebuttonPlaybackType.find_by(identifier: format[:type])
|
|
212
304
|
if playback_type.nil?
|
|
213
|
-
|
|
305
|
+
downloadable = BigbluebuttonRails.configuration.downloadable_playback_types.include?(format[:type])
|
|
306
|
+
attrs = {
|
|
307
|
+
identifier: format[:type],
|
|
308
|
+
visible: true,
|
|
309
|
+
downloadable: downloadable
|
|
310
|
+
}
|
|
214
311
|
playback_type = BigbluebuttonPlaybackType.create!(attrs)
|
|
215
312
|
end
|
|
216
313
|
|
|
217
|
-
|
|
218
|
-
length: format[:length].to_i, playback_type_id: playback_type.id }
|
|
219
|
-
BigbluebuttonPlaybackFormat.create!(attrs)
|
|
314
|
+
values << [ recording.id, format[:url], format[:length].to_i, playback_type.id ]
|
|
220
315
|
end
|
|
221
316
|
end
|
|
222
|
-
|
|
223
|
-
cleanup_playback_types
|
|
317
|
+
BigbluebuttonPlaybackFormat.import! columns, values, validate: true
|
|
224
318
|
end
|
|
225
319
|
|
|
226
320
|
# Remove the unused playback types from the list.
|
|
@@ -230,20 +324,22 @@ class BigbluebuttonRecording < ActiveRecord::Base
|
|
|
230
324
|
end
|
|
231
325
|
|
|
232
326
|
# Finds the BigbluebuttonMeeting that generated this recording. The meeting is searched using
|
|
233
|
-
# the
|
|
234
|
-
# the recording's ID.
|
|
327
|
+
# the meetingid associated with this recording and the create time of the meeting, taken from
|
|
328
|
+
# the recording's ID. There are some flexible clauses that try to match very close or truncated
|
|
329
|
+
# timestamps from recordings start times to meeting create times.
|
|
235
330
|
def self.find_matching_meeting(recording)
|
|
236
331
|
meeting = nil
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
332
|
+
unless recording.nil? #or recording.room.nil?
|
|
333
|
+
unless recording.start_time.nil?
|
|
334
|
+
start_time = recording.start_time
|
|
335
|
+
meeting = BigbluebuttonMeeting.where("meetingid = ? AND create_time = ?", recording.meetingid, start_time).last
|
|
336
|
+
if meeting.nil?
|
|
337
|
+
meeting = BigbluebuttonMeeting.where("meetingid = ? AND create_time DIV 1000 = ?", recording.meetingid, start_time).last
|
|
338
|
+
end
|
|
339
|
+
if meeting.nil?
|
|
340
|
+
div_start_time = (start_time/10)
|
|
341
|
+
meeting = BigbluebuttonMeeting.where("meetingid = ? AND create_time DIV 10 = ?", recording.meetingid, div_start_time).last
|
|
342
|
+
end
|
|
247
343
|
logger.info "Recording: meeting found for the recording #{recording.inspect}: #{meeting.inspect}"
|
|
248
344
|
end
|
|
249
345
|
end
|