From 2b915baa47de30cafc1970842222ee3a19ec9195 Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 24 Mar 2023 09:30:46 +0000 Subject: [PATCH 1/8] Static SIP --- app/assets/locales/de.json | 4 +++- app/assets/locales/en.json | 4 +++- app/controllers/api/v1/meetings_controller.rb | 4 ++-- app/controllers/api/v1/rooms_controller.rb | 4 ++-- app/javascript/components/rooms/RoomCard.jsx | 15 ++++++++++++++- app/javascript/components/rooms/room/Room.jsx | 18 +++++++++++++++++- app/models/room.rb | 15 ++++++++++++++- app/serializers/current_room_serializer.rb | 7 +++++++ app/serializers/room_serializer.rb | 6 ++++++ app/services/meeting_starter.rb | 2 +- app/services/room_settings_getter.rb | 11 ++++++++++- config/application.rb | 2 ++ .../20230321125010_add_voice_brige_to_romms.rb | 6 ++++++ db/schema.rb | 4 +++- greenlight-v3.nginx | 4 ++-- 15 files changed, 92 insertions(+), 14 deletions(-) create mode 100644 db/migrate/20230321125010_add_voice_brige_to_romms.rb diff --git a/app/assets/locales/de.json b/app/assets/locales/de.json index a5936bdc0a..bfa8ae4b5d 100644 --- a/app/assets/locales/de.json +++ b/app/assets/locales/de.json @@ -17,6 +17,7 @@ "close": "Schließen", "delete": "Löschen", "copy": "Einladungslink kopieren", + "copy_voice_bridge": "Telefoneinwahl kopieren", "or": "oder", "online": "Online", "help_center": "Hilfezentrum", @@ -376,7 +377,8 @@ "access_code_copied": "Zugangscode kopiert.", "access_code_generated": "Zugangscode generiert.", "access_code_deleted": "Zugriffcode wurde gelöscht.", - "copied_meeting_url": "Die URL der Konferenz wurde kopiert. Der Link kann verwendet werden, um an der Konferenz teilzunehmen." + "copied_meeting_url": "Die URL der Konferenz wurde kopiert. Der Link kann verwendet werden, um an der Konferenz teilzunehmen.", + "copied_voice_bridge": "Die Telefonnummer und der Pin wurden kopiert. Diese können genutzt werden um an der Konferenz teilzunehmen." }, "site_settings": { "site_setting_updated": "Grundeinstellungen aktualisiert.", diff --git a/app/assets/locales/en.json b/app/assets/locales/en.json index 29f095eccf..9cf4506b8a 100644 --- a/app/assets/locales/en.json +++ b/app/assets/locales/en.json @@ -17,6 +17,7 @@ "close": "Close", "delete": "Delete", "copy": "Copy Join Link", + "copy_voice_bridge": "Copy phone dialup", "or": "Or", "online": "Online", "help_center": "Help Center", @@ -376,7 +377,8 @@ "access_code_copied": "The access code has been copied.", "access_code_generated": "A new access code has been generated.", "access_code_deleted": "The access code has been deleted.", - "copied_meeting_url": "The meeting URL has been copied. The link can be used to join the meeting." + "copied_meeting_url": "The meeting URL has been copied. The link can be used to join the meeting.", + "copied_voice_bridge": "The phone number and pin have been copied. They can be used to join the conference." }, "site_settings": { "site_setting_updated": "The site setting has been updated.", diff --git a/app/controllers/api/v1/meetings_controller.rb b/app/controllers/api/v1/meetings_controller.rb index 15e02f2936..0f5b10e751 100644 --- a/app/controllers/api/v1/meetings_controller.rb +++ b/app/controllers/api/v1/meetings_controller.rb @@ -30,8 +30,8 @@ class MeetingsController < ApiController def start begin MeetingStarter.new(room: @room, base_url: root_url, current_user:).call - rescue BigBlueButton::BigBlueButtonException => e - return render_error status: :bad_request unless e.key == 'idNotUnique' + #rescue BigBlueButton::BigBlueButtonException => e + # return render_error status: :bad_request unless e.key == 'idNotUnique' end render_data data: BigBlueButtonApi.new.join_meeting( diff --git a/app/controllers/api/v1/rooms_controller.rb b/app/controllers/api/v1/rooms_controller.rb index 8714f18dc6..06c05877dd 100644 --- a/app/controllers/api/v1/rooms_controller.rb +++ b/app/controllers/api/v1/rooms_controller.rb @@ -92,7 +92,7 @@ def create room = Room.new(name: room_params[:name], user_id: room_params[:user_id]) if room.save - logger.info "room(friendly_id):#{room.friendly_id} created for user(id):#{room.user_id}" + logger.info "room(friendly_id):#{room.friendly_id} created for user(id):#{room.user_id} with voice brige: #{room.voice_bridge}" render_data status: :created else render_error errors: room.errors.to_a, status: :bad_request @@ -149,7 +149,7 @@ def find_room end def room_params - params.require(:room).permit(:name, :user_id, :presentation) + params.require(:room).permit(:name, :user_id, :voice_bridge, :presentation) end end end diff --git a/app/javascript/components/rooms/RoomCard.jsx b/app/javascript/components/rooms/RoomCard.jsx index 63790698b8..5993612a75 100644 --- a/app/javascript/components/rooms/RoomCard.jsx +++ b/app/javascript/components/rooms/RoomCard.jsx @@ -18,7 +18,7 @@ import React, { useCallback } from 'react'; import { useNavigate } from 'react-router-dom'; import { Button, Card, Stack } from 'react-bootstrap'; import PropTypes from 'prop-types'; -import { DocumentDuplicateIcon, LinkIcon } from '@heroicons/react/24/outline'; +import { DocumentDuplicateIcon, LinkIcon, PhoneIcon } from '@heroicons/react/24/outline'; import { toast } from 'react-toastify'; import { useTranslation } from 'react-i18next'; import { useAuth } from '../../contexts/auth/AuthProvider'; @@ -41,6 +41,11 @@ export default function RoomCard({ room }) { toast.success(t('toast.success.room.copied_meeting_url')); } + function copyVoiceBridge(voice_bridge, voice_bridge_phone_number) { + navigator.clipboard.writeText(`Tel.: ${voice_bridge_phone_number} Pin: ${voice_bridge}`); + toast.success(t('toast.success.room.copied_voice_bridge')); + } + return ( @@ -73,6 +78,12 @@ export default function RoomCard({ room }) { > + {typeof room.voice_bridge_phone_number !== 'undefined' && } + { typeof room.voice_bridge_phone_number !== 'undefined' && }) +} diff --git a/app/models/room.rb b/app/models/room.rb index 37bb3b480e..1626268c3a 100644 --- a/app/models/room.rb +++ b/app/models/room.rb @@ -30,6 +30,7 @@ class Room < ApplicationRecord validates :name, presence: true validates :friendly_id, presence: true, uniqueness: true validates :meeting_id, presence: true, uniqueness: true + validates :voice_bridge, uniqueness: true validates :presentation, content_type: %i[.doc .docx .ppt .pptx .pdf .xls .xlsx .txt .rtf .odt .ods .odp .odg .odc .odi .jpg .jpeg .png], size: { less_than: 30.megabytes } @@ -37,7 +38,7 @@ class Room < ApplicationRecord validates :name, length: { minimum: 2, maximum: 255 } validates :recordings_processing, numericality: { only_integer: true, greater_than_or_equal_to: 0 } - before_validation :set_friendly_id, :set_meeting_id, on: :create + before_validation :set_friendly_id, :set_meeting_id, :set_voice_brige, on: :create after_create :create_meeting_options attr_accessor :shared, :active, :participants @@ -95,4 +96,16 @@ def set_meeting_id rescue StandardError retry end + + # Create unique pin for voice brige max 10^6 - 1000 unique ids + def set_voice_brige + if Rails.application.config.voice_bridge_phone_number != nil + id = SecureRandom.random_number((10.pow(5)) - 1) + raise if Room.exists?(voice_bridge: id) || id < 10000 + + self.voice_bridge = id + end + rescue StandardError + retry + end end diff --git a/app/serializers/current_room_serializer.rb b/app/serializers/current_room_serializer.rb index d4e8e98785..515747c704 100644 --- a/app/serializers/current_room_serializer.rb +++ b/app/serializers/current_room_serializer.rb @@ -23,6 +23,9 @@ class CurrentRoomSerializer < ApplicationSerializer attribute :last_session, if: -> { object.last_session } + attribute :voice_bridge, if: -> { Rails.application.config.voice_bridge_phone_number } + attribute :voice_bridge_phone_number, if: -> { Rails.application.config.voice_bridge_phone_number } + def presentation_name presentation_file_name(object) end @@ -34,4 +37,8 @@ def thumbnail def owner_name object.user.name end + + def voice_bridge_phone_number + Rails.application.config.voice_bridge_phone_number + end end diff --git a/app/serializers/room_serializer.rb b/app/serializers/room_serializer.rb index c236a94ed8..6f5adddb1b 100644 --- a/app/serializers/room_serializer.rb +++ b/app/serializers/room_serializer.rb @@ -20,8 +20,14 @@ class RoomSerializer < ApplicationSerializer attributes :id, :name, :friendly_id, :online, :participants, :last_session attribute :shared_owner, if: -> { object.shared } + attribute :voice_bridge, if: -> { Rails.application.config.voice_bridge_phone_number } + attribute :voice_bridge_phone_number, if: -> { Rails.application.config.voice_bridge_phone_number } def shared_owner object.user.name end + + def voice_bridge_phone_number + Rails.application.config.voice_bridge_phone_number + end end diff --git a/app/services/meeting_starter.rb b/app/services/meeting_starter.rb index ecd0674d82..0f10f3abd9 100644 --- a/app/services/meeting_starter.rb +++ b/app/services/meeting_starter.rb @@ -27,7 +27,7 @@ def initialize(room:, base_url:, current_user:) def call # TODO: amir - Check the legitimately of the action. - options = RoomSettingsGetter.new(room_id: @room.id, provider: @room.user.provider, current_user: @current_user, only_bbb_options: true).call + options = RoomSettingsGetter.new(room_id: @room.id, provider: @room.user.provider, current_user: @current_user, only_bbb_options: true, voice_bridge: @room.voice_bridge).call viewer_code = RoomSettingsGetter.new( room_id: @room.id, provider: @room.user.provider, diff --git a/app/services/room_settings_getter.rb b/app/services/room_settings_getter.rb index 1d033d41aa..52b85666d0 100644 --- a/app/services/room_settings_getter.rb +++ b/app/services/room_settings_getter.rb @@ -23,13 +23,14 @@ class RoomSettingsGetter # Hash(` => {'true' => , 'false' => })` SPECIAL_OPTIONS = { 'guestPolicy' => { 'true' => 'ASK_MODERATOR', 'false' => 'ALWAYS_ACCEPT' } }.freeze - def initialize(room_id:, provider:, current_user:, settings: [], show_codes: false, only_enabled: false, only_bbb_options: false) + def initialize(room_id:, provider:, current_user:, settings: [], show_codes: false, only_enabled: false, only_bbb_options: false, voice_bridge: nil) @current_user = current_user @room_id = room_id @only_bbb_options = only_bbb_options # When used only BBB options (not prefixed with 'gl') will be returned. @only_enabled = only_enabled # When used only optional and force enabled options will be returned. @show_codes = show_codes # When used access code values will be returned. @settings = settings # When given only the settings contained in the Array will be returned. + @voice_bridge = voice_bridge # Fetching only rooms configs that are not optional to overwrite the settings values. @rooms_configs = MeetingOption.joins(:rooms_configurations) @@ -55,6 +56,8 @@ def call infer_codes(room_settings:, access_codes:) # Access codes should map their forced values as intended. infer_can_record(room_settings:) if room_settings['record'] && @rooms_configs['record'].nil? + set_voice_brige(room_settings:) + room_settings end @@ -98,4 +101,10 @@ def infer_can_record(room_settings:) room_settings['record'] = 'false' end + + def set_voice_brige(room_settings:) + if @voice_bridge != nil + room_settings['voiceBridge'] = "#{@voice_bridge}" + end + end end diff --git a/config/application.rb b/config/application.rb index 288ba39971..0079fa0e7d 100644 --- a/config/application.rb +++ b/config/application.rb @@ -62,5 +62,7 @@ class Application < Rails::Application config.bigbluebutton_endpoint = File.join(config.bigbluebutton_endpoint, '/api/') unless config.bigbluebutton_endpoint.end_with?('api', 'api/') config.bigbluebutton_secret = ENV.fetch('BIGBLUEBUTTON_SECRET', '8cd8ef52e8e101574e400365b55e11a6') + + config.voice_bridge_phone_number = ENV.fetch('VOICE_BRIDGE_PHONE_NUMBER', nil) end end diff --git a/db/migrate/20230321125010_add_voice_brige_to_romms.rb b/db/migrate/20230321125010_add_voice_brige_to_romms.rb new file mode 100644 index 0000000000..42fac35f2a --- /dev/null +++ b/db/migrate/20230321125010_add_voice_brige_to_romms.rb @@ -0,0 +1,6 @@ +class AddVoiceBrigeToRomms < ActiveRecord::Migration[7.0] + def change + add_column :rooms, :voice_bridge, :integer, null: true, default: nil + add_index :rooms, :voice_bridge + end +end diff --git a/db/schema.rb b/db/schema.rb index fc646ce713..bc89aa2e7c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_02_27_213252) do +ActiveRecord::Schema[7.0].define(version: 2023_03_21_125010) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -132,9 +132,11 @@ t.datetime "updated_at", null: false t.integer "recordings_processing", default: 0 t.boolean "online", default: false + t.integer "voice_bridge" t.index ["friendly_id"], name: "index_rooms_on_friendly_id", unique: true t.index ["meeting_id"], name: "index_rooms_on_meeting_id", unique: true t.index ["user_id"], name: "index_rooms_on_user_id" + t.index ["voice_bridge"], name: "index_rooms_on_voice_bridge" end create_table "rooms_configurations", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| diff --git a/greenlight-v3.nginx b/greenlight-v3.nginx index c0331915fb..1840bfc28a 100644 --- a/greenlight-v3.nginx +++ b/greenlight-v3.nginx @@ -1,7 +1,7 @@ ### Greenlight version 3: location /cable { - proxy_pass http://127.0.0.1:5050; + proxy_pass http://127.0.0.1:3000; proxy_redirect off; proxy_set_header Host $http_host; @@ -20,7 +20,7 @@ location /cable { location @bbb-fe { - proxy_pass http://127.0.0.1:5050; + proxy_pass http://127.0.0.1:3000; proxy_read_timeout 60s; proxy_redirect off; From d55c30fcced8c0cec26b83d190f488b8f523d18a Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 24 Mar 2023 10:40:50 +0000 Subject: [PATCH 2/8] revert locale dev change --- greenlight-v3.nginx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/greenlight-v3.nginx b/greenlight-v3.nginx index 1840bfc28a..c0331915fb 100644 --- a/greenlight-v3.nginx +++ b/greenlight-v3.nginx @@ -1,7 +1,7 @@ ### Greenlight version 3: location /cable { - proxy_pass http://127.0.0.1:3000; + proxy_pass http://127.0.0.1:5050; proxy_redirect off; proxy_set_header Host $http_host; @@ -20,7 +20,7 @@ location /cable { location @bbb-fe { - proxy_pass http://127.0.0.1:3000; + proxy_pass http://127.0.0.1:5050; proxy_read_timeout 60s; proxy_redirect off; From 7fab7affff0e10dc99133d630388514d23bf11e3 Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 24 Mar 2023 10:43:47 +0000 Subject: [PATCH 3/8] revert locale dev change --- app/controllers/api/v1/meetings_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/v1/meetings_controller.rb b/app/controllers/api/v1/meetings_controller.rb index 0f5b10e751..15e02f2936 100644 --- a/app/controllers/api/v1/meetings_controller.rb +++ b/app/controllers/api/v1/meetings_controller.rb @@ -30,8 +30,8 @@ class MeetingsController < ApiController def start begin MeetingStarter.new(room: @room, base_url: root_url, current_user:).call - #rescue BigBlueButton::BigBlueButtonException => e - # return render_error status: :bad_request unless e.key == 'idNotUnique' + rescue BigBlueButton::BigBlueButtonException => e + return render_error status: :bad_request unless e.key == 'idNotUnique' end render_data data: BigBlueButtonApi.new.join_meeting( From af1c240f1cdfba6b639c296cf5ac47c22d3746db Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 24 Mar 2023 11:07:09 +0000 Subject: [PATCH 4/8] sample.env update with VoiceBrige config --- sample.env | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sample.env b/sample.env index b9f0036d21..cae7a006bd 100644 --- a/sample.env +++ b/sample.env @@ -61,3 +61,7 @@ REDIS_URL= # [en, ar, fr, es] #DEFAULT_LOCALE=en +# Define the phone number for the voice bridge. +# This number is not sent to bbb and is only displayed in the greenlight UI, but it should match the number in the bbb instance to avoid user confusion. +# If this number is defined, each newly created room will be assigned a static voiceBridge pin. +#VOICE_BRIDGE_PHONE_NUMBER= \ No newline at end of file From ebc4a87a54bc2a3f10876c7c13754d165714c178 Mon Sep 17 00:00:00 2001 From: SebastianAppDev <128802341+SebastianAppDev@users.noreply.github.com> Date: Mon, 27 Mar 2023 08:25:11 +0200 Subject: [PATCH 5/8] Update room.rb, mistake in comment --- app/models/room.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/room.rb b/app/models/room.rb index 1626268c3a..380a18e666 100644 --- a/app/models/room.rb +++ b/app/models/room.rb @@ -97,7 +97,7 @@ def set_meeting_id retry end - # Create unique pin for voice brige max 10^6 - 1000 unique ids + # Create unique pin for voice brige max 10^5 - 10000 unique ids def set_voice_brige if Rails.application.config.voice_bridge_phone_number != nil id = SecureRandom.random_number((10.pow(5)) - 1) From 96df717c3bc6b20531ae3dbaf016bde1fe538dac Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 29 Mar 2023 06:20:13 +0000 Subject: [PATCH 6/8] Voice Brige database migration for existing rooms --- ...populate_voice_brige_for_existing_rooms.rb | 21 +++++++++++++++++++ db/data_schema.rb | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 db/data/20230328124724_populate_voice_brige_for_existing_rooms.rb diff --git a/db/data/20230328124724_populate_voice_brige_for_existing_rooms.rb b/db/data/20230328124724_populate_voice_brige_for_existing_rooms.rb new file mode 100644 index 0000000000..b5b2823344 --- /dev/null +++ b/db/data/20230328124724_populate_voice_brige_for_existing_rooms.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class PopulateVoiceBrigeForExistingRooms < ActiveRecord::Migration[7.0] + def up + i = 0 + Room.where(voice_bridge: nil).each do |room| + while Room.where(voice_bridge: 10000+i).length > 0 + i = i + 1 + if i >= 99999 + raise "The db contains to many rooms to assign each one a unique voice_brige" + end + end + room.update(voice_bridge: 10000 + i) + i = i + 1 + end + end + + def down + Room.update_all(voice_bridge: nil) + end +end diff --git a/db/data_schema.rb b/db/data_schema.rb index 4013193075..157472de8b 100644 --- a/db/data_schema.rb +++ b/db/data_schema.rb @@ -1 +1 @@ -DataMigrate::Data.define(version: 20230228193705) +DataMigrate::Data.define(version: 20230328124724) From 32efa9132e2b5ed9c46a5a8f4e14c137d85f3cbf Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 29 Mar 2023 09:15:23 +0000 Subject: [PATCH 7/8] Improved data migration --- .../20230328124724_populate_voice_brige_for_existing_rooms.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/db/data/20230328124724_populate_voice_brige_for_existing_rooms.rb b/db/data/20230328124724_populate_voice_brige_for_existing_rooms.rb index b5b2823344..b6d1a9b568 100644 --- a/db/data/20230328124724_populate_voice_brige_for_existing_rooms.rb +++ b/db/data/20230328124724_populate_voice_brige_for_existing_rooms.rb @@ -2,6 +2,9 @@ class PopulateVoiceBrigeForExistingRooms < ActiveRecord::Migration[7.0] def up + if Rails.application.config.voice_bridge_phone_number == nil + return + end i = 0 Room.where(voice_bridge: nil).each do |room| while Room.where(voice_bridge: 10000+i).length > 0 From 359640573edd3f35f68cac1563a35ff614ede0f4 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 29 Mar 2023 09:50:13 +0000 Subject: [PATCH 8/8] improved database voice_brige population --- ...populate_voice_brige_for_existing_rooms.rb | 24 +++++++++++++------ db/schema.rb | 8 +++++++ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/db/data/20230328124724_populate_voice_brige_for_existing_rooms.rb b/db/data/20230328124724_populate_voice_brige_for_existing_rooms.rb index b6d1a9b568..acdb99b8a8 100644 --- a/db/data/20230328124724_populate_voice_brige_for_existing_rooms.rb +++ b/db/data/20230328124724_populate_voice_brige_for_existing_rooms.rb @@ -5,16 +5,26 @@ def up if Rails.application.config.voice_bridge_phone_number == nil return end - i = 0 + + if Room.all.length > 89999 + raise "The db contains to many rooms to assign each one a unique voice_brige" + end + Room.where(voice_bridge: nil).each do |room| - while Room.where(voice_bridge: 10000+i).length > 0 - i = i + 1 - if i >= 99999 - raise "The db contains to many rooms to assign each one a unique voice_brige" + id = SecureRandom.random_number((10.pow(5)) - 1) + + if id < 10000 + id = id + 10000 + end + + while Room.exists?(voice_bridge: id) + id = id + 1 + if id >= 99999 + id = 10000 end end - room.update(voice_bridge: 10000 + i) - i = i + 1 + + room.update(voice_bridge: id) end end diff --git a/db/schema.rb b/db/schema.rb index bc89aa2e7c..0d4cc3b862 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -175,6 +175,14 @@ t.index ["setting_id"], name: "index_site_settings_on_setting_id" end + create_table "tenants", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.string "name", null: false + t.string "client_secret", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["name"], name: "index_tenants_on_name", unique: true + end + create_table "users", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.string "name", null: false t.string "email", null: false