Merge remote-tracking branch 'upstream/v2.5.x-release' into html5-show-ejectedReason
This commit is contained in:
commit
89ea5d07d3
19
.github/workflows/automated-tests.yml
vendored
19
.github/workflows/automated-tests.yml
vendored
@ -112,7 +112,7 @@ jobs:
|
||||
run: |
|
||||
sudo sh -c '
|
||||
cd /root/ && wget -q https://ubuntu.bigbluebutton.org/bbb-install-2.5.sh -O bbb-install.sh
|
||||
cat bbb-install.sh | sed "s|> /etc/apt/sources.list.d/bigbluebutton.list||g" | bash -s -- -v focal-25-dev -s bbb-ci.test -d /certs/
|
||||
cat bbb-install.sh | sed "s|> /etc/apt/sources.list.d/bigbluebutton.list||g" | bash -s -- -v focal-25-dev -s bbb-ci.test -j -d /certs/
|
||||
bbb-conf --salt bbbci
|
||||
echo "NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/bbb-dev/bbb-dev-ca.crt" >> /usr/share/meteor/bundle/bbb-html5-with-roles.conf
|
||||
bbb-conf --restart
|
||||
@ -132,7 +132,22 @@ jobs:
|
||||
ACTIONS_RUNNER_DEBUG: true
|
||||
BBB_URL: https://bbb-ci.test/bigbluebutton/api
|
||||
BBB_SECRET: bbbci
|
||||
run: npm run test-ci
|
||||
run: npm run test-chromium-ci
|
||||
- name: Run Firefox tests
|
||||
working-directory: ./bigbluebutton-tests/playwright
|
||||
if: ${{ contains(github.event.pull_request.labels.*.name, 'test Firefox')
|
||||
|| contains(github.event.pull_request.labels.*.name, 'Test Firefox') }}
|
||||
env:
|
||||
NODE_EXTRA_CA_CERTS: /usr/local/share/ca-certificates/bbb-dev/bbb-dev-ca.crt
|
||||
ACTIONS_RUNNER_DEBUG: true
|
||||
BBB_URL: https://bbb-ci.test/bigbluebutton/api
|
||||
BBB_SECRET: bbbci
|
||||
# patch playwright's firefox so that it uses the system's root certificate authority
|
||||
run: |
|
||||
sh -c '
|
||||
find $HOME/.cache/ms-playwright -name libnssckbi.so -exec rm {} \; -exec ln -s /usr/lib/x86_64-linux-gnu/pkcs11/p11-kit-trust.so {} \;
|
||||
npm run test-firefox-ci
|
||||
'
|
||||
- if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
|
@ -24,7 +24,7 @@ trait PresentationPageCountErrorPubMsgHdlr {
|
||||
liveMeeting.props.meetingProp.intId, msg.header.userId
|
||||
)
|
||||
|
||||
val body = PresentationPageCountErrorEvtMsgBody(msg.body.podId, msg.body.messageKey, msg.body.code, msg.body.presentationId, msg.body.numberOfPages, msg.body.maxNumberPages, msg.body.presName)
|
||||
val body = PresentationPageCountErrorEvtMsgBody(msg.body.podId, msg.body.messageKey, msg.body.code, msg.body.presentationId, msg.body.numberOfPages, msg.body.maxNumberPages, msg.body.presName, msg.body.temporaryPresentationId)
|
||||
val event = PresentationPageCountErrorEvtMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
bus.outGW.send(msgEvent)
|
||||
|
@ -19,7 +19,7 @@ trait PresentationUploadTokenReqMsgHdlr extends RightsManagementTrait {
|
||||
val envelope = BbbCoreEnvelope(PresentationUploadTokenPassRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(PresentationUploadTokenPassRespMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
|
||||
|
||||
val body = PresentationUploadTokenPassRespMsgBody(msg.body.podId, token, msg.body.filename, msg.body.tmpPresId)
|
||||
val body = PresentationUploadTokenPassRespMsgBody(msg.body.podId, token, msg.body.filename, msg.body.temporaryPresentationId)
|
||||
val event = PresentationUploadTokenPassRespMsg(header, body)
|
||||
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
|
||||
bus.outGW.send(msgEvent)
|
||||
|
@ -13,7 +13,7 @@ case class RemovePresentationPodPubMsgBody(podId: String)
|
||||
|
||||
object PresentationUploadTokenReqMsg { val NAME = "PresentationUploadTokenReqMsg" }
|
||||
case class PresentationUploadTokenReqMsg(header: BbbClientMsgHeader, body: PresentationUploadTokenReqMsgBody) extends StandardMsg
|
||||
case class PresentationUploadTokenReqMsgBody(podId: String, filename: String, tmpPresId: String)
|
||||
case class PresentationUploadTokenReqMsgBody(podId: String, filename: String, temporaryPresentationId: String)
|
||||
|
||||
object GetAllPresentationPodsReqMsg { val NAME = "GetAllPresentationPodsReqMsg" }
|
||||
case class GetAllPresentationPodsReqMsg(header: BbbClientMsgHeader, body: GetAllPresentationPodsReqMsgBody) extends StandardMsg
|
||||
@ -65,7 +65,7 @@ case class PresentationPageCountErrorSysPubMsg(
|
||||
body: PresentationPageCountErrorSysPubMsgBody
|
||||
) extends StandardMsg
|
||||
case class PresentationPageCountErrorSysPubMsgBody(podId: String, messageKey: String, code: String, presentationId: String,
|
||||
numberOfPages: Int, maxNumberPages: Int, presName: String)
|
||||
numberOfPages: Int, maxNumberPages: Int, presName: String, temporaryPresentationId: String)
|
||||
|
||||
object PdfConversionInvalidErrorSysPubMsg { val NAME = "PdfConversionInvalidErrorSysPubMsg" }
|
||||
case class PdfConversionInvalidErrorSysPubMsg(
|
||||
@ -182,7 +182,7 @@ case class PdfConversionInvalidErrorEvtMsgBody(podId: String, messageKey: String
|
||||
|
||||
object PresentationUploadTokenPassRespMsg { val NAME = "PresentationUploadTokenPassRespMsg" }
|
||||
case class PresentationUploadTokenPassRespMsg(header: BbbClientMsgHeader, body: PresentationUploadTokenPassRespMsgBody) extends StandardMsg
|
||||
case class PresentationUploadTokenPassRespMsgBody(podId: String, authzToken: String, filename: String, tmpPresId: String)
|
||||
case class PresentationUploadTokenPassRespMsgBody(podId: String, authzToken: String, filename: String, temporaryPresentationId: String)
|
||||
|
||||
object PresentationUploadTokenFailRespMsg { val NAME = "PresentationUploadTokenFailRespMsg" }
|
||||
case class PresentationUploadTokenFailRespMsg(header: BbbClientMsgHeader, body: PresentationUploadTokenFailRespMsgBody) extends StandardMsg
|
||||
@ -194,7 +194,7 @@ case class PresentationConversionUpdateEvtMsgBody(podId: String, messageKey: Str
|
||||
|
||||
object PresentationPageCountErrorEvtMsg { val NAME = "PresentationPageCountErrorEvtMsg" }
|
||||
case class PresentationPageCountErrorEvtMsg(header: BbbClientMsgHeader, body: PresentationPageCountErrorEvtMsgBody) extends BbbCoreMsg
|
||||
case class PresentationPageCountErrorEvtMsgBody(podId: String, messageKey: String, code: String, presentationId: String, numberOfPages: Int, maxNumberPages: Int, presName: String)
|
||||
case class PresentationPageCountErrorEvtMsgBody(podId: String, messageKey: String, code: String, presentationId: String, numberOfPages: Int, maxNumberPages: Int, presName: String, temporaryPresentationId: String)
|
||||
|
||||
object PresentationPageGeneratedEvtMsg { val NAME = "PresentationPageGeneratedEvtMsg" }
|
||||
case class PresentationPageGeneratedEvtMsg(header: BbbClientMsgHeader, body: PresentationPageGeneratedEvtMsgBody) extends BbbCoreMsg
|
||||
|
@ -927,6 +927,13 @@ public class MeetingService implements MessageListener {
|
||||
User user = new User(message.userId, message.externalUserId,
|
||||
message.name, message.role, message.avatarURL, message.guest, message.guestStatus,
|
||||
message.clientType);
|
||||
|
||||
if(m.getMaxUsers() > 0 && m.getUsers().size() >= m.getMaxUsers()) {
|
||||
m.removeEnteredUser(user.getInternalUserId());
|
||||
gw.ejectDuplicateUser(message.meetingId, user.getInternalUserId(), user.getFullname(), user.getExternalUserId());
|
||||
return;
|
||||
}
|
||||
|
||||
m.userJoined(user);
|
||||
m.setGuestStatusWithId(user.getInternalUserId(), message.guestStatus);
|
||||
UserSession userSession = getUserSessionWithUserId(user.getInternalUserId());
|
||||
|
@ -24,7 +24,7 @@ public class GuestPolicyValidator implements ConstraintValidator<GuestPolicyCons
|
||||
MeetingService meetingService = ServiceUtils.getMeetingService();
|
||||
UserSession userSession = meetingService.getUserSessionWithAuthToken(sessionToken);
|
||||
|
||||
if(userSession == null || userSession.guestStatus.equals(GuestPolicy.DENY)) {
|
||||
if(userSession == null || !userSession.guestStatus.equals(GuestPolicy.ALLOW)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -39,9 +39,8 @@ public class MaxParticipantsValidator implements ConstraintValidator<MaxParticip
|
||||
boolean rejoin = meeting.getUserById(userSession.internalUserId) != null;
|
||||
boolean reenter = meeting.getEnteredUserById(userSession.internalUserId) != null;
|
||||
int joinedUsers = meeting.getUsers().size();
|
||||
int enteredUsers = meeting.getEnteredUsers().size();
|
||||
|
||||
boolean reachedMax = (joinedUsers + enteredUsers) >= maxParticipants;
|
||||
boolean reachedMax = joinedUsers >= maxParticipants;
|
||||
if(enabled && !rejoin && !reenter && reachedMax) {
|
||||
return false;
|
||||
}
|
||||
|
@ -206,7 +206,8 @@ public class PresentationFileProcessor {
|
||||
DocPageCountFailed progress = new DocPageCountFailed(pres.getPodId(), pres.getMeetingId(),
|
||||
pres.getId(), pres.getId(),
|
||||
pres.getName(), "notUsedYet", "notUsedYet",
|
||||
pres.isDownloadable(), pres.isRemovable(), ConversionMessageConstants.PAGE_COUNT_FAILED_KEY);
|
||||
pres.isDownloadable(), pres.isRemovable(), ConversionMessageConstants.PAGE_COUNT_FAILED_KEY,
|
||||
pres.getTemporaryPresentationId());
|
||||
|
||||
notifier.sendDocConversionProgress(progress);
|
||||
|
||||
@ -232,7 +233,7 @@ public class PresentationFileProcessor {
|
||||
pres.getId(), pres.getId(),
|
||||
pres.getName(), "notUsedYet", "notUsedYet",
|
||||
pres.isDownloadable(), pres.isRemovable(), ConversionMessageConstants.PAGE_COUNT_EXCEEDED_KEY,
|
||||
e.getPageCount(), e.getMaxNumberOfPages());
|
||||
e.getPageCount(), e.getMaxNumberOfPages(), pres.getTemporaryPresentationId());
|
||||
|
||||
notifier.sendDocConversionProgress(progress);
|
||||
}
|
||||
|
@ -13,11 +13,12 @@ public class DocPageCountExceeded implements IDocConversionMsg {
|
||||
public final String key;
|
||||
public final Integer numPages;
|
||||
public final Integer maxNumPages;
|
||||
public final String temporaryPresentationId;
|
||||
|
||||
public DocPageCountExceeded(String podId, String meetingId, String presId, String presInstance,
|
||||
String filename, String uploaderId, String authzToken,
|
||||
Boolean downloadable, Boolean removable, String key,
|
||||
Integer numPages, Integer maxNumPages) {
|
||||
Integer numPages, Integer maxNumPages, String temporaryPresentationId) {
|
||||
this.podId = podId;
|
||||
this.meetingId = meetingId;
|
||||
this.presId = presId;
|
||||
@ -30,5 +31,6 @@ public class DocPageCountExceeded implements IDocConversionMsg {
|
||||
this.key = key;
|
||||
this.numPages = numPages;
|
||||
this.maxNumPages = maxNumPages;
|
||||
this.temporaryPresentationId = temporaryPresentationId;
|
||||
}
|
||||
}
|
||||
|
@ -11,10 +11,11 @@ public class DocPageCountFailed implements IDocConversionMsg {
|
||||
public final Boolean downloadable;
|
||||
public final Boolean removable;
|
||||
public final String key;
|
||||
public final String temporaryPresentationId;
|
||||
|
||||
public DocPageCountFailed(String podId, String meetingId, String presId, String presInstance,
|
||||
String filename, String uploaderId, String authzToken,
|
||||
Boolean downloadable, Boolean removable, String key) {
|
||||
Boolean downloadable, Boolean removable, String key, String temporaryPresentationId) {
|
||||
this.podId = podId;
|
||||
this.meetingId = meetingId;
|
||||
this.presId = presId;
|
||||
@ -25,5 +26,6 @@ public class DocPageCountFailed implements IDocConversionMsg {
|
||||
this.downloadable = downloadable;
|
||||
this.removable = removable;
|
||||
this.key = key;
|
||||
this.temporaryPresentationId = temporaryPresentationId;
|
||||
}
|
||||
}
|
||||
|
@ -193,7 +193,7 @@ object MsgBuilder {
|
||||
val header = BbbClientMsgHeader(PresentationPageCountErrorSysPubMsg.NAME, msg.meetingId, msg.authzToken)
|
||||
|
||||
val body = PresentationPageCountErrorSysPubMsgBody(podId = msg.podId, messageKey = msg.key,
|
||||
code = msg.key, msg.presId, 0, 0, msg.filename)
|
||||
code = msg.key, msg.presId, 0, 0, msg.filename, msg.temporaryPresentationId)
|
||||
val req = PresentationPageCountErrorSysPubMsg(header, body)
|
||||
BbbCommonEnvCoreMsg(envelope, req)
|
||||
}
|
||||
@ -204,7 +204,7 @@ object MsgBuilder {
|
||||
val header = BbbClientMsgHeader(PresentationPageCountErrorSysPubMsg.NAME, msg.meetingId, msg.authzToken)
|
||||
|
||||
val body = PresentationPageCountErrorSysPubMsgBody(podId = msg.podId, messageKey = msg.key,
|
||||
code = msg.key, msg.presId, msg.numPages.intValue(), msg.maxNumPages.intValue(), msg.filename)
|
||||
code = msg.key, msg.presId, msg.numPages.intValue(), msg.maxNumPages.intValue(), msg.filename, msg.temporaryPresentationId)
|
||||
val req = PresentationPageCountErrorSysPubMsg(header, body)
|
||||
BbbCommonEnvCoreMsg(envelope, req)
|
||||
}
|
||||
|
@ -1,11 +1,9 @@
|
||||
FROM openjdk:11-jre-bullseye
|
||||
FROM openjdk:17-slim-bullseye
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
|
||||
RUN echo "deb http://deb.debian.org/debian bullseye-backports main" >> /etc/apt/sources.list
|
||||
RUN apt update && apt -y install locales-all fontconfig libxt6 libxrender1
|
||||
RUN apt update && apt -y install -t \
|
||||
bullseye-backports \
|
||||
libreoffice \
|
||||
RUN apt update && apt -y install libreoffice \
|
||||
&& rm -f \
|
||||
/usr/share/java/ant-apache-log4j-1.10.9.jar \
|
||||
/usr/share/java/log4j-1.2-1.2.17.jar /usr/share/java/log4j-1.2.jar \
|
||||
|
@ -1 +1 @@
|
||||
BIGBLUEBUTTON_RELEASE=2.5.5
|
||||
BIGBLUEBUTTON_RELEASE=2.5.6
|
||||
|
@ -30,15 +30,19 @@ fi
|
||||
|
||||
BBB_WEB_ETC_CONFIG=/etc/bigbluebutton/bbb-web.properties
|
||||
|
||||
# We'll create a newline file to ensure bigbluebutton.properties ends with a newline
|
||||
tmpfile=$(mktemp /tmp/carriage-return.XXXXXX)
|
||||
echo "\n" > $tmpfile
|
||||
|
||||
PROTOCOL=http
|
||||
if [ -f $SERVLET_DIR/WEB-INF/classes/bigbluebutton.properties ]; then
|
||||
SERVER_URL=$(cat $SERVLET_DIR/WEB-INF/classes/bigbluebutton.properties $BBB_WEB_ETC_CONFIG | grep -v '#' | sed -n '/^bigbluebutton.web.serverURL/{s/.*\///;p}' | tail -n 1)
|
||||
if cat $SERVLET_DIR/WEB-INF/classes/bigbluebutton.properties $BBB_WEB_ETC_CONFIG | grep -v '#' | grep ^bigbluebutton.web.serverURL | tail -n 1 | grep -q https; then
|
||||
SERVER_URL=$(cat $SERVLET_DIR/WEB-INF/classes/bigbluebutton.properties $tmpfile $BBB_WEB_ETC_CONFIG | grep -v '#' | sed -n '/^bigbluebutton.web.serverURL/{s/.*\///;p}' | tail -n 1)
|
||||
if cat $SERVLET_DIR/WEB-INF/classes/bigbluebutton.properties $tmpfile $BBB_WEB_ETC_CONFIG | grep -v '#' | grep ^bigbluebutton.web.serverURL | tail -n 1 | grep -q https; then
|
||||
PROTOCOL=https
|
||||
fi
|
||||
fi
|
||||
|
||||
HOST=$(cat $SERVLET_DIR/WEB-INF/classes/bigbluebutton.properties $BBB_WEB_ETC_CONFIG | grep -v '#' | sed -n '/^bigbluebutton.web.serverURL/{s/.*\///;p}' | tail -n 1)
|
||||
HOST=$(cat $SERVLET_DIR/WEB-INF/classes/bigbluebutton.properties $tmpfile $BBB_WEB_ETC_CONFIG | grep -v '#' | sed -n '/^bigbluebutton.web.serverURL/{s/.*\///;p}' | tail -n 1)
|
||||
|
||||
HTML5_CONFIG=/usr/share/meteor/bundle/programs/server/assets/app/config/settings.yml
|
||||
BBB_WEB_CONFIG=$SERVLET_DIR/WEB-INF/classes/bigbluebutton.properties
|
||||
|
@ -418,15 +418,15 @@ start_bigbluebutton () {
|
||||
|
||||
if systemctl list-units --full -all | grep -q $TOMCAT_USER.service; then
|
||||
TOMCAT_SERVICE=$TOMCAT_USER
|
||||
fi
|
||||
|
||||
systemctl start $TOMCAT_SERVICE || {
|
||||
echo
|
||||
echo "# Warning: $TOMCAT_SERVICE could not be started. Please, check BBB-LTI or BBB-Demo."
|
||||
echo "# Run the command:"
|
||||
echo "# sudo journalctl -u $TOMCAT_SERVICE"
|
||||
echo "# To better understand the ERROR"
|
||||
}
|
||||
[ -z "$TOMCAT_SERVICE" ] || systemctl start $TOMCAT_SERVICE || {
|
||||
echo
|
||||
echo "# Warning: $TOMCAT_SERVICE could not be started. Please, check BBB-LTI or BBB-Demo."
|
||||
echo "# Run the command:"
|
||||
echo "# sudo journalctl -u $TOMCAT_SERVICE"
|
||||
echo "# To better understand the ERROR"
|
||||
}
|
||||
fi
|
||||
|
||||
systemctl start nginx freeswitch $REDIS_SERVICE bbb-apps-akka bbb-fsesl-akka bbb-rap-resque-worker bbb-rap-starter.service bbb-rap-caption-inbox.service $HTML5 $WEBHOOKS $ETHERPAD $PADS $BBB_WEB $BBB_LTI
|
||||
|
||||
@ -1154,16 +1154,19 @@ check_state() {
|
||||
|
||||
if bbb-conf --status | grep -q inactive; then
|
||||
|
||||
if bbb-conf --status | grep -q tomcat9; then
|
||||
echo "# Warning: $TOMCAT_SERVICE is not started correctly"
|
||||
echo "#"
|
||||
echo "# $(bbb-conf --status | grep inactive | grep $TOMCAT_SERVICE)"
|
||||
echo "#"
|
||||
if systemctl list-units --full -all | grep -q $TOMCAT_USER.service; then
|
||||
TOMCAT_SERVICE=$TOMCAT_USER
|
||||
|
||||
if bbb-conf --status | grep -q inactive | grep -q $TOMCAT_SERVICE; then
|
||||
echo "# Warning: $TOMCAT_SERVICE is not started correctly"
|
||||
echo "#"
|
||||
fi
|
||||
fi
|
||||
if bbb-conf --status | grep inactive | grep -vq tomcat9; then
|
||||
|
||||
if bbb-conf --status | grep inactive; then
|
||||
echo "# Error: Detected some processes have not started correctly"
|
||||
echo "#"
|
||||
echo "# $(bbb-conf --status | grep inactive | grep -v $TOMCAT_SERVICE)"
|
||||
echo "# $(bbb-conf --status | grep inactive)"
|
||||
echo "#"
|
||||
fi
|
||||
fi
|
||||
|
@ -4,7 +4,7 @@
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-Light.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-Light.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@ -13,7 +13,7 @@
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-Light.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-Light.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@ -22,7 +22,7 @@
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-Light.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-Light.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
||||
/* vietnamese */
|
||||
@ -31,7 +31,7 @@
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro'), local('SourceSansPro-Regular'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-Regular.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-Regular.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@ -40,7 +40,7 @@
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro'), local('SourceSansPro-Regular'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-Regular.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-Regular.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@ -49,7 +49,7 @@
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro'), local('SourceSansPro-Regular'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-Regular.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-Regular.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
||||
/* vietnamese */
|
||||
@ -58,7 +58,7 @@
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro Semibold'), local('SourceSansPro-Semibold'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-Semibold.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-Semibold.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@ -67,7 +67,7 @@
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro Semibold'), local('SourceSansPro-Semibold'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-Semibold.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-Semibold.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@ -76,7 +76,7 @@
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro Semibold'), local('SourceSansPro-Semibold'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-Semibold.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-Semibold.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
||||
/* vietnamese */
|
||||
@ -85,7 +85,7 @@
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-Bold.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-Bold.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@ -94,7 +94,7 @@
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-Bold.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-Bold.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@ -103,7 +103,7 @@
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-Bold.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-Bold.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
||||
/* vietnamese */
|
||||
@ -112,7 +112,7 @@
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light Italic'), local('SourceSansPro-LightIt'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-LightItalic.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-LightItalic.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@ -121,7 +121,7 @@
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light Italic'), local('SourceSansPro-LightIt'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-LightItalic.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-LightItalic.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@ -130,7 +130,7 @@
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light Italic'), local('SourceSansPro-LightIt'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-LightItalic.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-LightItalic.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
||||
/* vietnamese */
|
||||
@ -139,7 +139,7 @@
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Italic'), local('SourceSansPro-It'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-Italic.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-Italic.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@ -148,7 +148,7 @@
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Italic'), local('SourceSansPro-It'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-Italic.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-Italic.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@ -157,7 +157,7 @@
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Italic'), local('SourceSansPro-It'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-Italic.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-Italic.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
||||
/* vietnamese */
|
||||
@ -166,7 +166,7 @@
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro Semibold Italic'), local('SourceSansPro-SemiboldIt'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-SemiboldItalic.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-SemiboldItalic.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@ -175,7 +175,7 @@
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro Semibold Italic'), local('SourceSansPro-SemiboldIt'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-SemiboldItalic.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-SemiboldItalic.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@ -184,7 +184,7 @@
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro Semibold Italic'), local('SourceSansPro-SemiboldIt'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-SemiboldItalic.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-SemiboldItalic.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
||||
/* vietnamese */
|
||||
@ -193,7 +193,7 @@
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold Italic'), local('SourceSansPro-BoldIt'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-BoldItalic.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-BoldItalic.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@ -202,7 +202,7 @@
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold Italic'), local('SourceSansPro-BoldIt'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-BoldItalic.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-BoldItalic.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@ -211,6 +211,6 @@
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold Italic'), local('SourceSansPro-BoldIt'),
|
||||
url('fonts/SourceSansPro/SourceSansPro-BoldItalic.woff') format('woff');
|
||||
url('fonts/SourceSansPro/SourceSansPro-BoldItalic.woff?v=VERSION') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
||||
|
@ -19,6 +19,22 @@ function breakouts() {
|
||||
const User = Users.findOne({ userId, meetingId }, { fields: { role: 1 } });
|
||||
Logger.debug('Publishing Breakouts', { meetingId, userId });
|
||||
|
||||
const fields = {
|
||||
fields: {
|
||||
[`url_${userId}`]: 1,
|
||||
breakoutId: 1,
|
||||
externalId: 1,
|
||||
freeJoin: 1,
|
||||
isDefaultName: 1,
|
||||
joinedUsers: 1,
|
||||
name: 1,
|
||||
parentMeetingId: 1,
|
||||
sequence: 1,
|
||||
shortName: 1,
|
||||
timeRemaining: 1,
|
||||
},
|
||||
};
|
||||
|
||||
if (!!User && User.role === ROLE_MODERATOR) {
|
||||
const presenterSelector = {
|
||||
$or: [
|
||||
@ -39,7 +55,7 @@ function breakouts() {
|
||||
return condition;
|
||||
};
|
||||
publicationSafeGuard(comparisonFunc, this);
|
||||
return Breakouts.find(presenterSelector);
|
||||
return Breakouts.find(presenterSelector, fields);
|
||||
}
|
||||
|
||||
const selector = {
|
||||
@ -58,22 +74,6 @@ function breakouts() {
|
||||
],
|
||||
};
|
||||
|
||||
const fields = {
|
||||
fields: {
|
||||
[`url_${userId}`]: 1,
|
||||
breakoutId: 1,
|
||||
externalId: 1,
|
||||
freeJoin: 1,
|
||||
isDefaultName: 1,
|
||||
joinedUsers: 1,
|
||||
name: 1,
|
||||
parentMeetingId: 1,
|
||||
sequence: 1,
|
||||
shortName: 1,
|
||||
timeRemaining: 1,
|
||||
},
|
||||
};
|
||||
|
||||
return Breakouts.find(selector, fields);
|
||||
}
|
||||
|
||||
|
@ -7,20 +7,20 @@ export default function handlePresentationUploadTokenPass({ body, header }, meet
|
||||
check(body, Object);
|
||||
|
||||
const { userId } = header;
|
||||
const { podId, authzToken, filename, tmpPresId } = body;
|
||||
const { podId, authzToken, filename, temporaryPresentationId } = body;
|
||||
|
||||
check(userId, String);
|
||||
check(podId, String);
|
||||
check(authzToken, String);
|
||||
check(filename, String);
|
||||
check(tmpPresId, String)
|
||||
check(temporaryPresentationId, String)
|
||||
|
||||
const selector = {
|
||||
meetingId,
|
||||
podId,
|
||||
userId,
|
||||
filename,
|
||||
tmpPresId,
|
||||
temporaryPresentationId,
|
||||
};
|
||||
|
||||
const modifier = {
|
||||
@ -29,7 +29,7 @@ export default function handlePresentationUploadTokenPass({ body, header }, meet
|
||||
userId,
|
||||
filename,
|
||||
authzToken,
|
||||
tmpPresId,
|
||||
temporaryPresentationId,
|
||||
failed: false,
|
||||
used: false,
|
||||
};
|
||||
|
@ -3,7 +3,7 @@ import { check } from 'meteor/check';
|
||||
import { extractCredentials } from '/imports/api/common/server/helpers';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
|
||||
export default function requestPresentationUploadToken(podId, filename, tmpPresId) {
|
||||
export default function requestPresentationUploadToken(podId, filename, temporaryPresentationId) {
|
||||
const REDIS_CONFIG = Meteor.settings.private.redis;
|
||||
const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
|
||||
const EVENT_NAME = 'PresentationUploadTokenReqMsg';
|
||||
@ -15,12 +15,12 @@ export default function requestPresentationUploadToken(podId, filename, tmpPresI
|
||||
check(requesterUserId, String);
|
||||
check(podId, String);
|
||||
check(filename, String);
|
||||
check(tmpPresId, String);
|
||||
check(temporaryPresentationId, String);
|
||||
|
||||
const payload = {
|
||||
podId,
|
||||
filename,
|
||||
tmpPresId
|
||||
temporaryPresentationId
|
||||
};
|
||||
|
||||
RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
|
||||
|
@ -4,7 +4,7 @@ import PresentationUploadToken from '/imports/api/presentation-upload-token';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import AuthTokenValidation, { ValidationStates } from '/imports/api/auth-token-validation';
|
||||
|
||||
function presentationUploadToken(podId, filename, tmpPresId) {
|
||||
function presentationUploadToken(podId, filename, temporaryPresentationId) {
|
||||
const tokenValidation = AuthTokenValidation.findOne({ connectionId: this.connection.id });
|
||||
|
||||
if (!tokenValidation || tokenValidation.validationStatus !== ValidationStates.VALIDATED) {
|
||||
@ -16,14 +16,14 @@ function presentationUploadToken(podId, filename, tmpPresId) {
|
||||
|
||||
check(podId, String);
|
||||
check(filename, String);
|
||||
check(tmpPresId, String);
|
||||
check(temporaryPresentationId, String);
|
||||
|
||||
const selector = {
|
||||
meetingId,
|
||||
podId,
|
||||
userId,
|
||||
filename,
|
||||
tmpPresId,
|
||||
temporaryPresentationId,
|
||||
};
|
||||
|
||||
Logger.debug('Publishing PresentationUploadToken', { meetingId, userId });
|
||||
|
@ -25,6 +25,7 @@ export default function handlePresentationConversionUpdate({ body }, meetingId)
|
||||
|
||||
const {
|
||||
presentationId, podId, messageKey: status, presName: presentationName,
|
||||
temporaryPresentationId
|
||||
} = body;
|
||||
|
||||
check(meetingId, String);
|
||||
@ -73,9 +74,17 @@ export default function handlePresentationConversionUpdate({ body }, meetingId)
|
||||
id: presentationId ?? body.presentationToken,
|
||||
};
|
||||
|
||||
const modifier = {
|
||||
$set: Object.assign({ meetingId, podId }, statusModifier),
|
||||
};
|
||||
let modifier
|
||||
if (temporaryPresentationId){
|
||||
modifier = {
|
||||
$set: Object.assign({ meetingId, podId, temporaryPresentationId, }, statusModifier),
|
||||
};
|
||||
} else {
|
||||
modifier = {
|
||||
$set: Object.assign({ meetingId, podId }, statusModifier),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
const { insertedId } = Presentations.upsert(selector, modifier);
|
||||
|
@ -17,6 +17,7 @@ const propTypes = {
|
||||
|
||||
const DEFAULT_LANGUAGE = Meteor.settings.public.app.defaultSettings.application.fallbackLocale;
|
||||
const CLIENT_VERSION = Meteor.settings.public.app.html5ClientBuild;
|
||||
const FALLBACK_ON_EMPTY_STRING = Meteor.settings.public.app.fallbackOnEmptyLocaleString;
|
||||
|
||||
const RTL_LANGUAGES = ['ar', 'dv', 'fa', 'he'];
|
||||
const LARGE_FONT_LANGUAGES = ['te', 'km'];
|
||||
@ -163,7 +164,7 @@ class IntlStartup extends Component {
|
||||
|
||||
{normalizedLocale
|
||||
&& (
|
||||
<IntlProvider locale={normalizedLocale} messages={messages}>
|
||||
<IntlProvider fallbackOnEmptyString={FALLBACK_ON_EMPTY_STRING} locale={normalizedLocale} messages={messages}>
|
||||
{children}
|
||||
</IntlProvider>
|
||||
)
|
||||
|
@ -34,6 +34,26 @@ process.on('uncaughtException', (err) => {
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
const formatMemoryUsage = (data) => `${Math.round(data / 1024 / 1024 * 100) / 100} MB`
|
||||
|
||||
const serverHealth = () => {
|
||||
const memoryData = process.memoryUsage();
|
||||
const memoryUsage = {
|
||||
rss: formatMemoryUsage(memoryData.rss),
|
||||
heapTotal: formatMemoryUsage(memoryData.heapTotal),
|
||||
heapUsed: formatMemoryUsage(memoryData.heapUsed),
|
||||
external: formatMemoryUsage(memoryData.external),
|
||||
}
|
||||
|
||||
const cpuData = process.cpuUsage();
|
||||
const cpuUsage = {
|
||||
system: formatMemoryUsage(cpuData.system),
|
||||
user: formatMemoryUsage(cpuData.user),
|
||||
}
|
||||
|
||||
Logger.info('Server health ', {memoryUsage, cpuUsage});
|
||||
};
|
||||
|
||||
Meteor.startup(() => {
|
||||
const APP_CONFIG = Meteor.settings.public.app;
|
||||
const CDN_URL = APP_CONFIG.cdn;
|
||||
@ -41,6 +61,16 @@ Meteor.startup(() => {
|
||||
|
||||
Logger.warn(`Started bbb-html5 process with instanceId=${instanceId}`);
|
||||
|
||||
const LOG_CONFIG = Meteor.settings.private.serverLog;
|
||||
const { healthChecker } = LOG_CONFIG;
|
||||
const { enable: enableHealthCheck, intervalMs: healthCheckInterval } = healthChecker;
|
||||
|
||||
if (enableHealthCheck) {
|
||||
Meteor.setInterval(() => {
|
||||
serverHealth();
|
||||
}, healthCheckInterval);
|
||||
}
|
||||
|
||||
const { customHeartbeat } = APP_CONFIG;
|
||||
|
||||
if (customHeartbeat) {
|
||||
|
@ -3,7 +3,17 @@ import { createLogger, format, transports } from 'winston';
|
||||
import WinstonPromTransport from './prom-metrics/winstonPromTransport';
|
||||
|
||||
const LOG_CONFIG = Meteor?.settings?.private?.serverLog || {};
|
||||
const { level } = LOG_CONFIG;
|
||||
const { level, includeServerInfo } = LOG_CONFIG;
|
||||
|
||||
const serverInfoFormat = format.printf(({ level, message, timestamp, ...metadata }) => {
|
||||
const instanceId = parseInt(process.env.INSTANCE_ID, 10) || 1;
|
||||
const role = process.env.BBB_HTML5_ROLE;
|
||||
const server = includeServerInfo && !Meteor?.isDevelopment ? `${role}-${instanceId} ` : "";
|
||||
|
||||
let msg = `${timestamp} ${server}[${level}] : ${message}`;
|
||||
if (metadata) msg += JSON.stringify(metadata)
|
||||
return msg
|
||||
});
|
||||
|
||||
const Logger = createLogger({
|
||||
level,
|
||||
@ -11,6 +21,8 @@ const Logger = createLogger({
|
||||
format.colorize({ level: true }),
|
||||
format.splat(),
|
||||
format.simple(),
|
||||
format.timestamp(),
|
||||
serverInfoFormat,
|
||||
),
|
||||
transports: [
|
||||
// console logging
|
||||
|
@ -203,12 +203,9 @@ const AssignBtns = styled(Button)`
|
||||
color: ${colorPrimary};
|
||||
font-size: ${fontSizeSmall};
|
||||
white-space: nowrap;
|
||||
margin: 0 auto 0 0;
|
||||
margin: 3px auto;
|
||||
align-self: flex-end;
|
||||
|
||||
[dir="rtl"] & {
|
||||
margin: 0 0 0 auto;
|
||||
}
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const CheckBoxesContainer = styled(FlexRow)`
|
||||
|
@ -172,7 +172,7 @@ class LockViewersComponent extends Component {
|
||||
<Styled.Bold>{intl.formatMessage(intlMessages.featuresLable)}</Styled.Bold>
|
||||
<Styled.Bold>{intl.formatMessage(intlMessages.lockStatusLabel)}</Styled.Bold>
|
||||
</Styled.SubHeader>
|
||||
<Styled.Row>
|
||||
<Styled.Row data-test="lockShareWebcamItem">
|
||||
<Styled.Col aria-hidden="true">
|
||||
<Styled.FormElement>
|
||||
<Styled.Label>
|
||||
@ -197,7 +197,7 @@ class LockViewersComponent extends Component {
|
||||
</Styled.FormElementRight>
|
||||
</Styled.Col>
|
||||
</Styled.Row>
|
||||
<Styled.Row>
|
||||
<Styled.Row data-test="lockSeeOtherViewersWebcamItem">
|
||||
<Styled.Col aria-hidden="true">
|
||||
<Styled.FormElement>
|
||||
<Styled.Label>
|
||||
@ -222,7 +222,7 @@ class LockViewersComponent extends Component {
|
||||
</Styled.FormElementRight>
|
||||
</Styled.Col>
|
||||
</Styled.Row>
|
||||
<Styled.Row>
|
||||
<Styled.Row data-test="lockShareMicrophoneItem">
|
||||
<Styled.Col aria-hidden="true">
|
||||
<Styled.FormElement>
|
||||
<Styled.Label>
|
||||
@ -250,7 +250,7 @@ class LockViewersComponent extends Component {
|
||||
|
||||
{isChatEnabled() ? (
|
||||
<Fragment>
|
||||
<Styled.Row>
|
||||
<Styled.Row data-test="lockPublicChatItem">
|
||||
<Styled.Col aria-hidden="true">
|
||||
<Styled.FormElement>
|
||||
<Styled.Label>
|
||||
@ -275,7 +275,7 @@ class LockViewersComponent extends Component {
|
||||
</Styled.FormElementRight>
|
||||
</Styled.Col>
|
||||
</Styled.Row>
|
||||
<Styled.Row>
|
||||
<Styled.Row data-test="lockPrivateChatItem">
|
||||
<Styled.Col aria-hidden="true">
|
||||
<Styled.FormElement>
|
||||
<Styled.Label>
|
||||
@ -305,7 +305,7 @@ class LockViewersComponent extends Component {
|
||||
}
|
||||
{NotesService.isEnabled()
|
||||
? (
|
||||
<Styled.Row>
|
||||
<Styled.Row data-test="lockEditSharedNotesItem">
|
||||
<Styled.Col aria-hidden="true">
|
||||
<Styled.FormElement>
|
||||
<Styled.Label>
|
||||
@ -333,7 +333,7 @@ class LockViewersComponent extends Component {
|
||||
)
|
||||
: null
|
||||
}
|
||||
<Styled.Row>
|
||||
<Styled.Row data-test="lockUserListItem">
|
||||
<Styled.Col aria-hidden="true">
|
||||
<Styled.FormElement>
|
||||
<Styled.Label>
|
||||
@ -359,7 +359,7 @@ class LockViewersComponent extends Component {
|
||||
</Styled.Col>
|
||||
</Styled.Row>
|
||||
|
||||
<Styled.Row>
|
||||
<Styled.Row data-test="hideViewersCursorItem">
|
||||
<Styled.Col aria-hidden="true">
|
||||
<Styled.FormElement>
|
||||
<Styled.Label>
|
||||
|
@ -205,7 +205,7 @@ class Presentation extends PureComponent {
|
||||
this.currentPresentationToastId = toast(this.renderCurrentPresentationToast(), {
|
||||
onClose: () => { this.currentPresentationToastId = null; },
|
||||
autoClose: shouldCloseToast,
|
||||
className: 'actionToast',
|
||||
className: 'actionToast currentPresentationToast',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -275,32 +275,45 @@ class PresentationUploader extends Component {
|
||||
...propPresentations,
|
||||
...presentations,
|
||||
});
|
||||
const presStateMapped = presState.map((presentation) => {
|
||||
propPresentations.forEach((propPres) => {
|
||||
if (propPres.id === presentation.id) {
|
||||
const prevPropPres = prevPropPresentations.find((pres) => pres.id === propPres.id);
|
||||
if (propPres.isCurrent !== prevPropPres?.isCurrent) {
|
||||
presentation.isCurrent = propPres.isCurrent;
|
||||
shouldUpdateState = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
return presentation;
|
||||
}).filter((presentation) => {
|
||||
const presStateFiltered = presState.filter((presentation) => {
|
||||
const currentPropPres = propPresentations.find((pres) => pres.id === presentation.id);
|
||||
const prevPropPres = prevPropPresentations.find((pres) => pres.id === presentation.id);
|
||||
const hasConversionError = presentation?.conversion?.error;
|
||||
const finishedConversion = presentation?.conversion?.done || currentPropPres?.conversion?.done;
|
||||
const hasTemporaryId = presentation.id.startsWith(presentation.filename);
|
||||
|
||||
if (hasConversionError || (!finishedConversion && hasTemporaryId)) return true;
|
||||
if (!currentPropPres) return false;
|
||||
|
||||
if(presentation?.conversion?.done !== finishedConversion) {
|
||||
shouldUpdateState = true;
|
||||
}
|
||||
|
||||
if (currentPropPres.isCurrent !== prevPropPres?.isCurrent) {
|
||||
presentation.isCurrent = currentPropPres.isCurrent;
|
||||
}
|
||||
|
||||
presentation.conversion = currentPropPres.conversion;
|
||||
presentation.isDownloadable = currentPropPres.isDownloadable;
|
||||
presentation.isRemovable = currentPropPres.isRemovable;
|
||||
|
||||
return true;
|
||||
}).filter(presentation => {
|
||||
const duplicated = presentations.find(
|
||||
(pres) => pres.filename === presentation.filename
|
||||
&& pres.id !== presentation.id
|
||||
);
|
||||
if (duplicated
|
||||
&& duplicated.id.startsWith(presentation.filename)
|
||||
&& !presentation.id.startsWith(presentation.filename)
|
||||
&& presentation?.conversion?.done === duplicated?.conversion?.done) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (shouldUpdateState) {
|
||||
this.setState({
|
||||
presentations: presStateMapped,
|
||||
presentations: _.uniqBy(presStateFiltered, 'id')
|
||||
});
|
||||
}
|
||||
|
||||
@ -729,7 +742,7 @@ class PresentationUploader extends Component {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{presentationsSorted.map((item) => this.renderPresentationItem(item))}
|
||||
{_.uniqBy(presentationsSorted, 'id').map((item) => this.renderPresentationItem(item))}
|
||||
</tbody>
|
||||
</Styled.Table>
|
||||
</Styled.FileList>
|
||||
@ -747,7 +760,7 @@ class PresentationUploader extends Component {
|
||||
let converted = 0;
|
||||
|
||||
let presentationsSorted = presentations
|
||||
.filter((p) => (p.upload.progress || p.conversion.status) && p.file)
|
||||
.filter((p) => (p.upload.progress || p.upload.error || p.conversion.status) && p.file)
|
||||
.sort((a, b) => a.uploadTimestamp - b.uploadTimestamp)
|
||||
.sort((a, b) => a.conversion.done - b.conversion.done);
|
||||
|
||||
@ -992,7 +1005,7 @@ class PresentationUploader extends Component {
|
||||
}
|
||||
|
||||
renderPresentationItemStatus(item) {
|
||||
const { intl } = this.props;
|
||||
const { intl, fileSizeMax } = this.props;
|
||||
if (!item.upload.done && item.upload.progress === 0) {
|
||||
return intl.formatMessage(intlMessages.fileToUpload);
|
||||
}
|
||||
@ -1006,13 +1019,13 @@ class PresentationUploader extends Component {
|
||||
const constraint = {};
|
||||
|
||||
if (item.upload.done && item.upload.error) {
|
||||
if (item.conversion.status === 'FILE_TOO_LARGE') {
|
||||
constraint['0'] = ((item.conversion.maxFileSize) / 1000 / 1000).toFixed(2);
|
||||
}
|
||||
|
||||
if (item.upload.progress < 100) {
|
||||
const errorMessage = intlMessages.badConnectionError;
|
||||
return intl.formatMessage(errorMessage);
|
||||
if (item.conversion.status === 'FILE_TOO_LARGE' || item.upload.status === 413) {
|
||||
constraint['0'] = (fileSizeMax / 1000 / 1000).toFixed(2);
|
||||
} else {
|
||||
if (item.upload.progress < 100) {
|
||||
const errorMessage = intlMessages.badConnectionError;
|
||||
return intl.formatMessage(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
const errorMessage = intlMessages[item.upload.status] || intlMessages.genericError;
|
||||
|
@ -68,7 +68,7 @@ const dispatchTogglePresentationDownloadable = (presentation, newState) => {
|
||||
|
||||
const observePresentationConversion = (
|
||||
meetingId,
|
||||
tmpPresId,
|
||||
temporaryPresentationId,
|
||||
onConversion,
|
||||
) => new Promise((resolve) => {
|
||||
const conversionTimeout = setTimeout(() => {
|
||||
@ -89,7 +89,7 @@ const observePresentationConversion = (
|
||||
|
||||
query.observe({
|
||||
added: (doc) => {
|
||||
if (doc.temporaryPresentationId !== tmpPresId) return;
|
||||
if (doc.temporaryPresentationId !== temporaryPresentationId) return;
|
||||
|
||||
if (doc.conversion.status === 'FILE_TOO_LARGE' || doc.conversion.status === 'UNSUPPORTED_DOCUMENT') {
|
||||
onConversion(doc.conversion);
|
||||
@ -98,7 +98,7 @@ const observePresentationConversion = (
|
||||
}
|
||||
},
|
||||
changed: (newDoc) => {
|
||||
if (newDoc.temporaryPresentationId !== tmpPresId) return;
|
||||
if (newDoc.temporaryPresentationId !== temporaryPresentationId) return;
|
||||
|
||||
onConversion(newDoc.conversion);
|
||||
|
||||
@ -117,12 +117,12 @@ const observePresentationConversion = (
|
||||
});
|
||||
|
||||
const requestPresentationUploadToken = (
|
||||
tmpPresId,
|
||||
temporaryPresentationId,
|
||||
podId,
|
||||
meetingId,
|
||||
filename,
|
||||
) => new Promise((resolve, reject) => {
|
||||
makeCall('requestPresentationUploadToken', podId, filename, tmpPresId);
|
||||
makeCall('requestPresentationUploadToken', podId, filename, temporaryPresentationId);
|
||||
|
||||
let computation = null;
|
||||
const timeout = setTimeout(() => {
|
||||
@ -132,13 +132,13 @@ const requestPresentationUploadToken = (
|
||||
|
||||
Tracker.autorun((c) => {
|
||||
computation = c;
|
||||
const sub = Meteor.subscribe('presentation-upload-token', podId, filename, tmpPresId);
|
||||
const sub = Meteor.subscribe('presentation-upload-token', podId, filename, temporaryPresentationId);
|
||||
if (!sub.ready()) return;
|
||||
|
||||
const PresentationToken = PresentationUploadToken.findOne({
|
||||
podId,
|
||||
meetingId,
|
||||
tmpPresId,
|
||||
temporaryPresentationId,
|
||||
used: false,
|
||||
});
|
||||
|
||||
@ -165,13 +165,13 @@ const uploadAndConvertPresentation = (
|
||||
onProgress,
|
||||
onConversion,
|
||||
) => {
|
||||
const tmpPresId = _.uniqueId(Random.id(20))
|
||||
const temporaryPresentationId = _.uniqueId(Random.id(20))
|
||||
|
||||
const data = new FormData();
|
||||
data.append('fileUpload', file);
|
||||
data.append('conference', meetingId);
|
||||
data.append('room', meetingId);
|
||||
data.append('temporaryPresentationId', tmpPresId);
|
||||
data.append('temporaryPresentationId', temporaryPresentationId);
|
||||
|
||||
// TODO: Currently the uploader is not related to a POD so the id is fixed to the default
|
||||
data.append('pod_id', podId);
|
||||
@ -183,12 +183,12 @@ const uploadAndConvertPresentation = (
|
||||
body: data,
|
||||
};
|
||||
|
||||
return requestPresentationUploadToken(tmpPresId, podId, meetingId, file.name)
|
||||
return requestPresentationUploadToken(temporaryPresentationId, podId, meetingId, file.name)
|
||||
.then((token) => {
|
||||
makeCall('setUsedToken', token);
|
||||
return futch(endpoint.replace('upload', `${token}/upload`), opts, onProgress);
|
||||
})
|
||||
.then(() => observePresentationConversion(meetingId, tmpPresId, onConversion))
|
||||
.then(() => observePresentationConversion(meetingId, temporaryPresentationId, onConversion))
|
||||
// Trap the error so we can have parallel upload
|
||||
.catch((error) => {
|
||||
logger.debug({
|
||||
@ -197,7 +197,7 @@ const uploadAndConvertPresentation = (
|
||||
error,
|
||||
},
|
||||
}, 'Generic presentation upload exception catcher');
|
||||
observePresentationConversion(meetingId, tmpPresId, onConversion);
|
||||
observePresentationConversion(meetingId, temporaryPresentationId, onConversion);
|
||||
onUpload({ error: true, done: true, status: error.code });
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
@ -314,12 +314,33 @@ class VideoPreview extends Component {
|
||||
});
|
||||
}
|
||||
|
||||
updateVirtualBackgroundInfo = () => {
|
||||
const { webcamDeviceId } = this.state;
|
||||
|
||||
// Update this session's virtual camera effect information if it's enabled
|
||||
setSessionVirtualBackgroundInfo(
|
||||
this.currentVideoStream.virtualBgType,
|
||||
this.currentVideoStream.virtualBgName,
|
||||
webcamDeviceId,
|
||||
);
|
||||
};
|
||||
|
||||
// Resolves into true if the background switch is successful, false otherwise
|
||||
handleVirtualBgSelected(type, name) {
|
||||
const { sharedDevices } = this.props;
|
||||
const { webcamDeviceId } = this.state;
|
||||
const shared = sharedDevices.includes(webcamDeviceId);
|
||||
|
||||
if (type !== EFFECT_TYPES.NONE_TYPE) {
|
||||
return this.startVirtualBackground(this.currentVideoStream, type, name);
|
||||
return this.startVirtualBackground(this.currentVideoStream, type, name).then((switched) => {
|
||||
// If it's not shared we don't have to update here because
|
||||
// it will be updated in the handleStartSharing method.
|
||||
if (switched && shared) this.updateVirtualBackgroundInfo();
|
||||
return switched;
|
||||
});
|
||||
} else {
|
||||
this.stopVirtualBackground(this.currentVideoStream);
|
||||
if (shared) this.updateVirtualBackgroundInfo();
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
}
|
||||
@ -366,12 +387,7 @@ class VideoPreview extends Component {
|
||||
this.currentVideoStream.stop();
|
||||
}
|
||||
|
||||
// Update this session's virtual camera effect information if it's enabled
|
||||
setSessionVirtualBackgroundInfo(
|
||||
this.currentVideoStream.virtualBgType,
|
||||
this.currentVideoStream.virtualBgName,
|
||||
webcamDeviceId,
|
||||
);
|
||||
this.updateVirtualBackgroundInfo();
|
||||
this.cleanupStreamAndVideo();
|
||||
startSharing(webcamDeviceId);
|
||||
if (resolve) resolve();
|
||||
|
@ -27,7 +27,7 @@ const clearPreview = (annotation) => {
|
||||
|
||||
const clearFakeAnnotations = () => {
|
||||
UnsentAnnotations.remove({});
|
||||
Annotations.remove({ id: /-fake/g });
|
||||
Annotations.remove({ id: /-fake/g, annotationType: { $ne: 'text' } });
|
||||
}
|
||||
|
||||
function handleAddedLiveSyncPreviewAnnotation({
|
||||
|
@ -240,16 +240,22 @@ class VirtualBackgroundService {
|
||||
|
||||
changeBackgroundImage(parameters = null) {
|
||||
const virtualBackgroundImagePath = getVirtualBgImagePath();
|
||||
let imagesrc = virtualBackgroundImagePath + '';
|
||||
let name = '';
|
||||
let type = 'blur';
|
||||
let isVirtualBackground = false;
|
||||
if (parameters != null && Object.keys(parameters).length > 0) {
|
||||
imagesrc = parameters.name;
|
||||
name = parameters.name;
|
||||
type = parameters.type;
|
||||
this._options.virtualBackground.isVirtualBackground = parameters.isVirtualBackground;
|
||||
isVirtualBackground = parameters.isVirtualBackground;
|
||||
}
|
||||
this._options.virtualBackground.virtualSource = virtualBackgroundImagePath + name;
|
||||
this._options.virtualBackground.backgroundType = type;
|
||||
this._options.virtualBackground.isVirtualBackground = isVirtualBackground;
|
||||
if (this._options.virtualBackground.backgroundType === 'image') {
|
||||
this._virtualImage = document.createElement('img');
|
||||
this._virtualImage.crossOrigin = 'anonymous';
|
||||
this._virtualImage.src = virtualBackgroundImagePath + name;
|
||||
}
|
||||
this._virtualImage = document.createElement('img');
|
||||
this._virtualImage.crossOrigin = 'anonymous';
|
||||
this._virtualImage.src = virtualBackgroundImagePath + imagesrc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
224
bigbluebutton-html5/package-lock.json
generated
224
bigbluebutton-html5/package-lock.json
generated
@ -423,43 +423,140 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@formatjs/intl-displaynames": {
|
||||
"version": "1.2.10",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/intl-displaynames/-/intl-displaynames-1.2.10.tgz",
|
||||
"integrity": "sha512-GROA2RP6+7Ouu0WnHFF78O5XIU7pBfI19WM1qm93l6MFWibUk67nCfVCK3VAYJkLy8L8ZxjkYT11VIAfvSz8wg==",
|
||||
"@formatjs/ecma402-abstract": {
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.12.0.tgz",
|
||||
"integrity": "sha512-0/wm9b7brUD40kx7KSE0S532T8EfH06Zc41rGlinoNyYXnuusR6ull2x63iFJgVXgwahm42hAW7dcYdZ+llZzA==",
|
||||
"requires": {
|
||||
"@formatjs/intl-utils": "^2.3.0"
|
||||
"@formatjs/intl-localematcher": "0.2.31",
|
||||
"tslib": "2.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
||||
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@formatjs/fast-memoize": {
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-1.2.6.tgz",
|
||||
"integrity": "sha512-9CWZ3+wCkClKHX+i5j+NyoBVqGf0pIskTo6Xl6ihGokYM2yqSSS68JIgeo+99UIHc+7vi9L3/SDSz/dWI9SNlA==",
|
||||
"requires": {
|
||||
"tslib": "2.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
||||
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@formatjs/icu-messageformat-parser": {
|
||||
"version": "2.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.1.7.tgz",
|
||||
"integrity": "sha512-KM4ikG5MloXMulqn39Js3ypuVzpPKq/DDplvl01PE2qD9rAzFO8YtaUCC9vr9j3sRXwdHPeTe8r3J/8IJgvYEQ==",
|
||||
"requires": {
|
||||
"@formatjs/ecma402-abstract": "1.12.0",
|
||||
"@formatjs/icu-skeleton-parser": "1.3.13",
|
||||
"tslib": "2.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
||||
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@formatjs/icu-skeleton-parser": {
|
||||
"version": "1.3.13",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.13.tgz",
|
||||
"integrity": "sha512-qb1kxnA4ep76rV+d9JICvZBThBpK5X+nh1dLmmIReX72QyglicsaOmKEcdcbp7/giCWfhVs6CXPVA2JJ5/ZvAw==",
|
||||
"requires": {
|
||||
"@formatjs/ecma402-abstract": "1.12.0",
|
||||
"tslib": "2.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
||||
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@formatjs/intl": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/intl/-/intl-2.4.0.tgz",
|
||||
"integrity": "sha512-6b3ex1nz9ZET+Jx/ApYhX62Q/SvZvNK81qG1XAFUKWylJUIFd/bm8hG6CMgh7QVzAeFPa3LIf1y0BkNAQ9VYEw==",
|
||||
"requires": {
|
||||
"@formatjs/ecma402-abstract": "1.12.0",
|
||||
"@formatjs/fast-memoize": "1.2.6",
|
||||
"@formatjs/icu-messageformat-parser": "2.1.7",
|
||||
"@formatjs/intl-displaynames": "6.1.2",
|
||||
"@formatjs/intl-listformat": "7.1.2",
|
||||
"intl-messageformat": "10.1.4",
|
||||
"tslib": "2.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
||||
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@formatjs/intl-displaynames": {
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/intl-displaynames/-/intl-displaynames-6.1.2.tgz",
|
||||
"integrity": "sha512-JbZANoYwNXNy+6NlicVe1/tpiyp+NKJD0WTHgp14aQbMaAg66VVPNAruFmhfhkIABF4jGvc4tdKYAANmWD8W6w==",
|
||||
"requires": {
|
||||
"@formatjs/ecma402-abstract": "1.12.0",
|
||||
"@formatjs/intl-localematcher": "0.2.31",
|
||||
"tslib": "2.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
||||
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@formatjs/intl-listformat": {
|
||||
"version": "1.4.8",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/intl-listformat/-/intl-listformat-1.4.8.tgz",
|
||||
"integrity": "sha512-WNMQlEg0e50VZrGIkgD5n7+DAMGt3boKi1GJALfhFMymslJb5i+5WzWxyj/3a929Z6MAFsmzRIJjKuv+BxKAOQ==",
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/intl-listformat/-/intl-listformat-7.1.2.tgz",
|
||||
"integrity": "sha512-WfWkJ8k41jZIhXgBtC2T1SpTSKYig99g9MVqrVRco4kduv/6GUWq1eMjk84qZfbU4rwdwc8qct+/gB6DTS17+w==",
|
||||
"requires": {
|
||||
"@formatjs/intl-utils": "^2.3.0"
|
||||
"@formatjs/ecma402-abstract": "1.12.0",
|
||||
"@formatjs/intl-localematcher": "0.2.31",
|
||||
"tslib": "2.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
||||
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@formatjs/intl-relativetimeformat": {
|
||||
"version": "4.5.16",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/intl-relativetimeformat/-/intl-relativetimeformat-4.5.16.tgz",
|
||||
"integrity": "sha512-IQ0haY97oHAH5OYUdykNiepdyEWj3SAT+Fp9ZpR85ov2JNiFx+12WWlxlVS8ehdyncC2ZMt/SwFIy2huK2+6/A==",
|
||||
"@formatjs/intl-localematcher": {
|
||||
"version": "0.2.31",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.31.tgz",
|
||||
"integrity": "sha512-9QTjdSBpQ7wHShZgsNzNig5qT3rCPvmZogS/wXZzKotns5skbXgs0I7J8cuN0PPqXyynvNVuN+iOKhNS2eb+ZA==",
|
||||
"requires": {
|
||||
"@formatjs/intl-utils": "^2.3.0"
|
||||
"tslib": "2.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
||||
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@formatjs/intl-unified-numberformat": {
|
||||
"version": "3.3.7",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/intl-unified-numberformat/-/intl-unified-numberformat-3.3.7.tgz",
|
||||
"integrity": "sha512-KnWgLRHzCAgT9eyt3OS34RHoyD7dPDYhRcuKn+/6Kv2knDF8Im43J6vlSW6Hm1w63fNq3ZIT1cFk7RuVO3Psag==",
|
||||
"requires": {
|
||||
"@formatjs/intl-utils": "^2.3.0"
|
||||
}
|
||||
},
|
||||
"@formatjs/intl-utils": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/intl-utils/-/intl-utils-2.3.0.tgz",
|
||||
"integrity": "sha512-KWk80UPIzPmUg+P0rKh6TqspRw0G6eux1PuJr+zz47ftMaZ9QDwbGzHZbtzWkl5hgayM/qrKRutllRC7D/vVXQ=="
|
||||
},
|
||||
"@humanwhocodes/config-array": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz",
|
||||
@ -640,11 +737,6 @@
|
||||
"hoist-non-react-statics": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"@types/invariant": {
|
||||
"version": "2.2.34",
|
||||
"resolved": "https://registry.npmjs.org/@types/invariant/-/invariant-2.2.34.tgz",
|
||||
"integrity": "sha512-lYUtmJ9BqUN688fGY1U1HZoWT1/Jrmgigx2loq4ZcJpICECm/Om3V314BxdzypO0u5PORKGMM6x0OXaljV1YFg=="
|
||||
},
|
||||
"@types/json5": {
|
||||
"version": "0.0.29",
|
||||
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
|
||||
@ -2926,26 +3018,22 @@
|
||||
"side-channel": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"intl-format-cache": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/intl-format-cache/-/intl-format-cache-4.3.1.tgz",
|
||||
"integrity": "sha512-OEUYNA7D06agqPOYhbTkl0T8HA3QKSuwWh1HiClEnpd9vw7N+3XsQt5iZ0GUEchp5CW1fQk/tary+NsbF3yQ1Q=="
|
||||
},
|
||||
"intl-messageformat": {
|
||||
"version": "7.8.4",
|
||||
"resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-7.8.4.tgz",
|
||||
"integrity": "sha512-yS0cLESCKCYjseCOGXuV4pxJm/buTfyCJ1nzQjryHmSehlptbZbn9fnlk1I9peLopZGGbjj46yHHiTAEZ1qOTA==",
|
||||
"version": "10.1.4",
|
||||
"resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.1.4.tgz",
|
||||
"integrity": "sha512-tXCmWCXhbeHOF28aIf5b9ce3kwdwGyIiiSXVZsyDwksMiGn5Tp0MrMvyeuHuz4uN1UL+NfGOztHmE+6aLFp1wQ==",
|
||||
"requires": {
|
||||
"intl-format-cache": "^4.2.21",
|
||||
"intl-messageformat-parser": "^3.6.4"
|
||||
}
|
||||
},
|
||||
"intl-messageformat-parser": {
|
||||
"version": "3.6.4",
|
||||
"resolved": "https://registry.npmjs.org/intl-messageformat-parser/-/intl-messageformat-parser-3.6.4.tgz",
|
||||
"integrity": "sha512-RgPGwue0mJtoX2Ax8EmMzJzttxjnva7gx0Q7mKJ4oALrTZvtmCeAw5Msz2PcjW4dtCh/h7vN/8GJCxZO1uv+OA==",
|
||||
"requires": {
|
||||
"@formatjs/intl-unified-numberformat": "^3.2.0"
|
||||
"@formatjs/ecma402-abstract": "1.12.0",
|
||||
"@formatjs/fast-memoize": "1.2.6",
|
||||
"@formatjs/icu-messageformat-parser": "2.1.7",
|
||||
"tslib": "2.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
||||
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"invariant": {
|
||||
@ -5210,22 +5298,27 @@
|
||||
"integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA=="
|
||||
},
|
||||
"react-intl": {
|
||||
"version": "3.12.1",
|
||||
"resolved": "https://registry.npmjs.org/react-intl/-/react-intl-3.12.1.tgz",
|
||||
"integrity": "sha512-cgumW29mwROIqyp8NXStYsoIm27+8FqnxykiLSawWjOxGIBeLuN/+p2srei5SRIumcJefOkOIHP+NDck05RgHg==",
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-intl/-/react-intl-6.1.0.tgz",
|
||||
"integrity": "sha512-aNy7wX/ZfKgpTv2x27E1sio50fnTrSWD96yfQdVfUfvZrIed6rVPccVxfAtLnIK/M9L1TGrckne3kwFj3Ipikg==",
|
||||
"requires": {
|
||||
"@formatjs/intl-displaynames": "^1.2.0",
|
||||
"@formatjs/intl-listformat": "^1.4.1",
|
||||
"@formatjs/intl-relativetimeformat": "^4.5.9",
|
||||
"@formatjs/intl-unified-numberformat": "^3.2.0",
|
||||
"@formatjs/intl-utils": "^2.2.0",
|
||||
"@formatjs/ecma402-abstract": "1.12.0",
|
||||
"@formatjs/icu-messageformat-parser": "2.1.7",
|
||||
"@formatjs/intl": "2.4.0",
|
||||
"@formatjs/intl-displaynames": "6.1.2",
|
||||
"@formatjs/intl-listformat": "7.1.2",
|
||||
"@types/hoist-non-react-statics": "^3.3.1",
|
||||
"@types/invariant": "^2.2.31",
|
||||
"@types/react": "16 || 17 || 18",
|
||||
"hoist-non-react-statics": "^3.3.2",
|
||||
"intl-format-cache": "^4.2.21",
|
||||
"intl-messageformat": "^7.8.4",
|
||||
"intl-messageformat-parser": "^3.6.4",
|
||||
"shallow-equal": "^1.2.1"
|
||||
"intl-messageformat": "10.1.4",
|
||||
"tslib": "2.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
||||
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
@ -5573,11 +5666,6 @@
|
||||
"crypt": ">= 0.0.1"
|
||||
}
|
||||
},
|
||||
"shallow-equal": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz",
|
||||
"integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA=="
|
||||
},
|
||||
"shallowequal": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
|
||||
|
@ -62,7 +62,7 @@
|
||||
"react-dom": "^16.14.0",
|
||||
"react-draggable": "^4.4.5",
|
||||
"react-dropzone": "^7.0.1",
|
||||
"react-intl": "^3.12.1",
|
||||
"react-intl": "^6.1.0",
|
||||
"react-loading-skeleton": "^3.0.3",
|
||||
"react-modal": "~3.6.1",
|
||||
"react-player": "^2.10.0",
|
||||
|
@ -203,6 +203,10 @@ public:
|
||||
- critical
|
||||
- danger
|
||||
- warning
|
||||
# Whether the fallback mechanism should be used
|
||||
# when the locale string is empty. If false, the empty
|
||||
# string will be returned.
|
||||
fallbackOnEmptyLocaleString: true
|
||||
externalVideoPlayer:
|
||||
enabled: true
|
||||
kurento:
|
||||
@ -794,6 +798,10 @@ private:
|
||||
serverLog:
|
||||
level: info
|
||||
streamerLog: false
|
||||
includeServerInfo: true
|
||||
healthChecker:
|
||||
enable: true
|
||||
intervalMs: 30000
|
||||
minBrowserVersions:
|
||||
- browser: chrome
|
||||
version: 72
|
||||
|
@ -661,7 +661,7 @@
|
||||
"app.notification.recordingStop": "این جلسه ضبط نمیشود",
|
||||
"app.notification.recordingPaused": "این جلسه دیگر ضبط نمیشود",
|
||||
"app.notification.recordingAriaLabel": "زمان ضبطشده",
|
||||
"app.notification.userJoinPushAlert": "{0} به جلسه پیوستند",
|
||||
"app.notification.userJoinPushAlert": "{0} به جلسه پیوست",
|
||||
"app.notification.userLeavePushAlert": "{0} جلسه را ترک کرد",
|
||||
"app.submenu.notification.raiseHandLabel": "بالابردن دست",
|
||||
"app.shortcut-help.title": "میانبرهای صفحه کلید",
|
||||
|
@ -643,6 +643,7 @@
|
||||
"app.userList.guest.privateMessageLabel": "Message",
|
||||
"app.userList.guest.acceptLabel": "Accepter",
|
||||
"app.userList.guest.denyLabel": "Refuser",
|
||||
"app.userList.guest.feedbackMessage": "Opération en cours :",
|
||||
"app.user-info.title": "Recherche dans l'annuaire",
|
||||
"app.toast.breakoutRoomEnded": "La réunion privée s'est terminée. Veuillez rejoindre l'audio.",
|
||||
"app.toast.chat.public": "Nouveau message de discussion publique",
|
||||
|
@ -643,6 +643,7 @@
|
||||
"app.userList.guest.privateMessageLabel": "Üzenet",
|
||||
"app.userList.guest.acceptLabel": "Engedélyezés",
|
||||
"app.userList.guest.denyLabel": "Tiltás",
|
||||
"app.userList.guest.feedbackMessage": "Alkalmazott művelet:",
|
||||
"app.user-info.title": "Címtárkeresés",
|
||||
"app.toast.breakoutRoomEnded": "A csoportterem bezárult. Csatlakozz újra a megbeszéléshez",
|
||||
"app.toast.chat.public": "Új nyilvános üzenet",
|
||||
@ -1018,6 +1019,11 @@
|
||||
"app.learningDashboard.userDetails.response": "Válasz",
|
||||
"app.learningDashboard.userDetails.mostCommonAnswer": "Leggyakoribb válasz",
|
||||
"app.learningDashboard.userDetails.anonymousAnswer": "Névtelen szavazás",
|
||||
"app.learningDashboard.userDetails.talkTime": "Beszélgetés ideje",
|
||||
"app.learningDashboard.userDetails.messages": "Üzenetek",
|
||||
"app.learningDashboard.userDetails.emojis": "Hangulatjelek",
|
||||
"app.learningDashboard.userDetails.raiseHands": "Kézfeltartások",
|
||||
"app.learningDashboard.userDetails.pollVotes": "Szavazatok",
|
||||
"app.learningDashboard.usersTable.title": "Áttekintés",
|
||||
"app.learningDashboard.usersTable.colOnline": "Kapcsolódás ideje",
|
||||
"app.learningDashboard.usersTable.colTalk": "Beszélgetés ideje",
|
||||
|
@ -64,7 +64,7 @@
|
||||
"app.userList.sharingWebcam": "Webcam",
|
||||
"app.userList.menuTitleContext": "Opsi yang tersedia",
|
||||
"app.userList.chatListItem.unreadSingular": "Satu pesan baru",
|
||||
"app.userList.chatListItem.unreadPlural": "[0] pesan baru",
|
||||
"app.userList.chatListItem.unreadPlural": "{0} pesan baru",
|
||||
"app.userList.menu.chat.label": "Mulai obrolan privat",
|
||||
"app.userList.menu.clearStatus.label": "Bersihkan status",
|
||||
"app.userList.menu.removeUser.label": "Hapus pengguna",
|
||||
|
@ -73,7 +73,7 @@
|
||||
"app.userList.you": "당신",
|
||||
"app.userList.locked": "잠김",
|
||||
"app.userList.byModerator": "(주관자)에 의해 ",
|
||||
"app.userList.label": "사용자 리스트",
|
||||
"app.userList.label": "사용자 목록",
|
||||
"app.userList.toggleCompactView.label": "간단한 보기로 전환",
|
||||
"app.userList.moderator": "주관자",
|
||||
"app.userList.mobile": "모바일",
|
||||
@ -345,7 +345,7 @@
|
||||
"app.navBar.settingsDropdown.helpDesc": "비디오 도움말로 사용자 연결 (새로운탭 열어서)",
|
||||
"app.navBar.settingsDropdown.endMeetingDesc": "현재 미팅 끝내기",
|
||||
"app.navBar.settingsDropdown.endMeetingLabel": "미팅 끝",
|
||||
"app.navBar.userListToggleBtnLabel": "사용자 리스트 전환",
|
||||
"app.navBar.userListToggleBtnLabel": "사용자 목록보기 전환",
|
||||
"app.navBar.toggleUserList.ariaLabel": "사용자와 메시지 전환",
|
||||
"app.navBar.toggleUserList.newMessages": "새로운 메시지 알림과 함께",
|
||||
"app.navBar.toggleUserList.newMsgAria": "{0}으로 부터 신규 메시지",
|
||||
@ -608,7 +608,7 @@
|
||||
"app.error.fallback.presentation.title": "에러 발생",
|
||||
"app.error.fallback.presentation.description": "기록 되었습니다. 페이지를 새로고침 해 보세요 ",
|
||||
"app.error.fallback.presentation.reloadButton": "새로고침",
|
||||
"app.guest.waiting": "합류 허가를 기다림",
|
||||
"app.guest.waiting": "승인 대기 중",
|
||||
"app.guest.errorSeeConsole": "오류: 자세한 내용은 콘솔에서 확인",
|
||||
"app.guest.noModeratorResponse": "주관자가 응답하지 않습니다.",
|
||||
"app.guest.noSessionToken": "세션 토큰을 수신하지 못했습니다.",
|
||||
@ -619,16 +619,16 @@
|
||||
"app.guest.meetingEnded": "미팅이 종료되었습니다.",
|
||||
"app.guest.guestWait": "주관자가 회의참여를 승인할 때까지 기다려주십시오.",
|
||||
"app.guest.guestDeny": "미팅 참가가 거부된 게스트",
|
||||
"app.guest.seatWait": "승인을 대기 중인 게스트",
|
||||
"app.guest.seatWait": "승인을 기다리는 게스트",
|
||||
"app.guest.allow": "승인된 게스트",
|
||||
"app.guest.firstPositionInWaitingQueue": "귀하는 대기열의 첫번째에 있습니다.",
|
||||
"app.guest.positionInWaitingQueue": "대기열 내 귀하의 위치:",
|
||||
"app.guest.guestInvalid": "게스트 사용자가 유효하지 않습니다",
|
||||
"app.guest.meetingForciblyEnded": "강제 종료된 회의에는 참여할 수 없습니다",
|
||||
"app.userList.guest.waitingUsers": "사용자 기다림",
|
||||
"app.userList.guest.waitingUsers": "대기중인 사용자",
|
||||
"app.userList.guest.waitingUsersTitle": "사용자 관리",
|
||||
"app.userList.guest.optionTitle": "보류중인 사용자 검토",
|
||||
"app.userList.guest.allowAllAuthenticated": "인증된 자를 모두 허용",
|
||||
"app.userList.guest.optionTitle": "대기중인 사용자 보기",
|
||||
"app.userList.guest.allowAllAuthenticated": "인증되었으면 허용",
|
||||
"app.userList.guest.allowAllGuests": "모든 게스트 허용",
|
||||
"app.userList.guest.allowEveryone": "모두 허용",
|
||||
"app.userList.guest.denyEveryone": "모두 거절",
|
||||
|
@ -6,10 +6,10 @@
|
||||
"app.chat.disconnected": "Вы отсоединены, сообщения не могут быть отправлены",
|
||||
"app.chat.locked": "Чат заблокирован, сообщения не могут быть отправлены",
|
||||
"app.chat.inputLabel": "Ввод сообщений для чата {0}",
|
||||
"app.chat.inputPlaceholder": "Сообщение {0}",
|
||||
"app.chat.inputPlaceholder": "Сообщение в {0}",
|
||||
"app.chat.titlePublic": "Общий чат",
|
||||
"app.chat.titlePrivate": "Приватный чат с {0}",
|
||||
"app.chat.partnerDisconnected": "{0} покинул конференцию",
|
||||
"app.chat.partnerDisconnected": "{0} покинул(а) конференцию",
|
||||
"app.chat.closeChatLabel": "Закрыть {0}",
|
||||
"app.chat.hideChatLabel": "Скрыть {0}",
|
||||
"app.chat.moreMessages": "Больше сообщений ниже",
|
||||
@ -43,7 +43,9 @@
|
||||
"app.captions.menu.backgroundColor": "Цвет фона",
|
||||
"app.captions.menu.previewLabel": "Предварительный просмотр",
|
||||
"app.captions.menu.cancelLabel": "Отмена",
|
||||
"app.captions.hide": "Скрыть скрытые субтитры",
|
||||
"app.captions.hide": "Скрыть субтитры",
|
||||
"app.captions.ownership": "Стать владельцем",
|
||||
"app.captions.ownershipTooltip": "Вы будете назначены владельцем {0} субтитров",
|
||||
"app.captions.dictationStart": "Начать диктовку",
|
||||
"app.captions.dictationStop": "Остановить диктовку",
|
||||
"app.captions.dictationOnDesc": "Включить распознавание речи",
|
||||
@ -171,6 +173,7 @@
|
||||
"app.presentation.options.fullscreen": "Полный экран",
|
||||
"app.presentation.options.exitFullscreen": "Выход из режима полного экрана",
|
||||
"app.presentation.options.minimize": "Свернуть",
|
||||
"app.presentation.options.snapshot": "Снимок текущего слайда",
|
||||
"app.presentation.options.downloading": "Загрузка...",
|
||||
"app.presentation.options.downloaded": "Текущая презентация была скачана",
|
||||
"app.presentation.options.downloadFailed": "Невозможно скачать текущую презентацию",
|
||||
@ -339,7 +342,7 @@
|
||||
"app.navBar.settingsDropdown.hotkeysLabel": "Клавиши быстрого доступа",
|
||||
"app.navBar.settingsDropdown.hotkeysDesc": "Список доступных клавиш быстрого доступа",
|
||||
"app.navBar.settingsDropdown.helpLabel": "Справка",
|
||||
"app.navBar.settingsDropdown.helpDesc": "Ссылает пользователей на видеоуроки ( в новой вкладке)",
|
||||
"app.navBar.settingsDropdown.helpDesc": "Ссылает пользователей на видеоуроки (в новой вкладке)",
|
||||
"app.navBar.settingsDropdown.endMeetingDesc": "Прервать текущую конференцию",
|
||||
"app.navBar.settingsDropdown.endMeetingLabel": "Закончить конференцию",
|
||||
"app.navBar.userListToggleBtnLabel": "Включить/Выключить список пользователей",
|
||||
@ -390,7 +393,7 @@
|
||||
"app.submenu.application.paginationEnabledLabel": "Разделение видео",
|
||||
"app.submenu.application.layoutOptionLabel": "Тип компоновки",
|
||||
"app.submenu.notification.SectionTitle": "Уведомления",
|
||||
"app.submenu.notification.Desc": "Определить как и о чём вы будете оповещаться.",
|
||||
"app.submenu.notification.Desc": "Определить, как и о чём вы будете оповещаться.",
|
||||
"app.submenu.notification.audioAlertLabel": "Звуковые оповещения",
|
||||
"app.submenu.notification.pushAlertLabel": "Всплывающие оповещения",
|
||||
"app.submenu.notification.messagesLabel": "Сообщение чата",
|
||||
@ -417,6 +420,7 @@
|
||||
"app.settings.main.save.label.description": "Сохраняет изменения и закрывает меню настроек",
|
||||
"app.settings.dataSavingTab.label": "Сохранение данных",
|
||||
"app.settings.dataSavingTab.webcam": "Отображать веб-камеры",
|
||||
"app.settings.dataSavingTab.screenShare": "Отображать демонстрацию рабочего стола",
|
||||
"app.settings.dataSavingTab.description": "Чтобы сохранить устойчивую скорость соединения, выберите, что будет отображаться",
|
||||
"app.settings.save-notification.label": "Настройки сохранены",
|
||||
"app.statusNotifier.lowerHands": "Опустить руки",
|
||||
@ -578,7 +582,7 @@
|
||||
"app.modal.close": "Закрыть",
|
||||
"app.modal.close.description": "Сбрасывает изменения и закрывает окно",
|
||||
"app.modal.confirm": "Готово",
|
||||
"app.modal.newTab": "( откроет новую вкладку )",
|
||||
"app.modal.newTab": "(откроет новую вкладку)",
|
||||
"app.modal.confirm.description": "Сохранить изменения и закрыть окно",
|
||||
"app.modal.randomUser.noViewers.description": "Недостаточно участников для случайного выбора",
|
||||
"app.modal.randomUser.selected.description": "Вы были выбраны случайным образом",
|
||||
@ -639,6 +643,7 @@
|
||||
"app.userList.guest.privateMessageLabel": "Сообщение",
|
||||
"app.userList.guest.acceptLabel": "Принять",
|
||||
"app.userList.guest.denyLabel": "Отклонить",
|
||||
"app.userList.guest.feedbackMessage": "Выполненное действие: ",
|
||||
"app.user-info.title": "Поиск в каталоге",
|
||||
"app.toast.breakoutRoomEnded": "Групповая работа закончилась. Пожалуйста, снова присоединитесь к аудио конференции.",
|
||||
"app.toast.chat.public": "Новое сообщение в публичном чате",
|
||||
@ -955,8 +960,8 @@
|
||||
"playback.button.fullscreen.aria": "Полноэкранный контент",
|
||||
"playback.button.restore.aria": "Восстановить контент",
|
||||
"playback.button.search.aria": "Поиск",
|
||||
"playback.button.section.aria": "Боковая секция",
|
||||
"playback.button.swap.aria": "Изменить контент",
|
||||
"playback.button.section.aria": "Боковая панель",
|
||||
"playback.button.swap.aria": "Поменять местами контент",
|
||||
"playback.button.theme.aria": "Изменить тему",
|
||||
"playback.error.wrapper.aria": "Область ошибок",
|
||||
"playback.loader.wrapper.aria": "Область загрузки",
|
||||
@ -964,7 +969,9 @@
|
||||
"playback.player.about.modal.shortcuts.title": "Ярлыки",
|
||||
"playback.player.about.modal.shortcuts.alt": "Alt",
|
||||
"playback.player.about.modal.shortcuts.shift": "Shift",
|
||||
"playback.player.about.modal.shortcuts.fullscreen": "Включить/выключить полноэкранный режим",
|
||||
"playback.player.about.modal.shortcuts.play": "Старт/Пауза",
|
||||
"playback.player.about.modal.shortcuts.section": "Включить/выключить боковую панель",
|
||||
"playback.player.about.modal.shortcuts.seek.backward": "Перемотка назад",
|
||||
"playback.player.about.modal.shortcuts.seek.forward": "Перемотка вперед",
|
||||
"playback.player.about.modal.shortcuts.skip.next": "Следующий слайд",
|
||||
@ -1012,6 +1019,11 @@
|
||||
"app.learningDashboard.userDetails.response": "Ответ",
|
||||
"app.learningDashboard.userDetails.mostCommonAnswer": "Самый распространенный ответ",
|
||||
"app.learningDashboard.userDetails.anonymousAnswer": "Анонимное голосование",
|
||||
"app.learningDashboard.userDetails.talkTime": "Время разговора",
|
||||
"app.learningDashboard.userDetails.messages": "Сообщений",
|
||||
"app.learningDashboard.userDetails.emojis": "Смайликов",
|
||||
"app.learningDashboard.userDetails.raiseHands": "Поднятых рук",
|
||||
"app.learningDashboard.userDetails.pollVotes": "Варианты ответов",
|
||||
"app.learningDashboard.usersTable.title": "Обзор",
|
||||
"app.learningDashboard.usersTable.colOnline": "Время в сети",
|
||||
"app.learningDashboard.usersTable.colTalk": "Время разговора",
|
||||
@ -1039,11 +1051,17 @@
|
||||
"app.learningDashboard.statusTimelineTable.thumbnail": "Миниатюра презентации",
|
||||
"app.learningDashboard.errors.invalidToken": "Неверный токен сеанса",
|
||||
"app.learningDashboard.errors.dataUnavailable": "Данные больше не доступны",
|
||||
"mobileApp.portals.list.empty.addFirstPortal.label": "Создайте ваш первый портал с помощью кнопки выше, ",
|
||||
"mobileApp.portals.list.empty.orUseOurDemoServer.label": "или используйте наш демо-сервер.",
|
||||
"mobileApp.portals.list.add.button.label": "Создать портал",
|
||||
"mobileApp.portals.fields.name.label": "Имя портала",
|
||||
"mobileApp.portals.fields.name.placeholder": "Демонстрация BigBlueButton",
|
||||
"mobileApp.portals.fields.url.label": "URL сервера",
|
||||
"mobileApp.portals.addPortalPopup.confirm.button.label": "Сохранить",
|
||||
"mobileApp.portals.drawerNavigation.button.label": "Порталы",
|
||||
"mobileApp.portals.addPortalPopup.validation.emptyFields": "Поля, обязательные для заполнения",
|
||||
"mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "Имя уже используется",
|
||||
"mobileApp.portals.addPortalPopup.validation.urlInvalid": "Ошибка при загрузке страницы. Проверьте URL и Интернет соединение."
|
||||
"mobileApp.portals.addPortalPopup.validation.urlInvalid": "Ошибка при загрузке страницы. Проверьте URL и сетевое подключение."
|
||||
|
||||
}
|
||||
|
||||
|
@ -298,7 +298,7 @@
|
||||
"app.poll.liveResult.usersTitle": "Kullanıcılar",
|
||||
"app.poll.liveResult.responsesTitle": "Yanıt",
|
||||
"app.poll.liveResult.secretLabel": "Bu isimsiz bir ankettir. Bireysel cevaplar gösterilmez.",
|
||||
"app.poll.removePollOpt": "Kaldırılan Anket seçenekleri [0]",
|
||||
"app.poll.removePollOpt": "Kaldırılan Anket seçenekleri {0}",
|
||||
"app.poll.emptyPollOpt": "Boş",
|
||||
"app.polling.pollingTitle": "Anket seçenekleri",
|
||||
"app.polling.pollQuestionTitle": "Anket Sorusu",
|
||||
|
@ -47,6 +47,8 @@
|
||||
"app.captions.ownership": "接管",
|
||||
"app.textInput.sendLabel": "发送",
|
||||
"app.title.defaultViewLabel": "默认演讲视图",
|
||||
"app.notes.title": "共享笔记",
|
||||
"app.notes.label": "笔记",
|
||||
"app.user.activityCheck": "用户活动检查",
|
||||
"app.user.activityCheck.label": "确认用户是否仍然会议中({0})",
|
||||
"app.user.activityCheck.check": "检查",
|
||||
@ -132,6 +134,7 @@
|
||||
"app.screenshare.viewerLoadingLabel": "正在加载演讲者屏幕",
|
||||
"app.screenshare.presenterSharingLabel": "你正在分享自己的屏幕",
|
||||
"app.screenshare.screenshareFinalError": "代码 {0}。 无法共享屏幕。",
|
||||
"app.screenshare.screenshareRetryError": "允许其他成员桌面共享",
|
||||
"app.meeting.ended": "此会议已结束",
|
||||
"app.meeting.meetingTimeRemaining": "会议时间剩余:{0} ",
|
||||
"app.meeting.meetingTimeHasEnded": "结束时间到。会议即将结束 ",
|
||||
@ -222,6 +225,11 @@
|
||||
"app.poll.customPlaceholder": "增加选项",
|
||||
"app.poll.noPresentationSelected": "没有选择演示文件!请选择。",
|
||||
"app.poll.clickHereToSelect": "点击选择",
|
||||
"app.poll.question.label" : "输入问题",
|
||||
"app.poll.optionalQuestion.label" : "输入问题(可选)",
|
||||
"app.poll.userResponse.label" : "简答",
|
||||
"app.poll.responseTypes.label" : "问题类型",
|
||||
"app.poll.addItem.label" : "增加选项",
|
||||
"app.poll.secretPoll.label" : "匿名投票",
|
||||
"app.poll.questionErr": "必须输入投票问题",
|
||||
"app.poll.optionErr": "输入一个投票选项",
|
||||
@ -231,6 +239,8 @@
|
||||
"app.poll.tf": "真/假",
|
||||
"app.poll.y": "是",
|
||||
"app.poll.n": "否",
|
||||
"app.poll.abstention": "放弃",
|
||||
"app.poll.yna": "是 / 否 / 放弃",
|
||||
"app.poll.a2": "A / B",
|
||||
"app.poll.a3": "A / B / C",
|
||||
"app.poll.a4": "A / B / C / D",
|
||||
@ -239,6 +249,7 @@
|
||||
"app.poll.answer.false": "错误",
|
||||
"app.poll.answer.yes": "是",
|
||||
"app.poll.answer.no": "否",
|
||||
"app.poll.answer.abstention": "放弃",
|
||||
"app.poll.answer.a": "A",
|
||||
"app.poll.answer.b": "B",
|
||||
"app.poll.answer.c": "C",
|
||||
@ -259,6 +270,7 @@
|
||||
"app.navBar.settingsDropdown.fullscreenLabel": "全屏显示",
|
||||
"app.navBar.settingsDropdown.settingsLabel": "设置",
|
||||
"app.navBar.settingsDropdown.aboutLabel": "关于",
|
||||
"app.navBar.settingsDropdown.leaveSessionLabel": "离开会议",
|
||||
"app.navBar.settingsDropdown.exitFullscreenLabel": "退出全屏",
|
||||
"app.navBar.settingsDropdown.fullscreenDesc": "将设置菜单全屏显示",
|
||||
"app.navBar.settingsDropdown.settingsDesc": "更改通用设置",
|
||||
@ -280,6 +292,7 @@
|
||||
"app.navBar.emptyAudioBrdige": "没有活动麦克风。分享麦克风可将音频添加到录像中。",
|
||||
"app.leaveConfirmation.confirmLabel": "退出",
|
||||
"app.leaveConfirmation.confirmDesc": "您将从会议退出",
|
||||
"app.endMeeting.title": "结束{0}",
|
||||
"app.endMeeting.noUserDescription": "您确定要结束此会议吗?",
|
||||
"app.endMeeting.yesLabel": "是",
|
||||
"app.endMeeting.noLabel": "否",
|
||||
@ -297,9 +310,11 @@
|
||||
"app.actionsBar.raiseLabel": "举手",
|
||||
"app.actionsBar.label": "操作栏",
|
||||
"app.actionsBar.actionsDropdown.restorePresentationLabel": "恢复演示文件",
|
||||
"app.actionsBar.actionsDropdown.minimizePresentationLabel": "最小化演示文件",
|
||||
"app.screenshare.screenShareLabel" : "分享屏幕",
|
||||
"app.submenu.application.applicationSectionTitle": "应用",
|
||||
"app.submenu.application.animationsLabel": "动画",
|
||||
"app.submenu.application.audioFilterLabel": "麦克风音频过滤",
|
||||
"app.submenu.application.fontSizeControlLabel": "字号",
|
||||
"app.submenu.application.increaseFontBtnLabel": "增大界面字号",
|
||||
"app.submenu.application.decreaseFontBtnLabel": "减小界面字号",
|
||||
@ -307,12 +322,14 @@
|
||||
"app.submenu.application.languageLabel": "界面语言",
|
||||
"app.submenu.application.languageOptionLabel": "选择语言",
|
||||
"app.submenu.application.noLocaleOptionLabel": "没有可用的语言",
|
||||
"app.submenu.application.layoutOptionLabel": "界面布局",
|
||||
"app.submenu.notification.SectionTitle": "通知",
|
||||
"app.submenu.notification.Desc": "定义通知方式和内容。",
|
||||
"app.submenu.notification.audioAlertLabel": "音频提醒",
|
||||
"app.submenu.notification.pushAlertLabel": "弹窗提醒",
|
||||
"app.submenu.notification.messagesLabel": "聊天消息",
|
||||
"app.submenu.notification.userJoinLabel": "用户加入",
|
||||
"app.submenu.notification.userLeaveLabel": "用户离开",
|
||||
"app.submenu.audio.micSourceLabel": "麦克风源",
|
||||
"app.submenu.audio.speakerSourceLabel": "扬声器源",
|
||||
"app.submenu.audio.streamVolumeLabel": "您音频流的音量",
|
||||
@ -337,6 +354,8 @@
|
||||
"app.settings.save-notification.label": "设置已保存",
|
||||
"app.statusNotifier.lowerHands": "没举手",
|
||||
"app.statusNotifier.raisedHandsTitle": "已举手",
|
||||
"app.statusNotifier.raisedHandDesc": "{0}人举手",
|
||||
"app.statusNotifier.raisedHandDescOneUser": "{0}人举手",
|
||||
"app.statusNotifier.and": "和",
|
||||
"app.switch.onLabel": "开启",
|
||||
"app.switch.offLabel": "关闭",
|
||||
@ -344,6 +363,7 @@
|
||||
"app.talkingIndicator.isTalking" : "{0} 正在说话...",
|
||||
"app.talkingIndicator.wasTalking" : "{0} 沉默了",
|
||||
"app.actionsBar.actionsDropdown.actionsLabel": "操作",
|
||||
"app.actionsBar.actionsDropdown.presentationLabel": "管理演示文件",
|
||||
"app.actionsBar.actionsDropdown.initPollLabel": "发起投票",
|
||||
"app.actionsBar.actionsDropdown.desktopShareLabel": "分享您的桌面",
|
||||
"app.actionsBar.actionsDropdown.stopDesktopShareLabel": "停止分享您的桌面",
|
||||
@ -360,9 +380,11 @@
|
||||
"app.actionsBar.actionsDropdown.captionsDesc": "切换字幕面板",
|
||||
"app.actionsBar.actionsDropdown.takePresenter": "我当演示者",
|
||||
"app.actionsBar.actionsDropdown.takePresenterDesc": "设定自己为新的演示者",
|
||||
"app.actionsBar.actionsDropdown.selectRandUserLabel": "随机选择用户",
|
||||
"app.actionsBar.emojiMenu.statusTriggerLabel": "设置状态",
|
||||
"app.actionsBar.emojiMenu.awayLabel": "离开",
|
||||
"app.actionsBar.emojiMenu.awayDesc": "更改您的状态为离开",
|
||||
"app.actionsBar.emojiMenu.raiseHandLabel": "举手",
|
||||
"app.actionsBar.emojiMenu.raiseHandDesc": "举手提问",
|
||||
"app.actionsBar.emojiMenu.neutralLabel": "未决定",
|
||||
"app.actionsBar.emojiMenu.neutralDesc": "更改您的状态为未决定",
|
||||
@ -436,6 +458,7 @@
|
||||
"app.audioModal.playAudio.arialabel" : "播放音频",
|
||||
"app.audioDial.tipIndicator": "提醒",
|
||||
"app.audioDial.tipMessage": "按手机上的“0”键可静音/取消静音。",
|
||||
"app.audioModal.connecting": "正在建立音频连接",
|
||||
"app.audioManager.joinedAudio": "您已加入会议的音频交流",
|
||||
"app.audioManager.joinedEcho": "您已开始回音测试",
|
||||
"app.audioManager.leftAudio": "您已退出会议音频交流",
|
||||
@ -550,6 +573,10 @@
|
||||
"app.connection-status.title": "连接状态",
|
||||
"app.connection-status.description": "查看用户的连接状态",
|
||||
"app.connection-status.more": "更多",
|
||||
"app.connection-status.no": "否",
|
||||
"app.connection-status.yes": "是",
|
||||
"app.learning-dashboard.label": "学习分析面板",
|
||||
"app.learning-dashboard.clickHereToOpen": "打开学习分析面板",
|
||||
"app.recording.startTitle": "开始录制",
|
||||
"app.recording.stopTitle": "暂停录制",
|
||||
"app.recording.resumeTitle": "恢复录制",
|
||||
@ -714,6 +741,10 @@
|
||||
"app.layout.style.smart": "智能布局",
|
||||
"app.layout.style.presentationFocus": "聚焦到演讲",
|
||||
"app.layout.style.videoFocus": "聚焦到视频",
|
||||
"app.layout.style.customPush": "自定义(发布到所有成员)",
|
||||
"app.layout.style.smartPush": "智能布局(发布到所有成员)",
|
||||
"app.layout.style.presentationFocusPush": "聚集到演示(发布到所有成员)",
|
||||
"app.layout.style.videoFocusPush": "聚集到视频(发布到所有成员)",
|
||||
"playback.button.about.aria": "关于",
|
||||
"playback.button.clear.aria": "清楚搜索记录",
|
||||
"playback.button.close.aria": "关闭弹窗",
|
||||
@ -732,9 +763,11 @@
|
||||
"playback.player.screenshare.wrapper.aria": "屏幕分享区",
|
||||
"playback.player.search.modal.title": "搜索",
|
||||
"playback.player.thumbnails.wrapper.aria": "缩略图区域",
|
||||
"app.learningDashboard.dashboardTitle": "学习分析面板",
|
||||
"app.learningDashboard.indicators.usersOnline": "活跃用户",
|
||||
"app.learningDashboard.indicators.usersTotal": "参会人员总数",
|
||||
"app.learningDashboard.indicators.polls": "投票",
|
||||
"app.learningDashboard.userDetails.raiseHands": "举手",
|
||||
"app.learningDashboard.usersTable.title": "概览",
|
||||
"app.learningDashboard.usersTable.colOnline": "在线时长",
|
||||
"app.learningDashboard.usersTable.colTalk": "发言时长",
|
||||
|
@ -98,6 +98,7 @@ exports.etherpadEditable = 'body[id="innerdocbody"]';
|
||||
|
||||
// Notifications
|
||||
exports.smallToastMsg = 'div[data-test="toastSmallMsg"]';
|
||||
exports.currentPresentationToast = 'div[data-test="toastSmallMsg"] > div';
|
||||
exports.notificationsTab = 'span[id="notificationTab"]';
|
||||
exports.chatPopupAlertsBtn = 'input[data-test="chatPopupAlertsBtn"]';
|
||||
exports.hasUnreadMessages = 'button[data-test="hasUnreadMessages"]';
|
||||
|
@ -35,7 +35,7 @@ class Page {
|
||||
const joinUrl = helpers.getJoinURL(this.meetingId, this.initParameters, isModerator, customParameter);
|
||||
const response = await this.page.goto(joinUrl);
|
||||
await expect(response.ok()).toBeTruthy();
|
||||
const hasErrorLabel = await this.page.evaluate(checkElement, [e.errorMessageLabel]);
|
||||
const hasErrorLabel = await this.checkElement(e.errorMessageLabel);
|
||||
await expect(hasErrorLabel, 'Getting error when joining. Check if the BBB_URL and BBB_SECRET are set correctly').toBeFalsy();
|
||||
this.settings = await generateSettingsData(this.page);
|
||||
const { autoJoinAudioModal } = this.settings;
|
||||
@ -87,9 +87,9 @@ class Page {
|
||||
await this.waitForSelector(e.videoPreview, videoPreviewTimeout);
|
||||
await this.waitAndClick(e.startSharingWebcam);
|
||||
}
|
||||
await this.waitForSelector(e.webcamConnecting);
|
||||
await this.waitForSelector(e.webcamContainer, VIDEO_LOADING_WAIT_TIME);
|
||||
await this.waitForSelector(e.leaveVideo, VIDEO_LOADING_WAIT_TIME);
|
||||
await this.wasRemoved(e.webcamConnecting);
|
||||
}
|
||||
|
||||
getLocator(selector) {
|
||||
|
@ -2,6 +2,15 @@ const { expect } = require("@playwright/test");
|
||||
|
||||
// Common
|
||||
function checkElement([element, index = 0]) {
|
||||
/* Because this function is passed to a page.evaluate, it can only
|
||||
* take a single argument; that's why we pass it an array. It's so
|
||||
* easy to pass it a string by mistake that we check to make sure
|
||||
* the second argument is an integer and not a character from a
|
||||
* destructured string.
|
||||
*/
|
||||
if (typeof index != "number") {
|
||||
throw Error("Assert failed: index not a number");
|
||||
}
|
||||
return document.querySelectorAll(element)[index] !== undefined;
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,9 @@ test.describe.parallel('Notifications', () => {
|
||||
await presenterNotifications.fileUploaderNotification();
|
||||
});
|
||||
|
||||
test('Screenshare notification', async ({ browser, context, page }) => {
|
||||
test('Screenshare notification', async ({ browser, browserName, context, page }) => {
|
||||
test.skip(browserName === 'firefox' && process.env.DISPLAY === undefined,
|
||||
"Screenshare tests not able in Firefox browser without desktop");
|
||||
const presenterNotifications = new PresenterNotifications(browser, context);
|
||||
await presenterNotifications.initModPage(page);
|
||||
await presenterNotifications.screenshareToast();
|
||||
|
@ -2,7 +2,6 @@ const { expect } = require('@playwright/test');
|
||||
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
|
||||
const e = require('../core/elements');
|
||||
const { sleep } = require('../core/helpers');
|
||||
const { checkElement } = require('../core/util');
|
||||
|
||||
async function enableChatPopup(test) {
|
||||
await test.waitAndClick(e.notificationsTab);
|
||||
@ -55,9 +54,9 @@ async function waitAndClearNotification(testPage) {
|
||||
}
|
||||
|
||||
async function waitAndClearDefaultPresentationNotification(testPage) {
|
||||
const hasPresentationUploaded = await testPage.page.evaluate(checkElement, e.whiteboard);
|
||||
if (!hasPresentationUploaded) {
|
||||
await testPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
|
||||
await testPage.waitForSelector(e.whiteboard,ELEMENT_WAIT_LONGER_TIME);
|
||||
const hasCurrentPresentationToast = await testPage.checkElement(e.currentPresentationToast);
|
||||
if (hasCurrentPresentationToast) {
|
||||
await waitAndClearNotification(testPage);
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,8 @@
|
||||
"test:filter": "npx playwright test -g",
|
||||
"test:headed": "npx playwright test --headed",
|
||||
"test:debug": "npx playwright test --debug -g",
|
||||
"test-ci": "export CI='true' && npx playwright test --project=chromium --grep @ci"
|
||||
"test-chromium-ci": "export CI='true' && npx playwright test --project=chromium --grep @ci",
|
||||
"test-firefox-ci": "export CI='true' && npx playwright test --project=firefox --grep @ci"
|
||||
},
|
||||
"dependencies": {
|
||||
"@playwright/test": "^1.19.2",
|
||||
@ -13,4 +14,4 @@
|
||||
"dotenv": "^16.0.0",
|
||||
"sha1": "^1.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,9 @@ const { test, devices } = require('@playwright/test');
|
||||
const { ScreenShare } = require('./screenshare');
|
||||
|
||||
test.describe.parallel('Screenshare', () => {
|
||||
test('Share screen @ci', async ({ browser, page }) => {
|
||||
test('Share screen @ci', async ({ browser, browserName, page }) => {
|
||||
test.skip(browserName === 'firefox' && process.env.DISPLAY === undefined,
|
||||
"Screenshare tests not able in Firefox browser without desktop");
|
||||
const screenshare = new ScreenShare(browser, page);
|
||||
await screenshare.init(true, true);
|
||||
await screenshare.startSharing();
|
||||
|
@ -418,4 +418,4 @@ endWhenNoModeratorDelayInMinutes=1
|
||||
#disabledFeatures=
|
||||
|
||||
# Allow endpoint with current BigBlueButton version
|
||||
allowRevealOfBBBVersion=false
|
||||
allowRevealOfBBBVersion=false
|
@ -31,6 +31,7 @@ import org.bigbluebutton.api.domain.GuestPolicy
|
||||
import org.bigbluebutton.api.domain.Meeting
|
||||
import org.bigbluebutton.api.domain.UserSession
|
||||
import org.bigbluebutton.api.service.ValidationService
|
||||
import org.bigbluebutton.api.service.ServiceUtils
|
||||
import org.bigbluebutton.api.util.ParamsUtil
|
||||
import org.bigbluebutton.api.util.ResponseBuilder
|
||||
import org.bigbluebutton.presentation.PresentationUrlDownloadService
|
||||
@ -229,16 +230,9 @@ class ApiController {
|
||||
|
||||
String fullName = ParamsUtil.stripControlChars(params.fullName)
|
||||
|
||||
String externalMeetingId = params.meetingID
|
||||
|
||||
String attPW = params.password
|
||||
|
||||
// Everything is good so far. Translate the external meeting id to an internal meeting id. If
|
||||
// we can't find the meeting, complain.
|
||||
String internalMeetingId = paramsProcessorUtil.convertToInternalMeetingId(externalMeetingId);
|
||||
|
||||
log.info("Retrieving meeting ${internalMeetingId}")
|
||||
Meeting meeting = meetingService.getMeeting(internalMeetingId);
|
||||
Meeting meeting = ServiceUtils.findMeetingFromMeetingID(params.meetingID);
|
||||
|
||||
// the createTime mismatch with meeting's createTime, complain
|
||||
// In the future, the createTime param will be required
|
||||
@ -511,13 +505,7 @@ class ApiController {
|
||||
return
|
||||
}
|
||||
|
||||
String externalMeetingId = params.meetingID
|
||||
|
||||
// Everything is good so far. Translate the external meeting id to an internal meeting id. If
|
||||
// we can't find the meeting, complain.
|
||||
String internalMeetingId = paramsProcessorUtil.convertToInternalMeetingId(externalMeetingId);
|
||||
log.info("Retrieving meeting ${internalMeetingId}")
|
||||
Meeting meeting = meetingService.getMeeting(internalMeetingId);
|
||||
Meeting meeting = ServiceUtils.findMeetingFromMeetingID(params.meetingID);
|
||||
boolean isRunning = meeting != null && meeting.isRunning();
|
||||
|
||||
response.addHeader("Cache-Control", "no-cache")
|
||||
@ -548,10 +536,7 @@ class ApiController {
|
||||
return
|
||||
}
|
||||
|
||||
String externalMeetingId = params.meetingID
|
||||
String internalMeetingId = paramsProcessorUtil.convertToInternalMeetingId(externalMeetingId)
|
||||
log.info("Retrieving meeting ${internalMeetingId}")
|
||||
Meeting meeting = meetingService.getMeeting(internalMeetingId)
|
||||
Meeting meeting = ServiceUtils.findMeetingFromMeetingID(params.meetingID);
|
||||
|
||||
Map<String, Object> logData = new HashMap<String, Object>();
|
||||
logData.put("meetingid", meeting.getInternalId());
|
||||
@ -595,10 +580,7 @@ class ApiController {
|
||||
return
|
||||
}
|
||||
|
||||
String externalMeetingId = params.meetingID
|
||||
String internalMeetingId = paramsProcessorUtil.convertToInternalMeetingId(externalMeetingId);
|
||||
log.info("Retrieving meeting ${internalMeetingId}")
|
||||
Meeting meeting = meetingService.getMeeting(internalMeetingId);
|
||||
Meeting meeting = ServiceUtils.findMeetingFromMeetingID(params.meetingID);
|
||||
|
||||
withFormat {
|
||||
xml {
|
||||
@ -721,9 +703,7 @@ class ApiController {
|
||||
}
|
||||
|
||||
|
||||
// Translate the external meeting id into an internal meeting id.
|
||||
String internalMeetingId = paramsProcessorUtil.convertToInternalMeetingId(params.meetingID);
|
||||
Meeting meeting = meetingService.getMeeting(internalMeetingId);
|
||||
Meeting meeting = ServiceUtils.findMeetingFromMeetingID(params.meetingID);
|
||||
|
||||
String pollXML = params.pollXML
|
||||
|
||||
@ -905,6 +885,7 @@ class ApiController {
|
||||
reject = true
|
||||
respMessage = "The maximum number of participants allowed for this meeting has been reached."
|
||||
} else {
|
||||
log.info("User ${us.internalUserId} has entered")
|
||||
meeting.userEntered(us.internalUserId)
|
||||
}
|
||||
}
|
||||
@ -1167,10 +1148,7 @@ class ApiController {
|
||||
return
|
||||
}
|
||||
|
||||
String externalMeetingId = params.meetingID
|
||||
String internalMeetingId = paramsProcessorUtil.convertToInternalMeetingId(externalMeetingId)
|
||||
log.info("Retrieving meeting ${internalMeetingId}")
|
||||
Meeting meeting = meetingService.getMeeting(internalMeetingId)
|
||||
Meeting meeting = ServiceUtils.findMeetingFromMeetingID(params.meetingID);
|
||||
|
||||
if (meeting != null){
|
||||
uploadDocuments(meeting, true);
|
||||
@ -1327,7 +1305,11 @@ class ApiController {
|
||||
requestBody = StringUtils.isEmpty(requestBody) ? null : requestBody;
|
||||
Boolean isDefaultPresentationCurrent = false;
|
||||
def listOfPresentation = []
|
||||
def presentationListHasCurrent = false
|
||||
|
||||
// This part of the code is responsible for organize the presentations in a certain order
|
||||
// It selects the one that has the current=true, and put it in the 0th place.
|
||||
// Afterwards, the 0th presentation is going to be uploaded first, which spares processing time
|
||||
if (requestBody == null) {
|
||||
if (isFromInsertAPI){
|
||||
log.warn("Insert Document API called without a payload - ignoring")
|
||||
@ -1363,6 +1345,7 @@ class ApiController {
|
||||
}
|
||||
}
|
||||
}
|
||||
presentationListHasCurrent = hasCurrent;
|
||||
}
|
||||
|
||||
listOfPresentation.eachWithIndex { document, index ->
|
||||
@ -1382,10 +1365,14 @@ class ApiController {
|
||||
}
|
||||
// The array has already been processed to let the first be the current. (This way it is
|
||||
// ensured that only one document is current)
|
||||
if (index == 0) {
|
||||
if (index == 0 && isFromInsertAPI) {
|
||||
if (presentationListHasCurrent) {
|
||||
isCurrent = true
|
||||
}
|
||||
} else if (index == 0 && !isFromInsertAPI){
|
||||
isCurrent = true
|
||||
}
|
||||
isCurrent = isCurrent && !isFromInsertAPI
|
||||
|
||||
// Verifying whether the document is a base64 encoded or a url to download.
|
||||
if (!StringUtils.isEmpty(document.@url.toString())) {
|
||||
def fileName;
|
||||
@ -1659,7 +1646,10 @@ class ApiController {
|
||||
// Users that are entering the meeting
|
||||
int enteredUsers = meeting.getEnteredUsers().size()
|
||||
|
||||
Boolean reachedMax = (joinedUsers + enteredUsers) >= maxParticipants;
|
||||
log.info("Joined users - ${joinedUsers}")
|
||||
log.info("Entered users - ${enteredUsers}")
|
||||
|
||||
Boolean reachedMax = joinedUsers >= maxParticipants;
|
||||
if (enabled && !rejoin && !reenter && reachedMax) {
|
||||
return true;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ PACKAGE=$(echo $TARGET | cut -d'_' -f1)
|
||||
VERSION=$(echo $TARGET | cut -d'_' -f2)
|
||||
DISTRO=$(echo $TARGET | cut -d'_' -f3)
|
||||
TAG=$(echo $TARGET | cut -d'_' -f4)
|
||||
BUILD=$1
|
||||
|
||||
#
|
||||
# Clean up directories
|
||||
@ -17,7 +18,7 @@ rm -rf staging
|
||||
|
||||
# New format
|
||||
if [ -f private/config/settings.yml ]; then
|
||||
sed -i "s/HTML5_CLIENT_VERSION/$(($1))/" private/config/settings.yml
|
||||
sed -i "s/HTML5_CLIENT_VERSION/$(($BUILD))/g" private/config/settings.yml
|
||||
fi
|
||||
|
||||
mkdir -p staging/usr/share/bigbluebutton/nginx
|
||||
@ -98,10 +99,13 @@ fi
|
||||
|
||||
cp node-v14.19.1-linux-x64.tar.gz staging/usr/share
|
||||
|
||||
# replace v=VERSION with build number in head and css files
|
||||
if [ -f staging/usr/share/meteor/bundle/programs/web.browser/head.html ]; then
|
||||
sed -i "s/VERSION/$(($BUILD))/" staging/usr/share/meteor/bundle/programs/web.browser/head.html
|
||||
fi
|
||||
|
||||
find staging/usr/share/meteor/bundle/programs/web.browser -name '*.css' -exec sed -i "s/VERSION/$(($BUILD))/g" '{}' \;
|
||||
|
||||
# Compress CSS, Javascript and tensorflow WASM binaries used for virtual backgrounds. Keep the
|
||||
# uncompressed versions as well so it works with mismatched nginx location blocks
|
||||
find staging/usr/share/meteor/bundle/programs/web.browser -name '*.js' -exec gzip -k -f -9 '{}' \;
|
||||
|
@ -552,7 +552,7 @@ module BigBlueButton
|
||||
|
||||
ffmpeg_filter << ",trim=end=#{ms_to_s(duration)}"
|
||||
|
||||
ffmpeg_cmd = [*FFMPEG]
|
||||
ffmpeg_cmd = [*FFMPEG, '-copyts']
|
||||
ffmpeg_inputs.each do |input|
|
||||
ffmpeg_cmd += ['-ss', ms_to_s(input[:seek]), '-i', input[:filename]]
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user