From 070aa3425fad50e8988b381645a8bc3d2c0ecb41 Mon Sep 17 00:00:00 2001 From: Arthurk12 Date: Tue, 30 Aug 2022 18:22:01 +0000 Subject: [PATCH 01/43] Revert "fix: don't clear text fake annotations" This reverts commit 74c4c1c4ccc8f183704121a5747c769a3802bd15. Reverting this commit because it causes fake annotations from the text tool not to be removed. Since the text tool is the only one that generates fake annotations(because it is the only one that is live synced), the function to clear fake annotations is directly intended to clear them. --- bigbluebutton-html5/imports/ui/components/whiteboard/service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/service.js b/bigbluebutton-html5/imports/ui/components/whiteboard/service.js index de6129f071..dad83cca5f 100755 --- a/bigbluebutton-html5/imports/ui/components/whiteboard/service.js +++ b/bigbluebutton-html5/imports/ui/components/whiteboard/service.js @@ -27,7 +27,7 @@ const clearPreview = (annotation) => { const clearFakeAnnotations = () => { UnsentAnnotations.remove({}); - Annotations.remove({ id: /-fake/g, annotationType: { $ne: 'text' } }); + Annotations.remove({ id: /-fake/g }); } function handleAddedLiveSyncPreviewAnnotation({ From 480925517c6fd74bc5c797cbfe80db47511e6f73 Mon Sep 17 00:00:00 2001 From: Arthurk12 Date: Tue, 30 Aug 2022 19:37:50 +0000 Subject: [PATCH 02/43] fix(whiteboard): text annotations stuck as fake Cleans up and modifies the added annotation handler to suit only for text annotation. As soon as the DRAW_END message is sent, the local fake annotations are removed and replaced by the complete/not fake annotation. --- .../ui/components/whiteboard/service.js | 46 ++----------------- 1 file changed, 3 insertions(+), 43 deletions(-) diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/service.js b/bigbluebutton-html5/imports/ui/components/whiteboard/service.js index dad83cca5f..4e2a71263f 100755 --- a/bigbluebutton-html5/imports/ui/components/whiteboard/service.js +++ b/bigbluebutton-html5/imports/ui/components/whiteboard/service.js @@ -41,50 +41,10 @@ function handleAddedLiveSyncPreviewAnnotation({ return; } - const fakeAnnotation = Annotations.findOne({ id: `${annotation.id}-fake` }); - let fakePoints; - - if (fakeAnnotation) { - fakePoints = fakeAnnotation.annotationInfo.points; - const { points: lastPoints } = annotation.annotationInfo; - - if (annotation.annotationType !== 'pencil') { - Annotations.update(fakeAnnotation._id, { - $set: { - position: annotation.position, - 'annotationInfo.color': isEqual(fakePoints, lastPoints) || annotation.status === DRAW_END - ? annotation.annotationInfo.color : fakeAnnotation.annotationInfo.color, - }, - $inc: { version: 1 }, // TODO: Remove all this version stuff - }); - return; - } + if (annotation.status === DRAW_END) { + Annotations.remove({ id: `${annotation.id}-fake` }); + Annotations.upsert(query.selector, query.modifier); } - - Annotations.upsert(query.selector, query.modifier, (err) => { - if (err) { - logger.error({ - logCode: 'whiteboard_annotation_upsert_error', - extraInfo: { error: err }, - }, 'Error on adding an annotation'); - return; - } - - // Remove fake annotation for pencil on draw end - if (annotation.status === DRAW_END) { - Annotations.remove({ id: `${annotation.id}-fake` }); - return; - } - - if (annotation.status === DRAW_START) { - Annotations.update(fakeAnnotation._id, { - $set: { - position: annotation.position - 1, - }, - $inc: { version: 1 }, // TODO: Remove all this version stuff - }); - } - }); } function handleAddedAnnotation({ From d2b2acbf2d2922ed41a6ce892f458166bed38864 Mon Sep 17 00:00:00 2001 From: Arthurk12 Date: Tue, 30 Aug 2022 19:47:47 +0000 Subject: [PATCH 03/43] fix(whiteboard): re-adds right click to cancel Re-adds cancelling text annotation on right click. To achieve this, some mechanisms that were previously used to handle live synced annotations were rescued. So this partially reverts 40b18b0. --- .../imports/ui/components/whiteboard/service.js | 9 +++++++-- .../whiteboard/whiteboard-overlay/component.jsx | 6 ++++++ .../whiteboard/whiteboard-overlay/container.jsx | 3 +++ .../whiteboard/whiteboard-overlay/service.js | 3 ++- .../text-draw-listener/component.jsx | 14 ++++++++++---- 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/service.js b/bigbluebutton-html5/imports/ui/components/whiteboard/service.js index 4e2a71263f..2e95ff2a35 100755 --- a/bigbluebutton-html5/imports/ui/components/whiteboard/service.js +++ b/bigbluebutton-html5/imports/ui/components/whiteboard/service.js @@ -17,10 +17,15 @@ const DRAW_END = ANNOTATION_CONFIG.status.end; const ANNOTATION_TYPE_PENCIL = 'pencil'; const ANNOTATION_TYPE_TEXT = 'text'; +const discardedList = []; let annotationsStreamListener = null; +export function addAnnotationToDiscardedList(annotation) { + if (!discardedList.includes(annotation)) discardedList.push(annotation); +} + const clearPreview = (annotation) => { UnsentAnnotations.remove({ id: annotation }); }; @@ -108,7 +113,7 @@ export function initAnnotationsStreamListener() { annotationsStreamListener.on('added', ({ annotations }) => { annotations.forEach((annotation) => { const tool = annotation.annotation.annotationType; - if (tool === ANNOTATION_TYPE_TEXT) { + if (tool === ANNOTATION_TYPE_TEXT && !discardedList.includes(annotation.id)) { handleAddedLiveSyncPreviewAnnotation(annotation); } else { handleAddedAnnotation(annotation); @@ -162,7 +167,7 @@ const proccessAnnotationsQueue = async () => { const annotations = annotationsQueue.splice(0, queueSize); - const isAnnotationSent = await makeCall('sendBulkAnnotations', annotations); + const isAnnotationSent = await makeCall('sendBulkAnnotations', annotations.filter(({ id }) => !discardedList.includes(id))); if (!isAnnotationSent) { // undo splice diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-overlay/component.jsx b/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-overlay/component.jsx index bae3353227..c16f7c6616 100755 --- a/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-overlay/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-overlay/component.jsx @@ -238,6 +238,8 @@ export default class WhiteboardOverlay extends Component { setTextShapeActiveId, contextMenuHandler, clearPreview, + addAnnotationToDiscardedList, + undoAnnotation, updateCursor, } = this.props; @@ -255,6 +257,8 @@ export default class WhiteboardOverlay extends Component { setTextShapeActiveId, contextMenuHandler, clearPreview, + addAnnotationToDiscardedList, + undoAnnotation, }; return ( @@ -319,4 +323,6 @@ WhiteboardOverlay.propTypes = { setTextShapeActiveId: PropTypes.func.isRequired, // Defines a handler to publish cursor position to the server updateCursor: PropTypes.func.isRequired, + addAnnotationToDiscardedList: PropTypes.func.isRequired, + undoAnnotation: PropTypes.func.isRequired, }; diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-overlay/container.jsx b/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-overlay/container.jsx index 589e6606d5..7e3ebae614 100755 --- a/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-overlay/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-overlay/container.jsx @@ -2,6 +2,7 @@ import React from 'react'; import { withTracker } from 'meteor/react-meteor-data'; import PropTypes from 'prop-types'; import WhiteboardOverlayService from './service'; +import WhiteboardToolbarService from '../whiteboard-toolbar/service'; import WhiteboardOverlay from './component'; const WhiteboardOverlayContainer = (props) => { @@ -15,10 +16,12 @@ const WhiteboardOverlayContainer = (props) => { }; export default withTracker(() => ({ + undoAnnotation: WhiteboardToolbarService.undoAnnotation, clearPreview: WhiteboardOverlayService.clearPreview, contextMenuHandler: WhiteboardOverlayService.contextMenuHandler, sendAnnotation: WhiteboardOverlayService.sendAnnotation, sendLiveSyncPreviewAnnotation: WhiteboardOverlayService.sendLiveSyncPreviewAnnotation, + addAnnotationToDiscardedList: WhiteboardOverlayService.addAnnotationToDiscardedList, setTextShapeActiveId: WhiteboardOverlayService.setTextShapeActiveId, resetTextShapeSession: WhiteboardOverlayService.resetTextShapeSession, drawSettings: WhiteboardOverlayService.getWhiteboardToolbarValues(), diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-overlay/service.js b/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-overlay/service.js index fe9f3f1fde..44f0011b5d 100755 --- a/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-overlay/service.js +++ b/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-overlay/service.js @@ -1,6 +1,6 @@ import Storage from '/imports/ui/services/storage/session'; import Auth from '/imports/ui/services/auth'; -import { sendAnnotation, sendLiveSyncPreviewAnnotation, clearPreview } from '/imports/ui/components/whiteboard/service'; +import { sendAnnotation, sendLiveSyncPreviewAnnotation, clearPreview, addAnnotationToDiscardedList } from '/imports/ui/components/whiteboard/service'; import { publishCursorUpdate } from '/imports/ui/components/cursor/service'; const DRAW_SETTINGS = 'drawSettings'; @@ -55,6 +55,7 @@ const updateCursor = (payload) => { }; export default { + addAnnotationToDiscardedList, sendAnnotation, sendLiveSyncPreviewAnnotation, getWhiteboardToolbarValues, diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-overlay/text-draw-listener/component.jsx b/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-overlay/text-draw-listener/component.jsx index 25888f54f4..2896dbbbd0 100755 --- a/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-overlay/text-draw-listener/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-overlay/text-draw-listener/component.jsx @@ -218,11 +218,12 @@ export default class TextDrawListener extends Component { } // second case is when a user finished writing the text and publishes the final result - } else if (isRightClick) { - this.discardAnnotation(); } else { // publishing the final shape and resetting the state this.sendLastMessage(); + if (isRightClick) { + this.discardAnnotation(); + } } } @@ -485,15 +486,18 @@ export default class TextDrawListener extends Component { discardAnnotation() { const { actions, + whiteboardId, } = this.props; const { getCurrentShapeId, - clearPreview, + undoAnnotation, + addAnnotationToDiscardedList, } = actions; this.resetState(); - clearPreview(getCurrentShapeId()); + undoAnnotation(whiteboardId); + addAnnotationToDiscardedList(getCurrentShapeId()); } render() { @@ -598,5 +602,7 @@ TextDrawListener.propTypes = { resetTextShapeSession: PropTypes.func.isRequired, // Defines a function that sets a session value for the current active text shape setTextShapeActiveId: PropTypes.func.isRequired, + undoAnnotation: PropTypes.func.isRequired, + addAnnotationToDiscardedList: PropTypes.func.isRequired, }).isRequired, }; From 0efb5d90f9927fea5fb9a7cc8f8c7f3773039f67 Mon Sep 17 00:00:00 2001 From: Brent Baccala Date: Mon, 19 Sep 2022 16:37:22 -0400 Subject: [PATCH 04/43] on breakout room create meeting API call, lookup the parent meeting, throw exception if it doesn't exist, and use its internal meeting ID for parentMeetingId if it does --- .../main/java/org/bigbluebutton/api/ParamsProcessorUtil.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/ParamsProcessorUtil.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/ParamsProcessorUtil.java index 3a7699e185..58dea97d9f 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/ParamsProcessorUtil.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/ParamsProcessorUtil.java @@ -47,6 +47,7 @@ import org.bigbluebutton.api.domain.BreakoutRoomsParams; import org.bigbluebutton.api.domain.LockSettingsParams; import org.bigbluebutton.api.domain.Meeting; import org.bigbluebutton.api.domain.Group; +import org.bigbluebutton.api.service.ServiceUtils; import org.bigbluebutton.api.util.ParamsUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -638,7 +639,7 @@ public class ParamsProcessorUtil { String parentMeetingId = ""; if (isBreakout) { internalMeetingId = params.get(ApiParams.MEETING_ID); - parentMeetingId = params.get(ApiParams.PARENT_MEETING_ID); + parentMeetingId = ServiceUtils.findMeetingFromMeetingID(params.get(ApiParams.PARENT_MEETING_ID)).getInternalId(); // We rebuild the the external meeting using the has of the parent // meeting, the shared timestamp and the sequence number String timeStamp = StringUtils.substringAfter(internalMeetingId, "-"); From 09bec2daf9ef90fb12e1d25972d9050f05df3c7b Mon Sep 17 00:00:00 2001 From: Paulo Lanzarin <4529051+prlanzarin@users.noreply.github.com> Date: Fri, 30 Sep 2022 10:10:57 -0300 Subject: [PATCH 05/43] build(bbb-webrtc-sfu): v2.8.7 See https://github.com/bigbluebutton/bbb-webrtc-sfu/releases/tag/v2.8.7 --- bbb-webrtc-sfu.placeholder.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbb-webrtc-sfu.placeholder.sh b/bbb-webrtc-sfu.placeholder.sh index f00d3e026b..644e379473 100755 --- a/bbb-webrtc-sfu.placeholder.sh +++ b/bbb-webrtc-sfu.placeholder.sh @@ -1 +1 @@ -git clone --branch v2.8.6 --depth 1 https://github.com/bigbluebutton/bbb-webrtc-sfu bbb-webrtc-sfu +git clone --branch v2.8.7 --depth 1 https://github.com/bigbluebutton/bbb-webrtc-sfu bbb-webrtc-sfu From 25b81b6de1b03193f2c7109409768d13ccd96bab Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Mon, 10 Oct 2022 14:09:18 +0200 Subject: [PATCH 06/43] fix: spelling errors in session keys --- bigbluebutton-html5/imports/ui/services/settings/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bigbluebutton-html5/imports/ui/services/settings/index.js b/bigbluebutton-html5/imports/ui/services/settings/index.js index 4c5a190337..562e0d6949 100644 --- a/bigbluebutton-html5/imports/ui/services/settings/index.js +++ b/bigbluebutton-html5/imports/ui/services/settings/index.js @@ -12,7 +12,7 @@ const SETTINGS = [ ]; const CHANGED_SETTINGS = 'changed_settings'; -const DEFAULT_SETTINGS = 'dafault_settings'; +const DEFAULT_SETTINGS = 'default_settings'; class Settings { constructor(defaultValues = {}) { From 6ce3dd39cd77d8b52b47621c888c047a37c4946f Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Tue, 11 Oct 2022 15:48:11 +0200 Subject: [PATCH 07/43] fix: show learning dashboard after session was ended in cluster proxy scenario Closes: #15821 --- .../imports/ui/components/learning-dashboard/service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bigbluebutton-html5/imports/ui/components/learning-dashboard/service.js b/bigbluebutton-html5/imports/ui/components/learning-dashboard/service.js index 8839ddf224..d7011f0c60 100644 --- a/bigbluebutton-html5/imports/ui/components/learning-dashboard/service.js +++ b/bigbluebutton-html5/imports/ui/components/learning-dashboard/service.js @@ -42,7 +42,7 @@ const setLearningDashboardCookie = () => { const openLearningDashboardUrl = (lang) => { const APP = Meteor.settings.public.app; if (getLearningDashboardAccessToken() && setLearningDashboardCookie()) { - window.open(`${APP.learningDashboardBase}/?meeting=${Auth.meetingID}&lang=${lang}`, '_blank'); + window.open(`${APP.learningDashboardBase}/?meeting=${Auth.meetingID}&lang=${lang}&report=${getLearningDashboardAccessToken()}`, '_blank'); } else { window.open(`${APP.learningDashboardBase}/?meeting=${Auth.meetingID}&sessionToken=${Auth.sessionToken}&lang=${lang}`, '_blank'); } From 1931223fbefebd7710f1d97cf7386e5667b155c7 Mon Sep 17 00:00:00 2001 From: Brent Baccala Date: Sun, 16 Oct 2022 13:07:12 -0400 Subject: [PATCH 08/43] silence sonarcloud warnings on some old HTML --- bbb-api-demo/src/main/webapp/demo3.jsp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/bbb-api-demo/src/main/webapp/demo3.jsp b/bbb-api-demo/src/main/webapp/demo3.jsp index 39bd21b5af..b0deec19d6 100755 --- a/bbb-api-demo/src/main/webapp/demo3.jsp +++ b/bbb-api-demo/src/main/webapp/demo3.jsp @@ -28,7 +28,7 @@ Author: Fred Dixon - + Join Password @@ -151,7 +151,15 @@ if (request.getParameterMap().isEmpty()) {
- + +
+
Session Information
From c37359687b5d5c20c144fb5cdd1fb8e2ded7d6e2 Mon Sep 17 00:00:00 2001 From: Brent Baccala Date: Sun, 16 Oct 2022 13:18:55 -0400 Subject: [PATCH 09/43] sonarcloud was still complaining about the previous commit --- bbb-api-demo/src/main/webapp/demo3.jsp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bbb-api-demo/src/main/webapp/demo3.jsp b/bbb-api-demo/src/main/webapp/demo3.jsp index b0deec19d6..28523abc1a 100755 --- a/bbb-api-demo/src/main/webapp/demo3.jsp +++ b/bbb-api-demo/src/main/webapp/demo3.jsp @@ -27,8 +27,8 @@ Author: Fred Dixon %> - - + + Join Password @@ -158,8 +158,8 @@ th, td { padding: 5px; } /* cellspacing="5" */ table { border-collapse: separate; border-spacing: 5px; } - - +
Session Information
+
Session Parameters
From de4eba1aee2834643fe443b94eff212ff9041c0d Mon Sep 17 00:00:00 2001 From: Brent Baccala Date: Sun, 16 Oct 2022 15:24:36 -0400 Subject: [PATCH 10/43] convert table to styled div's; sonarcloud doesn't like using tables for layout --- bbb-api-demo/src/main/webapp/demo3.jsp | 119 ++++++++++--------------- 1 file changed, 45 insertions(+), 74 deletions(-) diff --git a/bbb-api-demo/src/main/webapp/demo3.jsp b/bbb-api-demo/src/main/webapp/demo3.jsp index 28523abc1a..a4855d6ea7 100755 --- a/bbb-api-demo/src/main/webapp/demo3.jsp +++ b/bbb-api-demo/src/main/webapp/demo3.jsp @@ -152,81 +152,52 @@ if (request.getParameterMap().isEmpty()) { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Session Parameters
-   - Full Name: -   -
-   - Session: -   - - - -
-   - Password: -   -
-   - Guest: -   -
-   -   -   -
+
+
+
 
+
Full Name:
+
 
+
+
+
+
 
+
Session:
+
 
+
+ +
+
+
+
 
+
Password:
+
 
+
+
+
+
 
+
Guest:
+
 
+
+
+
+
 
+
 
+
 
+
+
+
From 25535e0cded9a504e2bb52106da0d59eb500e852 Mon Sep 17 00:00:00 2001 From: Brent Baccala Date: Mon, 24 Oct 2022 23:02:53 -0400 Subject: [PATCH 11/43] Add stun-client package dependency to bbb-config, so that bbb-conf will run STUN checks --- build/packages-template/bbb-config/opts-focal.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/packages-template/bbb-config/opts-focal.sh b/build/packages-template/bbb-config/opts-focal.sh index 386c16e7f0..be7e75e184 100644 --- a/build/packages-template/bbb-config/opts-focal.sh +++ b/build/packages-template/bbb-config/opts-focal.sh @@ -1,4 +1,4 @@ . ./opts-global.sh AKKA_APPS="bbb-fsesl-akka,bbb-apps-akka" -OPTS="$OPTS -t deb -d netcat-openbsd,bbb-html5,bbb-playback-presentation,bbb-playback,bbb-freeswitch-core,$AKKA_APPS" +OPTS="$OPTS -t deb -d netcat-openbsd,stun-client,bbb-html5,bbb-playback-presentation,bbb-playback,bbb-freeswitch-core,$AKKA_APPS" From c0704bd6b1fa55f5339c949cbb2a0fac5b5b55e0 Mon Sep 17 00:00:00 2001 From: Gustavo Trott Date: Tue, 25 Oct 2022 10:28:12 -0300 Subject: [PATCH 12/43] Revert "fix: show learning dashboard after session was ended in cluster proxy scenario" --- .../imports/ui/components/learning-dashboard/service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bigbluebutton-html5/imports/ui/components/learning-dashboard/service.js b/bigbluebutton-html5/imports/ui/components/learning-dashboard/service.js index d7011f0c60..8839ddf224 100644 --- a/bigbluebutton-html5/imports/ui/components/learning-dashboard/service.js +++ b/bigbluebutton-html5/imports/ui/components/learning-dashboard/service.js @@ -42,7 +42,7 @@ const setLearningDashboardCookie = () => { const openLearningDashboardUrl = (lang) => { const APP = Meteor.settings.public.app; if (getLearningDashboardAccessToken() && setLearningDashboardCookie()) { - window.open(`${APP.learningDashboardBase}/?meeting=${Auth.meetingID}&lang=${lang}&report=${getLearningDashboardAccessToken()}`, '_blank'); + window.open(`${APP.learningDashboardBase}/?meeting=${Auth.meetingID}&lang=${lang}`, '_blank'); } else { window.open(`${APP.learningDashboardBase}/?meeting=${Auth.meetingID}&sessionToken=${Auth.sessionToken}&lang=${lang}`, '_blank'); } From a0ddd9d178e561799b189a70d57872904cdcc268 Mon Sep 17 00:00:00 2001 From: Bohdan Zhemelinskyi Date: Tue, 25 Oct 2022 15:08:04 +0000 Subject: [PATCH 13/43] upgrade dependencies --- bigbluebutton-web/build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bigbluebutton-web/build.gradle b/bigbluebutton-web/build.gradle index a2076b3acf..e601580f86 100755 --- a/bigbluebutton-web/build.gradle +++ b/bigbluebutton-web/build.gradle @@ -79,13 +79,13 @@ dependencies { //--- BigBlueButton Dependencies Start - Transitive dependencies have to be re-defined below implementation "org.bigbluebutton:bbb-common-message_2.13:0.0.21-SNAPSHOT" implementation "org.bigbluebutton:bbb-common-web:0.0.3-SNAPSHOT" - implementation "io.lettuce:lettuce-core:6.1.5.RELEASE" + implementation "io.lettuce:lettuce-core:6.1.9.RELEASE" implementation "org.reactivestreams:reactive-streams:1.0.3" implementation "io.projectreactor:reactor-core:3.4.12" implementation "org.freemarker:freemarker:2.3.31" implementation "com.google.code.gson:gson:2.8.9" implementation "org.json:json:20211205" - implementation "com.zaxxer:nuprocess:2.0.2" + implementation "com.zaxxer:nuprocess:2.0.5" implementation "net.java.dev.jna:jna:5.10.0" // https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload implementation group: 'commons-fileupload', name: 'commons-fileupload', version: '1.4' @@ -101,9 +101,9 @@ dependencies { testImplementation "org.grails:grails-gorm-testing-support" testImplementation "org.grails.plugins:geb" testImplementation "org.grails:grails-web-testing-support" - testRuntimeOnly "org.seleniumhq.selenium:selenium-chrome-driver:2.47.1" + testRuntimeOnly "org.seleniumhq.selenium:selenium-chrome-driver:4.0.0" testRuntimeOnly "org.seleniumhq.selenium:selenium-htmlunit-driver:2.47.1" - testRuntimeOnly "net.sourceforge.htmlunit:htmlunit:2.18" + testRuntimeOnly "net.sourceforge.htmlunit:htmlunit:2.63.0" testImplementation "com.github.javafaker:javafaker:0.12" } From 401ddc401424a1e6775752800940baf8a0af3a92 Mon Sep 17 00:00:00 2001 From: prlanzarin <4529051+prlanzarin@users.noreply.github.com> Date: Fri, 28 Oct 2022 13:33:21 +0000 Subject: [PATCH 14/43] fix: guarantee cleanup of stale data on re-subscriptions Currently, collection cleanup code is only run when an added event is received from the server. Where that fails is in scenarios where a server-side collection turns empty while an affected users is disconnected - and then reconnects. There's no removed (or updated) event so no cleanup code is run and you have stale data. This commit guarantees a stale data check is run whenever a subscription is established again. The `added` check was also maintained, although I'm not too sure anymore it's is still needed. That may need to be revisited. --- .../client/collection-mirror-initializer.js | 107 +++++++----------- .../ui/components/subscriptions/component.jsx | 17 ++- .../LocalCollectionSynchronizer.js | 37 +++--- 3 files changed, 76 insertions(+), 85 deletions(-) diff --git a/bigbluebutton-html5/client/collection-mirror-initializer.js b/bigbluebutton-html5/client/collection-mirror-initializer.js index 022185e2c6..ab7323647e 100644 --- a/bigbluebutton-html5/client/collection-mirror-initializer.js +++ b/bigbluebutton-html5/client/collection-mirror-initializer.js @@ -27,72 +27,51 @@ import Users, { CurrentUser } from '/imports/api/users'; import { Slides, SlidePositions } from '/imports/api/slides'; // Custom Publishers -export const localCurrentPollSync = new AbstractCollection(CurrentPoll, CurrentPoll); -export const localCurrentUserSync = new AbstractCollection(CurrentUser, CurrentUser); -export const localSlidesSync = new AbstractCollection(Slides, Slides); -export const localSlidePositionsSync = new AbstractCollection(SlidePositions, SlidePositions); -export const localPollsSync = new AbstractCollection(Polls, Polls); -export const localPresentationsSync = new AbstractCollection(Presentations, Presentations); -export const localPresentationPodsSync = new AbstractCollection(PresentationPods, PresentationPods); -export const localPresentationUploadTokenSync = new AbstractCollection(PresentationUploadToken, PresentationUploadToken); -export const localScreenshareSync = new AbstractCollection(Screenshare, Screenshare); -export const localUserInfosSync = new AbstractCollection(UserInfos, UserInfos); -export const localUsersPersistentDataSync = new AbstractCollection(UsersPersistentData, UsersPersistentData); -export const localUserSettingsSync = new AbstractCollection(UserSettings, UserSettings); -export const localVideoStreamsSync = new AbstractCollection(VideoStreams, VideoStreams); -export const localVoiceUsersSync = new AbstractCollection(VoiceUsers, VoiceUsers); -export const localWhiteboardMultiUserSync = new AbstractCollection(WhiteboardMultiUser, WhiteboardMultiUser); -export const localGroupChatSync = new AbstractCollection(GroupChat, GroupChat); -export const localConnectionStatusSync = new AbstractCollection(ConnectionStatus, ConnectionStatus); -export const localCaptionsSync = new AbstractCollection(Captions, Captions); -export const localPadsSync = new AbstractCollection(Pads, Pads); -export const localPadsSessionsSync = new AbstractCollection(PadsSessions, PadsSessions); -export const localPadsUpdatesSync = new AbstractCollection(PadsUpdates, PadsUpdates); -export const localAuthTokenValidationSync = new AbstractCollection(AuthTokenValidation, AuthTokenValidation); -export const localAnnotationsSync = new AbstractCollection(Annotations, Annotations); -export const localRecordMeetingsSync = new AbstractCollection(RecordMeetings, RecordMeetings); -export const localExternalVideoMeetingsSync = new AbstractCollection(ExternalVideoMeetings, ExternalVideoMeetings); -export const localMeetingTimeRemainingSync = new AbstractCollection(MeetingTimeRemaining, MeetingTimeRemaining); -export const localUsersTypingSync = new AbstractCollection(UsersTyping, UsersTyping); -export const localBreakoutsSync = new AbstractCollection(Breakouts, Breakouts); -export const localBreakoutsHistorySync = new AbstractCollection(BreakoutsHistory, BreakoutsHistory); -export const localGuestUsersSync = new AbstractCollection(guestUsers, guestUsers); -export const localMeetingsSync = new AbstractCollection(Meetings, Meetings); -export const localUsersSync = new AbstractCollection(Users, Users); +export const localCollectionRegistry = { + localCurrentPollSync: new AbstractCollection(CurrentPoll, CurrentPoll), + localCurrentUserSync: new AbstractCollection(CurrentUser, CurrentUser), + localSlidesSync: new AbstractCollection(Slides, Slides), + localSlidePositionsSync: new AbstractCollection(SlidePositions, SlidePositions), + localPollsSync: new AbstractCollection(Polls, Polls), + localPresentationsSync: new AbstractCollection(Presentations, Presentations), + localPresentationPodsSync: new AbstractCollection(PresentationPods, PresentationPods), + localPresentationUploadTokenSync: new AbstractCollection( + PresentationUploadToken, + PresentationUploadToken, + ), + localScreenshareSync: new AbstractCollection(Screenshare, Screenshare), + localUserInfosSync: new AbstractCollection(UserInfos, UserInfos), + localUsersPersistentDataSync: new AbstractCollection(UsersPersistentData, UsersPersistentData), + localUserSettingsSync: new AbstractCollection(UserSettings, UserSettings), + localVideoStreamsSync: new AbstractCollection(VideoStreams, VideoStreams), + localVoiceUsersSync: new AbstractCollection(VoiceUsers, VoiceUsers), + localWhiteboardMultiUserSync: new AbstractCollection(WhiteboardMultiUser, WhiteboardMultiUser), + localGroupChatSync: new AbstractCollection(GroupChat, GroupChat), + localConnectionStatusSync: new AbstractCollection(ConnectionStatus, ConnectionStatus), + localCaptionsSync: new AbstractCollection(Captions, Captions), + localPadsSync: new AbstractCollection(Pads, Pads), + localPadsSessionsSync: new AbstractCollection(PadsSessions, PadsSessions), + localPadsUpdatesSync: new AbstractCollection(PadsUpdates, PadsUpdates), + localAuthTokenValidationSync: new AbstractCollection(AuthTokenValidation, AuthTokenValidation), + localAnnotationsSync: new AbstractCollection(Annotations, Annotations), + localRecordMeetingsSync: new AbstractCollection(RecordMeetings, RecordMeetings), + localExternalVideoMeetingsSync: new AbstractCollection( + ExternalVideoMeetings, + ExternalVideoMeetings, + ), + localMeetingTimeRemainingSync: new AbstractCollection(MeetingTimeRemaining, MeetingTimeRemaining), + localUsersTypingSync: new AbstractCollection(UsersTyping, UsersTyping), + localBreakoutsSync: new AbstractCollection(Breakouts, Breakouts), + localBreakoutsHistorySync: new AbstractCollection(BreakoutsHistory, BreakoutsHistory), + localGuestUsersSync: new AbstractCollection(guestUsers, guestUsers), + localMeetingsSync: new AbstractCollection(Meetings, Meetings), + localUsersSync: new AbstractCollection(Users, Users), +}; const collectionMirrorInitializer = () => { - localCurrentPollSync.setupListeners(); - localCurrentUserSync.setupListeners(); - localSlidesSync.setupListeners(); - localSlidePositionsSync.setupListeners(); - localPollsSync.setupListeners(); - localPresentationsSync.setupListeners(); - localPresentationPodsSync.setupListeners(); - localPresentationUploadTokenSync.setupListeners(); - localScreenshareSync.setupListeners(); - localUserInfosSync.setupListeners(); - localUsersPersistentDataSync.setupListeners(); - localUserSettingsSync.setupListeners(); - localVideoStreamsSync.setupListeners(); - localVoiceUsersSync.setupListeners(); - localWhiteboardMultiUserSync.setupListeners(); - localGroupChatSync.setupListeners(); - localConnectionStatusSync.setupListeners(); - localCaptionsSync.setupListeners(); - localPadsSync.setupListeners(); - localPadsSessionsSync.setupListeners(); - localPadsUpdatesSync.setupListeners(); - localAuthTokenValidationSync.setupListeners(); - localAnnotationsSync.setupListeners(); - localRecordMeetingsSync.setupListeners(); - localExternalVideoMeetingsSync.setupListeners(); - localMeetingTimeRemainingSync.setupListeners(); - localUsersTypingSync.setupListeners(); - localBreakoutsSync.setupListeners(); - localBreakoutsHistorySync.setupListeners(); - localGuestUsersSync.setupListeners(); - localMeetingsSync.setupListeners(); - localUsersSync.setupListeners(); + Object.values(localCollectionRegistry).forEach((localCollection) => { + localCollection.setupListeners(); + }); }; export default collectionMirrorInitializer; diff --git a/bigbluebutton-html5/imports/ui/components/subscriptions/component.jsx b/bigbluebutton-html5/imports/ui/components/subscriptions/component.jsx index 659b234ecf..17a0271153 100755 --- a/bigbluebutton-html5/imports/ui/components/subscriptions/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/subscriptions/component.jsx @@ -8,11 +8,7 @@ import Users from '/imports/api/users'; import AnnotationsTextService from '/imports/ui/components/whiteboard/annotations/text/service'; import { Annotations as AnnotationsLocal } from '/imports/ui/components/whiteboard/service'; import { - localBreakoutsSync, - localBreakoutsHistorySync, - localGuestUsersSync, - localMeetingsSync, - localUsersSync, + localCollectionRegistry, } from '/client/collection-mirror-initializer'; import SubscriptionRegistry, { subscriptionReactivity } from '../../services/subscription-registry/subscriptionRegistry'; import { isChatEnabled } from '/imports/ui/services/features'; @@ -29,6 +25,13 @@ const SUBSCRIPTIONS = [ 'connection-status', 'voice-call-states', 'external-video-meetings', 'breakouts', 'breakouts-history', 'pads', 'pads-sessions', 'pads-updates', ]; +const { + localBreakoutsSync, + localBreakoutsHistorySync, + localGuestUsersSync, + localMeetingsSync, + localUsersSync, +} = localCollectionRegistry; const EVENT_NAME = 'bbb-group-chat-messages-subscription-has-stoppped'; const EVENT_NAME_SUBSCRIPTION_READY = 'bbb-group-chat-messages-subscriptions-ready'; @@ -164,6 +167,10 @@ export default withTracker(() => { }, ...subscriptionErrorHandler, }); + + Object.values(localCollectionRegistry).forEach( + (localCollection) => localCollection.checkForStaleData(), + ); } return { diff --git a/bigbluebutton-html5/imports/ui/services/LocalCollectionSynchronizer/LocalCollectionSynchronizer.js b/bigbluebutton-html5/imports/ui/services/LocalCollectionSynchronizer/LocalCollectionSynchronizer.js index 94763d9680..92684d0f62 100644 --- a/bigbluebutton-html5/imports/ui/services/LocalCollectionSynchronizer/LocalCollectionSynchronizer.js +++ b/bigbluebutton-html5/imports/ui/services/LocalCollectionSynchronizer/LocalCollectionSynchronizer.js @@ -2,7 +2,7 @@ import SubscriptionRegistry from '/imports/ui/services/subscription-registry/sub import CollectionEventsBroker from '/imports/ui/services/LiveDataEventBroker/LiveDataEventBroker'; /* -This class connects a local collection with the LiveDataEventBroker, propagating the changes of a server-side published cursor to a local collection. +This class connects a local collection with the LiveDataEventBroker, propagating the changes of a server-side published cursor to a local collection. It also guarantee that in case of a reconnection or a re-subscription, the data is only removed after subscription is ready, avoiding the situation of missing data during re-synchronization. */ @@ -15,6 +15,7 @@ class LocalCollectionSynchronizer { this.lastSubscriptionId = ''; this.options = options; this.ignoreDeletes = false; + this.checkForStaleData = this.checkForStaleData.bind(this); } /* @@ -31,26 +32,12 @@ class LocalCollectionSynchronizer { const self = this; const addedCallback = function (item) { - const subscription = SubscriptionRegistry - .getSubscription(self.serverCollection._name); if (item.id === 'publication-stop-marker' && item.stopped) { self.ignoreDeletes = true; return; } - // If the subscriptionId changes means the subscriptions was redone - // or theres more than one subscription per collection - if (subscription && (self.lastSubscriptionId !== subscription.subscriptionId)) { - const wasEmpty = self.lastSubscriptionId === ''; - self.lastSubscriptionId = subscription.subscriptionId; - if (!wasEmpty) { - self.callWhenSubscriptionReady(() => { - self.ignoreDeletes = false; - Session.set('globalIgnoreDeletes', false); - self.removeOldSubscriptionData(); - }); - } - } + self.checkForStaleData(); const selector = { referenceId: item.referenceId }; const itemExistInCollection = self.localCollection.findOne(selector); @@ -117,6 +104,24 @@ class LocalCollectionSynchronizer { return tempPromise; } + checkForStaleData() { + const subscription = SubscriptionRegistry.getSubscription(this.serverCollection._name); + + // If the subscriptionId changes means the subscriptions was redone + // or theres more than one subscription per collection + if (subscription && (this.lastSubscriptionId !== subscription.subscriptionId)) { + const wasEmpty = this.lastSubscriptionId === ''; + this.lastSubscriptionId = subscription.subscriptionId; + if (!wasEmpty) { + this.callWhenSubscriptionReady(() => { + this.ignoreDeletes = false; + Session.set('globalIgnoreDeletes', false); + this.removeOldSubscriptionData(); + }); + } + } + } + /* This method removes data from previous subscriptions after the current one is ready. */ From 13503b1db8d407bd3b7d063d9942824cdfd9669b Mon Sep 17 00:00:00 2001 From: Gustavo Trott Date: Mon, 31 Oct 2022 11:13:49 -0300 Subject: [PATCH 15/43] Removes JCenter from repositories list as it is failing --- bigbluebutton-web/build.gradle | 2 -- bigbluebutton-web/pres-checker/build.gradle | 1 - 2 files changed, 3 deletions(-) diff --git a/bigbluebutton-web/build.gradle b/bigbluebutton-web/build.gradle index a2076b3acf..401d5e189e 100755 --- a/bigbluebutton-web/build.gradle +++ b/bigbluebutton-web/build.gradle @@ -1,6 +1,5 @@ buildscript { repositories { - jcenter() mavenLocal() maven { url "https://repo1.maven.org/maven2" } maven { url "https://repo.grails.org/artifactory/core" } @@ -44,7 +43,6 @@ task copyWebInf(type: Copy) { processResources.dependsOn copyWebInf repositories { - jcenter() mavenLocal() maven { url "https://repo1.maven.org/maven2" } maven { url "https://repo.grails.org/artifactory/core" } diff --git a/bigbluebutton-web/pres-checker/build.gradle b/bigbluebutton-web/pres-checker/build.gradle index eca2216635..4007d7fa4e 100755 --- a/bigbluebutton-web/pres-checker/build.gradle +++ b/bigbluebutton-web/pres-checker/build.gradle @@ -15,7 +15,6 @@ task resolveDeps(type: Copy) { } repositories { - jcenter() mavenLocal() } From 7530ac80197d95d40a081ba192e5b953286fba4b Mon Sep 17 00:00:00 2001 From: Gustavo Trott Date: Mon, 31 Oct 2022 14:51:01 -0300 Subject: [PATCH 16/43] Add mavenCentral as replacement for jcenter --- bigbluebutton-web/build.gradle | 2 ++ bigbluebutton-web/pres-checker/build.gradle | 1 + 2 files changed, 3 insertions(+) diff --git a/bigbluebutton-web/build.gradle b/bigbluebutton-web/build.gradle index 401d5e189e..81846e8c15 100755 --- a/bigbluebutton-web/build.gradle +++ b/bigbluebutton-web/build.gradle @@ -1,5 +1,6 @@ buildscript { repositories { + mavenCentral() mavenLocal() maven { url "https://repo1.maven.org/maven2" } maven { url "https://repo.grails.org/artifactory/core" } @@ -43,6 +44,7 @@ task copyWebInf(type: Copy) { processResources.dependsOn copyWebInf repositories { + mavenCentral() mavenLocal() maven { url "https://repo1.maven.org/maven2" } maven { url "https://repo.grails.org/artifactory/core" } diff --git a/bigbluebutton-web/pres-checker/build.gradle b/bigbluebutton-web/pres-checker/build.gradle index 4007d7fa4e..f19440276f 100755 --- a/bigbluebutton-web/pres-checker/build.gradle +++ b/bigbluebutton-web/pres-checker/build.gradle @@ -15,6 +15,7 @@ task resolveDeps(type: Copy) { } repositories { + mavenCentral() mavenLocal() } From 1fb5240f703009a7a9dba46d99796a34eee80335 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ram=C3=B3n=20Souza?= Date: Fri, 4 Nov 2022 10:13:16 -0300 Subject: [PATCH 17/43] fix previous slide icon in rtl --- .../ui/components/presentation/presentation-toolbar/styles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/styles.js b/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/styles.js index 39c9729cef..b88364c89c 100644 --- a/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/styles.js +++ b/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/styles.js @@ -87,7 +87,7 @@ const PresentationSlideControls = styled.div` const PrevSlideButton = styled(Button)` border: none !important; - & > i { + i { font-size: 1rem; [dir="rtl"] & { From 94c91d8f7902b1bf3813bf0013c6e45d50571e38 Mon Sep 17 00:00:00 2001 From: Joao Victor Date: Mon, 7 Nov 2022 10:23:31 -0300 Subject: [PATCH 18/43] fix: poll chat message popup notification --- .../ui/components/chat/alert/component.jsx | 28 +++++++++++++++++-- .../ui/components/chat/alert/styles.js | 5 ++++ bigbluebutton-html5/public/locales/en.json | 2 ++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/bigbluebutton-html5/imports/ui/components/chat/alert/component.jsx b/bigbluebutton-html5/imports/ui/components/chat/alert/component.jsx index ee5704dbf8..5e7391dc88 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/alert/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/chat/alert/component.jsx @@ -14,6 +14,7 @@ import { usePreviousValue } from '/imports/ui/components/utils/hooks'; const CHAT_CONFIG = Meteor.settings.public.chat; const PUBLIC_CHAT_CLEAR = CHAT_CONFIG.chat_clear; const PUBLIC_CHAT_ID = CHAT_CONFIG.public_id; +const POLL_RESULT_KEY = CHAT_CONFIG.system_messages_keys.chat_poll_result; const propTypes = { pushAlertEnabled: PropTypes.bool.isRequired, @@ -56,6 +57,14 @@ const intlMessages = defineMessages({ id: 'app.toast.chat.private', description: 'private chat toast message title', }, + pollResults: { + id: 'app.toast.chat.poll', + description: 'chat toast message for polls', + }, + pollResultsClick: { + id: 'app.toast.chat.pollClick', + description: 'chat toast click message for polls', + }, }); const ALERT_INTERVAL = 5000; // 5 seconds @@ -168,6 +177,13 @@ const ChatAlert = (props) => { ); + const createPollMessage = () => ( + + {intl.formatMessage(intlMessages.pollResults)} + {intl.formatMessage(intlMessages.pollResultsClick)} + + ); + if (_.isEqual(prevUnreadMessages, unreadMessages)) { return null; } @@ -175,9 +191,15 @@ const ChatAlert = (props) => { return pushAlertEnabled ? unreadMessages.map((timeWindow) => { const mappedMessage = Service.mapGroupMessage(timeWindow); - const content = mappedMessage - ? createMessage(mappedMessage.sender.name, mappedMessage.content.slice(-5)) - : null; + + let content = null; + if (mappedMessage) { + if (mappedMessage.id.includes(POLL_RESULT_KEY)) { + content = createPollMessage(); + } else { + content = createMessage(mappedMessage.sender.name, mappedMessage.content.slice(-5)); + } + } const messageChatId = mappedMessage.chatId === 'MAIN-PUBLIC-GROUP-CHAT' ? PUBLIC_CHAT_ID : mappedMessage.chatId; diff --git a/bigbluebutton-html5/imports/ui/components/chat/alert/styles.js b/bigbluebutton-html5/imports/ui/components/chat/alert/styles.js index 0530edd8bc..fc320013d0 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/alert/styles.js +++ b/bigbluebutton-html5/imports/ui/components/chat/alert/styles.js @@ -38,8 +38,13 @@ const ContentMessage = styled.div` max-height: calc(${fontSizeSmall} * 10); `; +const ContentMessagePoll = styled(ContentMessage)` + margin-top: ${fontSizeSmall}; +`; + export default { PushMessageContent, UserNameMessage, ContentMessage, + ContentMessagePoll, }; diff --git a/bigbluebutton-html5/public/locales/en.json b/bigbluebutton-html5/public/locales/en.json index 66e5185f55..f20d80fae8 100755 --- a/bigbluebutton-html5/public/locales/en.json +++ b/bigbluebutton-html5/public/locales/en.json @@ -653,6 +653,8 @@ "app.toast.chat.public": "New Public Chat message", "app.toast.chat.private": "New Private Chat message", "app.toast.chat.system": "System", + "app.toast.chat.poll": "Poll Results", + "app.toast.chat.pollClick": "Poll results were published. Click here to see.", "app.toast.clearedEmoji.label": "Emoji status cleared", "app.toast.setEmoji.label": "Emoji status set to {0}", "app.toast.meetingMuteOn.label": "All users have been muted", From 0c4f8b7c44d26f667a0a25b1a779d061a4d873bb Mon Sep 17 00:00:00 2001 From: Joao Victor Date: Mon, 7 Nov 2022 14:47:20 -0300 Subject: [PATCH 19/43] fix: don't show published poll notification if chat push alert is active --- .../imports/ui/components/app/component.jsx | 11 +++++++++-- .../imports/ui/components/app/container.jsx | 1 + .../ui/components/chat/alert/component.jsx | 19 +++++++++++++++++-- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/bigbluebutton-html5/imports/ui/components/app/component.jsx b/bigbluebutton-html5/imports/ui/components/app/component.jsx index f26cedbe62..d23be3814a 100755 --- a/bigbluebutton-html5/imports/ui/components/app/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/app/component.jsx @@ -46,6 +46,7 @@ import LayoutService from '/imports/ui/components/layout/service'; import { registerTitleView } from '/imports/utils/dom-utils'; import GlobalStyles from '/imports/ui/stylesheets/styled-components/globalStyles'; import MediaService from '/imports/ui/components/media/service'; +import { toast } from 'react-toastify'; const MOBILE_MEDIA = 'only screen and (max-width: 40em)'; const APP_CONFIG = Meteor.settings.public.app; @@ -128,6 +129,8 @@ const defaultProps = { const isLayeredView = window.matchMedia(`(max-width: ${SMALL_VIEWPORT_BREAKPOINT}px)`); +let publishedPollToast = null; + class App extends Component { static renderWebcamsContainer() { return ; @@ -252,6 +255,7 @@ class App extends Component { pushLayoutToEveryone, // is layout pushed layoutContextDispatch, mountRandomUserModal, + ignorePollNotifications, } = this.props; if (meetingLayout !== prevProps.meetingLayout) { @@ -313,10 +317,11 @@ class App extends Component { intl.formatMessage(intlMessages.meetingMuteOff), 'info', 'unmute', ); } - if (!prevProps.hasPublishedPoll && hasPublishedPoll) { - notify( + if (!prevProps.hasPublishedPoll && hasPublishedPoll && !ignorePollNotifications) { + const id = notify( intl.formatMessage(intlMessages.pollPublishedLabel), 'info', 'polling', ); + if (id) publishedPollToast = id; } if (prevProps.currentUserRole === VIEWER && currentUserRole === MODERATOR) { notify( @@ -330,6 +335,8 @@ class App extends Component { } if (deviceType === null || prevProps.deviceType !== deviceType) this.throttledDeviceType(); + + if (ignorePollNotifications && publishedPollToast) toast.dismiss(publishedPollToast); } componentWillUnmount() { diff --git a/bigbluebutton-html5/imports/ui/components/app/container.jsx b/bigbluebutton-html5/imports/ui/components/app/container.jsx index 844d07e43f..7374dc0d17 100755 --- a/bigbluebutton-html5/imports/ui/components/app/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/app/container.jsx @@ -250,6 +250,7 @@ export default injectIntl(withModalMounter(withTracker(({ intl, baseControls }) autoSwapLayout: getFromUserSettings('bbb_auto_swap_layout', LAYOUT_CONFIG.autoSwapLayout), hideActionsBar: getFromUserSettings('bbb_hide_actions_bar', false), isModalOpen: !!getModal(), + ignorePollNotifications: Session.get('ignorePollNotifications'), }; })(AppContainer))); diff --git a/bigbluebutton-html5/imports/ui/components/chat/alert/component.jsx b/bigbluebutton-html5/imports/ui/components/chat/alert/component.jsx index 5e7391dc88..115704392b 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/alert/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/chat/alert/component.jsx @@ -10,6 +10,7 @@ import { stripTags, unescapeHtml } from '/imports/utils/string-utils'; import Service from '../service'; import Styled from './styles'; import { usePreviousValue } from '/imports/ui/components/utils/hooks'; +import { Session } from 'meteor/session'; const CHAT_CONFIG = Meteor.settings.public.chat; const PUBLIC_CHAT_CLEAR = CHAT_CONFIG.chat_clear; @@ -193,9 +194,11 @@ const ChatAlert = (props) => { const mappedMessage = Service.mapGroupMessage(timeWindow); let content = null; + let isPollResult = false; if (mappedMessage) { if (mappedMessage.id.includes(POLL_RESULT_KEY)) { content = createPollMessage(); + isPollResult = true; } else { content = createMessage(mappedMessage.sender.name, mappedMessage.content.slice(-5)); } @@ -218,10 +221,22 @@ const ChatAlert = (props) => { : {intl.formatMessage(intlMessages.appToastChatPrivate)} } onOpen={ - () => setUnreadMessages(newUnreadMessages) + () => { + if (isPollResult) { + Session.set('ignorePollNotifications', true); + } + + setUnreadMessages(newUnreadMessages); + } } onClose={ - () => setUnreadMessages(newUnreadMessages) + () => { + if (isPollResult) { + Session.set('ignorePollNotifications', false); + } + + setUnreadMessages(newUnreadMessages); + } } alertDuration={timeWindow.durationDiff} layoutContextDispatch={layoutContextDispatch} From 0e57e6049e57a2e700b08a1ae359b7f46042a4c3 Mon Sep 17 00:00:00 2001 From: Brent Baccala Date: Mon, 5 Sep 2022 23:45:53 -0400 Subject: [PATCH 20/43] test suite: add API tests for getMeetings/getMeetingInfo This also creates a new package requirement (xml2js) for the playwright test suite and adds a new helper function to make an API call and obtain its parsed XML response as a JavaScript object --- bigbluebutton-tests/playwright/api/api.js | 87 +++++++++++++++++++ .../playwright/api/api.spec.js | 11 +++ .../playwright/core/helpers.js | 22 +++++ .../playwright/package-lock.json | 47 +++++++++- bigbluebutton-tests/playwright/package.json | 5 +- 5 files changed, 169 insertions(+), 3 deletions(-) create mode 100644 bigbluebutton-tests/playwright/api/api.js create mode 100644 bigbluebutton-tests/playwright/api/api.spec.js diff --git a/bigbluebutton-tests/playwright/api/api.js b/bigbluebutton-tests/playwright/api/api.js new file mode 100644 index 0000000000..fdcd5e053f --- /dev/null +++ b/bigbluebutton-tests/playwright/api/api.js @@ -0,0 +1,87 @@ +// const util = require('node:util'); + +const { expect } = require("@playwright/test"); + +const Page = require('../core/page'); +const parameters = require('../core/parameters'); +const { createMeeting, getMeetings, getMeetingInfo } = require('../core/helpers'); +const e = require('../core/elements'); + +class API { + + constructor(browser, context, page) { + this.modPage = new Page(browser, page); + this.browser = browser; + this.context = context; + this.userPages = []; + } + + async getNewPageTab() { + return this.browser.newPage(); + } + + async getMeetingInfo() { + const meetingId = await createMeeting(parameters); + const modPage = new Page(this.browser, await this.getNewPageTab()); + const userPage = new Page(this.browser, await this.getNewPageTab()); + await Promise.all([ + modPage.init(true, false, { meetingId, fullName: 'Moderator' }), + userPage.init(false, false, { meetingId, fullName: 'Attendee' }), + ]); + await modPage.waitForSelector(e.audioModal); + await userPage.waitForSelector(e.audioModal); + + await modPage.waitAndClick(e.microphoneButton); + await userPage.waitAndClick(e.microphoneButton); + await modPage.waitAndClick(e.echoYesButton, modPage.settings.listenOnlyCallTimeout); + await userPage.waitAndClick(e.echoYesButton, userPage.settings.listenOnlyCallTimeout); + + await modPage.hasElement(e.leaveAudio); + await userPage.hasElement(e.leaveAudio); + + /* hasJoinedVoice: ['true'] is not part of these expectedUser patterns because it isn't consistently true + * in the API's returned data structures. Is there something we can await on the browser page that + * should ensure that the API will report hasJoinedVoice? + */ + + const expectedUsers = [expect.objectContaining({fullName: ['Moderator'], + role: ['MODERATOR'], + isPresenter: ['true'], + }), + expect.objectContaining({fullName: ['Attendee'], + role: ['VIEWER'], + isPresenter: ['false'], + }) + ]; + const expectedMeeting = {meetingName : [meetingId], + running : ['true'], + participantCount : ['2'], + moderatorCount : ['1'], + isBreakout: ['false'], + attendees: [{ attendee: expect.arrayContaining(expectedUsers) }] + }; + + /* check that this meeting is in the server's list of all meetings */ + const response = await getMeetings(); + // console.log(util.inspect(response, false, null)); + expect(response.response.returncode).toEqual(['SUCCESS']); + expect(response.response.meetings[0].meeting).toContainEqual(expect.objectContaining(expectedMeeting)); + + /* check that we can retrieve this meeting by its meetingId */ + const response2 = await getMeetingInfo(meetingId); + // console.log(util.inspect(response2, false, null)); + expect(response2.response.returncode).toEqual(['SUCCESS']); + expect(response2.response).toMatchObject(expectedMeeting); + + /* check that we can retrieve this meeting by its internal meeting ID */ + const response3 = await getMeetingInfo(response2.response.internalMeetingID[0]); + // console.log(util.inspect(response3, false, null)); + expect(response3.response.returncode).toEqual(['SUCCESS']); + expect(response3.response).toMatchObject(expectedMeeting); + + await modPage.page.close(); + await userPage.page.close(); + } +} + +exports.API = API; diff --git a/bigbluebutton-tests/playwright/api/api.spec.js b/bigbluebutton-tests/playwright/api/api.spec.js new file mode 100644 index 0000000000..85c8c07cbf --- /dev/null +++ b/bigbluebutton-tests/playwright/api/api.spec.js @@ -0,0 +1,11 @@ +const { test } = require('@playwright/test'); +const { API } = require('./api.js'); + +test.describe.parallel('API', () => { + + test('getMeetings / getMeetingInfo', async ({ browser, context, page }) => { + const api = new API(browser, context, page); + await api.getMeetingInfo(); + }); + +}); diff --git a/bigbluebutton-tests/playwright/core/helpers.js b/bigbluebutton-tests/playwright/core/helpers.js index a996423bb7..b8856db3a0 100644 --- a/bigbluebutton-tests/playwright/core/helpers.js +++ b/bigbluebutton-tests/playwright/core/helpers.js @@ -2,6 +2,9 @@ require('dotenv').config(); const sha1 = require('sha1'); const path = require('path'); const axios = require('axios'); +const xml2js = require('xml2js'); + +const parameters = require('./parameters'); const httpPath = path.join(path.dirname(require.resolve('axios')), 'lib/adapters/http'); const http = require(httpPath); @@ -12,6 +15,22 @@ function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min)) + min; } +async function apiCall(name, callParams) { + const query = new URLSearchParams(callParams).toString(); + const apicall = `${name}${query}${parameters.secret}`; + const checksum = sha1(apicall); + const url = `${parameters.server}/${name}?${query}&checksum=${checksum}`; + return axios.get(url, { adapter: http }).then(response => xml2js.parseStringPromise(response.data)); +} + +async function getMeetings() { + return apiCall('getMeetings', {}); +} + +async function getMeetingInfo(meetingID) { + return apiCall('getMeetingInfo', {meetingID: meetingID}); +} + async function createMeeting(params, customParameter) { const meetingID = `random-${getRandomInt(1000000, 10000000).toString()}`; const mp = params.moderatorPW; @@ -43,6 +62,9 @@ function sleep(time) { } exports.getRandomInt = getRandomInt; +exports.apiCall = apiCall; +exports.getMeetings = getMeetings; +exports.getMeetingInfo = getMeetingInfo; exports.createMeeting = createMeeting; exports.getJoinURL = getJoinURL; exports.sleep = sleep; diff --git a/bigbluebutton-tests/playwright/package-lock.json b/bigbluebutton-tests/playwright/package-lock.json index 4fccd9dcc9..629d8c3ea8 100644 --- a/bigbluebutton-tests/playwright/package-lock.json +++ b/bigbluebutton-tests/playwright/package-lock.json @@ -9,7 +9,8 @@ "axios": "^0.26.1", "dotenv": "^16.0.0", "playwright": "^1.19.2", - "sha1": "^1.1.1" + "sha1": "^1.1.1", + "xml2js": "^0.4.23" } }, "node_modules/@playwright/test": { @@ -109,6 +110,11 @@ "node": ">=14" } }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, "node_modules/sha1": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz", @@ -120,6 +126,26 @@ "engines": { "node": "*" } + }, + "node_modules/xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" + } } }, "dependencies": { @@ -178,6 +204,11 @@ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.22.2.tgz", "integrity": "sha512-w/hc/Ld0RM4pmsNeE6aL/fPNWw8BWit2tg+TfqJ3+p59c6s3B6C8mXvXrIPmfQEobkcFDc+4KirNzOQ+uBSP1Q==" }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, "sha1": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz", @@ -186,6 +217,20 @@ "charenc": ">= 0.0.1", "crypt": ">= 0.0.1" } + }, + "xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" } } } diff --git a/bigbluebutton-tests/playwright/package.json b/bigbluebutton-tests/playwright/package.json index 4e7bbecd1e..ab220bdd1f 100644 --- a/bigbluebutton-tests/playwright/package.json +++ b/bigbluebutton-tests/playwright/package.json @@ -9,9 +9,10 @@ }, "dependencies": { "@playwright/test": "^1.19.2", - "playwright": "^1.19.2", "axios": "^0.26.1", "dotenv": "^16.0.0", - "sha1": "^1.1.1" + "playwright": "^1.19.2", + "sha1": "^1.1.1", + "xml2js": "^0.4.23" } } From e2b65c546afe0fd607cf7f02e05a56e743964f7d Mon Sep 17 00:00:00 2001 From: Brent Baccala Date: Sun, 9 Oct 2022 15:10:05 -0400 Subject: [PATCH 21/43] API calls: refactor createMeeting to separate out URL calculation, creating a promise, and resolving the promise. Also split API tests apart and name them less confusingly. --- bigbluebutton-tests/playwright/api/api.js | 47 ++++++++++++++++++- .../playwright/api/api.spec.js | 9 +++- .../playwright/core/helpers.js | 30 +++++++++--- 3 files changed, 77 insertions(+), 9 deletions(-) diff --git a/bigbluebutton-tests/playwright/api/api.js b/bigbluebutton-tests/playwright/api/api.js index fdcd5e053f..1b1160f10f 100644 --- a/bigbluebutton-tests/playwright/api/api.js +++ b/bigbluebutton-tests/playwright/api/api.js @@ -20,7 +20,7 @@ class API { return this.browser.newPage(); } - async getMeetingInfo() { + async testGetMeetings() { const meetingId = await createMeeting(parameters); const modPage = new Page(this.browser, await this.getNewPageTab()); const userPage = new Page(this.browser, await this.getNewPageTab()); @@ -67,6 +67,51 @@ class API { expect(response.response.returncode).toEqual(['SUCCESS']); expect(response.response.meetings[0].meeting).toContainEqual(expect.objectContaining(expectedMeeting)); + await modPage.page.close(); + await userPage.page.close(); + } + + async testGetMeetingInfo() { + const meetingId = await createMeeting(parameters); + const modPage = new Page(this.browser, await this.getNewPageTab()); + const userPage = new Page(this.browser, await this.getNewPageTab()); + await Promise.all([ + modPage.init(true, false, { meetingId, fullName: 'Moderator' }), + userPage.init(false, false, { meetingId, fullName: 'Attendee' }), + ]); + await modPage.waitForSelector(e.audioModal); + await userPage.waitForSelector(e.audioModal); + + await modPage.waitAndClick(e.microphoneButton); + await userPage.waitAndClick(e.microphoneButton); + await modPage.waitAndClick(e.echoYesButton, modPage.settings.listenOnlyCallTimeout); + await userPage.waitAndClick(e.echoYesButton, userPage.settings.listenOnlyCallTimeout); + + await modPage.hasElement(e.leaveAudio); + await userPage.hasElement(e.leaveAudio); + + /* hasJoinedVoice: ['true'] is not part of these expectedUser patterns because it isn't consistently true + * in the API's returned data structures. Is there something we can await on the browser page that + * should ensure that the API will report hasJoinedVoice? + */ + + const expectedUsers = [expect.objectContaining({fullName: ['Moderator'], + role: ['MODERATOR'], + isPresenter: ['true'], + }), + expect.objectContaining({fullName: ['Attendee'], + role: ['VIEWER'], + isPresenter: ['false'], + }) + ]; + const expectedMeeting = {meetingName : [meetingId], + running : ['true'], + participantCount : ['2'], + moderatorCount : ['1'], + isBreakout: ['false'], + attendees: [{ attendee: expect.arrayContaining(expectedUsers) }] + }; + /* check that we can retrieve this meeting by its meetingId */ const response2 = await getMeetingInfo(meetingId); // console.log(util.inspect(response2, false, null)); diff --git a/bigbluebutton-tests/playwright/api/api.spec.js b/bigbluebutton-tests/playwright/api/api.spec.js index 85c8c07cbf..bc5216adb7 100644 --- a/bigbluebutton-tests/playwright/api/api.spec.js +++ b/bigbluebutton-tests/playwright/api/api.spec.js @@ -3,9 +3,14 @@ const { API } = require('./api.js'); test.describe.parallel('API', () => { - test('getMeetings / getMeetingInfo', async ({ browser, context, page }) => { + test('getMeetings', async ({ browser, context, page }) => { const api = new API(browser, context, page); - await api.getMeetingInfo(); + await api.testGetMeetings(); + }); + + test('getMeetingInfo', async ({ browser, context, page }) => { + const api = new API(browser, context, page); + await api.testGetMeetingInfo(); }); }); diff --git a/bigbluebutton-tests/playwright/core/helpers.js b/bigbluebutton-tests/playwright/core/helpers.js index b8856db3a0..d1a5e12a58 100644 --- a/bigbluebutton-tests/playwright/core/helpers.js +++ b/bigbluebutton-tests/playwright/core/helpers.js @@ -15,23 +15,28 @@ function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min)) + min; } -async function apiCall(name, callParams) { +function apiCallUrl(name, callParams) { const query = new URLSearchParams(callParams).toString(); const apicall = `${name}${query}${parameters.secret}`; const checksum = sha1(apicall); const url = `${parameters.server}/${name}?${query}&checksum=${checksum}`; + return url; +} + +function apiCall(name, callParams) { + const url = apiCallUrl(name, callParams); return axios.get(url, { adapter: http }).then(response => xml2js.parseStringPromise(response.data)); } -async function getMeetings() { +function getMeetings() { return apiCall('getMeetings', {}); } -async function getMeetingInfo(meetingID) { +function getMeetingInfo(meetingID) { return apiCall('getMeetingInfo', {meetingID: meetingID}); } -async function createMeeting(params, customParameter) { +function createMeetingUrl(params, customParameter) { const meetingID = `random-${getRandomInt(1000000, 10000000).toString()}`; const mp = params.moderatorPW; const ap = params.attendeePW; @@ -42,8 +47,18 @@ async function createMeeting(params, customParameter) { const apicall = `create${query}${params.secret}`; const checksum = sha1(apicall); const url = `${params.server}/create?${query}&checksum=${checksum}`; - await axios.get(url, { adapter: http }); - return meetingID; + return url; +} + +function createMeetingPromise(params, customParameter) { + const url = createMeetingUrl(params, customParameter); + return axios.get(url, { adapter: http }); +} + +async function createMeeting(params, customParameter) { + const promise = createMeetingPromise(params, customParameter); + const response = await promise.then(response => xml2js.parseStringPromise(response.data)); + return response.response.meetingID[0]; } function getJoinURL(meetingID, params, moderator, customParameter) { @@ -62,9 +77,12 @@ function sleep(time) { } exports.getRandomInt = getRandomInt; +exports.apiCallUrl = apiCallUrl; exports.apiCall = apiCall; exports.getMeetings = getMeetings; exports.getMeetingInfo = getMeetingInfo; +exports.createMeetingUrl = createMeetingUrl; +exports.createMeetingPromise = createMeetingPromise; exports.createMeeting = createMeeting; exports.getJoinURL = getJoinURL; exports.sleep = sleep; From 6f7c82641f026700fd5f32ac9a9122631a0c00b2 Mon Sep 17 00:00:00 2001 From: Brent Baccala Date: Sun, 9 Oct 2022 15:27:28 -0400 Subject: [PATCH 22/43] API calls: refactor code to call joinMicrophone instead of duplicating that logic --- bigbluebutton-tests/playwright/api/api.js | 31 ++++++----------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/bigbluebutton-tests/playwright/api/api.js b/bigbluebutton-tests/playwright/api/api.js index 1b1160f10f..4e5689a1f0 100644 --- a/bigbluebutton-tests/playwright/api/api.js +++ b/bigbluebutton-tests/playwright/api/api.js @@ -28,16 +28,10 @@ class API { modPage.init(true, false, { meetingId, fullName: 'Moderator' }), userPage.init(false, false, { meetingId, fullName: 'Attendee' }), ]); - await modPage.waitForSelector(e.audioModal); - await userPage.waitForSelector(e.audioModal); - - await modPage.waitAndClick(e.microphoneButton); - await userPage.waitAndClick(e.microphoneButton); - await modPage.waitAndClick(e.echoYesButton, modPage.settings.listenOnlyCallTimeout); - await userPage.waitAndClick(e.echoYesButton, userPage.settings.listenOnlyCallTimeout); - - await modPage.hasElement(e.leaveAudio); - await userPage.hasElement(e.leaveAudio); + await Promise.all([ + modPage.joinMicrophone(), + userPage.joinMicrophone() + ]); /* hasJoinedVoice: ['true'] is not part of these expectedUser patterns because it isn't consistently true * in the API's returned data structures. Is there something we can await on the browser page that @@ -63,7 +57,6 @@ class API { /* check that this meeting is in the server's list of all meetings */ const response = await getMeetings(); - // console.log(util.inspect(response, false, null)); expect(response.response.returncode).toEqual(['SUCCESS']); expect(response.response.meetings[0].meeting).toContainEqual(expect.objectContaining(expectedMeeting)); @@ -79,16 +72,10 @@ class API { modPage.init(true, false, { meetingId, fullName: 'Moderator' }), userPage.init(false, false, { meetingId, fullName: 'Attendee' }), ]); - await modPage.waitForSelector(e.audioModal); - await userPage.waitForSelector(e.audioModal); - - await modPage.waitAndClick(e.microphoneButton); - await userPage.waitAndClick(e.microphoneButton); - await modPage.waitAndClick(e.echoYesButton, modPage.settings.listenOnlyCallTimeout); - await userPage.waitAndClick(e.echoYesButton, userPage.settings.listenOnlyCallTimeout); - - await modPage.hasElement(e.leaveAudio); - await userPage.hasElement(e.leaveAudio); + await Promise.all([ + modPage.joinMicrophone(), + userPage.joinMicrophone() + ]); /* hasJoinedVoice: ['true'] is not part of these expectedUser patterns because it isn't consistently true * in the API's returned data structures. Is there something we can await on the browser page that @@ -114,13 +101,11 @@ class API { /* check that we can retrieve this meeting by its meetingId */ const response2 = await getMeetingInfo(meetingId); - // console.log(util.inspect(response2, false, null)); expect(response2.response.returncode).toEqual(['SUCCESS']); expect(response2.response).toMatchObject(expectedMeeting); /* check that we can retrieve this meeting by its internal meeting ID */ const response3 = await getMeetingInfo(response2.response.internalMeetingID[0]); - // console.log(util.inspect(response3, false, null)); expect(response3.response.returncode).toEqual(['SUCCESS']); expect(response3.response).toMatchObject(expectedMeeting); From f2b53df4fc62ab8b46784aa8fdbad460d4e326fc Mon Sep 17 00:00:00 2001 From: Brent Baccala Date: Sun, 9 Oct 2022 15:35:07 -0400 Subject: [PATCH 23/43] move two simple API routines from core/helpers.js to api/api.js --- bigbluebutton-tests/playwright/api/api.js | 10 +++++++++- bigbluebutton-tests/playwright/core/helpers.js | 10 ---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/bigbluebutton-tests/playwright/api/api.js b/bigbluebutton-tests/playwright/api/api.js index 4e5689a1f0..a55cbbd03f 100644 --- a/bigbluebutton-tests/playwright/api/api.js +++ b/bigbluebutton-tests/playwright/api/api.js @@ -4,9 +4,17 @@ const { expect } = require("@playwright/test"); const Page = require('../core/page'); const parameters = require('../core/parameters'); -const { createMeeting, getMeetings, getMeetingInfo } = require('../core/helpers'); +const { apiCall, createMeeting } = require('../core/helpers'); const e = require('../core/elements'); +function getMeetings() { + return apiCall('getMeetings', {}); +} + +function getMeetingInfo(meetingID) { + return apiCall('getMeetingInfo', {meetingID: meetingID}); +} + class API { constructor(browser, context, page) { diff --git a/bigbluebutton-tests/playwright/core/helpers.js b/bigbluebutton-tests/playwright/core/helpers.js index d1a5e12a58..2e42033dcd 100644 --- a/bigbluebutton-tests/playwright/core/helpers.js +++ b/bigbluebutton-tests/playwright/core/helpers.js @@ -28,14 +28,6 @@ function apiCall(name, callParams) { return axios.get(url, { adapter: http }).then(response => xml2js.parseStringPromise(response.data)); } -function getMeetings() { - return apiCall('getMeetings', {}); -} - -function getMeetingInfo(meetingID) { - return apiCall('getMeetingInfo', {meetingID: meetingID}); -} - function createMeetingUrl(params, customParameter) { const meetingID = `random-${getRandomInt(1000000, 10000000).toString()}`; const mp = params.moderatorPW; @@ -79,8 +71,6 @@ function sleep(time) { exports.getRandomInt = getRandomInt; exports.apiCallUrl = apiCallUrl; exports.apiCall = apiCall; -exports.getMeetings = getMeetings; -exports.getMeetingInfo = getMeetingInfo; exports.createMeetingUrl = createMeetingUrl; exports.createMeetingPromise = createMeetingPromise; exports.createMeeting = createMeeting; From 8ba3d236b733f3d6a0771c29d644183a99f907ff Mon Sep 17 00:00:00 2001 From: Brent Baccala Date: Mon, 7 Nov 2022 16:59:16 -0500 Subject: [PATCH 24/43] test suite: explicitly require create meeting API calls to return SUCCESS, instead of waiting for a more confusing message when parsing the response --- bigbluebutton-tests/playwright/core/helpers.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bigbluebutton-tests/playwright/core/helpers.js b/bigbluebutton-tests/playwright/core/helpers.js index 2e42033dcd..bb0b4c54e8 100644 --- a/bigbluebutton-tests/playwright/core/helpers.js +++ b/bigbluebutton-tests/playwright/core/helpers.js @@ -4,6 +4,8 @@ const path = require('path'); const axios = require('axios'); const xml2js = require('xml2js'); +const { expect } = require("@playwright/test"); + const parameters = require('./parameters'); const httpPath = path.join(path.dirname(require.resolve('axios')), 'lib/adapters/http'); @@ -49,8 +51,10 @@ function createMeetingPromise(params, customParameter) { async function createMeeting(params, customParameter) { const promise = createMeetingPromise(params, customParameter); - const response = await promise.then(response => xml2js.parseStringPromise(response.data)); - return response.response.meetingID[0]; + const response = await promise; + expect(response.data.response.returncode).toEqual('SUCCESS'); + const xmlresponse = await xml2js.parseStringPromise(response.data); + return xmlresponse.response.meetingID[0]; } function getJoinURL(meetingID, params, moderator, customParameter) { From 04d97e57a7d596ef60d2b2cd14a848895500c9ee Mon Sep 17 00:00:00 2001 From: Brent Baccala Date: Mon, 7 Nov 2022 18:22:14 -0500 Subject: [PATCH 25/43] test suite: can't check XML data before it's been parsed; check HTTP status instead --- bigbluebutton-tests/playwright/core/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bigbluebutton-tests/playwright/core/helpers.js b/bigbluebutton-tests/playwright/core/helpers.js index bb0b4c54e8..9ece262fd7 100644 --- a/bigbluebutton-tests/playwright/core/helpers.js +++ b/bigbluebutton-tests/playwright/core/helpers.js @@ -52,7 +52,7 @@ function createMeetingPromise(params, customParameter) { async function createMeeting(params, customParameter) { const promise = createMeetingPromise(params, customParameter); const response = await promise; - expect(response.data.response.returncode).toEqual('SUCCESS'); + expect(response.status).toEqual(200); const xmlresponse = await xml2js.parseStringPromise(response.data); return xmlresponse.response.meetingID[0]; } From ad1ea593d8be0af46bf8e9de6610adb474f7686c Mon Sep 17 00:00:00 2001 From: Brent Baccala Date: Thu, 20 Oct 2022 04:26:07 +0000 Subject: [PATCH 26/43] Initial attempt at console logging. Handles format strings, colorization, drops http references --- bigbluebutton-tests/playwright/core/page.js | 76 +++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/bigbluebutton-tests/playwright/core/page.js b/bigbluebutton-tests/playwright/core/page.js index b37012b181..6d9d96cd80 100644 --- a/bigbluebutton-tests/playwright/core/page.js +++ b/bigbluebutton-tests/playwright/core/page.js @@ -4,10 +4,82 @@ const { readFileSync } = require('fs'); const parameters = require('./parameters'); const helpers = require('./helpers'); const e = require('./elements'); +const { env } = require('node:process'); const { ELEMENT_WAIT_TIME, ELEMENT_WAIT_LONGER_TIME, VIDEO_LOADING_WAIT_TIME } = require('./constants'); const { checkElement, checkElementLengthEqualTo } = require('./util'); const { generateSettingsData, getSettings } = require('./settings'); +async function strcolors(msg) { + var arguments = await Promise.all(msg.args().map(itm => itm.jsonValue())); + var s = arguments[0]; + var split_str = s.split("%"); + var result = ""; + + for (i=1; i itm.jsonValue())); + var s = arguments[0]; + var split_str = s.split("%"); + var result = split_str[0]; + + for (i=1; i console.log(this.username, await strformat(msg))); + } + this.meetingId = (meetingId) ? meetingId : await helpers.createMeeting(parameters, customParameter); const joinUrl = helpers.getJoinURL(this.meetingId, this.initParameters, isModerator, customParameter); const response = await this.page.goto(joinUrl); From 9a6cb967234eddf3a6c778107e9d86ccc1d2a7d4 Mon Sep 17 00:00:00 2001 From: Brent Baccala Date: Fri, 21 Oct 2022 18:36:33 -0400 Subject: [PATCH 27/43] testsuite: update outdated instructions in README for browser selection --- bigbluebutton-tests/playwright/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bigbluebutton-tests/playwright/README.md b/bigbluebutton-tests/playwright/README.md index 9dd97d8214..cf159f0907 100644 --- a/bigbluebutton-tests/playwright/README.md +++ b/bigbluebutton-tests/playwright/README.md @@ -28,9 +28,9 @@ $ npm test You can also run a single test suite and limit the execution to only one browser: ```bash -$ npx playwright test chat --browser=firefox +$ npx playwright test chat --project=firefox or -$ npm test chat -- --browser=firefox +$ npm test chat -- --project=firefox ``` #### Additional commands From d3f9625bfa5d46f4cdfd3c72d7c59eb01af09a83 Mon Sep 17 00:00:00 2001 From: Brent Baccala Date: Fri, 21 Oct 2022 18:37:06 -0400 Subject: [PATCH 28/43] testsuite console logging: handle Firefox, add five options and update README --- bigbluebutton-tests/playwright/README.md | 19 +++++- bigbluebutton-tests/playwright/core/page.js | 65 ++++++++++++++++++--- 2 files changed, 74 insertions(+), 10 deletions(-) diff --git a/bigbluebutton-tests/playwright/README.md b/bigbluebutton-tests/playwright/README.md index cf159f0907..af289bb4e3 100644 --- a/bigbluebutton-tests/playwright/README.md +++ b/bigbluebutton-tests/playwright/README.md @@ -28,9 +28,9 @@ $ npm test You can also run a single test suite and limit the execution to only one browser: ```bash -$ npx playwright test chat --project=firefox +$ npx playwright test chat --browser=firefox or -$ npm test chat -- --project=firefox +$ npm test chat -- --browser=firefox ``` #### Additional commands @@ -49,3 +49,18 @@ You can also use this also through the test tree, adding the test suite / group ```bash $ npm run test:filter "notifications chat" ``` + +You can print the browser console log to standard output by setting the environment variable `CONSOLE`: +``` +$ CONSOLE= npm test chat -- --project=firefox +``` + +`CONSOLE` can be blank (as in the example), or can be a comma-separated list of the following options: + +| Option | Meaning | +| ------ | ------- | +| color | (or "colour") colorize the output | +| label | label each line with the BigBlueButton user | +| norefs | remove JavaScript reference URLs | +| nots | remove timestamps | +| nocl | remove "clientLogger:" strings | diff --git a/bigbluebutton-tests/playwright/core/page.js b/bigbluebutton-tests/playwright/core/page.js index 6d9d96cd80..d33ce6e63e 100644 --- a/bigbluebutton-tests/playwright/core/page.js +++ b/bigbluebutton-tests/playwright/core/page.js @@ -34,13 +34,23 @@ async function strcolors(msg) { return result; } -async function strformat(msg) { +async function strformat(msg, CONSOLE_options) { var arguments = await Promise.all(msg.args().map(itm => itm.jsonValue())); var s = arguments[0]; var split_str = s.split("%"); var result = split_str[0]; + var surpress_further_output = false; - for (i=1; i console.log(this.username, await strformat(msg))); + if (env.CONSOLE !== undefined) { + const CONSOLE_strings = env.CONSOLE.split(',').map(opt => opt.trim().toLowerCase()); + const CONSOLE_options = { + colorize: CONSOLE_strings.includes('color') || CONSOLE_strings.includes('colour'), + drop_references: CONSOLE_strings.includes('norefs'), + drop_timestamps: CONSOLE_strings.includes('nots'), + line_label: CONSOLE_strings.includes('label') ? this.username + " " : undefined, + noClientLogger: CONSOLE_strings.includes('nocl') || CONSOLE_strings.includes('noclientlogger'), + }; + this.page.on('console', async (msg) => console.log(await strformat(msg, CONSOLE_options))); } this.meetingId = (meetingId) ? meetingId : await helpers.createMeeting(parameters, customParameter); From d2700acb9292f36ab2db78ea48a3f110361dd974 Mon Sep 17 00:00:00 2001 From: Brent Baccala Date: Mon, 24 Oct 2022 18:42:51 -0400 Subject: [PATCH 29/43] testsuite console logging: use npm package 'chalk' to parse colors --- bigbluebutton-tests/playwright/core/page.js | 75 +++--------- .../playwright/package-lock.json | 108 ++++++++++++++++++ bigbluebutton-tests/playwright/package.json | 1 + 3 files changed, 128 insertions(+), 56 deletions(-) diff --git a/bigbluebutton-tests/playwright/core/page.js b/bigbluebutton-tests/playwright/core/page.js index d33ce6e63e..beb4ed87fc 100644 --- a/bigbluebutton-tests/playwright/core/page.js +++ b/bigbluebutton-tests/playwright/core/page.js @@ -1,6 +1,10 @@ require('dotenv').config(); const { expect, default: test } = require('@playwright/test'); const { readFileSync } = require('fs'); + +// This is version 4 of chalk, not version 5, which uses ESM +const chalk = require('chalk'); + const parameters = require('./parameters'); const helpers = require('./helpers'); const e = require('./elements'); @@ -9,46 +13,12 @@ const { ELEMENT_WAIT_TIME, ELEMENT_WAIT_LONGER_TIME, VIDEO_LOADING_WAIT_TIME } = const { checkElement, checkElementLengthEqualTo } = require('./util'); const { generateSettingsData, getSettings } = require('./settings'); -async function strcolors(msg) { - var arguments = await Promise.all(msg.args().map(itm => itm.jsonValue())); - var s = arguments[0]; - var split_str = s.split("%"); - var result = ""; - - for (i=1; i itm.jsonValue())); - var s = arguments[0]; - var split_str = s.split("%"); + const arguments = await Promise.all(msg.args().map(itm => itm.jsonValue())); + const split_str = arguments[0].split("%"); var result = split_str[0]; var surpress_further_output = false; - if (CONSOLE_options.line_label) { - if (CONSOLE_options.colorize) { - result = "\033[38;5;34m" + CONSOLE_options.line_label + "\033[38;5;0m" + result; - } else { - result = CONSOLE_options.line_label + result; - } - } - argloop: for (i=1, j=1; i=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/axios": { "version": "0.26.1", "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", @@ -41,6 +56,21 @@ "follow-redirects": "^1.14.8" } }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/charenc": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", @@ -49,6 +79,22 @@ "node": "*" } }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "node_modules/crypt": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", @@ -84,6 +130,14 @@ } } }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, "node_modules/playwright": { "version": "1.22.2", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.22.2.tgz", @@ -127,6 +181,17 @@ "node": "*" } }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/xml2js": { "version": "0.4.23", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", @@ -163,6 +228,14 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.40.tgz", "integrity": "sha512-UXdBxNGqTMtm7hCwh9HtncFVLrXoqA3oJW30j6XWp5BH/wu3mVeaxo7cq5benFdBw34HB3XDT2TRPI7rXZ+mDg==" }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, "axios": { "version": "0.26.1", "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", @@ -171,11 +244,33 @@ "follow-redirects": "^1.14.8" } }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, "charenc": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==" }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "crypt": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", @@ -191,6 +286,11 @@ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==" }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, "playwright": { "version": "1.22.2", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.22.2.tgz", @@ -218,6 +318,14 @@ "crypt": ">= 0.0.1" } }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, "xml2js": { "version": "0.4.23", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", diff --git a/bigbluebutton-tests/playwright/package.json b/bigbluebutton-tests/playwright/package.json index ab220bdd1f..aeda0f19f9 100644 --- a/bigbluebutton-tests/playwright/package.json +++ b/bigbluebutton-tests/playwright/package.json @@ -10,6 +10,7 @@ "dependencies": { "@playwright/test": "^1.19.2", "axios": "^0.26.1", + "chalk": "^4.1.2", "dotenv": "^16.0.0", "playwright": "^1.19.2", "sha1": "^1.1.1", From ee44663de809595e9a408432d5b6055c6b73af8c Mon Sep 17 00:00:00 2001 From: Brent Baccala Date: Mon, 24 Oct 2022 20:33:52 -0400 Subject: [PATCH 30/43] testsuite console logging: use node.js util.format to process format string --- bigbluebutton-tests/playwright/core/page.js | 68 ++++++++++----------- 1 file changed, 31 insertions(+), 37 deletions(-) diff --git a/bigbluebutton-tests/playwright/core/page.js b/bigbluebutton-tests/playwright/core/page.js index beb4ed87fc..12e3517aef 100644 --- a/bigbluebutton-tests/playwright/core/page.js +++ b/bigbluebutton-tests/playwright/core/page.js @@ -1,6 +1,7 @@ require('dotenv').config(); const { expect, default: test } = require('@playwright/test'); const { readFileSync } = require('fs'); +const { format } = require('node:util'); // This is version 4 of chalk, not version 5, which uses ESM const chalk = require('chalk'); @@ -13,61 +14,54 @@ const { ELEMENT_WAIT_TIME, ELEMENT_WAIT_LONGER_TIME, VIDEO_LOADING_WAIT_TIME } = const { checkElement, checkElementLengthEqualTo } = require('./util'); const { generateSettingsData, getSettings } = require('./settings'); -async function strformat(msg, CONSOLE_options) { - const arguments = await Promise.all(msg.args().map(itm => itm.jsonValue())); - const split_str = arguments[0].split("%"); - var result = split_str[0]; - var surpress_further_output = false; +async function console_format(msg, CONSOLE_options) { + // see playwright consoleMessage class documentation + var arguments = await Promise.all(msg.args().map(itm => itm.jsonValue())); - argloop: - for (i=1, j=1; i console.log(await strformat(msg, CONSOLE_options))); + this.page.on('console', async (msg) => console.log(await console_format(msg, CONSOLE_options))); } this.meetingId = (meetingId) ? meetingId : await helpers.createMeeting(parameters, customParameter); From ed39b09f6f8aa2e1863264ff264800b85799a6c3 Mon Sep 17 00:00:00 2001 From: Brent Baccala Date: Mon, 24 Oct 2022 21:49:52 -0400 Subject: [PATCH 31/43] testsuite console logging: address SonarCloud complaints --- bigbluebutton-tests/playwright/core/page.js | 37 +++++++++++---------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/bigbluebutton-tests/playwright/core/page.js b/bigbluebutton-tests/playwright/core/page.js index 12e3517aef..fe36aa4a85 100644 --- a/bigbluebutton-tests/playwright/core/page.js +++ b/bigbluebutton-tests/playwright/core/page.js @@ -14,33 +14,30 @@ const { ELEMENT_WAIT_TIME, ELEMENT_WAIT_LONGER_TIME, VIDEO_LOADING_WAIT_TIME } = const { checkElement, checkElementLengthEqualTo } = require('./util'); const { generateSettingsData, getSettings } = require('./settings'); -async function console_format(msg, CONSOLE_options) { - // see playwright consoleMessage class documentation - var arguments = await Promise.all(msg.args().map(itm => itm.jsonValue())); - - // For Chrome, arguments[0] is a format string that we will process - // using node.js's util.format, but that function discards css style - // information from "%c" format specifiers. So loop over the format - // string, replacing every "%c" with "%s" and replacing the +function formatWithCss(CONSOLE_options, ...args) { + // For Chrome, args[0] is a format string that we will process using + // node.js's util.format, but that function discards css style + // information from "%c" format specifiers. So first loop over the + // format string, replacing every "%c" with "%s" and replacing the // corresponding css style with an ANSI color sequence. // // See https://console.spec.whatwg.org/ sections 2.2.1 and 2.3.4 - var split_arg0 = arguments[0].split("%"); - for (i=1, j=1; i itm.jsonValue())); + let result = formatWithCss(CONSOLE_options, ...args); if (CONSOLE_options.drop_references) { // For Firefox, we "drop references" by discarding a URL at the end of the line From 0c32f307a79c37a4ca701dd2edfa4e1ddcbd1b95 Mon Sep 17 00:00:00 2001 From: Brent Baccala Date: Mon, 24 Oct 2022 22:07:40 -0400 Subject: [PATCH 32/43] testsuite console logging: still addressing SonarCloud issues --- bigbluebutton-tests/playwright/core/page.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/bigbluebutton-tests/playwright/core/page.js b/bigbluebutton-tests/playwright/core/page.js index fe36aa4a85..57780e15f6 100644 --- a/bigbluebutton-tests/playwright/core/page.js +++ b/bigbluebutton-tests/playwright/core/page.js @@ -24,17 +24,17 @@ function formatWithCss(CONSOLE_options, ...args) { // See https://console.spec.whatwg.org/ sections 2.2.1 and 2.3.4 let split_arg0 = args[0].split("%"); - for (var i=1, j=1; i Date: Fri, 18 Nov 2022 10:44:50 -0300 Subject: [PATCH 33/43] Add new nginx rules --- build/packages-template/bbb-config/after-install.sh | 2 +- build/packages-template/bbb-html5/bbb-html5.nginx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/build/packages-template/bbb-config/after-install.sh b/build/packages-template/bbb-config/after-install.sh index b353d00a00..ae506e4895 100644 --- a/build/packages-template/bbb-config/after-install.sh +++ b/build/packages-template/bbb-config/after-install.sh @@ -130,7 +130,7 @@ if [ -d /var/mediasoup/screenshare ]; then fi sed -i 's/worker_connections 768/worker_connections 4000/g' /etc/nginx/nginx.conf - +echo 'limit_conn_zone $uri zone=ws_zone:5m;' > /etc/nginx/conf.d/html5-conn-limit.conf if grep -q "worker_rlimit_nofile" /etc/nginx/nginx.conf; then num=$(grep worker_rlimit_nofile /etc/nginx/nginx.conf | grep -o '[0-9]*') if [[ "$num" -lt 10000 ]]; then diff --git a/build/packages-template/bbb-html5/bbb-html5.nginx b/build/packages-template/bbb-html5/bbb-html5.nginx index e0a14bc68c..dca62b58ff 100644 --- a/build/packages-template/bbb-html5/bbb-html5.nginx +++ b/build/packages-template/bbb-html5/bbb-html5.nginx @@ -4,6 +4,7 @@ location @html5client { proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; + limit_conn ws_zone 3; } location /html5client/locales { From 276e592c018900fbe1e069be6d7504fc46418475 Mon Sep 17 00:00:00 2001 From: Calvin Walton Date: Tue, 22 Nov 2022 13:12:07 -0500 Subject: [PATCH 34/43] Recording: Don't use stateful filters in ffmpeg video processing Because the input videos for BigBlueButton recording processing switch resolution and aspect ratio, the filter chain gets re-initialized, and any state in the filters is lost. This causes problems with the following filters: `color`: Timestamps restart from 0, rather than continuing at the point where they left off. `fps=start_time=12.345`: After reset, the fps filter thinks it's at the start of the file again, so the next frame it sees gets duplicated output for timestamps from the `start_time` until it catches back up. `setpts=PTS-STARTPTS`: The 'STARTPTS' is re-read as the first pts the filter sees after reinitialization, so timestamp of the next frame is reset to 0. (In practise, this didn't cause any problems because the duplicate frames created by the fps filter had the original start time.) The end result of all of these issues is that a lot of duplicate frames were created with invalid timestamps, which eventually get discarded by ffmpeg. But a lot of time is wasted, causing recordings to sometimes take hours to process when they should be ready in minutes. The fixes are as follows: * The `color` filters are used to generate the background and substitutes for missing videos. Move them out to separate filter chains by using the 'lavfi' input format, which lets you use a filter as if it was an input file. * Rather than use the `fps` filter's `start_time` feature, use the `trim` filter to remove early frames. * The actual start pts is already known by the script, so replace `setpts=PTS-STARTPTS` with `setpts=PTS-12.345/TB`, substituting in the absolute time. --- .../core/lib/recordandplayback/edl/video.rb | 44 ++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/record-and-playback/core/lib/recordandplayback/edl/video.rb b/record-and-playback/core/lib/recordandplayback/edl/video.rb index 4970525b40..084532bc0e 100644 --- a/record-and-playback/core/lib/recordandplayback/edl/video.rb +++ b/record-and-playback/core/lib/recordandplayback/edl/video.rb @@ -384,8 +384,13 @@ module BigBlueButton duration = cut[:next_timestamp] - cut[:timestamp] BigBlueButton.logger.info " Cut start time #{cut[:timestamp]}, duration #{duration}" - ffmpeg_inputs = [] - ffmpeg_filter = "color=c=white:s=#{layout[:width]}x#{layout[:height]}:r=#{layout[:framerate]}" + ffmpeg_inputs = [ + { + format: 'lavfi', + filename: "color=c=white:s=#{layout[:width]}x#{layout[:height]}:r=#{layout[:framerate]}" + } + ] + ffmpeg_filter = '[0]null' layout[:areas].each do |layout_area| area = cut[:areas][layout_area[:name]] video_count = area.length @@ -483,9 +488,16 @@ module BigBlueButton tile_y += 1 end - # Only create the video input if the seekpoint is before the end of the file + input_index = ffmpeg_inputs.length + + # If the seekpoint is at or after the end of the file, the filter chain will + # have problems. Substitute in a blank video. if seek >= this_videoinfo[:duration] - ffmpeg_filter << "color=c=white:s=#{tile_width}x#{tile_height}:r=#{layout[:framerate]}[#{pad_name}];" + ffmpeg_inputs << { + format: 'lavfi', + filename: "color=c=white:s=#{tile_width}x#{tile_height}:r=#{layout[:framerate]}" + } + ffmpeg_filter << "[#{input_index}]null[#{pad_name}];" next end @@ -496,7 +508,6 @@ module BigBlueButton if seek > 0 seek = seek + seek_offset end - input_index = ffmpeg_inputs.length ffmpeg_inputs << { filename: video[:filename], seek: seek, @@ -506,16 +517,15 @@ module BigBlueButton if !scale.nil? ffmpeg_filter << "setpts=PTS*#{scale}," end - # Subtract away the offset from the timestamps, so the trimming - # in the fps filter is accurate - ffmpeg_filter << "setpts=PTS-#{ms_to_s(seek_offset)}/TB" - # fps filter fills in frames up to the desired start point, and - # cuts the video there - ffmpeg_filter << ",fps=#{layout[:framerate]}:start_time=#{ms_to_s(video[:timestamp])}" - # Reset the timestamps to start at 0 so that everything is synced - # for the video tiling, and scale to the desired size. - ffmpeg_filter << ",setpts=PTS-STARTPTS,scale=w=#{tile_width}:h=#{tile_height}:force_original_aspect_ratio=decrease,setsar=1" - # And finally, pad the video to the desired aspect ratio + # Subtract away the offset from the timestamps, so the trimming is accurate + ffmpeg_filter << "setpts=PTS-#{ms_to_s(video[:timestamp])}/TB" + # Clean up the video framerate + ffmpeg_filter << ",fps=#{layout[:framerate]}" + # Trim any frames from before the desired start point (seek offset strangeness) + ffmpeg_filter << ',trim=start=0' + # Scale to the desired size + ffmpeg_filter << ",scale=w=#{tile_width}:h=#{tile_height}:force_original_aspect_ratio=decrease,setsar=1" + # Pad the video to the desired aspect ratio ffmpeg_filter << ",pad=w=#{tile_width}:h=#{tile_height}:x=-1:y=-1:color=white" # Extend the video to the desired length ffmpeg_filter << ",tpad=stop=-1:stop_mode=add:color=white" @@ -554,7 +564,9 @@ module BigBlueButton ffmpeg_cmd = [*FFMPEG, '-copyts'] ffmpeg_inputs.each do |input| - ffmpeg_cmd += ['-ss', ms_to_s(input[:seek]), '-i', input[:filename]] + ffmpeg_cmd << '-ss' << ms_to_s(input[:seek]) if input.include?(:seek) + ffmpeg_cmd << '-f' << input[:format] if input.include?(:format) + ffmpeg_cmd << '-i' << input[:filename] end BigBlueButton.logger.debug(' ffmpeg filter_complex_script:') From 4127f4ccc7a4137fcbb727c7f99db1efeea16715 Mon Sep 17 00:00:00 2001 From: Calvin Walton Date: Mon, 5 Dec 2022 11:49:16 -0500 Subject: [PATCH 35/43] Recording: Pre-process video files using separate ffmpeg Even with the filter changes made, there's still some cases where filter chain hangs can result from filter reconfigurations. To solve the issue completely, I have split out pre-processing video files to separate ffmpeg processes, so that the filter chain for compositing will not ever be reconfigured. Each input video now has a separate ffmpeg process run for it which does the scaling, padding, and video extending steps. To avoid issues with disk space usage and extra cpu usage or quality loss, the output from these separate processes is sent to the compositing ffmpeg process as uncompressed video in a pipe. To simplify the setup, named pipes (special files) are used rather than setting up pipes in the ruby code programmatically. The extra ffmpeg processes are configured to log to files, and when complete their log output is copied to the recording processing log. Processes are joined to ensure zombie processes are not created, and the return codes of all the processes are checked so errors can be detected. Due to the overhead of transferring video through pipes, this might be a bit slower than the 2.4 recording processing - but on the other hand, some of the video decoding and scaling happens in parallel, so it might balance out. --- .../core/lib/recordandplayback/edl/video.rb | 90 ++++++++++++------- 1 file changed, 60 insertions(+), 30 deletions(-) diff --git a/record-and-playback/core/lib/recordandplayback/edl/video.rb b/record-and-playback/core/lib/recordandplayback/edl/video.rb index 084532bc0e..834659e17b 100644 --- a/record-and-playback/core/lib/recordandplayback/edl/video.rb +++ b/record-and-playback/core/lib/recordandplayback/edl/video.rb @@ -19,6 +19,7 @@ require 'json' require 'set' +require 'shellwords' module BigBlueButton module EDL @@ -384,6 +385,7 @@ module BigBlueButton duration = cut[:next_timestamp] - cut[:timestamp] BigBlueButton.logger.info " Cut start time #{cut[:timestamp]}, duration #{duration}" + aux_ffmpeg_processes = [] ffmpeg_inputs = [ { format: 'lavfi', @@ -447,25 +449,18 @@ module BigBlueButton scale_width, scale_height = aspect_scale(video_width, video_height, tile_width, tile_height) BigBlueButton.logger.debug " scaled size: #{scale_width}x#{scale_height}" + seek = video[:timestamp] BigBlueButton.logger.debug(" start timestamp: #{video[:timestamp]}") seek_offset = this_videoinfo[:start_time] BigBlueButton.logger.debug(" seek offset: #{seek_offset}") BigBlueButton.logger.debug(" codec: #{this_videoinfo[:video][:codec_name].inspect}") BigBlueButton.logger.debug(" duration: #{this_videoinfo[:duration]}, original duration: #{video[:original_duration]}") - if this_videoinfo[:video][:codec_name] == "flashsv2" - # Desktop sharing videos in flashsv2 do not have regular - # keyframes, so seeking in them doesn't really work. - # To make processing more reliable, always decode them from the - # start in each cut. (Slow!) - seek = 0 - else - # Webcam videos are variable, low fps; it might be that there's - # no frame until some time after the seek point. Start decoding - # 10s before the desired point to avoid this issue. - seek = video[:timestamp] - 10000 - seek = 0 if seek < 0 - end + # Desktop sharing videos in flashsv2 do not have regular + # keyframes, so seeking in them doesn't really work. + # To make processing more reliable, always decode them from the + # start in each cut. (Slow!) + seek = 0 if this_videoinfo[:video][:codec_name] == 'flashsv2' # Workaround early 1.1 deskshare timestamp bug # It resulted in video files that were too short. To workaround, we @@ -508,27 +503,48 @@ module BigBlueButton if seek > 0 seek = seek + seek_offset end + + # Launch the ffmpeg process to use for this input to pre-process the video to constant video resolution + # This has to be done in an external process, since if it's done in the same process, the entire filter + # chain gets re-initialized on every resolution change, resulting in losing state on all stateful filters. + ffmpeg_preprocess_output = "#{output}.#{pad_name}.nut" + ffmpeg_preprocess_log = "#{output}.#{pad_name}.log" + FileUtils.rm_f(ffmpeg_preprocess_output) + File.mkfifo(ffmpeg_preprocess_output) + + # Pre-filtering: scaling, padding, and extending. + ffmpeg_preprocess_filter = \ + "[0:v:0]scale=w=#{tile_width}:h=#{tile_height}:force_original_aspect_ratio=decrease,setsar=1,"\ + "pad=w=#{tile_width}:h=#{tile_height}:x=-1:y=-1:color=white,tpad=stop=-1:stop_mode=clone[out]" + + # Set up filters and inputs for video pre-processing ffmpeg command + ffmpeg_preprocess_command = [ + 'ffmpeg', '-y', '-v', 'info', '-nostats', '-nostdin', '-max_error_rate', '1.0', + # Ensure timebase conversion is not done, and frames prior to seek point run through filters. + '-vsync', 'passthrough', '-noaccurate_seek', + '-ss', ms_to_s(seek).to_s, '-itsoffset', ms_to_s(seek).to_s, '-i', video[:filename], + '-filter_complex', ffmpeg_preprocess_filter, '-map', '[out]', + # Trim to end point so process exits cleanly + '-to', ms_to_s(video[:timestamp] + duration).to_s, + '-c:v', 'rawvideo', "#{output}.#{pad_name}.nut" + ] + BigBlueButton.logger.debug("Executing: #{Shellwords.join(ffmpeg_preprocess_command)}") + ffmpeg_preprocess_pid = spawn(*ffmpeg_preprocess_command, err: [ffmpeg_preprocess_log, 'w']) + aux_ffmpeg_processes << { + pid: ffmpeg_preprocess_pid, + log: ffmpeg_preprocess_log + } + ffmpeg_inputs << { - filename: video[:filename], - seek: seek, + filename: ffmpeg_preprocess_output } ffmpeg_filter << "[#{input_index}]" # Scale the video length for the deskshare timestamp workaround - if !scale.nil? - ffmpeg_filter << "setpts=PTS*#{scale}," - end - # Subtract away the offset from the timestamps, so the trimming is accurate - ffmpeg_filter << "setpts=PTS-#{ms_to_s(video[:timestamp])}/TB" - # Clean up the video framerate - ffmpeg_filter << ",fps=#{layout[:framerate]}" - # Trim any frames from before the desired start point (seek offset strangeness) - ffmpeg_filter << ',trim=start=0' - # Scale to the desired size - ffmpeg_filter << ",scale=w=#{tile_width}:h=#{tile_height}:force_original_aspect_ratio=decrease,setsar=1" - # Pad the video to the desired aspect ratio - ffmpeg_filter << ",pad=w=#{tile_width}:h=#{tile_height}:x=-1:y=-1:color=white" - # Extend the video to the desired length - ffmpeg_filter << ",tpad=stop=-1:stop_mode=add:color=white" + ffmpeg_filter << "setpts=PTS*#{scale}," unless scale.nil? + # Clean up the video framerate and set exact start time + ffmpeg_filter << "fps=#{layout[:framerate]}:start_time=#{ms_to_s(video[:timestamp])}" + # Apply PTS offset so '0' time is aligned + ffmpeg_filter << ",setpts=PTS-#{ms_to_s(video[:timestamp])}/TB" ffmpeg_filter << "[#{pad_name}];" end @@ -580,6 +596,20 @@ module BigBlueButton ffmpeg_cmd += ['-an', *FFMPEG_WF_ARGS, '-r', layout[:framerate].to_s, output] exitstatus = BigBlueButton.exec_ret(*ffmpeg_cmd) + + aux_ffmpeg_exitstatuses = [] + aux_ffmpeg_processes.each do |process| + aux_exitstatus = Process.waitpid2(process[:pid]) + aux_ffmpeg_exitstatuses << aux_exitstatus[1] + BigBlueButton.logger.info("Command output: #{File.basename(process[:log])} #{aux_exitstatus[1]}") + File.open(process[:log], 'r') do |io| + io.each_line do |line| + BigBlueButton.logger.info(line.chomp) + end + end + end + raise 'At least one auxiliary ffmpeg process failed' unless aux_ffmpeg_exitstatuses.all?(&:success?) + raise "ffmpeg failed, exit code #{exitstatus}" if exitstatus != 0 return output From 06d0e4d454c89cb9838f395b15c3a476fe95ba61 Mon Sep 17 00:00:00 2001 From: Calvin Walton Date: Tue, 6 Dec 2022 15:59:54 -0500 Subject: [PATCH 36/43] Recording: Move tpad filter to after fps filter The tpad filter is problematic on the variable-framerate webcam files, and the result can end up being hangs (or, at least, very slow processing) in the compositing. Move the tpad filter to the compositing process where it can run after the fps filter has converted the video to constant framerate. It still needs to run before the start trimming, so switch to using the trim filter rather than the fps filter's start_pts feature. --- .../core/lib/recordandplayback/edl/video.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/record-and-playback/core/lib/recordandplayback/edl/video.rb b/record-and-playback/core/lib/recordandplayback/edl/video.rb index 834659e17b..c19d9fac4e 100644 --- a/record-and-playback/core/lib/recordandplayback/edl/video.rb +++ b/record-and-playback/core/lib/recordandplayback/edl/video.rb @@ -515,7 +515,7 @@ module BigBlueButton # Pre-filtering: scaling, padding, and extending. ffmpeg_preprocess_filter = \ "[0:v:0]scale=w=#{tile_width}:h=#{tile_height}:force_original_aspect_ratio=decrease,setsar=1,"\ - "pad=w=#{tile_width}:h=#{tile_height}:x=-1:y=-1:color=white,tpad=stop=-1:stop_mode=clone[out]" + "pad=w=#{tile_width}:h=#{tile_height}:x=-1:y=-1:color=white[out]" # Set up filters and inputs for video pre-processing ffmpeg command ffmpeg_preprocess_command = [ @@ -541,10 +541,10 @@ module BigBlueButton ffmpeg_filter << "[#{input_index}]" # Scale the video length for the deskshare timestamp workaround ffmpeg_filter << "setpts=PTS*#{scale}," unless scale.nil? - # Clean up the video framerate and set exact start time - ffmpeg_filter << "fps=#{layout[:framerate]}:start_time=#{ms_to_s(video[:timestamp])}" - # Apply PTS offset so '0' time is aligned - ffmpeg_filter << ",setpts=PTS-#{ms_to_s(video[:timestamp])}/TB" + # Clean up the video framerate and extend the video if needed + ffmpeg_filter << "fps=#{layout[:framerate]},tpad=stop=-1:stop_mode=clone" + # Apply PTS offset so '0' time is aligned, and trim frames before start point + ffmpeg_filter << ",setpts=PTS-#{ms_to_s(video[:timestamp])}/TB,trim=start=0" ffmpeg_filter << "[#{pad_name}];" end From 06d32c672ce6413c64a188f6a22de5d99890e8ca Mon Sep 17 00:00:00 2001 From: Anton Georgiev Date: Thu, 8 Dec 2022 19:07:39 +0000 Subject: [PATCH 37/43] chore: Update meteor 2.7.1 to 2.9.0 --- bigbluebutton-html5/.meteor/packages | 16 +++---- bigbluebutton-html5/.meteor/release | 2 +- bigbluebutton-html5/.meteor/versions | 62 ++++++++++++++-------------- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/bigbluebutton-html5/.meteor/packages b/bigbluebutton-html5/.meteor/packages index e7649fe00f..23899021d5 100644 --- a/bigbluebutton-html5/.meteor/packages +++ b/bigbluebutton-html5/.meteor/packages @@ -5,20 +5,20 @@ meteor-base@1.5.1 mobile-experience@1.1.0 -mongo@1.15.0 -reactive-var@1.0.11 +mongo@1.16.3 +reactive-var@1.0.12 -standard-minifier-css@1.8.1 -standard-minifier-js@2.8.0 +standard-minifier-css@1.8.3 +standard-minifier-js@2.8.1 es5-shim@4.8.0 -ecmascript@0.16.2 +ecmascript@0.16.4 shell-server@0.5.0 static-html@1.3.2 react-meteor-data -session@1.2.0 -tracker@1.2.0 -check@1.3.1 +session@1.2.1 +tracker@1.2.1 +check@1.3.2 rocketchat:streamer meteortesting:mocha diff --git a/bigbluebutton-html5/.meteor/release b/bigbluebutton-html5/.meteor/release index 66dd7b6647..e1e355d0cd 100644 --- a/bigbluebutton-html5/.meteor/release +++ b/bigbluebutton-html5/.meteor/release @@ -1 +1 @@ -METEOR@2.7.3 +METEOR@2.9.0 diff --git a/bigbluebutton-html5/.meteor/versions b/bigbluebutton-html5/.meteor/versions index ab0881cd0b..1aae74ea2d 100644 --- a/bigbluebutton-html5/.meteor/versions +++ b/bigbluebutton-html5/.meteor/versions @@ -1,6 +1,6 @@ allow-deny@1.1.1 autoupdate@1.8.0 -babel-compiler@7.9.0 +babel-compiler@7.10.1 babel-runtime@1.5.1 base64@1.0.12 binary-heap@1.0.11 @@ -9,21 +9,21 @@ boilerplate-generator@1.7.1 caching-compiler@1.2.2 caching-html-compiler@1.2.1 callback-hook@1.4.0 -check@1.3.1 -ddp@1.4.0 -ddp-client@2.5.0 +check@1.3.2 +ddp@1.4.1 +ddp-client@2.6.1 ddp-common@1.4.0 -ddp-server@2.5.0 -diff-sequence@1.1.1 +ddp-server@2.6.0 +diff-sequence@1.1.2 dynamic-import@0.7.2 -ecmascript@0.16.2 +ecmascript@0.16.4 ecmascript-runtime@0.8.0 ecmascript-runtime-client@0.12.1 ecmascript-runtime-server@0.11.0 -ejson@1.1.2 +ejson@1.1.3 es5-shim@4.8.0 -fetch@0.1.1 -geojson-utils@1.0.10 +fetch@0.1.2 +geojson-utils@1.0.11 hot-code-push@1.0.4 html-tools@1.1.3 htmljs@1.1.1 @@ -33,46 +33,46 @@ inter-process-messaging@0.1.1 launch-screen@1.3.0 lmieulet:meteor-coverage@4.1.0 logging@1.3.1 -meteor@1.10.0 +meteor@1.10.3 meteor-base@1.5.1 meteortesting:browser-tests@1.3.5 meteortesting:mocha@2.0.3 meteortesting:mocha-core@8.1.2 -minifier-css@1.6.0 -minifier-js@2.7.4 -minimongo@1.8.0 +minifier-css@1.6.2 +minifier-js@2.7.5 +minimongo@1.9.1 mobile-experience@1.1.0 mobile-status-bar@1.1.0 -modern-browsers@0.1.8 -modules@0.18.0 -modules-runtime@0.13.0 -mongo@1.15.0 +modern-browsers@0.1.9 +modules@0.19.0 +modules-runtime@0.13.1 +mongo@1.16.3 mongo-decimal@0.1.3 mongo-dev-server@1.1.0 mongo-id@1.0.8 -npm-mongo@4.3.1 +npm-mongo@4.12.1 ordered-dict@1.1.0 -promise@0.12.0 -random@1.2.0 +promise@0.12.2 +random@1.2.1 react-fast-refresh@0.2.3 react-meteor-data@2.5.1 -reactive-dict@1.3.0 -reactive-var@1.0.11 +reactive-dict@1.3.1 +reactive-var@1.0.12 reload@1.3.1 retry@1.1.0 rocketchat:streamer@1.1.0 routepolicy@1.1.1 -session@1.2.0 +session@1.2.1 shell-server@0.5.0 socket-stream-client@0.5.0 spacebars-compiler@1.3.1 -standard-minifier-css@1.8.1 -standard-minifier-js@2.8.0 +standard-minifier-css@1.8.3 +standard-minifier-js@2.8.1 static-html@1.3.2 templating-tools@1.2.2 -tracker@1.2.0 -typescript@4.5.4 -underscore@1.0.10 +tracker@1.2.1 +typescript@4.6.4 +underscore@1.0.11 url@1.3.2 -webapp@1.13.1 -webapp-hashing@1.1.0 +webapp@1.13.2 +webapp-hashing@1.1.1 From 49c6f530e6200dc61e67c0f83cd37c1984a8adc9 Mon Sep 17 00:00:00 2001 From: Anton Georgiev Date: Thu, 8 Dec 2022 19:14:16 +0000 Subject: [PATCH 38/43] chore: set nodejs to 14.21.1 and meteor to 2.9.0 --- .gitlab-ci.yml | 2 +- build/packages-template/bbb-html5-nodejs/build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 95d1459ef2..d2a28c0003 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,7 +11,7 @@ stages: # define which docker image to use for builds default: - image: gitlab.senfcall.de:5050/senfcall-public/docker-bbb-build:v2022-07-12 + image: gitlab.senfcall.de:5050/senfcall-public/docker-bbb-build:v2022-12-08-meteor-290 # This stage uses git to find out since when each package has been unmodified. # it then checks an API endpoint on the package server to find out for which of diff --git a/build/packages-template/bbb-html5-nodejs/build.sh b/build/packages-template/bbb-html5-nodejs/build.sh index e376f1b144..4f1cbeb983 100755 --- a/build/packages-template/bbb-html5-nodejs/build.sh +++ b/build/packages-template/bbb-html5-nodejs/build.sh @@ -7,7 +7,7 @@ PACKAGE=$(echo $TARGET | cut -d'_' -f1) VERSION=$(echo $TARGET | cut -d'_' -f2) DISTRO=$(echo $TARGET | cut -d'_' -f3) -NODE_VERSION="14.19.3" +NODE_VERSION="14.21.1" NODE_DIRNAME="node-v${NODE_VERSION}-linux-x64" # From b5374f5b2821a166817d210096f12f261633eeb1 Mon Sep 17 00:00:00 2001 From: Bohdan Zhemelinskyi Date: Thu, 8 Dec 2022 23:18:20 +0000 Subject: [PATCH 39/43] bump up tomcat --- bigbluebutton-web/gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bigbluebutton-web/gradle.properties b/bigbluebutton-web/gradle.properties index 535320c838..f9973a374d 100644 --- a/bigbluebutton-web/gradle.properties +++ b/bigbluebutton-web/gradle.properties @@ -3,4 +3,4 @@ gormVersion=7.1.0 gradleWrapperVersion=7.3.1 grailsGradlePluginVersion=5.0.0 groovyVersion=3.0.9 -tomcatEmbedVersion=9.0.62 +tomcatEmbedVersion=9.0.70 From 6a90c798d8c6ce8c4c9772e6ad1197f91074ca91 Mon Sep 17 00:00:00 2001 From: Anton Georgiev Date: Mon, 12 Dec 2022 14:13:02 -0500 Subject: [PATCH 40/43] chore: rephrase keep pushing layout --- bigbluebutton-html5/public/locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bigbluebutton-html5/public/locales/en.json b/bigbluebutton-html5/public/locales/en.json index 9c51f16cdc..dbffde4b99 100755 --- a/bigbluebutton-html5/public/locales/en.json +++ b/bigbluebutton-html5/public/locales/en.json @@ -1112,7 +1112,7 @@ "app.layout.modal.confirm": "Confirm", "app.layout.modal.cancel": "Cancel", "app.layout.modal.layoutLabel": "Select your layout", - "app.layout.modal.keepPushingLayoutLabel": "Keep pushing to everyone", + "app.layout.modal.keepPushingLayoutLabel": "Push layout to all", "app.layout.modal.pushLayoutLabel": "Push to everyone", "app.layout.modal.layoutToastLabel": "Layout settings changed", "app.layout.modal.layoutSingular": "Layout", From 0babed1a8d0c5d5c756210335a30a9cc0d39cd44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ram=C3=B3n=20Souza?= Date: Tue, 13 Dec 2022 13:17:59 -0300 Subject: [PATCH 41/43] chore: Set bigbluebutton release to 2.6.0-beta.3 --- bigbluebutton-config/bigbluebutton-release | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bigbluebutton-config/bigbluebutton-release b/bigbluebutton-config/bigbluebutton-release index fd18c4f523..45d7bbb69a 100644 --- a/bigbluebutton-config/bigbluebutton-release +++ b/bigbluebutton-config/bigbluebutton-release @@ -1 +1 @@ -BIGBLUEBUTTON_RELEASE=2.6.0-beta.2 +BIGBLUEBUTTON_RELEASE=2.6.0-beta.3 From 93cffede4ddb73ef2f98cf9d8fac0ca2ea97c921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ram=C3=B3n=20Souza?= Date: Wed, 14 Dec 2022 09:15:20 -0300 Subject: [PATCH 42/43] update probe-image-size --- bigbluebutton-html5/package-lock.json | 360 ++++---------------------- bigbluebutton-html5/package.json | 2 +- 2 files changed, 55 insertions(+), 307 deletions(-) diff --git a/bigbluebutton-html5/package-lock.json b/bigbluebutton-html5/package-lock.json index 5c59b7743a..2df18eb6e4 100644 --- a/bigbluebutton-html5/package-lock.json +++ b/bigbluebutton-html5/package-lock.json @@ -1677,6 +1677,7 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -1739,11 +1740,6 @@ } } }, - "any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" - }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -2027,19 +2023,6 @@ } } }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, "assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -2063,11 +2046,6 @@ "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, "attr-accept": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-1.1.3.tgz", @@ -2101,16 +2079,6 @@ "resolved": "https://registry.npmjs.org/autosize/-/autosize-4.0.4.tgz", "integrity": "sha512-5yxLQ22O0fCRGoxGfeLSNt3J8LB1v+umtpMnPW6XjkTWXKoN0AmXAIhelJcDtFT/Y/wYWmfE+oqU10Q0b8FhaQ==" }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" - }, - "aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" - }, "axe-core": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.1.tgz", @@ -2169,14 +2137,6 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "requires": { - "tweetnacl": "^0.14.3" - } - }, "bintrees": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz", @@ -2286,11 +2246,6 @@ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001332.tgz", "integrity": "sha512-10T30NYOEQtN6C11YGg411yebhvpnC6Z102+B95eAsN0oB6KUs01ivE8u+G6FMIRtIrVlYXhL+LUwQ3/hXwDWw==" }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, "chai": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", @@ -2421,14 +2376,6 @@ "text-hex": "1.0.x" } }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, "commander": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", @@ -2463,11 +2410,6 @@ "integrity": "sha512-Lb+/XT4WC4PaCWWtZpNPaXmjiNDUe5CJuUtbkMrIM1kb1T/jJoAIp+bkVP/r5lHzMr+ZAAF8XHp7+my6Ol0ysQ==", "dev": true }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, "cosmiconfig": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", @@ -2575,14 +2517,6 @@ "resolved": "https://registry.npmjs.org/darkreader/-/darkreader-4.9.46.tgz", "integrity": "sha512-K+MG74C8mGXvrsY47geAQdAbKU2mw8zVCa/WT4vtW3UDgzYCmthCcLnY0+FR3RQRMOyY2fULxqREZhfVQ346AA==" }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "^1.0.0" - } - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -2620,11 +2554,6 @@ "object-keys": "^1.0.12" } }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, "denque": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz", @@ -2695,15 +2624,6 @@ "domhandler": "^4.2.0" } }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, "electron-to-chromium": { "version": "1.4.117", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.117.tgz", @@ -3392,25 +3312,17 @@ "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", "integrity": "sha1-KueOhdmJQVhnCwPUe+wfA72Ru50=" }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true }, "fast-levenshtein": { "version": "2.0.6", @@ -3536,21 +3448,6 @@ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, "fraction.js": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", @@ -3627,14 +3524,6 @@ "get-intrinsic": "^1.1.1" } }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "^1.0.0" - } - }, "glob": { "version": "7.1.7", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", @@ -3675,20 +3564,6 @@ } } }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } - }, "hark": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/hark/-/hark-1.2.3.tgz", @@ -3767,16 +3642,6 @@ "entities": "^2.0.0" } }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, "human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -3859,6 +3724,14 @@ "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, "idb-keyval": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.0.tgz", @@ -4111,11 +3984,6 @@ "has-symbols": "^1.0.2" } }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, "is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -4131,11 +3999,6 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -4151,11 +4014,6 @@ "esprima": "^4.0.0" } }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -4173,15 +4031,11 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, - "json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" - }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -4189,11 +4043,6 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, "json5": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", @@ -4203,17 +4052,6 @@ "minimist": "^1.2.0" } }, - "jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, "jss": { "version": "10.9.0", "resolved": "https://registry.npmjs.org/jss/-/jss-10.9.0.tgz", @@ -4521,8 +4359,7 @@ "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, "lodash.truncate": { "version": "4.4.2", @@ -5402,19 +5239,6 @@ "picomatch": "^2.2.3" } }, - "mime-db": { - "version": "1.48.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", - "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==" - }, - "mime-types": { - "version": "2.1.31", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", - "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", - "requires": { - "mime-db": "1.48.0" - } - }, "mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -5457,10 +5281,30 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" + "needle": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz", + "integrity": "sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==", + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } }, "nice-try": { "version": "1.0.5", @@ -5513,11 +5357,6 @@ } } }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" - }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -5955,11 +5794,6 @@ "resolved": "https://registry.npmjs.org/perfect-freehand/-/perfect-freehand-1.2.0.tgz", "integrity": "sha512-h/0ikF1M3phW7CwpZ5MMvKnfpHficWoOEyr//KVNTxV4F6deRK1eYMtHyBKEAKFK0aXIEUK9oBvlF6PNXMDsAw==" }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -6024,15 +5858,12 @@ "dev": true }, "probe-image-size": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/probe-image-size/-/probe-image-size-4.1.1.tgz", - "integrity": "sha512-42LqKZqTLxH/UvAZ2/cKhAsR4G/Y6B7i7fI2qtQu9hRBK4YjS6gqO+QRtwTjvojUx4+/+JuOMzLoFyRecT9qRw==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/probe-image-size/-/probe-image-size-7.2.3.tgz", + "integrity": "sha512-HubhG4Rb2UH8YtV4ba0Vp5bQ7L78RTONYu/ujmCu5nBI8wGv24s4E9xSKBi0N1MowRpxk76pFCpJtW0KPzOK0w==", "requires": { - "any-promise": "^1.3.0", - "deepmerge": "^4.0.0", - "inherits": "^2.0.3", - "next-tick": "^1.0.0", - "request": "^2.83.0", + "lodash.merge": "^4.6.2", + "needle": "^2.5.2", "stream-parser": "~0.3.1" } }, @@ -6060,11 +5891,6 @@ "react-is": "^16.13.1" } }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" - }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -6078,12 +5904,8 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true }, "queue": { "version": "6.0.2", @@ -6408,33 +6230,6 @@ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, "require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -6538,6 +6333,11 @@ } } }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, "scheduler": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", @@ -6728,22 +6528,6 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, "stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -6752,7 +6536,7 @@ "stream-parser": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/stream-parser/-/stream-parser-0.3.1.tgz", - "integrity": "sha1-FhhUhpRCACGhGC/wrxkRwSl2F3M=", + "integrity": "sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==", "requires": { "debug": "2" } @@ -7090,15 +6874,6 @@ "is-number": "^7.0.0" } }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, "triple-beam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", @@ -7121,19 +6896,6 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" - }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -7165,6 +6927,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, "requires": { "punycode": "^2.1.0" } @@ -7206,11 +6969,6 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - }, "v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", @@ -7227,16 +6985,6 @@ "spdx-expression-parse": "^3.0.0" } }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, "warning": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", diff --git a/bigbluebutton-html5/package.json b/bigbluebutton-html5/package.json index 28e7d28bd6..7f1cc4bec3 100755 --- a/bigbluebutton-html5/package.json +++ b/bigbluebutton-html5/package.json @@ -56,7 +56,7 @@ "meteor-node-stubs": "^1.2.1", "postcss-nested": "^5.0.6", "mobx": "6.4.2", - "probe-image-size": "^4.1.1", + "probe-image-size": "^7.2.3", "prom-client": "^13.2.0", "prop-types": "^15.8.1", "queue": "^6.0.2", From 8ad319fb605d4c98169d8c99852c2f189496aabe Mon Sep 17 00:00:00 2001 From: Localization Server <[bigbluebuttonlocalizeserver@googlegroups.com](mailto:bigbluebuttonlocalizeserver@googlegroups.com> Date: Wed, 14 Dec 2022 09:44:06 -0300 Subject: [PATCH 43/43] chore: Pulled the latest 2.6 HTML5 locales from Transifex --- bigbluebutton-html5/public/locales/de.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bigbluebutton-html5/public/locales/de.json b/bigbluebutton-html5/public/locales/de.json index 1259e8b3c8..b445c0e0e6 100644 --- a/bigbluebutton-html5/public/locales/de.json +++ b/bigbluebutton-html5/public/locales/de.json @@ -654,7 +654,7 @@ "app.toast.meetingMuteOn.label": "Alle Teilnehmer wurden stummgeschaltet", "app.toast.meetingMuteOff.label": "Konferenz-Stummschaltung ausgeschaltet", "app.toast.setEmoji.raiseHand": "Sie haben Ihre Hand gehoben", - "app.toast.setEmoji.lowerHand": "Habe meine Hand gesenkt", + "app.toast.setEmoji.lowerHand": "Ihre Hand wurde gesenkt", "app.toast.promotedLabel": "Zur Moderation ernannt worden", "app.toast.demotedLabel": "Nun wieder in der Rolle eine:r Teilnehmer:in", "app.notification.recordingStart": "Diese Konferenz wird jetzt aufgezeichnet",