Merge pull request #7626 from Tainan404/issue-7517

Fix DOM injection in number of rooms select
This commit is contained in:
Anton Georgiev 2019-06-26 15:36:57 -04:00 committed by GitHub
commit 6575ee3f48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 167 additions and 84 deletions

View File

@ -1,7 +1,7 @@
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import RedisPubSub from '/imports/startup/server/redis';
import _ from 'lodash';
import Logger from '/imports/startup/server/logger';
export default function createBreakoutRoom(credentials, rooms, durationInMinutes, record = false) {
const REDIS_CONFIG = Meteor.settings.private.redis;
@ -18,7 +18,7 @@ export default function createBreakoutRoom(credentials, rooms, durationInMinutes
check(requesterToken, String);
const eventName = 'CreateBreakoutRoomsCmdMsg';
if (rooms.length > 8) return Logger.info(`Attempt to create breakout rooms with invalid number of rooms in meeting id=${meetingId}`);
const payload = {
record,
durationInMinutes,

View File

@ -101,6 +101,10 @@ const intlMessages = defineMessages({
id: 'app.createBreakoutRoom.roomTime',
description: 'used to provide current room time for aria label',
},
numberOfRoomsIsValid: {
id: 'app.createBreakoutRoom.numberOfRoomsError',
description: 'Label an error message',
},
});
const MIN_BREAKOUT_ROOMS = 2;
@ -148,6 +152,7 @@ class BreakoutRoom extends Component {
this.setRecord = this.setRecord.bind(this);
this.blurDurationTime = this.blurDurationTime.bind(this);
this.removeRoomUsers = this.removeRoomUsers.bind(this);
this.renderErrorMessages = this.renderErrorMessages.bind(this);
this.state = {
numberOfRooms: MIN_BREAKOUT_ROOMS,
@ -160,6 +165,7 @@ class BreakoutRoom extends Component {
preventClosing: true,
valid: true,
record: false,
numberOfRoomsIsValid: true,
};
this.breakoutFormId = _.uniqueId('breakout-form-');
@ -203,12 +209,18 @@ class BreakoutRoom extends Component {
users,
freeJoin,
record,
numberOfRoomsIsValid,
} = this.state;
if (users.length === this.getUserByRoom(0).length && !freeJoin) {
this.setState({ valid: false });
return;
}
if (!numberOfRoomsIsValid) {
return;
}
this.setState({ preventClosing: false });
const { numberOfRooms, durationTime } = this.state;
const rooms = _.range(1, numberOfRooms + 1).map(value => ({
@ -340,7 +352,10 @@ class BreakoutRoom extends Component {
const idxUser = users.findIndex(user => user.userId === userId);
users[idxUser].room = room;
this.setState({ users });
this.setState({
users,
valid: this.getUserByRoom(0).length !== users.length,
});
}
increaseDurationTime() {
@ -364,7 +379,12 @@ class BreakoutRoom extends Component {
}
changeNumberOfRooms(event) {
this.setState({ numberOfRooms: Number.parseInt(event.target.value, 10) });
const numberOfRooms = Number.parseInt(event.target.value, 10);
this.setState({
numberOfRooms,
numberOfRoomsIsValid: numberOfRooms <= MAX_BREAKOUT_ROOMS
&& numberOfRooms >= MIN_BREAKOUT_ROOMS,
});
}
renderRoomsGrid() {
@ -373,6 +393,9 @@ class BreakoutRoom extends Component {
valid,
numberOfRooms,
} = this.state;
const rooms = (numberOfRooms > MAX_BREAKOUT_ROOMS
|| numberOfRooms < MIN_BREAKOUT_ROOMS)
? 0 : numberOfRooms;
const allowDrop = (ev) => {
ev.preventDefault();
};
@ -398,7 +421,7 @@ class BreakoutRoom extends Component {
</span>
</div>
{
_.range(1, numberOfRooms + 1).map(value => (
_.range(1, rooms + 1).map(value => (
<div key={`room-${value}`}>
<p className={styles.freeJoinLabel}>
{intl.formatMessage(intlMessages.roomLabel, { 0: (value) })}
@ -421,88 +444,102 @@ class BreakoutRoom extends Component {
const {
numberOfRooms,
durationTime,
numberOfRoomsIsValid,
} = this.state;
if (isInvitation) return null;
return (
<div className={styles.breakoutSettings} key={this.breakoutFormId}>
<div>
<p className={styles.labelText} aria-hidden>
{intl.formatMessage(intlMessages.numberOfRooms)}
</p>
<select
id="numberOfRooms"
name="numberOfRooms"
className={styles.inputRooms}
value={numberOfRooms}
onChange={this.changeNumberOfRooms}
aria-label={intl.formatMessage(intlMessages.numberOfRooms)}
>
{
_.range(MIN_BREAKOUT_ROOMS, MAX_BREAKOUT_ROOMS + 1).map(item => (<option key={_.uniqueId('value-')}>{item}</option>))
}
</select>
</div>
<label htmlFor="breakoutRoomTime">
<p className={styles.labelText} aria-hidden>
{intl.formatMessage(intlMessages.duration)}
</p>
<div className={styles.durationArea}>
<input
type="number"
className={styles.duration}
min="1"
value={durationTime}
onChange={this.changeDurationTime}
onBlur={this.blurDurationTime}
aria-label={intl.formatMessage(intlMessages.duration)}
/>
<HoldButton
key="decrease-breakout-time"
exec={this.decreaseDurationTime}
minBound={MIN_BREAKOUT_ROOMS}
value={durationTime}
className={styles.btnStyle}
<React.Fragment>
<div className={styles.breakoutSettings} key={this.breakoutFormId}>
<div>
<p
className={cx(styles.labelText, !numberOfRoomsIsValid
&& styles.withError)}
aria-hidden
>
<Button
label={intl.formatMessage(intlMessages.minusRoomTime)}
aria-label={
`${intl.formatMessage(intlMessages.minusRoomTime)} ${intl.formatMessage(intlMessages.roomTime, { 0: durationTime - 1 })}`
}
icon="substract"
onClick={() => {}}
hideLabel
circle
size="sm"
/>
</HoldButton>
<HoldButton
key="increase-breakout-time"
exec={this.increaseDurationTime}
className={styles.btnStyle}
{intl.formatMessage(intlMessages.numberOfRooms)}
</p>
<select
id="numberOfRooms"
name="numberOfRooms"
className={cx(styles.inputRooms, !numberOfRoomsIsValid
&& styles.errorBorder)}
value={numberOfRooms}
onChange={this.changeNumberOfRooms}
aria-label={intl.formatMessage(intlMessages.numberOfRooms)}
>
<Button
label={intl.formatMessage(intlMessages.addRoomTime)}
aria-label={
`${intl.formatMessage(intlMessages.addRoomTime)} ${intl.formatMessage(intlMessages.roomTime, { 0: durationTime + 1 })}`
}
icon="add"
onClick={() => {}}
hideLabel
circle
size="sm"
/>
</HoldButton>
{
_.range(MIN_BREAKOUT_ROOMS, MAX_BREAKOUT_ROOMS + 1).map(item => (<option key={_.uniqueId('value-')}>{item}</option>))
}
</select>
</div>
</label>
<Button
label={intl.formatMessage(intlMessages.randomlyAssign)}
className={styles.randomlyAssignBtn}
onClick={this.onAssignRandomly}
size="sm"
color="default"
/>
</div>
<label htmlFor="breakoutRoomTime">
<p className={styles.labelText} aria-hidden>
{intl.formatMessage(intlMessages.duration)}
</p>
<div className={styles.durationArea}>
<input
type="number"
className={styles.duration}
min="1"
value={durationTime}
onChange={this.changeDurationTime}
onBlur={this.blurDurationTime}
aria-label={intl.formatMessage(intlMessages.duration)}
/>
<HoldButton
key="decrease-breakout-time"
exec={this.decreaseDurationTime}
minBound={MIN_BREAKOUT_ROOMS}
value={durationTime}
className={styles.btnStyle}
>
<Button
label={intl.formatMessage(intlMessages.minusRoomTime)}
aria-label={
`${intl.formatMessage(intlMessages.minusRoomTime)} ${intl.formatMessage(intlMessages.roomTime, { 0: durationTime - 1 })}`
}
icon="substract"
onClick={() => {}}
hideLabel
circle
size="sm"
/>
</HoldButton>
<HoldButton
key="increase-breakout-time"
exec={this.increaseDurationTime}
className={styles.btnStyle}
>
<Button
label={intl.formatMessage(intlMessages.addRoomTime)}
aria-label={
`${intl.formatMessage(intlMessages.addRoomTime)} ${intl.formatMessage(intlMessages.roomTime, { 0: durationTime + 1 })}`
}
icon="add"
onClick={() => {}}
hideLabel
circle
size="sm"
/>
</HoldButton>
</div>
</label>
<Button
label={intl.formatMessage(intlMessages.randomlyAssign)}
className={styles.randomlyAssignBtn}
onClick={this.onAssignRandomly}
size="sm"
color="default"
disabled={!numberOfRoomsIsValid}
/>
</div>
<span className={!numberOfRoomsIsValid
? styles.withError : styles.dontShow}
>
{intl.formatMessage(intlMessages.numberOfRoomsIsValid)}
</span>
</React.Fragment>
);
}
@ -630,6 +667,30 @@ class BreakoutRoom extends Component {
);
}
renderErrorMessages() {
const {
intl,
} = this.props;
const {
valid,
numberOfRoomsIsValid,
} = this.state;
return (
<React.Fragment>
{!valid
&& (
<span className={styles.withError}>
{intl.formatMessage(intlMessages.leastOneWarnBreakout)}
</span>)}
{!numberOfRoomsIsValid
&& (
<span className={styles.withError}>
{intl.formatMessage(intlMessages.numberOfRoomsIsValid)}
</span>)}
</React.Fragment>
);
}
renderDesktop() {
return [
this.renderBreakoutForm(),
@ -642,14 +703,21 @@ class BreakoutRoom extends Component {
const { intl } = this.props;
const { formFillLevel } = this.state;
if (formFillLevel === 2) {
return this.renderRoomSortList();
return [
this.renderErrorMessages(),
this.renderRoomSortList(),
];
}
if (formFillLevel === 3) {
return this.renderSelectUserScreen();
return [
this.renderErrorMessages(),
this.renderSelectUserScreen(),
];
}
return [
this.renderErrorMessages(),
this.renderBreakoutForm(),
this.renderCheckboxes(),
this.renderButtonSetLevel(2, intl.formatMessage(intlMessages.nextLabel)),
@ -679,7 +747,11 @@ class BreakoutRoom extends Component {
render() {
const { intl, isInvitation } = this.props;
const { preventClosing } = this.state;
const {
preventClosing,
valid,
numberOfRoomsIsValid,
} = this.state;
const BROWSER_RESULTS = browser();
const isMobileBrowser = BROWSER_RESULTS.mobile || BROWSER_RESULTS.os.includes('Android');
@ -697,6 +769,7 @@ class BreakoutRoom extends Component {
? intl.formatMessage(intlMessages.invitationConfirm)
: intl.formatMessage(intlMessages.confirmButton),
callback: isInvitation ? this.onInviteBreakout : this.onCreateBreakouts,
disabled: !valid || !numberOfRoomsIsValid,
}
}
dismiss={{

View File

@ -27,7 +27,7 @@ input[type="number"]::-webkit-outer-spin-button, input[type="number"]::-webkit-i
grid-template-columns: 2fr 2fr 1fr;
grid-template-rows: 1fr;
grid-gap: 1rem;
margin-bottom: 1rem;
@include mq($small-only) {
grid-template-columns: 1fr ;
grid-template-rows: 1fr 1fr 1fr;
@ -334,4 +334,13 @@ input[type="number"]::-webkit-outer-spin-button, input[type="number"]::-webkit-i
.checkBoxesContainer {
display: flex;
flex-direction: row;
margin-top: 1rem;
}
.withError {
color: var(--color-danger);
}
.errorBorder {
border-color: var(--color-danger) !important;
}

View File

@ -639,6 +639,7 @@
"app.createBreakoutRoom.leastOneWarnBreakout": "You must place at least one user in a breakout room.",
"app.createBreakoutRoom.modalDesc": "Complete the steps below to create rooms in your session, To add participants to a room.",
"app.createBreakoutRoom.roomTime": "{0} minutes",
"app.createBreakoutRoom.numberOfRoomsError": "The number of rooms is invalid.",
"app.externalVideo.start": "Share a new video",
"app.externalVideo.title": "Share a YouTube video",
"app.externalVideo.input": "YouTube video URL",