Merge pull request #108 from bigbluebutton/workflow_redesign

Simplify workflow of starting a meeting
This commit is contained in:
Zachary Chai 2017-02-03 10:54:46 -05:00 committed by GitHub
commit 70d2189ee0
37 changed files with 486 additions and 198 deletions

View File

@ -23,10 +23,11 @@
}); });
}; };
var initRooms = function() { var enableMeetingUpdates = function() {
App.messages = App.cable.subscriptions.create({ App.meeting_update = App.cable.subscriptions.create({
channel: 'MeetingUpdatesChannel', channel: 'MeetingUpdatesChannel',
encrypted_id: $(".page-wrapper").data('id') admin_id: $(".page-wrapper.rooms").data('admin-id'),
meeting_id: $(".page-wrapper.rooms").data('id')
}, },
{ {
received: function(data) { received: function(data) {
@ -55,10 +56,21 @@
}); });
}; };
var disableMeetingUpdates = function() {
App.meeting_update.unsubscribe();
delete App.meeting_update
};
$(document).on("turbolinks:load", function() { $(document).on("turbolinks:load", function() {
// disable meeting updates if enabled from a previous page
if (App.meeting_update) {
disableMeetingUpdates();
}
if ($("body[data-controller=landing]").get(0)) { if ($("body[data-controller=landing]").get(0)) {
if ($("body[data-action=rooms]").get(0)) { if ($("body[data-action=rooms]").get(0)) {
initRooms(); if (!$(".page-wrapper.rooms").data('main-room')) {
enableMeetingUpdates();
}
} }
} }
}); });

View File

@ -16,10 +16,11 @@
(function() { (function() {
var initRooms = function() { var enableRecordingUpdates = function() {
App.messages = App.cable.subscriptions.create({ App.recording_update = App.cable.subscriptions.create({
channel: 'RecordingUpdatesChannel', channel: 'RecordingUpdatesChannel',
encrypted_id: $(".page-wrapper").data('id') admin_id: $(".page-wrapper.rooms").data('admin-id'),
meeting_id: $(".page-wrapper.rooms").data('id')
}, },
{ {
received: function(data) { received: function(data) {
@ -57,10 +58,19 @@
}); });
}; };
var disableRecordingUpdates = function() {
App.recording_update.unsubscribe();
delete App.recording_update
};
$(document).on("turbolinks:load", function() { $(document).on("turbolinks:load", function() {
// disable recording updates if enabled from a previous page
if (App.recording_update) {
disableRecordingUpdates();
}
if ($("body[data-controller=landing]").get(0)) { if ($("body[data-controller=landing]").get(0)) {
if ($("body[data-action=rooms]").get(0)) { if ($("body[data-action=rooms]").get(0)) {
initRooms(); enableRecordingUpdates();
} }
} }
}); });

View File

@ -41,8 +41,8 @@
// setup event handlers // setup event handlers
$('.center-panel-wrapper').on ('click', '.meeting-join', function (event) { $('.center-panel-wrapper').on ('click', '.meeting-join', function (event) {
var name = $('.meeting-user-name').val(); var name = $('.meeting-user-name').val();
Meeting.getInstance().setName(name); Meeting.getInstance().setUserName(name);
Meeting.getInstance().setId($(".page-wrapper").data('id')); Meeting.getInstance().setMeetingId($(".page-wrapper").data('id'));
// a user name is set, join the user into the session // a user name is set, join the user into the session
if (name !== undefined && name !== null) { if (name !== undefined && name !== null) {
@ -64,6 +64,10 @@
} }
}); });
$('.center-panel-wrapper').on ('click', '.meeting-start', function (event) {
Turbolinks.visit(Meeting.getInstance().getURL());
});
$('.center-panel-wrapper').on ('keypress', '.meeting-user-name', function (event) { $('.center-panel-wrapper').on ('keypress', '.meeting-user-name', function (event) {
if (event.keyCode === 13) { if (event.keyCode === 13) {
event.preventDefault(); event.preventDefault();
@ -148,7 +152,9 @@
$(document).tooltip(options); $(document).tooltip(options);
// focus name input or join button // focus name input or join button
if ($('.meeting-user-name').is(':visible')) { if ($('.meeting-name').is(':visible')) {
$('.meeting-name').focus();
} else if ($('.meeting-user-name').is(':visible')) {
$('.meeting-user-name').focus(); $('.meeting-user-name').focus();
} else { } else {
$('.meeting-join').focus(); $('.meeting-join').focus();
@ -156,21 +162,25 @@
}; };
var initIndex = function() { var initIndex = function() {
$('.generate-link').click (function (e) {
e.preventDefault(); $('.center-panel-wrapper').on('keyup', '.meeting-name', function (event, msg) {
var newId = Math.trunc(Math.random() * 1000000000); var newId = $(this).val();
Meeting.getInstance().setId(newId); Meeting.getInstance().setMeetingId(newId);
$(".page-wrapper.meetings").data('id', newId); $(".page-wrapper.meetings").data('id', newId);
$('.meeting-url').val(Meeting.getInstance().getURL()); $('.meeting-url').val(Meeting.getInstance().getURL());
$('.join-meeting-title').html(I18n.join_title.replace(/%{id}/, newId));
if (newId === '') {
$('.invite-join-wrapper').addClass('hidden');
} else {
$('.invite-join-wrapper').removeClass('hidden');
}
}); });
$('.generate-link').click();
$('ul.previously-joined').empty(); $('ul.previously-joined').empty();
var joinedMeetings = localStorage.getItem('joinedMeetings'); var joinedMeetings = localStorage.getItem('joinedMeetings');
if (joinedMeetings && joinedMeetings.length > 0) { if (joinedMeetings && joinedMeetings.length > 0) {
joinedMeetings = joinedMeetings.split(','); joinedMeetings = joinedMeetings.split(',');
$('.center-panel-wrapper .panel-footer').removeClass('hidden'); $('.center-panel-wrapper .previously-joined-wrapper').removeClass('hidden');
for (var i = joinedMeetings.length - 1; i >= 0; i--) { for (var i = joinedMeetings.length - 1; i >= 0; i--) {
$('ul.previously-joined').append('<li><a href="/meetings/'+joinedMeetings[i]+'">'+joinedMeetings[i]+'</a></li>'); $('ul.previously-joined').append('<li><a href="/meetings/'+joinedMeetings[i]+'">'+joinedMeetings[i]+'</a></li>');
@ -185,6 +195,39 @@
var initRooms = function() { var initRooms = function() {
displayRoomURL(); displayRoomURL();
$('.center-panel-wrapper').on('input', '.meeting-name', function (event, msg) {
var newId = $(this).val();
Meeting.getInstance().setMeetingId(newId);
$('.meeting-url').val(Meeting.getInstance().getURL());
$('.join-meeting-title').html(I18n.join_title.replace(/%{id}/, newId));
if (newId === '') {
$('.invite-join-wrapper').addClass('hidden');
} else {
$('.invite-join-wrapper').removeClass('hidden');
}
});
if ($(".page-wrapper.rooms").data('main-room')) {
$('.center-panel-wrapper').on('click', '.fill-meeting-name', function (event, msg) {
var name = $(this).text();
$('input.meeting-name').val(name).trigger('input');
});
$('ul.previously-joined').empty();
var joinedMeetings = localStorage.getItem('joinedRooms');
if (joinedMeetings && joinedMeetings.length > 0) {
joinedMeetings = joinedMeetings.split(',');
$('.center-panel-wrapper .previously-joined-wrapper').removeClass('hidden');
for (var i = joinedMeetings.length - 1; i >= 0; i--) {
$('ul.previously-joined').append('<li><a class="fill-meeting-name">'+joinedMeetings[i]+'</a></li>');
}
}
if ($('input.meeting-name').val() !== '') {
$('input.meeting-name').trigger('input');
}
}
Recordings.getInstance().refresh(); Recordings.getInstance().refresh();
Recordings.getInstance().setupActionHandlers(); Recordings.getInstance().setupActionHandlers();
}; };

View File

@ -19,24 +19,30 @@
_meetingInstance = null _meetingInstance = null
class @Meeting class @Meeting
constructor: (@id, @type, @name) -> constructor: (@meetingId, @type, @userName, @adminId) ->
# Gets the current instance or creates a new one # Gets the current instance or creates a new one
@getInstance: -> @getInstance: ->
if _meetingInstance if _meetingInstance
return _meetingInstance return _meetingInstance
id = $(".page-wrapper").data('id') meetingId = $(".page-wrapper").data('id')
if (type = location.pathname.split('/')[1]) != 'rooms' if (type = location.pathname.split('/')[1]) != 'rooms'
type = 'meetings' type = 'meetings'
name = $('.meeting-user-name').val() name = $('.meeting-user-name').val()
_meetingInstance = new Meeting(id, type, name) adminId = $(".page-wrapper").data('admin-id')
_meetingInstance = new Meeting(meetingId, type, name, adminId)
return _meetingInstance return _meetingInstance
@clear: -> @clear: ->
_meetingInstance = null _meetingInstance = null
@buildMeetingURL: (id, type) -> @buildMeetingURL: (meetingId, type, adminId) ->
return @buildFullDomainURL() + '/' + type + '/' + id fullId = ''
if adminId
fullId = encodeURIComponent(adminId) + '/' + encodeURIComponent(meetingId)
else
fullId = encodeURIComponent(meetingId)
return @buildFullDomainURL() + '/' + type + '/' + fullId
@buildFullDomainURL: -> @buildFullDomainURL: ->
url = location.protocol + '//' + location.hostname url = location.protocol + '//' + location.hostname
@ -56,28 +62,41 @@ class @Meeting
# Returns a response object # Returns a response object
# The response object contains the URL to join the meeting # The response object contains the URL to join the meeting
getJoinMeetingResponse: -> getJoinMeetingResponse: ->
return $.get @getURL() + "/join?name=" + @name, (data) => return $.get @getURL() + "/join?name=" + @userName, (data) =>
if data.messageKey == 'ok' && @type == 'meetings' # update name used to join meeting
# update name used to join meeting localStorage.setItem('lastJoinedName', @getUserName())
localStorage.setItem('lastJoinedName', @getName())
# update previously joined meetings on client if data.messageKey == 'ok'
key = ''
if @type == 'meetings'
key = 'joinedMeetings'
else if @type == 'rooms'
key = 'joinedRooms'
# update previously joined meetings/rooms on client
try try
joinedMeetings = localStorage.getItem('joinedMeetings') || '' joinedMeetings = localStorage.getItem(key) || ''
joinedMeetings = joinedMeetings.split(',') joinedMeetings = joinedMeetings.split(',')
joinedMeetings = joinedMeetings.filter (item) => item != @id.toString() joinedMeetings = joinedMeetings.filter (item) => item != @meetingId.toString()
if joinedMeetings.length >= 5 if joinedMeetings.length >= 5
joinedMeetings.splice(0, 1) joinedMeetings.splice(0, 1)
joinedMeetings.push(@id) joinedMeetings.push(@meetingId)
localStorage.setItem('joinedMeetings', joinedMeetings.join(',')) localStorage.setItem(key, joinedMeetings.join(','))
catch err catch err
localStorage.setItem('joinedMeetings', @id) localStorage.setItem(key, @meetingId)
getId: -> getMeetingId: ->
return @id return @meetingId
setId: (id) -> setMeetingId: (id) ->
@id = id @meetingId = id
return this
getAdminId: ->
return @adminId
setAdminId: (id) ->
@adminId = id
return this return this
getType: -> getType: ->
@ -88,13 +107,13 @@ class @Meeting
return this return this
getURL: -> getURL: ->
return Meeting.buildMeetingURL(@id, @type) return Meeting.buildMeetingURL(@meetingId, @type, @adminId)
getName: -> getUserName: ->
return @name return @userName
setName: (name) -> setUserName: (name) ->
@name = name @userName = name
return this return this
getModJoined: -> getModJoined: ->

View File

@ -34,8 +34,10 @@ class @Recordings
}, },
columns: [ columns: [
{ data: "start_time" }, { data: "start_time" },
{ data: "name", visible: $(".page-wrapper.rooms").data('main-room') },
{ data: "previews", orderable: false }, { data: "previews", orderable: false },
{ data: "duration", orderable: false }, { data: "duration", orderable: false },
{ data: "published" },
{ data: "playbacks", orderable: false }, { data: "playbacks", orderable: false },
{ data: "listed", visible: false }, { data: "listed", visible: false },
{ data: "id", orderable: false } { data: "id", orderable: false }
@ -55,7 +57,7 @@ class @Recordings
return data return data
}, },
{ {
targets: 1, targets: 2,
render: (data, type, row) -> render: (data, type, row) ->
if type == 'display' if type == 'display'
str = '' str = ''
@ -66,7 +68,22 @@ class @Recordings
return data return data
}, },
{ {
targets: 3, targets: 4,
render: (data, type, row) ->
visibility = ['unpublished', 'unlisted', 'published']
if row.published
if row.listed
state = visibility[2]
else
state = visibility[1]
else
state = visibility[0]
if type == 'display'
return I18n[state]
return state
}
{
targets: 5,
render: (data, type, row) -> render: (data, type, row) ->
if type == 'display' if type == 'display'
str = '' str = ''
@ -80,7 +97,7 @@ class @Recordings
targets: -1, targets: -1,
render: (data, type, row) -> render: (data, type, row) ->
if type == 'display' if type == 'display'
roomName = Meeting.getInstance().getId() roomName = Meeting.getInstance().getMeetingId()
recordingActions = $('.hidden-elements').find('.recording-actions') recordingActions = $('.hidden-elements').find('.recording-actions')
classes = ['recording-unpublished', 'recording-unlisted', 'recording-published'] classes = ['recording-unpublished', 'recording-unlisted', 'recording-published']
if row.published if row.published
@ -151,13 +168,13 @@ class @Recordings
draw: -> draw: ->
if !@isOwner() if !@isOwner()
@table.api().columns(4).search('true') @table.api().columns(6).search('true')
@table.api().columns.adjust().draw() @table.api().columns.adjust().draw()
# refresh the recordings from the server # refresh the recordings from the server
refresh: -> refresh: ->
table_api = this.table.api() table_api = this.table.api()
$.get "/rooms/"+Meeting.getInstance().getId()+"/recordings", (data) => $.get @getRecordingsURL(), (data) =>
@setOwner(data.is_owner) @setOwner(data.is_owner)
if !@owner if !@owner
table_api.column(-1).visible(false) table_api.column(-1).visible(false)
@ -172,11 +189,12 @@ class @Recordings
# setup click handlers for the action buttons # setup click handlers for the action buttons
setupActionHandlers: -> setupActionHandlers: ->
table_api = this.table.api() table_api = this.table.api()
recordingsObject = this
@getTable().on 'click', '.recording-update', (event) -> @getTable().on 'click', '.recording-update', (event) ->
btn = $(this) btn = $(this)
row = table_api.row($(this).closest('tr')).data() row = table_api.row($(this).closest('tr')).data()
url = $('.meeting-url').val() url = recordingsObject.getRecordingsURL()
id = row.id id = row.id
published = btn.data('visibility') == "unlisted" || published = btn.data('visibility') == "unlisted" ||
@ -189,7 +207,7 @@ class @Recordings
data["meta_" + GreenLight.META_LISTED] = listed.toString(); data["meta_" + GreenLight.META_LISTED] = listed.toString();
$.ajax({ $.ajax({
method: 'PATCH', method: 'PATCH',
url: url+'/recordings/'+id, url: url+'/'+id,
data: data data: data
}).done((data) -> }).done((data) ->
@ -200,12 +218,12 @@ class @Recordings
@getTable().on 'click', '.recording-delete', (event) -> @getTable().on 'click', '.recording-delete', (event) ->
btn = $(this) btn = $(this)
row = table_api.row($(this).closest('tr')).data() row = table_api.row($(this).closest('tr')).data()
url = $('.meeting-url').val() url = recordingsObject.getRecordingsURL()
id = row.id id = row.id
btn.prop('disabled', true) btn.prop('disabled', true)
$.ajax({ $.ajax({
method: 'DELETE', method: 'DELETE',
url: url+'/recordings/'+id url: url+'/'+id
}).done((data) -> }).done((data) ->
).fail((data) -> ).fail((data) ->
@ -218,6 +236,13 @@ class @Recordings
getTable: -> getTable: ->
@table @table
getRecordingsURL: ->
if $(".page-wrapper.rooms").data('main-room')
base_url = '/rooms/'+Meeting.getInstance().getAdminId()
else
base_url = $('.meeting-url').val()
base_url+'/recordings'
isOwner: -> isOwner: ->
@owner @owner

View File

@ -14,13 +14,16 @@
// You should have received a copy of the GNU Lesser General Public License along // You should have received a copy of the GNU Lesser General Public License along
// with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. // with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
.previously-joined {
list-style-type: none;
margin:auto;
width: 200px;
padding: 0;
cursor: pointer;
}
.meetings { .meetings {
.previously-joined {
list-style-type: none;
margin:auto;
width: 200px;
padding: 0;
}
} }
.rooms { .rooms {
@ -46,6 +49,11 @@
} }
} }
.meeting-url-button-group {
padding-top: 5px;
width: 100px;
}
} }
.img-thumbnail{ .img-thumbnail{
@ -67,19 +75,6 @@
.meeting-url-group { .meeting-url-group {
position: relative; position: relative;
.generate-link {
position: absolute;
right: 12px;
top: 10px;
z-index: 9;
color: #999;
cursor: pointer;
&:hover {
color: #000;
}
}
} }
.recording-update-trigger { .recording-update-trigger {

View File

@ -26,6 +26,10 @@ html, body {
background: #ffffff; background: #ffffff;
} }
.container-fluid {
height: 100%;
}
.background { .background {
height: 350px; height: 350px;
width: 100%; width: 100%;
@ -68,12 +72,17 @@ body[data-controller=landing][data-action=rooms].app-background {
.center-block { .center-block {
float: none; float: none;
} }
.center-panel-wrapper {
height: 100%;
}
.center-panel { .center-panel {
height: 100%;
.center-panel-size { .center-panel-size {
max-width: 900px max-width: 1200px
} }
.center-panel-content-size { .center-panel-content-size {
max-width: 800px; height: 100%;
max-width: 1100px;
} }
.input-spacing { .input-spacing {
@ -157,3 +166,16 @@ a.signin-link {
color: #444; color: #444;
} }
} }
.verticle-line {
// parent must be position relative to work
width: 1px;
background-color: lightgray;
height: 100%;
position: absolute;
left: 50%;
}
.invite-join-wrapper {
position: relative;
}

View File

@ -16,6 +16,12 @@
class MeetingUpdatesChannel < ApplicationCable::Channel class MeetingUpdatesChannel < ApplicationCable::Channel
def subscribed def subscribed
stream_from "#{params[:encrypted_id]}_meeting_updates_channel"
full_id = if params[:meeting_id].present?
"#{params[:admin_id]}-#{params[:meeting_id]}"
else
params[:admin_id]
end
stream_from "#{full_id}_meeting_updates_channel"
end end
end end

View File

@ -16,6 +16,11 @@
class RecordingUpdatesChannel < ApplicationCable::Channel class RecordingUpdatesChannel < ApplicationCable::Channel
def subscribed def subscribed
stream_from "#{params[:encrypted_id]}_recording_updates_channel" full_id = if params[:meeting_id].present?
"#{params[:admin_id]}-#{params[:meeting_id]}"
else
params[:admin_id]
end
stream_from "#{full_id}_recording_updates_channel"
end end
end end

View File

@ -24,17 +24,40 @@ class BbbController < ApplicationController
before_action :validate_checksum, only: :callback before_action :validate_checksum, only: :callback
# GET /:resource/:id/join # GET /:resource/:id/join
# GET /:resource/:room_id/:id/join
def join def join
if params[:name].blank? if params[:name].blank?
render_bbb_response("missing_parameter", "user name was not included", :unprocessable_entity) return render_bbb_response(
messageKey: "missing_parameter",
message: "user name was not included",
status: :unprocessable_entity
)
else else
user = User.find_by encrypted_id: params[:id] if params[:room_id]
user = User.find_by encrypted_id: params[:room_id]
if !user
return render_bbb_response(
messageKey: "not_found",
message: "User Not Found",
status: :not_found
)
end
meeting_id = "#{params[:room_id]}-#{params[:id]}"
meeting_name = params[:id]
meeting_path = "#{params[:room_id]}/#{params[:id]}"
else
user = User.find_by encrypted_id: params[:id]
meeting_id = params[:id]
meeting_path = meeting_id
end
options = if user options = if user
{ {
wait_for_moderator: true, wait_for_moderator: true,
meeting_recorded: true, meeting_recorded: true,
meeting_name: user.name, meeting_name: meeting_name,
room_owner: params[:room_id],
user_is_moderator: current_user == user user_is_moderator: current_user == user
} }
else else
@ -42,23 +65,26 @@ class BbbController < ApplicationController
user_is_moderator: true user_is_moderator: true
} }
end end
base_url = "#{request.base_url}/#{params[:resource]}/#{params[:id]}"
base_url = "#{request.base_url}/#{params[:resource]}/#{meeting_path}"
options[:meeting_logout_url] = base_url options[:meeting_logout_url] = base_url
options[:hook_url] = "#{base_url}/callback" options[:hook_url] = "#{base_url}/callback"
bbb_res = bbb_join_url( bbb_res = bbb_join_url(
params[:id], meeting_id,
params[:name], params[:name],
options options
) )
# the user can join the meeting # the user can join the meeting
if bbb_res[:returncode] && current_user && current_user == user if bbb_res[:returncode] && user
JoinMeetingJob.perform_later(params[:id]) if current_user == user
JoinMeetingJob.perform_later(user.encrypted_id, params[:id])
# user will be waiting for a moderator # user will be waiting for a moderator
else else
NotifyUserWaitingJob.perform_later(params[:id], params[:name]) NotifyUserWaitingJob.perform_later(user.encrypted_id, params[:id], params[:name])
end
end end
render_bbb_response bbb_res, bbb_res[:response] render_bbb_response bbb_res, bbb_res[:response]
@ -80,40 +106,49 @@ class BbbController < ApplicationController
end end
# DELETE /rooms/:id/end # DELETE /rooms/:id/end
# DELETE /rooms/:room_id/:id/end
def end def end
load_and_authorize_room_owner! load_and_authorize_room_owner!
bbb_res = bbb_end_meeting @user.encrypted_id bbb_res = bbb_end_meeting "#{@user.encrypted_id}-#{params[:id]}"
if bbb_res[:returncode] if bbb_res[:returncode]
EndMeetingJob.perform_later(@user.encrypted_id) EndMeetingJob.perform_later(@user.encrypted_id, params[:id])
end end
render_bbb_response bbb_res render_bbb_response bbb_res
end end
# GET /rooms/:id/recordings # GET /rooms/:id/recordings
# GET /rooms/:room_id/:id/recordings
def recordings def recordings
load_room! load_room!
bbb_res = bbb_get_recordings @user.encrypted_id # bbb_res = bbb_get_recordings "#{@user.encrypted_id}-#{params[:id]}"
options = { "meta_room-id": @user.encrypted_id }
if params[:id]
options["meta_meeting-name"] = params[:id]
end
bbb_res = bbb_get_recordings(options)
render_bbb_response bbb_res, bbb_res[:recordings] render_bbb_response bbb_res, bbb_res[:recordings]
end end
# PATCH /rooms/:id/recordings/:record_id # PATCH /rooms/:id/recordings/:record_id
# PATCH /rooms/:room_id/:id/recordings/:record_id
def update_recordings def update_recordings
published = params[:published] == 'true' published = params[:published] == 'true'
metadata = params.select{ |k, v| k.match(/^meta_/) } metadata = params.select{ |k, v| k.match(/^meta_/) }
bbb_res = bbb_update_recordings(params[:record_id], published, metadata) bbb_res = bbb_update_recordings(params[:record_id], published, metadata)
if bbb_res[:returncode] if bbb_res[:returncode]
RecordingUpdatesJob.perform_later(@user.encrypted_id, params[:record_id]) RecordingUpdatesJob.perform_later(@user.encrypted_id, params[:record_id], params[:id])
end end
render_bbb_response bbb_res render_bbb_response bbb_res
end end
# DELETE /rooms/:id/recordings/:record_id # DELETE /rooms/:id/recordings/:record_id
# DELETE /rooms/:room_id/:id/recordings/:record_id
def delete_recordings def delete_recordings
bbb_res = bbb_delete_recordings(params[:record_id]) bbb_res = bbb_delete_recordings(params[:record_id])
if bbb_res[:returncode] if bbb_res[:returncode]
RecordingDeletesJob.perform_later(@user.encrypted_id, params[:record_id]) RecordingDeletesJob.perform_later(@user.encrypted_id, params[:record_id], params[:id])
end end
render_bbb_response bbb_res render_bbb_response bbb_res
end end
@ -121,7 +156,7 @@ class BbbController < ApplicationController
private private
def load_room! def load_room!
@user = User.find_by encrypted_id: params[:id] @user = User.find_by encrypted_id: params[:room_id]
if !@user if !@user
render head(:not_found) && return render head(:not_found) && return
end end
@ -138,7 +173,7 @@ class BbbController < ApplicationController
def authorize_recording_owner! def authorize_recording_owner!
load_and_authorize_room_owner! load_and_authorize_room_owner!
recordings = bbb_get_recordings(params[:id])[:recordings] recordings = bbb_get_recordings({recordID: params[:record_id]})[:recordings]
recordings.each do |recording| recordings.each do |recording|
if recording[:recordID] == params[:record_id] if recording[:recordID] == params[:record_id]
return true return true
@ -171,7 +206,7 @@ class BbbController < ApplicationController
# the webhook event doesn't have all the data we need, so we need # the webhook event doesn't have all the data we need, so we need
# to send a getRecordings anyway # to send a getRecordings anyway
# TODO: if the webhooks included all data in the event we wouldn't need this # TODO: if the webhooks included all data in the event we wouldn't need this
rec_info = bbb_get_recordings(token, record_id) rec_info = bbb_get_recordings({recordID: record_id})
rec_info = rec_info[:recordings].first rec_info = rec_info[:recordings].first
RecordingCreatedJob.perform_later(token, parse_recording_for_view(rec_info)) RecordingCreatedJob.perform_later(token, parse_recording_for_view(rec_info))

View File

@ -35,12 +35,13 @@ class LandingController < ApplicationController
end end
def session_status_refresh def session_status_refresh
@user = User.find_by(encrypted_id: params[:id]) @user = User.find_by(encrypted_id: params[:room_id])
if @user.nil? if @user.nil?
render head(:not_found) && return render head(:not_found) && return
end end
@meeting_running = bbb_get_meeting_info(@user.encrypted_id)[:returncode] @meeting_id = params[:id]
@meeting_running = bbb_get_meeting_info("#{@user.encrypted_id}-#{params[:id]}")[:returncode]
render layout: false render layout: false
end end
@ -65,13 +66,15 @@ class LandingController < ApplicationController
def render_room def render_room
params[:action] = 'rooms' params[:action] = 'rooms'
@user = User.find_by(encrypted_id: params[:id]) @user = User.find_by(encrypted_id: params[:room_id] || params[:id])
if @user.nil? if @user.nil?
redirect_to root_path redirect_to root_path
return return
end end
@meeting_running = bbb_get_meeting_info(@user.encrypted_id)[:returncode] @meeting_id = params[:id]
@meeting_running = bbb_get_meeting_info("#{@user.encrypted_id}-#{@meeting_id}")[:returncode]
@main_room = @meeting_id.blank? || @meeting_id == @user.encrypted_id
render :action => 'rooms' render :action => 'rooms'
end end

View File

@ -47,10 +47,4 @@ module ApplicationHelper
def on_room_or_meeting_page? def on_room_or_meeting_page?
params[:id].present? params[:id].present?
end end
def version
Greenlight::VERSION
rescue
'development'
end
end end

View File

@ -17,6 +17,6 @@
module UsersHelper module UsersHelper
def is_room_owner def is_room_owner
token = current_user ? current_user.encrypted_id : nil token = current_user ? current_user.encrypted_id : nil
token.present? && params[:id].present? && token == params[:id] token.present? && params[:room_id].present? && token == params[:room_id]
end end
end end

View File

@ -19,15 +19,15 @@ class EndMeetingJob < ApplicationJob
queue_as :default queue_as :default
def perform(room) def perform(room, meeting)
tries = 0 tries = 0
sleep_time = 2 sleep_time = 2
while tries < 4 while tries < 4
bbb_res = bbb_get_meeting_info(room) bbb_res = bbb_get_meeting_info("#{room}-#{meeting}")
if !bbb_res[:returncode] if !bbb_res[:returncode]
ActionCable.server.broadcast "#{room}_meeting_updates_channel", ActionCable.server.broadcast "#{room}-#{meeting}_meeting_updates_channel",
action: 'meeting_ended' action: 'meeting_ended'
break break
end end

View File

@ -17,8 +17,8 @@
class JoinMeetingJob < ApplicationJob class JoinMeetingJob < ApplicationJob
queue_as :default queue_as :default
def perform(room) def perform(room, meeting)
ActionCable.server.broadcast "#{room}_meeting_updates_channel", ActionCable.server.broadcast "#{room}-#{meeting}_meeting_updates_channel",
action: 'moderator_joined', action: 'moderator_joined',
moderator: 'joined' moderator: 'joined'
end end

View File

@ -17,8 +17,8 @@
class NotifyUserWaitingJob < ApplicationJob class NotifyUserWaitingJob < ApplicationJob
queue_as :default queue_as :default
def perform(room, user) def perform(room, meeting, user)
ActionCable.server.broadcast "#{room}_meeting_updates_channel", ActionCable.server.broadcast "#{room}-#{meeting}_meeting_updates_channel",
{ action: 'user_waiting', user: user } { action: 'user_waiting', user: user }
end end
end end

View File

@ -19,16 +19,21 @@ class RecordingDeletesJob < ApplicationJob
queue_as :default queue_as :default
def perform(room, record_id) def perform(room, record_id, meeting=nil)
tries = 0 tries = 0
sleep_time = 2 sleep_time = 2
while tries < 4 while tries < 4
bbb_res = bbb_get_recordings(nil, record_id) bbb_res = bbb_get_recordings({recordID: record_id})
if !bbb_res[:recordings] || bbb_res[:messageKey] == 'noRecordings' if !bbb_res[:recordings] || bbb_res[:messageKey] == 'noRecordings'
full_id = room
full_id += "-#{recording[:metadata][:"meeting-name"]}"
ActionCable.server.broadcast "#{room}_recording_updates_channel", ActionCable.server.broadcast "#{room}_recording_updates_channel",
action: 'delete', action: 'delete',
id: record_id id: record_id
ActionCable.server.broadcast "#{full_id}_recording_updates_channel",
action: 'delete',
id: record_id
break break
end end
sleep sleep_time sleep sleep_time

View File

@ -19,13 +19,20 @@ class RecordingUpdatesJob < ApplicationJob
queue_as :default queue_as :default
def perform(room, record_id) def perform(room, record_id, meeting=nil)
bbb_res = bbb_get_recordings(nil, record_id) bbb_res = bbb_get_recordings({recordID: record_id})
recording = bbb_res[:recordings].first recording = bbb_res[:recordings].first
full_id = room
full_id += "-#{recording[:metadata][:"meeting-name"]}"
ActionCable.server.broadcast "#{room}_recording_updates_channel", ActionCable.server.broadcast "#{room}_recording_updates_channel",
action: 'update', action: 'update',
id: record_id, id: record_id,
published: recording[:published], published: recording[:published],
listed: bbb_is_recording_listed(recording) listed: bbb_is_recording_listed(recording)
ActionCable.server.broadcast "#{full_id}_recording_updates_channel",
action: 'update',
id: record_id,
published: recording[:published],
listed: bbb_is_recording_listed(recording)
end end
end end

View File

@ -47,6 +47,7 @@ module BbbApi
options[:wait_for_moderator] ||= false options[:wait_for_moderator] ||= false
options[:meeting_logout_url] ||= nil options[:meeting_logout_url] ||= nil
options[:meeting_name] ||= meeting_token options[:meeting_name] ||= meeting_token
options[:room_owner] ||= nil
if !bbb if !bbb
return call_invalid_res return call_invalid_res
@ -81,6 +82,12 @@ module BbbApi
{ "meta_#{BbbApi::META_HOOK_URL}": options[:hook_url] } { "meta_#{BbbApi::META_HOOK_URL}": options[:hook_url] }
) if options[:hook_url] ) if options[:hook_url]
# these parameters are used to filter recordings by room and meeting
meeting_options.merge!(
{ "meta_room-id": options[:room_owner],
"meta_meeting-name": options[:meeting_name]}
) if options[:room_owner]
if Rails.configuration.use_webhooks if Rails.configuration.use_webhooks
webhook_register(options[:hook_url], meeting_id) webhook_register(options[:hook_url], meeting_id)
end end
@ -114,13 +121,9 @@ module BbbApi
response_data = bbb_exception_res exc response_data = bbb_exception_res exc
end end
def bbb_get_recordings(meeting_id, record_id=nil) def bbb_get_recordings(options={})
options={} if options[:meetingID]
if record_id options[:meetingID] = bbb_meeting_id(options[:meetingID])
options[:recordID] = record_id
end
if meeting_id
options[:meetingID] = bbb_meeting_id(meeting_id)
end end
res = bbb_safe_execute :get_recordings, options res = bbb_safe_execute :get_recordings, options

View File

@ -0,0 +1,15 @@
<div class="invite-join-wrapper hidden">
<div class="col-xs-6">
<%= render 'shared/title', title: t('invite') do %>
<span><%= t('invite_description') %></span>
<% end %>
<%= render 'shared/meeting_url', hidden: false %>
</div>
<div class="verticle-line"></div>
<div class="col-xs-6">
<%= render 'shared/title', title: t('join'), title_class: 'join-meeting-title' %>
<button type="button" class="btn btn-primary center-block meeting-start">
<%= t('start_meeting') %>
</button>
</div>
</div>

View File

@ -0,0 +1,6 @@
<div class="previously-joined-wrapper hidden">
<div class="list-group text-center">
<h4><%= t('previously_joined_meetings') %></h4>
<ul class="previously-joined"></ul>
</div>
</div>

View File

@ -18,10 +18,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<h2> <h2>
<% if admin? && !@meeting_running %> <% if admin? && !@meeting_running %>
<%= t('your_personal_room') %> <%= t('your_personal_room') %>
<% elsif !admin? %>
<%= t('join_session_user', name: @user.username) %>
<% else %> <% else %>
<%= t('join_session') %> <%= t('user_person_room', name: @user.name) %>
<% end %> <% end %>
</h2> </h2>
</div> </div>
@ -30,10 +28,18 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<%= render layout: 'shared/center_panel' do %> <%= render layout: 'shared/center_panel' do %>
<div class="center-block center-panel-content-size col-xs-12"> <div class="center-block center-panel-content-size col-xs-12">
<% if admin? %> <% if admin? %>
<%= render 'shared/meeting_url', hidden: false %> <%= render 'shared/meeting_name_form' %>
<div class="row">
<%= render 'landing/previously_joined' %>
</div>
<div class="row">
<%= render 'landing/invite_join' %>
</div>
<% else %> <% else %>
<%= render 'shared/meeting_url', hidden: true %> <div class="text-center">
<div><%= t('are_you', name: @user.name) %></div>
<div class=""><%= link_to t('login'), '/users/login' %></div>
</div>
<% end %> <% end %>
<%= render 'shared/join_form' %>
</div> </div>
<% end %> <% end %>

View File

@ -0,0 +1,29 @@
<!--
BigBlueButton open source conferencing system - http://www.bigbluebutton.org/.
Copyright (c) 2016 BigBlueButton Inc. and by respective authors (see below).
This program is free software; you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 3.0 of the License, or (at your option) any later
version.
BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-->
<% content_for :title do %>
<div class="title">
<h2>
<%= t('join_session_id', id: @meeting_id) %>
</h2>
</div>
<% end %>
<%= render layout: 'shared/center_panel' do %>
<div class="center-block center-panel-content-size col-xs-12">
<%= render 'shared/meeting_url', hidden: true %>
<%= render 'shared/join_form' %>
</div>
<% end %>

View File

@ -15,16 +15,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<% content_for :title do %> <% content_for :title do %>
<div class="title"> <div class="title">
<h2><%= t('create_session') %></h2> <h2><%= t('home_title') %></h2>
</div>
<% end %>
<% content_for :footer do %>
<div class="panel-footer hidden">
<div class="list-group text-center">
<h4><%= t('previously_joined_meetings') %></h4>
<ul class="previously-joined"></ul>
</div>
</div> </div>
<% end %> <% end %>
@ -34,8 +25,16 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<div class="center-panel-wrapper"> <div class="center-panel-wrapper">
<%= render layout: 'shared/center_panel' do %> <%= render layout: 'shared/center_panel' do %>
<div class="center-block center-panel-content-size col-xs-12"> <div class="center-block center-panel-content-size col-xs-12">
<%= render 'shared/meeting_url', hidden: false %> <%= render 'shared/meeting_name_form' %>
<%= render 'shared/join_form' %>
<div class="row">
<%= render 'landing/previously_joined' %>
</div>
<div class="row">
<%= render 'landing/invite_join' %>
</div>
</div> </div>
<% end %> <% end %>
</div> </div>

View File

@ -22,11 +22,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<% content_for :footer do %> <% content_for :footer do %>
<div class="panel-footer"> <div class="panel-footer">
<div class="text-center"> <div class="text-center">
<% if current_user %> <%= link_to t('create_your_session'), root_path %>
<%= link_to t('return_to_room'), current_user.room_url %>
<% else %>
<%= link_to t('create_your_session'), root_path %>
<% end %>
</div> </div>
</div> </div>
<% end %> <% end %>

View File

@ -19,22 +19,30 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<% page_title= t('greet_guest', name: @user.username) %> <% page_title= t('greet_guest', name: @user.username) %>
<% end %> <% end %>
<div class="page-wrapper rooms" data-id="<%= @user.encrypted_id %>"> <div class="page-wrapper rooms" data-main-room="<%= @main_room %>" data-id="<%= @meeting_id %>" data-admin-id="<%= @user.encrypted_id %>">
<div class="container-fluid"> <div class="container-fluid">
<div class="center-panel-wrapper"> <div class="center-panel-wrapper">
<%= render 'rooms_center_panel' %> <% if @main_room %>
<%= render 'rooms_center_panel' %>
<% else %>
<%= render 'rooms_meetings_center_panel' %>
<% end %>
</div> </div>
<%= render 'shared/signup' %> <% unless @main_room && !current_user %>
<%= render 'shared/signup' %>
<% end %>
<div class="table-wrapper"> <div class="table-wrapper">
<table id="recordings" class="table" width="100%"> <table id="recordings" class="table" width="100%">
<thead> <thead>
<th><%= t('date_recorded') %></th> <th><%= t('date_recorded') %></th>
<th><%= t('meeting') %></th>
<th><%= t('thumbnails') %></th> <th><%= t('thumbnails') %></th>
<th><%= t('duration') %></th> <th><%= t('duration') %></th>
<th><%= t('views') %></th> <th><%= t('visibility') %></th>
<th><%= t('watch') %></th>
<th>published</th> <th>published</th>
<th><%= t('actions') %></th> <th><%= t('actions') %></th>
</thead> </thead>
@ -53,14 +61,14 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
</button> </button>
</div> </div>
<div class="recording-visibility-popover"> <div class="recording-visibility-popover">
<button type="button" class="btn btn-default btn-danger recording-update" data-visibility="unpublished"> <button type="button" class="btn btn-default btn-success recording-update" data-visibility="published">
<%= t('unpublished') %> <%= t('client.published') %>
</button> </button>
<button type="button" class="btn btn-default btn-warning recording-update" data-visibility="unlisted"> <button type="button" class="btn btn-default btn-warning recording-update" data-visibility="unlisted">
<%= t('unlisted') %> <%= t('client.unlisted') %>
</button> </button>
<button type="button" class="btn btn-default btn-success recording-update" data-visibility="published"> <button type="button" class="btn btn-default btn-danger recording-update" data-visibility="unpublished">
<%= t('published') %> <%= t('client.unpublished') %>
</button> </button>
</div> </div>
<div class="alert-template"> <div class="alert-template">

View File

@ -13,4 +13,4 @@ You should have received a copy of the GNU Lesser General Public License along
with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
--> -->
<%= render 'rooms_center_panel' %> <%= render 'rooms_meetings_center_panel' %>

View File

@ -43,7 +43,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<!-- Footer --> <!-- Footer -->
<div class='footer text-center'> <div class='footer text-center'>
<%= t('footer_html', greenlight_link: link_to('Greenlight', 'https://github.com/bigbluebutton/greenlight', target: "_blank"), version: version, bbb_link: link_to('BigBlueButton', 'http://bigbluebutton.org/', target: "_blank")) %> <%= t('footer_html', bbb_link: link_to('BigBlueButton', 'http://bigbluebutton.org/', target: "_blank")) %>
</div> </div>
<!-- End of Footer --> <!-- End of Footer -->
</body> </body>

View File

@ -0,0 +1,3 @@
<div class="meeting-name-form-wrapper">
<input type="text" class="form-control meeting-name" placeholder="<%= t('enter_meeting_name') %>"/>
</div>

View File

@ -14,34 +14,50 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
--> -->
<div <%= "hidden" if hidden %> class="meeting-url-wrapper"> <div <%= "hidden" if hidden %> class="meeting-url-wrapper">
<div class="input-group"> <div class="<%= 'input-group' unless @user %>">
<div class="meeting-url-group"> <div class="meeting-url-group">
<input type="text" class="form-control meeting-url"/> <input type="text" class="form-control meeting-url"/>
<% if params[:action] == 'index' %>
<i class="fa fa-refresh generate-link has-tooltip" aria-hidden="true"
title="<%= t('url_refresh_hint') %>"
></i>
<% end %>
</div> </div>
<span class="input-group-btn"> <% if current_user %>
<% body = t('meeting_invite.signed_in.body', user: current_user.name) %>
<% subject = t('meeting_invite.signed_in.subject', user: current_user.name) %>
<% else %>
<% body = t('meeting_invite.not_signed_in.body') %>
<% subject = t('meeting_invite.not_signed_in.subject') %>
<% end %>
<button type="button" class="btn btn-default meeting-url-copy has-tooltip" <% if @user %>
<div class="center-block meeting-url-button-group">
<button type="button" class="btn btn-default meeting-url-copy has-tooltip pull-left"
title="<%= t('url_copy_explanation') %>"
data-copied-hint="<%= t('copied') %>"
data-copy-error="<%= t('copy_error') %>"
data-copy-hint="<%= t('url_copy_explanation') %>"
>
<i class="fa fa-clipboard" aria-hidden="true"></i>
</button>
<button type="button" class="btn btn-default meeting-invite has-tooltip pull-right"
title="<%= t('meeting_invite.explanation') %>"
data-invite-body="<%= body %>"
data-invite-subject="<%= subject %>"
>
<i class="fa fa-envelope-o" aria-hidden="true"></i>
</button>
</div>
<% else %>
<span class="input-group-btn">
<button type="button" class="btn btn-default meeting-url-copy has-tooltip"
title="<%= t('url_copy_explanation') %>" title="<%= t('url_copy_explanation') %>"
data-copied-hint="<%= t('copied') %>" data-copied-hint="<%= t('copied') %>"
data-copy-error="<%= t('copy_error') %>" data-copy-error="<%= t('copy_error') %>"
data-copy-hint="<%= t('url_copy_explanation') %>" data-copy-hint="<%= t('url_copy_explanation') %>"
> >
<i class="fa fa-clipboard" aria-hidden="true"></i> <i class="fa fa-clipboard" aria-hidden="true"></i>
</button> </button>
<% if current_user %>
<% body = t('meeting_invite.signed_in.body', user: current_user.name) %>
<% subject = t('meeting_invite.signed_in.subject', user: current_user.name) %>
<% else %>
<% body = t('meeting_invite.not_signed_in.body') %>
<% subject = t('meeting_invite.not_signed_in.subject') %>
<% end %>
<button type="button" class="btn btn-default meeting-invite has-tooltip" <button type="button" class="btn btn-default meeting-invite has-tooltip"
title="<%= t('meeting_invite.explanation') %>" title="<%= t('meeting_invite.explanation') %>"
data-invite-body="<%= body %>" data-invite-body="<%= body %>"
@ -50,6 +66,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<i class="fa fa-envelope-o" aria-hidden="true"></i> <i class="fa fa-envelope-o" aria-hidden="true"></i>
</button> </button>
</span> </span>
<% end %>
</div> </div>
</div> </div>

View File

@ -1,13 +1,17 @@
<span class="signup"> <span class="signup">
<% if current_user %> <% if current_user %>
<div class="text-center"> <div class="text-center">
<span class=""><%= t('logged_in_description_html', link: link_to(current_user.name, current_user.room_url)) %></span> <% if @main_room %>
<div class=""><%= link_to t('logout'), user_logout_url %></div> <span><%= t('logged_in_description_html', link: link_to(current_user.name, current_user.room_url)) %></span>
<% else %>
<%= link_to(t('return_to_room'), current_user.room_url) %>
<% end %>
<div><%= link_to t('logout'), user_logout_url %></div>
</div> </div>
<% else %> <% else %>
<div class="text-center"> <div class="text-center">
<span class=""><%= t('login_description') %></span> <span><%= t('login_description') %></span>
<div class=""><%= link_to t('login'), '/users/login' %></div> <div><%= link_to t('login'), '/users/login' %></div>
</div> </div>
<% end %> <% end %>
</span> </span>

View File

@ -0,0 +1,7 @@
<% title_class ||= '' %>
<div class="title-wrapper text-center">
<div class="title">
<h2 class="<%= title_class if title_class %>"><%= title %></h2>
<%= yield %>
</div>
</div>

View File

@ -10,5 +10,4 @@ deployment:
hub: hub:
branch: master branch: master
commands: commands:
- ./scripts/set_version.sh
- ./scripts/build_image_master.sh - ./scripts/build_image_master.sh

View File

@ -37,44 +37,51 @@
en-US: en-US:
actions: Actions actions: Actions
are_you: Are you %{name}? are_you: Are you %{name} ?
are_you_sure: Are you sure? are_you_sure: Are you sure?
change_recording_visibility: "Change visibility to:" change_recording_visibility: "Change visibility to:"
client: client:
are_you_sure: Are you sure? are_you_sure: Are you sure?
delete_recording: Delete recording delete_recording: Delete recording
join_title: Join "%{id}"
meeting_ended: Meeting was ended meeting_ended: Meeting was ended
meeting_started: Meeting was started meeting_started: Meeting was started
no_recordings: No Recordings no_recordings: No Recordings
no_recordings_yet: No Recordings (Yet!) no_recordings_yet: No Recordings (Yet!)
publish_recording: Publish recording publish_recording: Publish recording
published: Everyone
recording_created: A recording was created recording_created: A recording was created
recording_deleted: Recording was deleted recording_deleted: Recording was deleted
recording_published: Recording was published recording_published: Recording was published
recording_unlisted: Recording was unlisted recording_unlisted: Recording was unlisted
recording_unpublished: Recording was unpublished recording_unpublished: Recording was unpublished
unpublish_recording: Hide recording unpublish_recording: Hide recording
unlisted: Unlisted
unpublished: No one
user_waiting_body: "%{user} is waiting to join your room!" user_waiting_body: "%{user} is waiting to join your room!"
user_waiting_title: A user is waiting user_waiting_title: A user is waiting
copied: Copied copied: Copied
copy_error: Use Ctrl-c to copy copy_error: Use Ctrl-c to copy
create_session: Invite others to a meeting
create_your_session: Create your own meeting create_your_session: Create your own meeting
date_recorded: Date date_recorded: Date
duration: Duration (minutes) duration: Duration (minutes)
end: End end: End
enter_name: Enter your name enter_name: Enter your name
enter_meeting_name: Enter a meeting name to start
footer_html: Powered by %{bbb_link}
greet_user: Welcome, %{name} greet_user: Welcome, %{name}
greet_guest: Welcome to %{name} Meeting Space greet_guest: Welcome to %{name} Meeting Space
hi_all: Hi Everyone hi_all: Hi Everyone
home_title: Welcome to BigBlueButton
invite: Invite
invite_description: (share this link below to invite others to this meeting)
join: Join join: Join
join_session: Join the current meeting
join_session_id: Join %{id} join_session_id: Join %{id}
join_session_user: Join %{name} meeting
logged_in_description_html: You are logged in as %{link} logged_in_description_html: You are logged in as %{link}
login: login login: login
login_description: Want your own recorded meetings? login_description: Want your own recorded meetings?
logout: logout logout: logout
meeting: Meeting
meeting_invite: meeting_invite:
explanation: Send an email with an invitation to this meeting explanation: Send an email with an invitation to this meeting
not_signed_in: not_signed_in:
@ -92,10 +99,8 @@ en-US:
phrase2: "Access the following website to view it and publish to other users: %{url}" phrase2: "Access the following website to view it and publish to other users: %{url}"
subject: "Your recording is ready!" subject: "Your recording is ready!"
past_recordings: Past Recordings past_recordings: Past Recordings
footer_html: "%{greenlight_link} build %{version}, Powered by %{bbb_link}"
presentation: Presentation presentation: Presentation
previously_joined_meetings: Previously Joined Meetings previously_joined_meetings: Previously Joined Meetings
published: Published
return_to_room: Return to your personal room return_to_room: Return to your personal room
session_url_explanation: The meeting will be taking place using the following URL session_url_explanation: The meeting will be taking place using the following URL
signin_text: Log in with %{provider} signin_text: Log in with %{provider}
@ -103,12 +108,11 @@ en-US:
start_meeting: Start Meeting start_meeting: Start Meeting
your_personal_room: Your Personal Room your_personal_room: Your Personal Room
thumbnails: Thumbnails thumbnails: Thumbnails
unlisted: Unlisted
unpublished: Unpublished
url_copy_explanation: Copy this URL to invite others to the meeting url_copy_explanation: Copy this URL to invite others to the meeting
url_refresh_hint: Generate a new meeting URL user_person_room: "%{name} personal room"
video: Video video: Video
views: Views visibility: Visibility
wait_for_mod_msg: Looks like you're the first one here... wait_for_mod_msg: Looks like you're the first one here...
wait_for_mod_explanation: You will automatically join when the meeting starts wait_for_mod_explanation: You will automatically join when the meeting starts
watch: Watch
yes: Yes yes: Yes

View File

@ -28,15 +28,29 @@ Rails.application.routes.draw do
# There are two resources [meetings|rooms] # There are two resources [meetings|rooms]
# meetings offer a landing page for NON authenticated users to create and join session in BigBlueButton # meetings offer a landing page for NON authenticated users to create and join session in BigBlueButton
# rooms offer a customized landing page for authenticated users to create and join session in BigBlueButton # rooms offer a customized landing page for authenticated users to create and join session in BigBlueButton
# recording routes for updating, deleting and viewing recordings
get '/rooms/:room_id/recordings', to: 'bbb#recordings', defaults: {format: 'json'}
patch '/rooms/:room_id/recordings/:record_id', to: 'bbb#update_recordings', defaults: {format: 'json'}
delete '/rooms/:room_id/recordings/:record_id', to: 'bbb#delete_recordings', defaults: {format: 'json'}
get '/rooms/:room_id/:id/recordings', to: 'bbb#recordings', defaults: {format: 'json'}
patch '/rooms/:room_id/:id/recordings/:record_id', to: 'bbb#update_recordings', defaults: {format: 'json'}
delete '/rooms/:room_id/:id/recordings/:record_id', to: 'bbb#delete_recordings', defaults: {format: 'json'}
# room routes for joining, ending, waiting and refreshing authenticated meetings
get '/rooms/:room_id', to: 'landing#resource', resource: 'rooms'
get '/rooms/:room_id/:id', to: 'landing#resource', resource: 'rooms'
get '/rooms/:room_id/:id/join', to: 'bbb#join', resource: 'rooms', defaults: {format: 'json'}
delete '/rooms/:room_id/:id/end', to: 'bbb#end', defaults: {format: 'json'}
# routes shared between meetings and rooms
get '/:resource/:id', to: 'landing#resource', as: :resource get '/:resource/:id', to: 'landing#resource', as: :resource
get '/:resource/:id/join', to: 'bbb#join', as: :bbb_join, defaults: {format: 'json'} get '/:resource/:id/join', to: 'bbb#join', as: :bbb_join, defaults: {format: 'json'}
get '/:resource/:id/wait', to: 'landing#wait_for_moderator'
get '/:resource/:id/session_status_refresh', to: 'landing#session_status_refresh'
post '/:resource/:id/callback', to: 'bbb#callback' #, defaults: {format: 'json'} post '/:resource/:id/callback', to: 'bbb#callback' #, defaults: {format: 'json'}
delete '/rooms/:id/end', to: 'bbb#end', defaults: {format: 'json'}
get '/rooms/:id/recordings', to: 'bbb#recordings', defaults: {format: 'json'}
patch '/rooms/:id/recordings/:record_id', to: 'bbb#update_recordings', defaults: {format: 'json'}
delete '/rooms/:id/recordings/:record_id', to: 'bbb#delete_recordings', defaults: {format: 'json'}
root to: 'landing#index', :resource => "meetings" get '/:resource/:room_id/:id/wait', to: 'landing#wait_for_moderator'
get '/:resource/:room_id/:id/session_status_refresh', to: 'landing#session_status_refresh'
root to: 'landing#index', :resource => 'meetings'
end end

View File

@ -1,3 +0,0 @@
#!/bin/bash
echo "module Greenlight VERSION = ${CIRCLE_BUILD_NUM} end" >| $HOME/greenlight/app/lib/version.rb

View File

@ -39,12 +39,12 @@ class LandingControllerTest < ActionController::TestCase
end end
test "should get wait for moderator" do test "should get wait for moderator" do
get :wait_for_moderator, params: { id: @user.encrypted_id, resource: 'rooms' } get :wait_for_moderator, params: { room_id: @user.encrypted_id, id: 'room1', resource: 'rooms' }
assert_response :success assert_response :success
end end
test "should get session status refresh" do test "should get session status refresh" do
get :wait_for_moderator, params: { id: @user.encrypted_id, resource: 'rooms' } get :wait_for_moderator, params: { room_id: @user.encrypted_id, id: 'room1', resource: 'rooms' }
assert_response :success assert_response :success
end end