From e20b121960af4683bae28bbe4a5eb886cdc20f23 Mon Sep 17 00:00:00 2001 From: Samuel Weirich <4281791+SamuelWei@users.noreply.github.com> Date: Thu, 13 Jun 2024 12:10:15 +0200 Subject: [PATCH 01/12] Add dial in # Conflicts: # app/Http/Resources/RoomResource.php # package-lock.json # package.json --- app/Http/Resources/LastMeetingResource.php | 4 +++ app/Services/RoomService.php | 7 ++++- config/bigbluebutton.php | 2 +- ...2_171150_add_dial_in_to_meetings_table.php | 30 +++++++++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 database/migrations/2024_06_12_171150_add_dial_in_to_meetings_table.php diff --git a/app/Http/Resources/LastMeetingResource.php b/app/Http/Resources/LastMeetingResource.php index 916f2139c7..dfca3feaab 100644 --- a/app/Http/Resources/LastMeetingResource.php +++ b/app/Http/Resources/LastMeetingResource.php @@ -24,6 +24,10 @@ public function toArray($request) 'usage' => $this->when($this->end == null, [ 'participant_count' => $this->room->participant_count, ]), + 'dial_in' => $this->when($this->end == null && ! in_array($this->dial_number, config('bigbluebutton.invalid_dial_numbers')), [ + 'number' => $this->dial_number, + 'pin' => $this->voice_bridge, + ]), 'server_connection_issues' => $this->end == null && $this->server->error_count > 0, ]; } diff --git a/app/Services/RoomService.php b/app/Services/RoomService.php index ac0b095fd4..186cdda313 100644 --- a/app/Services/RoomService.php +++ b/app/Services/RoomService.php @@ -86,7 +86,10 @@ public function start(): MeetingService $meetingService = new MeetingService($meeting); Log::info('Starting new meeting for room {room} on server {server}', ['room' => $this->room->getLogLabel(), 'server' => $server->getLogLabel()]); - if (! $meetingService->start()) { + + $createMeetingResponse = $meetingService->start(); + + if (! $createMeetingResponse) { // Creating Meeting failed, remove meeting $meeting->forceDelete(); @@ -103,6 +106,8 @@ public function start(): MeetingService // but the api call has not been completed yet therefore the meeting will not be found on the server // and the server poller will mark the meeting as ended immediately $meeting->start = date('Y-m-d H:i:s'); + $meeting->dial_number = $createMeetingResponse->getDialNumber(); + $meeting->voice_bridge = $createMeetingResponse->getVoiceBridge(); $meeting->save(); // Change latest meeting or the room to newly created meeting diff --git a/config/bigbluebutton.php b/config/bigbluebutton.php index e51b67dd83..f90290c5eb 100644 --- a/config/bigbluebutton.php +++ b/config/bigbluebutton.php @@ -20,7 +20,7 @@ 'room_refresh_rate' => (int) env('ROOM_REFRESH_RATE', 30), 'server_online_threshold' => (int) env('BBB_SERVER_ONLINE_THRESHOLD', 3), 'server_offline_threshold' => (int) env('BBB_SERVER_OFFLINE_THRESHOLD', 3), - + 'invalid_dial_numbers' => ['0', '613-555-1212', '613-555-1234', '0000'], 'load_new_meeting_min_user_count' => (int) env('BBB_LOAD_MIN_USER_COUNT', 15), 'load_new_meeting_min_user_interval' => (int) env('BBB_LOAD_MIN_USER_INTERVAL', 15), diff --git a/database/migrations/2024_06_12_171150_add_dial_in_to_meetings_table.php b/database/migrations/2024_06_12_171150_add_dial_in_to_meetings_table.php new file mode 100644 index 0000000000..a421bd7f11 --- /dev/null +++ b/database/migrations/2024_06_12_171150_add_dial_in_to_meetings_table.php @@ -0,0 +1,30 @@ +string('dial_number')->nullable(); + $table->integer('voice_bridge')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('meetings', function (Blueprint $table) { + $table->dropColumn('dial_number'); + $table->dropColumn('voice_bridge'); + }); + } +}; From e727b2f9b6df4fd2eb94bff2cbcfa526f3cfc1f0 Mon Sep 17 00:00:00 2001 From: Samuel Weirich <4281791+SamuelWei@users.noreply.github.com> Date: Fri, 14 Jun 2024 11:01:07 +0200 Subject: [PATCH 02/12] Join by phone --- lang/en/rooms.php | 8 ++ package-lock.json | 126 ++++++++++++++---- package.json | 2 + .../js/components/RoomJoinByPhoneButton.vue | 91 +++++++++++++ resources/js/views/RoomsView.vue | 5 + 5 files changed, 206 insertions(+), 26 deletions(-) create mode 100644 resources/js/components/RoomJoinByPhoneButton.vue diff --git a/lang/en/rooms.php b/lang/en/rooms.php index 238a8a87f9..ec15cae51d 100644 --- a/lang/en/rooms.php +++ b/lang/en/rooms.php @@ -306,6 +306,14 @@ 'room_link_copied' => 'The personalized room link for :firstname :lastname was copied to your clipboard.', 'title' => 'Personalized room links', ], + 'phone' => [ + 'join_by_phone' => 'Join by phone', + 'title' => 'Phone number and PIN', + 'number' => 'Phone number', + 'pin' => 'PIN', + 'qrcode' => 'QR-Code', + 'call' => 'Call', + ], 'placeholder_name' => 'John Doe', 'recording_accept' => 'I consent to the recording.', 'recording_attendance_accept' => 'I consent to the attendance logging.', diff --git a/package-lock.json b/package-lock.json index d543a80c71..f567cddb10 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "@vitejs/plugin-vue": "^6.0.7", "@vueuse/components": "^14.3.0", "@vueuse/core": "^14.3.0", + "@vueuse/integrations": "^14.3.0", "axe-core": "^4.12.1", "axios": "^1.18.1", "chart.js": "^4.5.1", @@ -35,6 +36,7 @@ "primeicons": "^7.0.0", "primelocale": "^2.4.0", "primevue": "^4.5.5", + "qrcode": "^1.5.4", "tailwindcss": "^4.1.14", "tailwindcss-primeui": "^0.6.1", "ua-parser-js": "^1.0.41", @@ -4690,6 +4692,72 @@ "vue": "^3.5.0" } }, + "node_modules/@vueuse/integrations": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-14.3.0.tgz", + "integrity": "sha512-76I5FT2ESvCmCaSwapI+a/u/CFtNXmzl9f9lNp1hRtx8vKB8hfiokJr8IvQqcQG5ckGXElyXK516b54ozV3MvA==", + "license": "MIT", + "dependencies": { + "@vueuse/core": "14.3.0", + "@vueuse/shared": "14.3.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "async-validator": "^4", + "axios": "^1", + "change-case": "^5", + "drauu": "^0.4", + "focus-trap": "^7 || ^8", + "fuse.js": "^7", + "idb-keyval": "^6", + "jwt-decode": "^4", + "nprogress": "^0.2", + "qrcode": "^1.5", + "sortablejs": "^1", + "universal-cookie": "^7 || ^8", + "vue": "^3.5.0" + }, + "peerDependenciesMeta": { + "async-validator": { + "optional": true + }, + "axios": { + "optional": true + }, + "change-case": { + "optional": true + }, + "drauu": { + "optional": true + }, + "focus-trap": { + "optional": true + }, + "fuse.js": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "jwt-decode": { + "optional": true + }, + "nprogress": { + "optional": true + }, + "qrcode": { + "optional": true + }, + "sortablejs": { + "optional": true + }, + "universal-cookie": { + "optional": true + } + } + }, "node_modules/@vueuse/metadata": { "version": "14.3.0", "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-14.3.0.tgz", @@ -5047,7 +5115,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -5057,7 +5124,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -5553,7 +5619,6 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -5776,7 +5841,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, "license": "ISC", "dependencies": { "string-width": "^4.2.0", @@ -5788,7 +5852,6 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -5803,7 +5866,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -5816,7 +5878,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, "license": "MIT" }, "node_modules/colorette": { @@ -6123,7 +6184,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6211,6 +6271,12 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/dijkstrajs": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", + "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", + "license": "MIT" + }, "node_modules/dompurify": { "version": "3.4.11", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.11.tgz", @@ -6274,7 +6340,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, "license": "MIT" }, "node_modules/empathic": { @@ -7319,7 +7384,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" @@ -7850,7 +7914,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9738,7 +9801,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -9797,7 +9859,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -10042,6 +10103,15 @@ "pathe": "^2.0.3" } }, + "node_modules/pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/postcss": { "version": "8.5.15", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", @@ -10435,6 +10505,23 @@ "node": ">=6" } }, + "node_modules/qrcode": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz", + "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==", + "license": "MIT", + "dependencies": { + "dijkstrajs": "^1.0.1", + "pngjs": "^5.0.0", + "yargs": "^15.3.1" + }, + "bin": { + "qrcode": "bin/qrcode" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/qs": { "version": "6.15.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", @@ -10602,7 +10689,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -10623,7 +10709,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true, "license": "ISC" }, "node_modules/resolve": { @@ -10994,7 +11079,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true, "license": "ISC" }, "node_modules/shebang-command": { @@ -11286,7 +11370,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -11317,7 +11400,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -12810,7 +12892,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "dev": true, "license": "ISC" }, "node_modules/word-wrap": { @@ -12976,7 +13057,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true, "license": "ISC" }, "node_modules/yallist": { @@ -13036,7 +13116,6 @@ "version": "15.4.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, "license": "MIT", "dependencies": { "cliui": "^6.0.0", @@ -13059,7 +13138,6 @@ "version": "18.1.3", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, "license": "ISC", "dependencies": { "camelcase": "^5.0.0", @@ -13073,7 +13151,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -13087,7 +13164,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -13100,7 +13176,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -13116,7 +13191,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.2.0" diff --git a/package.json b/package.json index 23962b81b1..7046815d2b 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "@vitejs/plugin-vue": "^6.0.7", "@vueuse/components": "^14.3.0", "@vueuse/core": "^14.3.0", + "@vueuse/integrations": "^14.3.0", "axe-core": "^4.12.1", "axios": "^1.18.1", "chart.js": "^4.5.1", @@ -67,6 +68,7 @@ "primeicons": "^7.0.0", "primelocale": "^2.4.0", "primevue": "^4.5.5", + "qrcode": "^1.5.4", "tailwindcss": "^4.1.14", "tailwindcss-primeui": "^0.6.1", "ua-parser-js": "^1.0.41", diff --git a/resources/js/components/RoomJoinByPhoneButton.vue b/resources/js/components/RoomJoinByPhoneButton.vue new file mode 100644 index 0000000000..28c7d99257 --- /dev/null +++ b/resources/js/components/RoomJoinByPhoneButton.vue @@ -0,0 +1,91 @@ + + diff --git a/resources/js/views/RoomsView.vue b/resources/js/views/RoomsView.vue index be3211e2d4..af4a3526a8 100644 --- a/resources/js/views/RoomsView.vue +++ b/resources/js/views/RoomsView.vue @@ -212,6 +212,11 @@ @guests-not-allowed="handleGuestsNotAllowed" @changed="reload(true)" /> + Date: Thu, 23 Jan 2025 12:42:22 +0100 Subject: [PATCH 03/12] Make invalid_dial_numbers configurable --- config/bigbluebutton.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/bigbluebutton.php b/config/bigbluebutton.php index f90290c5eb..eb149adc85 100644 --- a/config/bigbluebutton.php +++ b/config/bigbluebutton.php @@ -20,7 +20,7 @@ 'room_refresh_rate' => (int) env('ROOM_REFRESH_RATE', 30), 'server_online_threshold' => (int) env('BBB_SERVER_ONLINE_THRESHOLD', 3), 'server_offline_threshold' => (int) env('BBB_SERVER_OFFLINE_THRESHOLD', 3), - 'invalid_dial_numbers' => ['0', '613-555-1212', '613-555-1234', '0000'], + 'invalid_dial_numbers' => explode(',', env('BBB_INVALID_DIAL_NUMBERS', '0,613-555-1212,613-555-1234,0000')), 'load_new_meeting_min_user_count' => (int) env('BBB_LOAD_MIN_USER_COUNT', 15), 'load_new_meeting_min_user_interval' => (int) env('BBB_LOAD_MIN_USER_INTERVAL', 15), From 6b86e82f31840a6150c4099fb0f8c6bc6c67ce33 Mon Sep 17 00:00:00 2001 From: Samuel Weirich <4281791+SamuelWei@users.noreply.github.com> Date: Fri, 17 Jul 2026 16:25:02 +0200 Subject: [PATCH 04/12] Refactor popover, add more instructions, dark mode and a11y --- ...2_171150_add_dial_in_to_meetings_table.php | 2 + lang/en/rooms.php | 5 +- package-lock.json | 67 --------- package.json | 1 - .../js/components/RoomJoinByPhoneButton.vue | 141 +++++++++++++----- 5 files changed, 112 insertions(+), 104 deletions(-) diff --git a/database/migrations/2024_06_12_171150_add_dial_in_to_meetings_table.php b/database/migrations/2024_06_12_171150_add_dial_in_to_meetings_table.php index a421bd7f11..5fce22858f 100644 --- a/database/migrations/2024_06_12_171150_add_dial_in_to_meetings_table.php +++ b/database/migrations/2024_06_12_171150_add_dial_in_to_meetings_table.php @@ -1,5 +1,7 @@ 'Personalized room links', ], 'phone' => [ + 'call' => 'Call', 'join_by_phone' => 'Join by phone', - 'title' => 'Phone number and PIN', 'number' => 'Phone number', 'pin' => 'PIN', 'qrcode' => 'QR-Code', - 'call' => 'Call', + 'scan_qr_code' => 'Scan this QR code with your smartphone to join the meeting by phone', + 'title' => 'Phone number and PIN', ], 'placeholder_name' => 'John Doe', 'recording_accept' => 'I consent to the recording.', diff --git a/package-lock.json b/package-lock.json index f567cddb10..cbc854a453 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,6 @@ "@vitejs/plugin-vue": "^6.0.7", "@vueuse/components": "^14.3.0", "@vueuse/core": "^14.3.0", - "@vueuse/integrations": "^14.3.0", "axe-core": "^4.12.1", "axios": "^1.18.1", "chart.js": "^4.5.1", @@ -4692,72 +4691,6 @@ "vue": "^3.5.0" } }, - "node_modules/@vueuse/integrations": { - "version": "14.3.0", - "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-14.3.0.tgz", - "integrity": "sha512-76I5FT2ESvCmCaSwapI+a/u/CFtNXmzl9f9lNp1hRtx8vKB8hfiokJr8IvQqcQG5ckGXElyXK516b54ozV3MvA==", - "license": "MIT", - "dependencies": { - "@vueuse/core": "14.3.0", - "@vueuse/shared": "14.3.0" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "async-validator": "^4", - "axios": "^1", - "change-case": "^5", - "drauu": "^0.4", - "focus-trap": "^7 || ^8", - "fuse.js": "^7", - "idb-keyval": "^6", - "jwt-decode": "^4", - "nprogress": "^0.2", - "qrcode": "^1.5", - "sortablejs": "^1", - "universal-cookie": "^7 || ^8", - "vue": "^3.5.0" - }, - "peerDependenciesMeta": { - "async-validator": { - "optional": true - }, - "axios": { - "optional": true - }, - "change-case": { - "optional": true - }, - "drauu": { - "optional": true - }, - "focus-trap": { - "optional": true - }, - "fuse.js": { - "optional": true - }, - "idb-keyval": { - "optional": true - }, - "jwt-decode": { - "optional": true - }, - "nprogress": { - "optional": true - }, - "qrcode": { - "optional": true - }, - "sortablejs": { - "optional": true - }, - "universal-cookie": { - "optional": true - } - } - }, "node_modules/@vueuse/metadata": { "version": "14.3.0", "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-14.3.0.tgz", diff --git a/package.json b/package.json index 7046815d2b..fb1d36f1ac 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,6 @@ "@vitejs/plugin-vue": "^6.0.7", "@vueuse/components": "^14.3.0", "@vueuse/core": "^14.3.0", - "@vueuse/integrations": "^14.3.0", "axe-core": "^4.12.1", "axios": "^1.18.1", "chart.js": "^4.5.1", diff --git a/resources/js/components/RoomJoinByPhoneButton.vue b/resources/js/components/RoomJoinByPhoneButton.vue index 28c7d99257..d5d36ef35b 100644 --- a/resources/js/components/RoomJoinByPhoneButton.vue +++ b/resources/js/components/RoomJoinByPhoneButton.vue @@ -4,72 +4,106 @@ :label="$t('rooms.phone.join_by_phone')" icon="fa-solid fa-phone" severity="secondary" - @click="toggle" class="flex-shrink-0" + @click="toggle" /> - -
-
- - {{ $t("rooms.phone.title") }} - -
- - + +
+
+
+

+ {{ $t("rooms.phone.title") }} +

+
+
+
+
+ + - + +
- - - - +
+ + - +
-
+
+ -
+
+

+ {{ $t("rooms.phone.scan_qr_code") }} +

From 0274c4045e5bd5b9946eaf2c8872482f5637cef5 Mon Sep 17 00:00:00 2001 From: Samuel Weirich <4281791+SamuelWei@users.noreply.github.com> Date: Fri, 17 Jul 2026 16:39:07 +0200 Subject: [PATCH 05/12] Add note --- lang/en/rooms.php | 5 ++- .../js/components/RoomJoinByPhoneButton.vue | 44 +++++++++---------- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/lang/en/rooms.php b/lang/en/rooms.php index b5752ebed8..bf32beca9b 100644 --- a/lang/en/rooms.php +++ b/lang/en/rooms.php @@ -309,11 +309,12 @@ 'phone' => [ 'call' => 'Call', 'join_by_phone' => 'Join by phone', + 'note' => 'This phone number and pin is only valid for the duration of the meeting', 'number' => 'Phone number', - 'pin' => 'PIN', + 'pin' => 'Pin', 'qrcode' => 'QR-Code', 'scan_qr_code' => 'Scan this QR code with your smartphone to join the meeting by phone', - 'title' => 'Phone number and PIN', + 'title' => 'Phone number and Pin', ], 'placeholder_name' => 'John Doe', 'recording_accept' => 'I consent to the recording.', diff --git a/resources/js/components/RoomJoinByPhoneButton.vue b/resources/js/components/RoomJoinByPhoneButton.vue index d5d36ef35b..78f8a44cc1 100644 --- a/resources/js/components/RoomJoinByPhoneButton.vue +++ b/resources/js/components/RoomJoinByPhoneButton.vue @@ -8,28 +8,26 @@ @click="toggle" /> -
-
-
-

- {{ $t("rooms.phone.title") }} -

-
+
+
+

+ {{ $t("rooms.phone.title") }} +

+
@@ -72,6 +70,8 @@ />
+ + {{ $t("rooms.phone.note") }}
From 33fd2b7d1eb2cc768b4bed910625a18c734f9b07 Mon Sep 17 00:00:00 2001 From: Samuel Weirich <4281791+SamuelWei@users.noreply.github.com> Date: Mon, 20 Jul 2026 15:11:41 +0200 Subject: [PATCH 06/12] Only store valid numbers --- app/Http/Resources/LastMeetingResource.php | 2 +- app/Services/RoomService.php | 9 +++++++-- resources/js/views/RoomsView.vue | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/Http/Resources/LastMeetingResource.php b/app/Http/Resources/LastMeetingResource.php index dfca3feaab..1f600f9b68 100644 --- a/app/Http/Resources/LastMeetingResource.php +++ b/app/Http/Resources/LastMeetingResource.php @@ -24,7 +24,7 @@ public function toArray($request) 'usage' => $this->when($this->end == null, [ 'participant_count' => $this->room->participant_count, ]), - 'dial_in' => $this->when($this->end == null && ! in_array($this->dial_number, config('bigbluebutton.invalid_dial_numbers')), [ + 'dial_in' => $this->when($this->end == null, [ 'number' => $this->dial_number, 'pin' => $this->voice_bridge, ]), diff --git a/app/Services/RoomService.php b/app/Services/RoomService.php index 186cdda313..a61497410e 100644 --- a/app/Services/RoomService.php +++ b/app/Services/RoomService.php @@ -106,8 +106,13 @@ public function start(): MeetingService // but the api call has not been completed yet therefore the meeting will not be found on the server // and the server poller will mark the meeting as ended immediately $meeting->start = date('Y-m-d H:i:s'); - $meeting->dial_number = $createMeetingResponse->getDialNumber(); - $meeting->voice_bridge = $createMeetingResponse->getVoiceBridge(); + + // Store dial-in number and voice-bridge (pin) if valid + if (! in_array($createMeetingResponse->getDialNumber(), config('bigbluebutton.invalid_dial_numbers'))) { + $meeting->dial_number = $createMeetingResponse->getDialNumber(); + $meeting->voice_bridge = $createMeetingResponse->getVoiceBridge(); + } + $meeting->save(); // Change latest meeting or the room to newly created meeting diff --git a/resources/js/views/RoomsView.vue b/resources/js/views/RoomsView.vue index af4a3526a8..716dcdf590 100644 --- a/resources/js/views/RoomsView.vue +++ b/resources/js/views/RoomsView.vue @@ -213,7 +213,7 @@ @changed="reload(true)" /> From b6526203d21ba8ac39a35a59d9354dae55ff6aeb Mon Sep 17 00:00:00 2001 From: Samuel Weirich <4281791+SamuelWei@users.noreply.github.com> Date: Mon, 20 Jul 2026 15:11:51 +0200 Subject: [PATCH 07/12] Add backend tests --- .../Backend/Feature/api/v1/Room/RoomTest.php | 50 ++++++++++++- tests/Backend/Unit/RoomServiceTest.php | 73 +++++++++++++++++++ 2 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 tests/Backend/Unit/RoomServiceTest.php diff --git a/tests/Backend/Feature/api/v1/Room/RoomTest.php b/tests/Backend/Feature/api/v1/Room/RoomTest.php index f871656ca6..d2830a7dd8 100644 --- a/tests/Backend/Feature/api/v1/Room/RoomTest.php +++ b/tests/Backend/Feature/api/v1/Room/RoomTest.php @@ -1592,7 +1592,7 @@ public function test_room_view() ]); // Test with ended meeting - $meeting = Meeting::factory()->create(['room_id' => $room->id]); + $meeting = Meeting::factory()->create(['room_id' => $room->id, 'dial_number' => '613-555-1234', 'voice_bridge' => '1234']); $room->latestMeeting()->associate($meeting); $room->save(); @@ -1608,9 +1608,10 @@ public function test_room_view() ], ], ]) + ->assertJsonMissingPath('data.last_meeting.dial_in') ->assertJsonMissingPath('data.last_meeting.usage'); - // Test with running meeting and usage statistics + // Test with running meeting, usage statistics and dial-in $meeting->end = null; $meeting->save(); @@ -1626,11 +1627,56 @@ public function test_room_view() 'usage' => [ 'participant_count' => 10, ], + 'dial_in' => [ + 'number' => '613-555-1234', + 'pin' => '1234', + ], ], ], ]) ->assertJsonCount(1, 'data.last_meeting.usage'); + // Test without dial-in + $meeting->dial_number = null; + $meeting->voice_bridge = null; + $meeting->save(); + + $this->actingAs($this->user)->getJson(route('api.v1.rooms.show', ['room' => $room])) + ->assertStatus(200) + ->assertJson([ + 'data' => [ + 'last_meeting' => [ + 'start' => $meeting->start->toJson(), + 'end' => null, + 'detached' => null, + 'server_connection_issues' => false, + 'usage' => [ + 'participant_count' => 10, + ], + 'dial_in' => [ + 'number' => null, + 'pin' => null, + ], + ], + ], + ]); + + $this->actingAs($this->user)->getJson(route('api.v1.rooms.show', ['room' => $room])) + ->assertStatus(200) + ->assertJson([ + 'data' => [ + 'last_meeting' => [ + 'start' => $meeting->start->toJson(), + 'end' => null, + 'detached' => null, + 'server_connection_issues' => false, + 'usage' => [ + 'participant_count' => 10, + ], + ], + ], + ]); + // Test with server with connection issues $meeting->server->error_count = 1; $meeting->server->save(); diff --git a/tests/Backend/Unit/RoomServiceTest.php b/tests/Backend/Unit/RoomServiceTest.php new file mode 100644 index 0000000000..6e6f0ef163 --- /dev/null +++ b/tests/Backend/Unit/RoomServiceTest.php @@ -0,0 +1,73 @@ +room = Room::factory()->create(['access_code' => '123456789']); + } + + public function test_start_dial_in() + { + config(['bigbluebutton.invalid_dial_numbers' => ['0', '0000']]); + + $server = Server::factory()->create(); + $bbbFaker = new BigBlueButtonServerFaker($server->base_url, $server->secret); + $bbbFaker->addCreateMeetingRequest(); + $bbbFaker->addCreateMeetingRequest(); + + $this->room->roomType->serverPool->servers()->attach($server); + + // Start new meeting, result has a valid dial-in number + $roomService = new RoomService($this->room); + $roomService->start(); + + // Check meeting was created + $this->room->refresh(); + $this->assertCount(1, $this->room->meetings); + + // Check dial-in number and voice-bridge (pin) are set + $meeting = $this->room->latestMeeting; + $this->assertEquals('613-555-1234', $meeting->dial_number); + $this->assertEquals(92443, $meeting->voice_bridge); + + // Set meeting as ended + $meetingService = new MeetingService($meeting); + $meetingService->setEnd(); + + // Change list of invalid dial-in numbers + config(['bigbluebutton.invalid_dial_numbers' => ['0', '0000', '613-555-1234']]); + + // Start new meeting, result has an invalid dial-in number + $roomService->start(); + + // Check another meeting was created + $this->room->refresh(); + $this->assertCount(2, $this->room->meetings); + + // Check dial-in number and voice-bridge (pin) are not set + $meeting = $this->room->latestMeeting; + $this->assertNull($meeting->dial_number); + $this->assertNull($meeting->voice_bridge); + } +} From c847e24539d0333cd47e03ac7f679ae61e00af18 Mon Sep 17 00:00:00 2001 From: Samuel Weirich <4281791+SamuelWei@users.noreply.github.com> Date: Mon, 20 Jul 2026 15:46:17 +0200 Subject: [PATCH 08/12] Add frontend tests --- .../js/components/RoomJoinByPhoneButton.vue | 13 +++- tests/Frontend/e2e/RoomsViewMeetings.cy.js | 73 ++++++++++++++++++ .../fixtures/files/dial-in-qr-code.png | Bin 0 -> 1770 bytes 3 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 tests/Frontend/fixtures/files/dial-in-qr-code.png diff --git a/resources/js/components/RoomJoinByPhoneButton.vue b/resources/js/components/RoomJoinByPhoneButton.vue index 78f8a44cc1..77f80090ab 100644 --- a/resources/js/components/RoomJoinByPhoneButton.vue +++ b/resources/js/components/RoomJoinByPhoneButton.vue @@ -1,13 +1,18 @@