From a055b88eb7bb71b6630b0b7832074e961ac466aa Mon Sep 17 00:00:00 2001 From: farhatahmad <35435341+farhatahmad@users.noreply.github.com> Date: Mon, 22 Jul 2019 12:46:48 -0400 Subject: [PATCH] GRN2-129: Added server recordings and refactored adminsitrator panel (#662) * Added server recordings and refactored adminsitrator panel * Fixed some issues * Fixed issue with owner email search * Fixed issue with edit user --- app/assets/javascripts/admins.js | 4 +- app/assets/javascripts/recording.js | 41 ++ app/assets/javascripts/rename.js | 5 +- app/assets/javascripts/room.js.erb | 15 - app/assets/javascripts/search.js | 3 +- app/assets/javascripts/settings.js | 2 +- app/assets/javascripts/sort.js | 5 +- .../utilities/_primary_themes.scss | 2 + app/controllers/admins_controller.rb | 35 +- .../concerns/recorder.rb} | 50 +- app/controllers/recordings_controller.rb | 7 +- app/controllers/rooms_controller.rb | 7 +- app/controllers/users_controller.rb | 12 +- app/helpers/admins_helper.rb | 12 + app/models/room.rb | 32 +- app/models/user.rb | 28 +- .../admins/components/_menu_buttons.html.erb | 26 + .../admins/components/_recordings.html.erb | 91 +++ .../components/_server_recording_row.html.erb | 81 +++ .../admins/components/_setting_view.html.erb | 26 + .../components/_settings.html.erb} | 0 .../components}/_users.html.erb | 16 + app/views/admins/edit_user.html.erb | 27 + app/views/admins/index.html.erb | 22 +- app/views/admins/server_recordings.html.erb | 27 + app/views/admins/site_settings.html.erb | 27 + app/views/rooms/show.html.erb | 2 +- .../shared/modals/_delete_room_modal.html.erb | 4 +- app/views/users/edit.html.erb | 6 +- config/locales/en.yml | 3 + config/routes.rb | 2 + lib/bbb_api.rb | 10 +- spec/concerns/recorder_spec.rb | 567 ++++++++++++++++++ spec/controllers/admins_controller_spec.rb | 18 +- spec/controllers/rooms_controller_spec.rb | 4 +- spec/controllers/users_controller_spec.rb | 2 + spec/models/room_spec.rb | 414 ------------- spec/models/user_spec.rb | 93 --- 38 files changed, 1088 insertions(+), 640 deletions(-) create mode 100644 app/assets/javascripts/recording.js rename app/{models/concerns/api_concern.rb => controllers/concerns/recorder.rb} (65%) create mode 100644 app/views/admins/components/_menu_buttons.html.erb create mode 100644 app/views/admins/components/_recordings.html.erb create mode 100644 app/views/admins/components/_server_recording_row.html.erb create mode 100644 app/views/admins/components/_setting_view.html.erb rename app/views/{shared/admin_settings/_site_settings.html.erb => admins/components/_settings.html.erb} (100%) rename app/views/{shared/admin_settings => admins/components}/_users.html.erb (90%) create mode 100644 app/views/admins/edit_user.html.erb create mode 100644 app/views/admins/server_recordings.html.erb create mode 100644 app/views/admins/site_settings.html.erb create mode 100644 spec/concerns/recorder_spec.rb diff --git a/app/assets/javascripts/admins.js b/app/assets/javascripts/admins.js index 55fa3a4378..0b27efe0cc 100644 --- a/app/assets/javascripts/admins.js +++ b/app/assets/javascripts/admins.js @@ -43,9 +43,9 @@ $(document).on('turbolinks:load', function(){ window.location.replace(url); }) - - /* COLOR SELECTORS */ + } + if (controller == "admins" && action == "site_settings") { loadColourSelectors() } diff --git a/app/assets/javascripts/recording.js b/app/assets/javascripts/recording.js new file mode 100644 index 0000000000..213ca957b6 --- /dev/null +++ b/app/assets/javascripts/recording.js @@ -0,0 +1,41 @@ +// BigBlueButton open source conferencing system - http://www.bigbluebutton.org/. +// +// Copyright (c) 2018 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 . + +// Handle changing of settings tabs. +$(document).on('turbolinks:load', function(){ + var controller = $("body").data('controller'); + var action = $("body").data('action'); + + if (controller == "rooms" && action == "show" + || controller == "rooms" && action == "update" + || controller == "users" && action == "recordings" + || controller == "admins" && action == "server_recordings"){ + // Handle recording emails. + $('.email-link').each(function(){ + $(this).click(function(){ + var subject = $(".username").text() + " " + t('room.mailer.subject'); + var body = t('room.mailer.body') + "\n\n" + $(this).attr("data-pres-link"); + var autogenerated = "\n\n" + t('room.mailer.autogenerated') + "\n"; + var footer = t('room.mailer.footer'); + + var url = "mailto:?subject=" + encodeURIComponent(subject) + "&body=" + encodeURIComponent(body) + encodeURIComponent(autogenerated) + encodeURIComponent(footer); + var win = window.open(url, '_blank'); + + win.focus(); + }); + }); + } +}); \ No newline at end of file diff --git a/app/assets/javascripts/rename.js b/app/assets/javascripts/rename.js index 2057049812..a8f32c6a8d 100644 --- a/app/assets/javascripts/rename.js +++ b/app/assets/javascripts/rename.js @@ -18,7 +18,10 @@ $(document).on('turbolinks:load', function(){ var controller = $("body").data('controller'); var action = $("body").data('action'); - if(controller == "rooms" && action == "show" || controller == "rooms" && action == "update" || controller == "users" && action == "recordings"){ + if(controller == "rooms" && action == "show" + || controller == "rooms" && action == "update" + || controller == "users" && action == "recordings" + || controller == "admins" && action == "server_recordings"){ // Set a room header rename event var configure_room_header = function(room_title){ diff --git a/app/assets/javascripts/room.js.erb b/app/assets/javascripts/room.js.erb index f5be24f0db..1dc1367524 100644 --- a/app/assets/javascripts/room.js.erb +++ b/app/assets/javascripts/room.js.erb @@ -39,21 +39,6 @@ $(document).on('turbolinks:load', function(){ }, 2000) } }); - - // Handle recording emails. - $('.email-link').each(function(){ - $(this).click(function(){ - var subject = $(".username").text() + " " + t('room.mailer.subject'); - var body = t('room.mailer.body') + "\n\n" + $(this).attr("data-pres-link"); - var autogenerated = "\n\n" + t('room.mailer.autogenerated') + "\n"; - var footer = t('room.mailer.footer'); - - var url = "mailto:?subject=" + encodeURIComponent(subject) + "&body=" + encodeURIComponent(body) + encodeURIComponent(autogenerated) + encodeURIComponent(footer); - var win = window.open(url, '_blank'); - - win.focus(); - }); - }); } // Display and update all fields related to creating a room in the createRoomModal diff --git a/app/assets/javascripts/search.js b/app/assets/javascripts/search.js index de2c0f7861..6869ebb540 100644 --- a/app/assets/javascripts/search.js +++ b/app/assets/javascripts/search.js @@ -22,7 +22,8 @@ $(document).on('turbolinks:load', function(){ (controller == "rooms" && action == "show") || (controller == "rooms" && action == "update") || (controller == "rooms" && action == "join") || - (controller == "users" && action == "recordings")) { + (controller == "users" && action == "recordings") || + (controller == "admins" && action == "server_recordings")) { // Submit search if the user hits enter $("#search-input").keypress(function(key) { var keyPressed = key.which diff --git a/app/assets/javascripts/settings.js b/app/assets/javascripts/settings.js index bacd22b47b..42b7418e4c 100644 --- a/app/assets/javascripts/settings.js +++ b/app/assets/javascripts/settings.js @@ -20,7 +20,7 @@ $(document).on('turbolinks:load', function(){ var action = $("body").data('action'); // Only run on the settings page. - if ((controller == "users" && action == "edit") || (controller == "users" && action == "update") || (controller == "admins" && action == "index")){ + if ((controller == "users" && action == "edit") || (controller == "users" && action == "update")){ var settingsButtons = $('.setting-btn'); var settingsViews = $('.setting-view'); diff --git a/app/assets/javascripts/sort.js b/app/assets/javascripts/sort.js index a7903de6ef..effa8ea6bf 100644 --- a/app/assets/javascripts/sort.js +++ b/app/assets/javascripts/sort.js @@ -18,7 +18,10 @@ $(document).on('turbolinks:load', function(){ var controller = $("body").data('controller'); var action = $("body").data('action'); - if(controller == "rooms" && action == "show" || controller == "rooms" && action == "update" || controller == "users" && action == "recordings"){ + if(controller == "rooms" && action == "show" + || controller == "rooms" && action == "update" + || controller == "users" && action == "recordings" + || controller == "admins" && action == "server_recordings"){ // Choose active header // (Name, Length or Users) diff --git a/app/assets/stylesheets/utilities/_primary_themes.scss b/app/assets/stylesheets/utilities/_primary_themes.scss index 33d48d3129..c8a37695a7 100644 --- a/app/assets/stylesheets/utilities/_primary_themes.scss +++ b/app/assets/stylesheets/utilities/_primary_themes.scss @@ -84,6 +84,7 @@ a { color: #6e7687 !important; &:hover { color: $primary-color !important; + background-color: $primary-color-lighten !important; } &:active { background-color: $primary-color-lighten !important; @@ -130,6 +131,7 @@ input:focus, select:focus { } & a { + color: $primary-color !important; border-color: $primary-color !important; } diff --git a/app/controllers/admins_controller.rb b/app/controllers/admins_controller.rb index aa4977d37e..8a128b2302 100644 --- a/app/controllers/admins_controller.rb +++ b/app/controllers/admins_controller.rb @@ -20,6 +20,7 @@ class AdminsController < ApplicationController include Pagy::Backend include Themer include Emailer + include Recorder manage_users = [:edit_user, :promote, :demote, :ban_user, :unban_user, :approve] site_settings = [:branding, :coloring, :coloring_lighten, :coloring_darken, @@ -40,11 +41,27 @@ def index @pagy, @users = pagy(user_list) end + # GET /admins/site_settings + def site_settings + end + + # GET /admins/server_recordings + def server_recordings + server_rooms = if Rails.configuration.loadbalanced_configuration + Room.includes(:owner).where(users: { provider: user_settings_provider }).pluck(:bbb_id) + else + Room.pluck(:bbb_id) + end + + @search, @order_column, @order_direction, recs = + all_recordings(server_rooms, @user_domain, params.permit(:search, :column, :direction), true, true) + @pagy, @recordings = pagy_array(recs) + end + # MANAGE USERS # GET /admins/edit/:user_uid def edit_user - render "admins/index", locals: { setting_id: "account" } end # POST /admins/promote/:user_uid @@ -111,7 +128,7 @@ def invite # POST /admins/branding def branding @settings.update_value("Branding Image", params[:url]) - redirect_to admins_path, flash: { success: I18n.t("administrator.flash.settings") } + redirect_to admin_site_settings_path, flash: { success: I18n.t("administrator.flash.settings") } end # POST /admins/color @@ -119,23 +136,23 @@ def coloring @settings.update_value("Primary Color", params[:color]) @settings.update_value("Primary Color Lighten", color_lighten(params[:color])) @settings.update_value("Primary Color Darken", color_darken(params[:color])) - redirect_to admins_path, flash: { success: I18n.t("administrator.flash.settings") } + redirect_to admin_site_settings_path, flash: { success: I18n.t("administrator.flash.settings") } end def coloring_lighten @settings.update_value("Primary Color Lighten", params[:color]) - redirect_to admins_path, flash: { success: I18n.t("administrator.flash.settings") } + redirect_to admin_site_settings_path, flash: { success: I18n.t("administrator.flash.settings") } end def coloring_darken @settings.update_value("Primary Color Darken", params[:color]) - redirect_to admins_path, flash: { success: I18n.t("administrator.flash.settings") } + redirect_to admin_site_settings_path, flash: { success: I18n.t("administrator.flash.settings") } end # POST /admins/room_authentication def room_authentication @settings.update_value("Room Authentication", params[:value]) - redirect_to admins_path, flash: { success: I18n.t("administrator.flash.settings") } + redirect_to admin_site_settings_path, flash: { success: I18n.t("administrator.flash.settings") } end # POST /admins/registration_method/:method @@ -144,11 +161,11 @@ def registration_method # Only allow change to Join by Invitation if user has emails enabled if !Rails.configuration.enable_email_verification && new_method == Rails.configuration.registration_methods[:invite] - redirect_to admins_path, + redirect_to admin_site_settings_path, flash: { alert: I18n.t("administrator.flash.invite_email_verification") } else @settings.update_value("Registration Method", new_method) - redirect_to admins_path, + redirect_to admin_site_settings_path, flash: { success: I18n.t("administrator.flash.registration_method_updated") } end end @@ -156,7 +173,7 @@ def registration_method # POST /admins/room_limit def room_limit @settings.update_value("Room Limit", params[:limit]) - redirect_to admins_path, flash: { success: I18n.t("administrator.flash.settings") } + redirect_to admin_site_settings_path, flash: { success: I18n.t("administrator.flash.settings") } end private diff --git a/app/models/concerns/api_concern.rb b/app/controllers/concerns/recorder.rb similarity index 65% rename from app/models/concerns/api_concern.rb rename to app/controllers/concerns/recorder.rb index 2b25f586b2..0833e5f83d 100644 --- a/app/models/concerns/api_concern.rb +++ b/app/controllers/concerns/recorder.rb @@ -16,11 +16,50 @@ # You should have received a copy of the GNU Lesser General Public License along # with BigBlueButton; if not, see . -module APIConcern +module Recorder extend ActiveSupport::Concern + include ::BbbApi + + # Fetches all recordings for a room. + def recordings(room_bbb_id, provider, search_params = {}, ret_search_params = false) + res = bbb(provider).get_recordings(meetingID: room_bbb_id) + + format_recordings(res, search_params, ret_search_params) + end + + # Fetches a rooms public recordings. + def public_recordings(room_bbb_id, provider, search_params = {}, ret_search_params = false) + search, order_col, order_dir, recs = recordings(room_bbb_id, provider, search_params, ret_search_params) + [search, order_col, order_dir, recs.select { |r| r[:metadata][:"gl-listed"] == "true" }] + end + + # Makes paginated API calls to get recordings + def all_recordings(room_bbb_ids, provider, search_params = {}, ret_search_params = false, search_name = false) + pag_num = Rails.configuration.pagination_number + + pag_loops = room_bbb_ids.length / pag_num - 1 + + res = { recordings: [] } + + (0..pag_loops).each do |i| + pag_rooms = room_bbb_ids[pag_num * i, pag_num] + + # bbb.get_recordings returns an object + # take only the array portion of the object that is returned + full_res = bbb(provider).get_recordings(meetingID: pag_rooms) + res[:recordings].push(*full_res[:recordings]) + end + + last_pag_room = room_bbb_ids[pag_num * (pag_loops + 1), room_bbb_ids.length % pag_num] + + full_res = bbb(provider).get_recordings(meetingID: last_pag_room) + res[:recordings].push(*full_res[:recordings]) + + format_recordings(res, search_params, ret_search_params, search_name) + end # Format, filter, and sort recordings to match their current use in the app - def format_recordings(api_res, search_params, ret_search_params) + def format_recordings(api_res, search_params, ret_search_params, search_name = false) search = search_params[:search] || "" order_col = search_params[:column] && search_params[:direction] != "none" ? search_params[:column] : "end_time" order_dir = search_params[:column] && search_params[:direction] != "none" ? search_params[:direction] : "desc" @@ -40,7 +79,7 @@ def format_recordings(api_res, search_params, ret_search_params) r.delete(:playback) end - recs = filter_recordings(api_res, search) + recs = filter_recordings(api_res, search, search_name) recs = sort_recordings(recs, order_col, order_dir) if ret_search_params @@ -50,7 +89,7 @@ def format_recordings(api_res, search_params, ret_search_params) end end - def filter_recordings(api_res, search) + def filter_recordings(api_res, search, search_name = false) api_res[:recordings].select do |r| (!r[:metadata].nil? && ((!r[:metadata][:name].nil? && r[:metadata][:name].downcase.include?(search)) || @@ -59,7 +98,8 @@ def filter_recordings(api_res, search) ((r[:metadata].nil? || r[:metadata][:name].nil?) && r[:name].downcase.include?(search)) || r[:participants].include?(search) || - !r[:playbacks].select { |p| p[:type].downcase.include?(search) }.empty? + !r[:playbacks].select { |p| p[:type].downcase.include?(search) }.empty? || + (search_name && Room.find_by(bbb_id: r[:meetingID]).owner.email.downcase.include?(search)) end end diff --git a/app/controllers/recordings_controller.rb b/app/controllers/recordings_controller.rb index e1313f89af..2c4446ae22 100644 --- a/app/controllers/recordings_controller.rb +++ b/app/controllers/recordings_controller.rb @@ -50,6 +50,11 @@ def find_room # Ensure the user is logged into the room they are accessing. def verify_room_ownership - redirect_to root_path unless @room.owned_by?(current_user) + if !current_user || + !@room.owned_by?(current_user) || + !current_user.has_cached_role?(:admin) || + !current_user.has_cached_role?(:super_admin) + redirect_to root_path + end end end diff --git a/app/controllers/rooms_controller.rb b/app/controllers/rooms_controller.rb index e8e235408e..1e633d0db9 100644 --- a/app/controllers/rooms_controller.rb +++ b/app/controllers/rooms_controller.rb @@ -19,6 +19,7 @@ class RoomsController < ApplicationController include RecordingsHelper include Pagy::Backend + include Recorder before_action :validate_accepted_terms, unless: -> { !Rails.configuration.terms } before_action :validate_verified_email, except: [:show, :join], @@ -56,7 +57,7 @@ def create def show if current_user && @room.owned_by?(current_user) @search, @order_column, @order_direction, recs = - @room.recordings(params.permit(:search, :column, :direction), true) + recordings(@room.bbb_id, @user_domain, params.permit(:search, :column, :direction), true) @pagy, @recordings = pagy_array(recs) @@ -72,7 +73,7 @@ def show end @search, @order_column, @order_direction, pub_recs = - @room.public_recordings(params.permit(:search, :column, :direction), true) + public_recordings(@room.bbb_id, @user_domain, params.permit(:search, :column, :direction), true) @pagy, @public_recordings = pagy_array(pub_recs) @@ -135,7 +136,7 @@ def join search_params = params[@room.invite_path] || params @search, @order_column, @order_direction, pub_recs = - @room.public_recordings(search_params.permit(:search, :column, :direction), true) + public_recordings(@room.bbb_id, @user_domain, search_params.permit(:search, :column, :direction), true) @pagy, @public_recordings = pagy_array(pub_recs) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 0224d90552..c28d1c0f77 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -21,6 +21,7 @@ class UsersController < ApplicationController include Pagy::Backend include Emailer include Registrar + include Recorder before_action :find_user, only: [:edit, :update, :destroy] before_action :ensure_unauthenticated, only: [:new, :create] @@ -103,6 +104,8 @@ def edit # PATCH /u/:user_uid/edit def update + redirect_path = current_user.admin_of?(@user) ? admins_path : edit_user_path(@user) + if params[:setting] == "password" # Update the users password. errors = {} @@ -123,7 +126,7 @@ def update if errors.empty? && @user.save # Notify the user that their account has been updated. flash[:success] = I18n.t("info_update_success") - redirect_to edit_user_path(@user) + redirect_to redirect_path else # Append custom errors. errors.each { |k, v| @user.errors.add(k, v) } @@ -132,11 +135,11 @@ def update elsif user_params[:email] != @user.email && @user.update_attributes(user_params) @user.update_attributes(email_verified: false) flash[:success] = I18n.t("info_update_success") - redirect_to edit_user_path(@user) + redirect_to redirect_path elsif @user.update_attributes(user_params) update_locale(@user) flash[:success] = I18n.t("info_update_success") - redirect_to edit_user_path(@user) + redirect_to redirect_path else render :edit, params: { settings: params[:settings] } end @@ -165,7 +168,8 @@ def destroy def recordings if current_user && current_user.uid == params[:user_uid] @search, @order_column, @order_direction, recs = - current_user.all_recordings(params.permit(:search, :column, :direction), true) + all_recordings(current_user.rooms.pluck(:bbb_id), current_user.provider, + params.permit(:search, :column, :direction), true) @pagy, @recordings = pagy_array(recs) else redirect_to root_path diff --git a/app/helpers/admins_helper.rb b/app/helpers/admins_helper.rb index af23f73110..4019328394 100644 --- a/app/helpers/admins_helper.rb +++ b/app/helpers/admins_helper.rb @@ -19,6 +19,18 @@ module AdminsHelper include Pagy::Frontend + # Returns the action method of the current page + def active_page + route = Rails.application.routes.recognize_path(request.env['PATH_INFO']) + + route[:action] + end + + # Gets the email of the room owner to which the recording belongs to + def recording_owner_email(room_id) + Room.find_by(bbb_id: room_id).owner.email + end + def display_invite current_page?(admins_path) && invite_registration end diff --git a/app/models/room.rb b/app/models/room.rb index dc0b5af27e..728278fd1d 100644 --- a/app/models/room.rb +++ b/app/models/room.rb @@ -19,7 +19,6 @@ require 'bbb_api' class Room < ApplicationRecord - include ::APIConcern include ::BbbApi before_create :setup @@ -40,7 +39,7 @@ def owned_by?(user) # Checks if a room is running on the BigBlueButton server. def running? - bbb.is_meeting_running?(bbb_id) + bbb(owner.provider).is_meeting_running?(bbb_id) end # Determines the invite path for the room. @@ -62,7 +61,7 @@ def start_session(options = {}) # Send the create request. begin - meeting = bbb.create_meeting(name, bbb_id, create_options) + meeting = bbb(owner.provider).create_meeting(name, bbb_id, create_options) # Update session info. unless meeting[:messageKey] == 'duplicateWarning' update_attributes(sessions: sessions + 1, last_session: DateTime.now) @@ -84,10 +83,10 @@ def join_path(name, options = {}, uid = nil) options[:user_is_moderator] ||= false options[:meeting_recorded] ||= false - return call_invalid_res unless bbb + return call_invalid_res unless bbb(owner.provider) # Get the meeting info. - meeting_info = bbb.get_meeting_info(bbb_id, nil) + meeting_info = bbb(owner.provider).get_meeting_info(bbb_id, nil) # Determine the password to use when joining. password = if options[:user_is_moderator] @@ -101,7 +100,7 @@ def join_path(name, options = {}, uid = nil) join_opts[:userID] = uid if uid join_opts[:joinViaHtml5] = options[:join_via_html5] if options[:join_via_html5] - bbb.join_meeting_url(bbb_id, name, password, join_opts) + bbb(owner.provider).join_meeting_url(bbb_id, name, password, join_opts) end # Notify waiting users that a meeting has started. @@ -111,7 +110,7 @@ def notify_waiting # Retrieves all the users in a room. def participants - res = bbb.get_meeting_info(bbb_id, nil) + res = bbb(owner.provider).get_meeting_info(bbb_id, nil) res[:attendees].map do |att| User.find_by(uid: att[:userID], name: att[:fullName]) end @@ -120,27 +119,18 @@ def participants [] end - # Fetches all recordings for a room. - def recordings(search_params = {}, ret_search_params = false) - res = bbb.get_recordings(meetingID: bbb_id) - - format_recordings(res, search_params, ret_search_params) - end - - # Fetches a rooms public recordings. - def public_recordings(search_params = {}, ret_search_params = false) - search, order_col, order_dir, recs = recordings(search_params, ret_search_params) - [search, order_col, order_dir, recs.select { |r| r[:metadata][:"gl-listed"] == "true" }] + def recording_count + bbb(owner.provider).get_recordings(meetingID: bbb_id)[:recordings].length end def update_recording(record_id, meta) meta[:recordID] = record_id - bbb.send_api_request("updateRecordings", meta) + bbb(owner.provider).send_api_request("updateRecordings", meta) end # Deletes a recording from a room. def delete_recording(record_id) - bbb.delete_recordings(record_id) + bbb(owner.provider).delete_recordings(record_id) end private @@ -155,7 +145,7 @@ def setup # Deletes all recordings associated with the room. def delete_all_recordings - record_ids = recordings.map { |r| r[:recordID] } + record_ids = bbb(owner.provider).get_recordings(meetingID: bbb_id)[:recordings].pluck(:recordID) delete_recording(record_ids) unless record_ids.empty? end diff --git a/app/models/user.rb b/app/models/user.rb index ba914f9b17..6ed05a76e8 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -20,7 +20,6 @@ class User < ApplicationRecord rolify - include ::APIConcern include ::BbbApi attr_accessor :reset_token @@ -118,31 +117,8 @@ def self.admins_search(string) end def self.admins_order(column, direction) - order("#{column} #{direction}") - end - - def all_recordings(search_params = {}, ret_search_params = false) - pag_num = Rails.configuration.pagination_number - - pag_loops = rooms.length / pag_num - 1 - - res = { recordings: [] } - - (0..pag_loops).each do |i| - pag_rooms = rooms[pag_num * i, pag_num] - - # bbb.get_recordings returns an object - # take only the array portion of the object that is returned - full_res = bbb.get_recordings(meetingID: pag_rooms.pluck(:bbb_id)) - res[:recordings].push(*full_res[:recordings]) - end - - last_pag_room = rooms[pag_num * (pag_loops + 1), rooms.length % pag_num] - - full_res = bbb.get_recordings(meetingID: last_pag_room.pluck(:bbb_id)) - res[:recordings].push(*full_res[:recordings]) - - format_recordings(res, search_params, ret_search_params) + # Arel.sql to avoid sql injection + order(Arel.sql("#{column} #{direction}")) end # Activates an account and initialize a users main room diff --git a/app/views/admins/components/_menu_buttons.html.erb b/app/views/admins/components/_menu_buttons.html.erb new file mode 100644 index 0000000000..7dfcc8ffc6 --- /dev/null +++ b/app/views/admins/components/_menu_buttons.html.erb @@ -0,0 +1,26 @@ +<% +# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/. +# Copyright (c) 2018 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 . +%> + +
+ <%= link_to admins_path, class: "list-group-item list-group-item-action dropdown-item #{"active" if active_page == "index"}" do %> + <%= t("administrator.users.title") %> + <% end %> + <%= link_to admin_site_settings_path, class: "list-group-item list-group-item-action dropdown-item #{"active" if active_page == "site_settings"}" do %> + <%= t("administrator.site_settings.title") %> + <% end %> + <%= link_to admin_recordings_path, class: "list-group-item list-group-item-action dropdown-item #{"active" if active_page == "server_recordings"}" do %> + <%= t("administrator.recordings.title") %> + <% end %> +
\ No newline at end of file diff --git a/app/views/admins/components/_recordings.html.erb b/app/views/admins/components/_recordings.html.erb new file mode 100644 index 0000000000..2ffa9ee958 --- /dev/null +++ b/app/views/admins/components/_recordings.html.erb @@ -0,0 +1,91 @@ +<% +# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/. +# Copyright (c) 2018 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 . +%> + +
+
+
+ + + + + + + + + + + + + + + + <% if @recordings.empty? %> + + + + <% else %> + <% @recordings.each do |recording| %> + <%= render "admins/components/server_recording_row", recording: recording %> + <% end %> + <% end %> + +
"> + <%= t("recording.table.name") %> + <% if @order_column == "name" && @order_direction == "desc" %> + ↓ + <% elsif @order_column == "name" && @order_direction == "asc" %> + ↑ + <% end %> + "> + <%= t("recording.table.length") %> + <% if @order_column == "length" && @order_direction == "desc" %> + ↓ + <% elsif @order_column == "length" && @order_direction == "asc" %> + ↑ + <% end %> + "> + <%= t("recording.table.users") %> + <% if @order_column == "users" && @order_direction == "desc" %> + ↓ + <% elsif @order_column == "users" && @order_direction == "asc" %> + ↑ + <% end %> + "> + <%= t("recording.table.visibility") %> + <% if @order_column == "visibility" && @order_direction == "desc" %> + ↓ + <% elsif @order_column == "visibility" && @order_direction == "asc" %> + ↑ + <% end %> + "> + <%= t("recording.table.formats") %> + <% if @order_column == "formats" && @order_direction == "desc" %> + ↓ + <% elsif @order_column == "formats" && @order_direction == "asc" %> + ↑ + <% end %> +
+ <%= t("administrator.recordings.no_recordings") %> +
+ <% if !@recordings.empty?%> +
+ <%== pagy_bootstrap_nav(@pagy) %> +
+ <% end %> +
+
+
\ No newline at end of file diff --git a/app/views/admins/components/_server_recording_row.html.erb b/app/views/admins/components/_server_recording_row.html.erb new file mode 100644 index 0000000000..c62347553e --- /dev/null +++ b/app/views/admins/components/_server_recording_row.html.erb @@ -0,0 +1,81 @@ +<% +# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/. +# Copyright (c) 2018 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 . +%> + + + +
+ + <% if recording[:metadata][:name] %> + <%= recording[:metadata][:name] %> + <% else %> + <%= recording[:name] %> + <% end %> + + +
+
+ <%= t("recording.recorded_on", date: recording_date(recording[:startTime])) %> +
+
+ <%= recording_owner_email(recording[:meetingID]) %> +
+ + + <%= recording_length(recording[:playbacks]) %> + + + <%= recording[:participants] || "-" %> + + + + + + <% sorted_formats = recording[:playbacks].sort_by! { |p| p[:type] } %> + <% sorted_formats.each do |p| %> + <%= link_to t("recording.format.#{p[:type]}"), p[:url], class: "btn btn-sm btn-primary", target: "_blank" %> + <% end %> + + + + + diff --git a/app/views/admins/components/_setting_view.html.erb b/app/views/admins/components/_setting_view.html.erb new file mode 100644 index 0000000000..1b2eb6ecf3 --- /dev/null +++ b/app/views/admins/components/_setting_view.html.erb @@ -0,0 +1,26 @@ +<% +# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/. +# Copyright (c) 2018 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 . +%> + +<%= content_tag(:div, id: setting_id, class: "setting-view card") do %> +
+
+
+ <%= render "shared/components/subtitle", subtitle: setting_title, search: search %> +
+
+ + <%= render "admins/components/#{setting_id}" %> +
+<% end %> diff --git a/app/views/shared/admin_settings/_site_settings.html.erb b/app/views/admins/components/_settings.html.erb similarity index 100% rename from app/views/shared/admin_settings/_site_settings.html.erb rename to app/views/admins/components/_settings.html.erb diff --git a/app/views/shared/admin_settings/_users.html.erb b/app/views/admins/components/_users.html.erb similarity index 90% rename from app/views/shared/admin_settings/_users.html.erb rename to app/views/admins/components/_users.html.erb index df8422fae2..5d1ad1bd40 100644 --- a/app/views/shared/admin_settings/_users.html.erb +++ b/app/views/admins/components/_users.html.erb @@ -13,6 +13,21 @@ # with BigBlueButton; if not, see . %> +<% +# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/. +# Copyright (c) 2018 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 . +%> + <% if @role.present? %> <%= render "shared/components/admins_tags" %> <% end %> @@ -146,3 +161,4 @@ <%= render "shared/modals/invite_user_modal" %> + diff --git a/app/views/admins/edit_user.html.erb b/app/views/admins/edit_user.html.erb new file mode 100644 index 0000000000..54beeb8ec4 --- /dev/null +++ b/app/views/admins/edit_user.html.erb @@ -0,0 +1,27 @@ +<% +# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/. +# Copyright (c) 2018 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 . +%> + +
+ <%= render "shared/components/subtitle", subtitle: t("administrator.title"), search: false %> + +
+
+ <%= render "admins/components/menu_buttons" %> +
+
+ <%= render "shared/settings/setting_view", setting_id: "account", setting_title: t("settings.account.subtitle") %> +
+
+
diff --git a/app/views/admins/index.html.erb b/app/views/admins/index.html.erb index 1903f14ca0..d366aa23fb 100644 --- a/app/views/admins/index.html.erb +++ b/app/views/admins/index.html.erb @@ -18,26 +18,10 @@
-
- - -
+ <%= render "admins/components/menu_buttons" %>
- - -
- <% if defined?(setting_id) && setting_id == "account" %> - <%= render "shared/settings/setting_view", setting_id: "account", setting_title: t("administrator.users.edit.title") %> - <% else %> - <%= render "shared/settings/setting_view", admin_view: true, setting_id: "users", setting_title: t("administrator.users.title") %> - <%= render "shared/settings/setting_view", admin_view: true, setting_id: "site_settings", setting_title: t("administrator.site_settings.subtitle") %> - <% end %> - - <%= render "shared/modals/delete_account_modal", delete_location: relative_root %> +
+ <%= render "admins/components/setting_view", setting_id: "users", setting_title: t("administrator.users.title"), search: true %>
diff --git a/app/views/admins/server_recordings.html.erb b/app/views/admins/server_recordings.html.erb new file mode 100644 index 0000000000..a07b19cbcd --- /dev/null +++ b/app/views/admins/server_recordings.html.erb @@ -0,0 +1,27 @@ +<% +# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/. +# Copyright (c) 2018 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 . +%> + +
+ <%= render "shared/components/subtitle", subtitle: t("administrator.title"), search: false %> + +
+
+ <%= render "admins/components/menu_buttons" %> +
+
+ <%= render "admins/components/setting_view", setting_id: "recordings", setting_title: t("administrator.recordings.title"), search: true %> +
+
+
diff --git a/app/views/admins/site_settings.html.erb b/app/views/admins/site_settings.html.erb new file mode 100644 index 0000000000..c246ce7153 --- /dev/null +++ b/app/views/admins/site_settings.html.erb @@ -0,0 +1,27 @@ +<% +# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/. +# Copyright (c) 2018 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 . +%> + +
+ <%= render "shared/components/subtitle", subtitle: t("administrator.title"), search: false %> + +
+
+ <%= render "admins/components/menu_buttons" %> +
+
+ <%= render "admins/components/setting_view", setting_id: "settings", setting_title: t("administrator.site_settings.subtitle"), search: false %> +
+
+
\ No newline at end of file diff --git a/app/views/rooms/show.html.erb b/app/views/rooms/show.html.erb index d527be81e8..40725512f6 100644 --- a/app/views/rooms/show.html.erb +++ b/app/views/rooms/show.html.erb @@ -89,7 +89,7 @@ <%= render "shared/components/room_block", room: room %> <% end %> - <%= render "shared/modals/delete_room_modal", room: room %> + <%= render "shared/modals/delete_room_modal", recording_count: room.recording_count, room: room %> <% end %> <% end %> <% unless room_limit_exceeded %> diff --git a/app/views/shared/modals/_delete_room_modal.html.erb b/app/views/shared/modals/_delete_room_modal.html.erb index 27f92853e2..3b7a1d8d82 100644 --- a/app/views/shared/modals/_delete_room_modal.html.erb +++ b/app/views/shared/modals/_delete_room_modal.html.erb @@ -34,8 +34,8 @@ diff --git a/app/views/users/edit.html.erb b/app/views/users/edit.html.erb index bee0c1693c..8ee6186d7e 100644 --- a/app/views/users/edit.html.erb +++ b/app/views/users/edit.html.erb @@ -20,17 +20,17 @@
- <% if @user.social_uid.nil? %> - <% end %> -
diff --git a/config/locales/en.yml b/config/locales/en.yml index e04ed564b6..fdbec16aef 100755 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -73,6 +73,9 @@ en: registration_method_updated: Registration method successfully updated settings: Site Settings successfully changed unauthorized: You are not authorized to perform actions on this user + recordings: + title: Server Recordings + no_recordings: This server has no recordings. title: Organization Settings users: invite: Invite User diff --git a/config/routes.rb b/config/routes.rb index a1dc1eaafd..56dc67aeb3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -37,6 +37,8 @@ resources :admins, only: [:index] scope '/admins' do + get '/site_settings', to: 'admins#site_settings', as: :admin_site_settings + get '/recordings', to: 'admins#server_recordings', as: :admin_recordings post '/branding', to: 'admins#branding', as: :admin_branding post '/coloring', to: 'admins#coloring', as: :admin_coloring post '/room_authentication', to: 'admins#room_authentication', as: :admin_room_authentication diff --git a/lib/bbb_api.rb b/lib/bbb_api.rb index 46f9bdfdb1..b76b3c8147 100644 --- a/lib/bbb_api.rb +++ b/lib/bbb_api.rb @@ -12,15 +12,9 @@ def bbb_secret end # Sets a BigBlueButtonApi object for interacting with the API. - def bbb + def bbb(user_provider) if Rails.configuration.loadbalanced_configuration - if instance_of? Room - # currently in the Room Model - user_domain = retrieve_provider_info(owner.provider) - elsif instance_of? User - # currently in the User Model - user_domain = retrieve_provider_info(provider) - end + user_domain = retrieve_provider_info(user_provider) BigBlueButton::BigBlueButtonApi.new(remove_slash(user_domain["apiURL"]), user_domain["secret"], "0.8") else diff --git a/spec/concerns/recorder_spec.rb b/spec/concerns/recorder_spec.rb new file mode 100644 index 0000000000..7e082e1f92 --- /dev/null +++ b/spec/concerns/recorder_spec.rb @@ -0,0 +1,567 @@ +# frozen_string_literal: true + +# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/. +# +# Copyright (c) 2018 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 . + +require "rails_helper" +require 'bigbluebutton_api' + +shared_examples_for "recorder" do + let(:controller) { described_class } # the class that includes the concern + + before do + @user = create(:user) + @room = @user.main_room + + allow_any_instance_of(Room).to receive(:owner).and_return(@user) + end + + it "should properly find meeting recordings" do + allow_any_instance_of(BigBlueButton::BigBlueButtonApi).to receive(:get_recordings).and_return( + recordings: [ + { + name: "Example", + playback: { + format: + { + type: "presentation" + } + } + } + ] + ) + + expect(recordings(@room.bbb_id, @room.owner.provider)).to contain_exactly( + name: "Example", + playbacks: + [ + { + type: "presentation" + } + ] + ) + end + + it "gets all filtered and sorted recordings for the user" do + allow_any_instance_of(BigBlueButton::BigBlueButtonApi).to receive(:get_recordings).and_return( + recordings: [ + { + meetingID: @room.bbb_id, + name: "Example", + participants: "3", + playback: { + format: + { + type: "presentation" + } + }, + metadata: { + "gl-listed": "true", + } + }, + { + meetingID: @room.bbb_id, + name: "aExamaaa", + participants: "5", + playback: { + format: + { + type: "other" + } + }, + metadata: { + "gl-listed": "false", + } + }, + { + meetingID: @room.bbb_id, + name: "test", + participants: "1", + playback: { + format: + { + type: "presentation" + } + }, + metadata: { + "gl-listed": "true", + } + }, + { + meetingID: @room.bbb_id, + name: "Exam", + participants: "1", + playback: { + format: + { + type: "other" + } + }, + metadata: { + "gl-listed": "false", + name: "z", + } + } + ] + ) + + expect(all_recordings(@user.rooms.pluck(:bbb_id), @user.provider, search: "Exam", column: "name", + direction: "desc")).to eq( + [ + { + meetingID: @room.bbb_id, + name: "Example", + participants: "3", + playbacks: + [ + { + type: "presentation" + } + ], + metadata: { + "gl-listed": "true", + } + }, + { + meetingID: @room.bbb_id, + name: "aExamaaa", + participants: "5", + playbacks: + [ + { + type: "other" + } + ], + metadata: { + "gl-listed": "false", + } + } + ] + ) + end + + context '#filtering' do + before do + allow_any_instance_of(BigBlueButton::BigBlueButtonApi).to receive(:get_recordings).and_return( + recordings: [ + { + meetingID: @room.bbb_id, + name: "Example", + participants: "3", + playback: { + format: + { + type: "presentation" + } + }, + metadata: { + "gl-listed": "true", + } + }, + { + meetingID: @room.bbb_id, + name: "aExamaaa", + participants: "5", + playback: { + format: + { + type: "other" + } + }, + metadata: { + "gl-listed": "false", + } + }, + { + meetingID: @room.bbb_id, + name: "test", + participants: "1", + playback: { + format: + { + type: "presentation" + } + }, + metadata: { + "gl-listed": "true", + } + }, + { + meetingID: @room.bbb_id, + name: "Exam", + participants: "1", + playback: { + format: + { + type: "other" + } + }, + metadata: { + "gl-listed": "false", + name: "metadata", + } + } + ] + ) + end + + it "should filter recordings on name" do + expect(recordings(@room.bbb_id, @room.owner.provider, search: "Exam")).to contain_exactly( + { + meetingID: @room.bbb_id, + name: "aExamaaa", + participants: "5", + playbacks: + [ + { + type: "other" + } + ], + metadata: { + "gl-listed": "false", + } + }, + meetingID: @room.bbb_id, + name: "Example", + participants: "3", + playbacks: + [ + { + type: "presentation" + } + ], + metadata: { + "gl-listed": "true", + } + ) + end + + it "should filter recordings on participants" do + expect(recordings(@room.bbb_id, @room.owner.provider, search: "5")).to contain_exactly( + meetingID: @room.bbb_id, + name: "aExamaaa", + participants: "5", + playbacks: + [ + { + type: "other" + } + ], + metadata: { + "gl-listed": "false", + } + ) + end + + it "should filter recordings on format" do + expect(recordings(@room.bbb_id, @room.owner.provider, search: "presentation")).to contain_exactly( + { + meetingID: @room.bbb_id, + name: "test", + participants: "1", + playbacks: + [ + { + type: "presentation" + } + ], + metadata: { + "gl-listed": "true", + } + }, + meetingID: @room.bbb_id, + name: "Example", + participants: "3", + playbacks: + [ + { + type: "presentation" + } + ], + metadata: { + "gl-listed": "true", + } + ) + end + + it "should filter recordings on visibility" do + expect(recordings(@room.bbb_id, @room.owner.provider, search: "public")).to contain_exactly( + { + meetingID: @room.bbb_id, + name: "test", + participants: "1", + playbacks: + [ + { + type: "presentation" + } + ], + metadata: { + "gl-listed": "true", + }, + }, + meetingID: @room.bbb_id, + name: "Example", + participants: "3", + playbacks: + [ + { + type: "presentation" + } + ], + metadata: { + "gl-listed": "true", + } + ) + end + + it "should filter recordings on metadata name by default" do + expect(recordings(@room.bbb_id, @room.owner.provider, search: "metadata")).to contain_exactly( + meetingID: @room.bbb_id, + name: "Exam", + participants: "1", + playbacks: + [ + { + type: "other" + } + ], + metadata: { + "gl-listed": "false", + name: "metadata", + } + ) + end + end + + context '#sorting' do + before do + allow_any_instance_of(BigBlueButton::BigBlueButtonApi).to receive(:get_recordings).and_return( + recordings: [ + { + meetingID: @room.bbb_id, + name: "Example", + participants: "3", + playback: { + format: { + type: "presentation", + length: "4" + } + }, + metadata: { + "gl-listed": "true", + } + }, + { + meetingID: @room.bbb_id, + name: "aExamaaa", + participants: "1", + playback: { + format: { + type: "other", + length: "3" + } + }, + metadata: { + name: "Z", + "gl-listed": "false" + } + } + ] + ) + end + + it "should sort recordings on name" do + expect(recordings(@room.bbb_id, @room.owner.provider, column: "name", direction: "asc")).to eq( + [ + { + meetingID: @room.bbb_id, + name: "Example", + participants: "3", + playbacks: [ + { + type: "presentation", + length: "4" + } + ], + metadata: { + "gl-listed": "true", + } + }, + { + meetingID: @room.bbb_id, + name: "aExamaaa", + participants: "1", + playbacks: [ + { + type: "other", + length: "3" + } + ], + metadata: { + name: "Z", + "gl-listed": "false" + } + } + ] + ) + end + + it "should sort recordings on participants" do + expect(recordings(@room.bbb_id, @room.owner.provider, column: "users", direction: "desc")).to eq( + [ + { + meetingID: @room.bbb_id, + name: "Example", + participants: "3", + playbacks: [ + { + type: "presentation", + length: "4" + } + ], + metadata: { + "gl-listed": "true", + } + }, + { + meetingID: @room.bbb_id, + name: "aExamaaa", + participants: "1", + playbacks: [ + { + type: "other", + length: "3" + } + ], + metadata: { + name: "Z", + "gl-listed": "false" + } + } + ] + ) + end + + it "should sort recordings on visibility" do + expect(recordings(@room.bbb_id, @room.owner.provider, column: "visibility", direction: "desc")).to eq( + [ + { + meetingID: @room.bbb_id, + name: "Example", + participants: "3", + playbacks: [ + { + type: "presentation", + length: "4" + } + ], + metadata: { + "gl-listed": "true", + } + }, + { + meetingID: @room.bbb_id, + name: "aExamaaa", + participants: "1", + playbacks: [ + { + type: "other", + length: "3" + } + ], + metadata: { + name: "Z", + "gl-listed": "false" + } + } + ] + ) + end + + it "should sort recordings on length" do + expect(recordings(@room.bbb_id, @room.owner.provider, column: "length", direction: "asc")).to eq( + [ + { + meetingID: @room.bbb_id, + name: "aExamaaa", + participants: "1", + playbacks: [ + { + type: "other", + length: "3" + } + ], + metadata: { + name: "Z", + "gl-listed": "false" + } + }, + { + meetingID: @room.bbb_id, + name: "Example", + participants: "3", + playbacks: [ + { + type: "presentation", + length: "4" + } + ], + metadata: { + "gl-listed": "true", + } + } + ] + ) + end + + it "should sort recordings on format" do + expect(recordings(@room.bbb_id, @room.owner.provider, column: "formats", direction: "desc")).to eq( + [ + { + meetingID: @room.bbb_id, + name: "Example", + participants: "3", + playbacks: [ + { + type: "presentation", + length: "4" + } + ], + metadata: { + "gl-listed": "true", + } + }, + { + meetingID: @room.bbb_id, + name: "aExamaaa", + participants: "1", + playbacks: [ + { + type: "other", + length: "3" + } + ], + metadata: { + name: "Z", + "gl-listed": "false" + } + } + ] + ) + end + end +end diff --git a/spec/controllers/admins_controller_spec.rb b/spec/controllers/admins_controller_spec.rb index 3f55a2c084..d03576ca66 100644 --- a/spec/controllers/admins_controller_spec.rb +++ b/spec/controllers/admins_controller_spec.rb @@ -52,7 +52,7 @@ get :edit_user, params: { user_uid: @user.uid } - expect(response).to render_template(:index) + expect(response).to render_template(:edit_user) end end @@ -197,7 +197,7 @@ feature = Setting.find_by(provider: "provider1").features.find_by(name: "Branding Image") expect(feature[:value]).to eq(fake_image_url) - expect(response).to redirect_to(admins_path) + expect(response).to redirect_to(admin_site_settings_path) end end @@ -214,7 +214,7 @@ feature = Setting.find_by(provider: "provider1").features.find_by(name: "Primary Color") expect(feature[:value]).to eq(primary_color) - expect(response).to redirect_to(admins_path) + expect(response).to redirect_to(admin_site_settings_path) end it "changes the primary-lighten on the page" do @@ -229,7 +229,7 @@ feature = Setting.find_by(provider: "provider1").features.find_by(name: "Primary Color Lighten") expect(feature[:value]).to eq(primary_color) - expect(response).to redirect_to(admins_path) + expect(response).to redirect_to(admin_site_settings_path) end it "changes the primary-darken on the page" do @@ -244,7 +244,7 @@ feature = Setting.find_by(provider: "provider1").features.find_by(name: "Primary Color Darken") expect(feature[:value]).to eq(primary_color) - expect(response).to redirect_to(admins_path) + expect(response).to redirect_to(admin_site_settings_path) end end end @@ -264,7 +264,7 @@ expect(feature[:value]).to eq(Rails.configuration.registration_methods[:invite]) expect(flash[:success]).to be_present - expect(response).to redirect_to(admins_path) + expect(response).to redirect_to(admin_site_settings_path) end it "does not allow the user to change to invite if emails are off" do @@ -277,7 +277,7 @@ post :registration_method, params: { method: "invite" } expect(flash[:alert]).to be_present - expect(response).to redirect_to(admins_path) + expect(response).to redirect_to(admin_site_settings_path) end end @@ -293,7 +293,7 @@ feature = Setting.find_by(provider: "provider1").features.find_by(name: "Room Authentication") expect(feature[:value]).to eq("true") - expect(response).to redirect_to(admins_path) + expect(response).to redirect_to(admin_site_settings_path) end end @@ -309,7 +309,7 @@ feature = Setting.find_by(provider: "provider1").features.find_by(name: "Room Limit") expect(feature[:value]).to eq("5") - expect(response).to redirect_to(admins_path) + expect(response).to redirect_to(admin_site_settings_path) end end end diff --git a/spec/controllers/rooms_controller_spec.rb b/spec/controllers/rooms_controller_spec.rb index b9899079bb..7fe3b6b3bd 100644 --- a/spec/controllers/rooms_controller_spec.rb +++ b/spec/controllers/rooms_controller_spec.rb @@ -28,6 +28,8 @@ def random_valid_room_params end describe RoomsController, type: :controller do + it_behaves_like "recorder" + include Recorder describe "GET #show" do before do @user = create(:user) @@ -39,7 +41,7 @@ def random_valid_room_params get :show, params: { room_uid: @owner.main_room } - expect(assigns(:recordings)).to eql(@owner.main_room.recordings) + expect(assigns(:recordings)).to eql(recordings(@owner.main_room.bbb_id, @owner.provider)) expect(assigns(:is_running)).to eql(@owner.main_room.running?) end diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 42bc6103b6..23d40e8d69 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -302,6 +302,7 @@ def random_valid_user_params describe "PATCH #update" do it "properly updates user attributes" do user = create(:user) + @request.session[:user_id] = user.id params = random_valid_user_params patch :update, params: params.merge!(user_uid: user) @@ -315,6 +316,7 @@ def random_valid_user_params it "renders #edit on unsuccessful save" do @user = create(:user) + @request.session[:user_id] = @user.id patch :update, params: invalid_params.merge!(user_uid: @user) expect(response).to render_template(:edit) diff --git a/spec/models/room_spec.rb b/spec/models/room_spec.rb index a95a9684f6..2745aaa58a 100644 --- a/spec/models/room_spec.rb +++ b/spec/models/room_spec.rb @@ -133,420 +133,6 @@ end context "#recordings" do - it "should properly find meeting recordings" do - allow_any_instance_of(BigBlueButton::BigBlueButtonApi).to receive(:get_recordings).and_return( - recordings: [ - { - name: "Example", - playback: { - format: - { - type: "presentation" - } - } - } - ] - ) - - expect(@room.recordings).to contain_exactly( - name: "Example", - playbacks: - [ - { - type: "presentation" - } - ] - ) - end - - context '#filtering' do - before do - allow_any_instance_of(BigBlueButton::BigBlueButtonApi).to receive(:get_recordings).and_return( - recordings: [ - { - name: "Example", - participants: "3", - playback: { - format: - { - type: "presentation" - } - }, - metadata: { - "gl-listed": "true", - } - }, - { - name: "aExamaaa", - participants: "5", - playback: { - format: - { - type: "other" - } - }, - metadata: { - "gl-listed": "false", - } - }, - { - name: "test", - participants: "1", - playback: { - format: - { - type: "presentation" - } - }, - metadata: { - "gl-listed": "true", - } - }, - { - name: "Exam", - participants: "1", - playback: { - format: - { - type: "other" - } - }, - metadata: { - "gl-listed": "false", - name: "z", - } - } - ] - ) - end - - it "should filter recordings on name" do - expect(@room.recordings(search: "Exam")).to contain_exactly( - { - name: "aExamaaa", - participants: "5", - playbacks: - [ - { - type: "other" - } - ], - metadata: { - "gl-listed": "false", - } - }, - name: "Example", - participants: "3", - playbacks: - [ - { - type: "presentation" - } - ], - metadata: { - "gl-listed": "true", - } - ) - end - - it "should filter recordings on participants" do - expect(@room.recordings(search: "5")).to contain_exactly( - name: "aExamaaa", - participants: "5", - playbacks: - [ - { - type: "other" - } - ], - metadata: { - "gl-listed": "false", - } - ) - end - - it "should filter recordings on format" do - expect(@room.recordings(search: "presentation")).to contain_exactly( - { - name: "test", - participants: "1", - playbacks: - [ - { - type: "presentation" - } - ], - metadata: { - "gl-listed": "true", - } - }, - name: "Example", - participants: "3", - playbacks: - [ - { - type: "presentation" - } - ], - metadata: { - "gl-listed": "true", - } - ) - end - - it "should filter recordings on visibility" do - expect(@room.recordings(search: "public")).to contain_exactly( - { - name: "test", - participants: "1", - playbacks: - [ - { - type: "presentation" - } - ], - metadata: { - "gl-listed": "true", - }, - }, - name: "Example", - participants: "3", - playbacks: - [ - { - type: "presentation" - } - ], - metadata: { - "gl-listed": "true", - } - ) - end - - it "should filter recordings on metadata name by default" do - expect(@room.recordings(search: "z")).to contain_exactly( - name: "Exam", - participants: "1", - playbacks: - [ - { - type: "other" - } - ], - metadata: { - "gl-listed": "false", - name: "z", - } - ) - end - end - - context '#sorting' do - before do - allow_any_instance_of(BigBlueButton::BigBlueButtonApi).to receive(:get_recordings).and_return( - recordings: [ - { - name: "Example", - participants: "3", - playback: { - format: { - type: "presentation", - length: "4" - } - }, - metadata: { - "gl-listed": "true", - } - }, - { - name: "aExamaaa", - participants: "1", - playback: { - format: { - type: "other", - length: "3" - } - }, - metadata: { - name: "Z", - "gl-listed": "false" - } - } - ] - ) - end - - it "should sort recordings on name" do - expect(@room.recordings(column: "name", direction: "asc")).to eq( - [ - { - name: "Example", - participants: "3", - playbacks: [ - { - type: "presentation", - length: "4" - } - ], - metadata: { - "gl-listed": "true", - } - }, - { - name: "aExamaaa", - participants: "1", - playbacks: [ - { - type: "other", - length: "3" - } - ], - metadata: { - name: "Z", - "gl-listed": "false" - } - } - ] - ) - end - - it "should sort recordings on participants" do - expect(@room.recordings(column: "users", direction: "desc")).to eq( - [ - { - name: "Example", - participants: "3", - playbacks: [ - { - type: "presentation", - length: "4" - } - ], - metadata: { - "gl-listed": "true", - } - }, - { - name: "aExamaaa", - participants: "1", - playbacks: [ - { - type: "other", - length: "3" - } - ], - metadata: { - name: "Z", - "gl-listed": "false" - } - } - ] - ) - end - - it "should sort recordings on visibility" do - expect(@room.recordings(column: "visibility", direction: "desc")).to eq( - [ - { - name: "Example", - participants: "3", - playbacks: [ - { - type: "presentation", - length: "4" - } - ], - metadata: { - "gl-listed": "true", - } - }, - { - name: "aExamaaa", - participants: "1", - playbacks: [ - { - type: "other", - length: "3" - } - ], - metadata: { - name: "Z", - "gl-listed": "false" - } - } - ] - ) - end - - it "should sort recordings on length" do - expect(@room.recordings(column: "length", direction: "asc")).to eq( - [ - { - name: "aExamaaa", - participants: "1", - playbacks: [ - { - type: "other", - length: "3" - } - ], - metadata: { - name: "Z", - "gl-listed": "false" - } - }, - { - name: "Example", - participants: "3", - playbacks: [ - { - type: "presentation", - length: "4" - } - ], - metadata: { - "gl-listed": "true", - } - } - ] - ) - end - - it "should sort recordings on format" do - expect(@room.recordings(column: "formats", direction: "desc")).to eq( - [ - { - name: "Example", - participants: "3", - playbacks: [ - { - type: "presentation", - length: "4" - } - ], - metadata: { - "gl-listed": "true", - } - }, - { - name: "aExamaaa", - participants: "1", - playbacks: [ - { - type: "other", - length: "3" - } - ], - metadata: { - name: "Z", - "gl-listed": "false" - } - } - ] - ) - end - end - it "deletes the recording" do allow_any_instance_of(BigBlueButton::BigBlueButtonApi).to receive(:delete_recordings).and_return( returncode: true, deleted: true diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index dc38dc1120..fefb0b20c2 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -173,97 +173,4 @@ .to raise_exception(ActiveRecord::RecordInvalid, "Validation failed: Email can't be blank") end end - - context '#recordings' do - it "gets all filtered and sorted recordings for the user" do - allow_any_instance_of(BigBlueButton::BigBlueButtonApi).to receive(:get_recordings).and_return( - recordings: [ - { - name: "Example", - participants: "3", - playback: { - format: - { - type: "presentation" - } - }, - metadata: { - "gl-listed": "true", - } - }, - { - name: "aExamaaa", - participants: "5", - playback: { - format: - { - type: "other" - } - }, - metadata: { - "gl-listed": "false", - } - }, - { - name: "test", - participants: "1", - playback: { - format: - { - type: "presentation" - } - }, - metadata: { - "gl-listed": "true", - } - }, - { - name: "Exam", - participants: "1", - playback: { - format: - { - type: "other" - } - }, - metadata: { - "gl-listed": "false", - name: "z", - } - } - ] - ) - - expect(@user.all_recordings(search: "Exam", column: "name", direction: "desc")).to eq( - [ - { - name: "Example", - participants: "3", - playbacks: - [ - { - type: "presentation" - } - ], - metadata: { - "gl-listed": "true", - } - }, - { - name: "aExamaaa", - participants: "5", - playbacks: - [ - { - type: "other" - } - ], - metadata: { - "gl-listed": "false", - } - } - ] - ) - end - end end