diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/breakout/ExtendBreakoutRoomsTimeMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/breakout/ExtendBreakoutRoomsTimeMsgHdlr.scala index 667f926a3b..7b40411f0e 100644 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/breakout/ExtendBreakoutRoomsTimeMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/breakout/ExtendBreakoutRoomsTimeMsgHdlr.scala @@ -4,8 +4,9 @@ import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.core.api.{ ExtendBreakoutRoomTimeInternalMsg, SendTimeRemainingAuditInternalMsg } import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait } import org.bigbluebutton.core.bus.BigBlueButtonEvent -import org.bigbluebutton.core.domain.{ MeetingState2x } +import org.bigbluebutton.core.domain.MeetingState2x import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter } +import org.bigbluebutton.core.util.TimeUtil trait ExtendBreakoutRoomsTimeMsgHdlr extends RightsManagementTrait { this: MeetingActor => @@ -25,12 +26,35 @@ trait ExtendBreakoutRoomsTimeMsgHdlr extends RightsManagementTrait { } else { val updatedModel = for { breakoutModel <- state.breakout + startedOn <- breakoutModel.startedOn } yield { - breakoutModel.rooms.values.foreach { room => - eventBus.publish(BigBlueButtonEvent(room.id, ExtendBreakoutRoomTimeInternalMsg(props.breakoutProps.parentId, room.id, msg.body.extendTimeInMinutes))) + val breakoutRoomEndTime = TimeUtil.millisToSeconds(startedOn) + TimeUtil.minutesToSeconds(breakoutModel.durationInMinutes) + val breakoutRoomSecsRemaining = breakoutRoomEndTime - TimeUtil.millisToSeconds(System.currentTimeMillis()) + + var isExtendTimeHigherThanMeetingRemaining = false + + if (state.expiryTracker.durationInMs > 0) { + val mainRoomEndTime = state.expiryTracker.startedOnInMs + state.expiryTracker.durationInMs + val mainRoomSecsRemaining = TimeUtil.millisToSeconds(mainRoomEndTime - TimeUtil.timeNowInMs()) + val mainRoomTimeRemainingInMinutes = mainRoomSecsRemaining / 60 + + //Avoid breakout room end later than main room + //Keep 5 seconds of margin to finish breakout room and send informations to parent meeting + if (breakoutRoomSecsRemaining + TimeUtil.minutesToSeconds(msg.body.extendTimeInMinutes) > (mainRoomSecsRemaining - 5)) { + log.error("Error while trying to extend {} minutes for breakout rooms time in meeting {}. Parent meeting will end up in {} minutes!", msg.body.extendTimeInMinutes, props.meetingProp.intId, mainRoomTimeRemainingInMinutes) + isExtendTimeHigherThanMeetingRemaining = true + } + } + + if (isExtendTimeHigherThanMeetingRemaining) { + breakoutModel + } else { + breakoutModel.rooms.values.foreach { room => + eventBus.publish(BigBlueButtonEvent(room.id, ExtendBreakoutRoomTimeInternalMsg(props.breakoutProps.parentId, room.id, msg.body.extendTimeInMinutes))) + } + log.debug("Extending {} minutes for breakout rooms time in meeting {}", msg.body.extendTimeInMinutes, props.meetingProp.intId) + breakoutModel.extendTime(msg.body.extendTimeInMinutes) } - log.debug("Extending {} minutes for breakout rooms time in meeting {}", msg.body.extendTimeInMinutes, props.meetingProp.intId) - breakoutModel.extendTime(msg.body.extendTimeInMinutes) } val event = buildExtendBreakoutRoomsTimeEvtMsg(msg.body.extendTimeInMinutes) diff --git a/bigbluebutton-html5/imports/ui/components/breakout-room/component.jsx b/bigbluebutton-html5/imports/ui/components/breakout-room/component.jsx index 2ce8a002e8..a9cb36f2e9 100644 --- a/bigbluebutton-html5/imports/ui/components/breakout-room/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/breakout-room/component.jsx @@ -71,6 +71,10 @@ const intlMessages = defineMessages({ id: 'app.createBreakoutRoom.extendTimeCancel', description: 'Button label to cancel extend breakout rooms time', }, + extendTimeHigherThanMeetingTimeError: { + id: 'app.createBreakoutRoom.extendTimeHigherThanMeetingTimeError', + description: 'Label for error when extend breakout rooms time would be higher than remaining time in parent meeting', + }, }); class BreakoutRoom extends PureComponent { @@ -103,6 +107,7 @@ class BreakoutRoom extends PureComponent { joinedAudioOnly: false, breakoutId: '', visibleExtendTimeForm: false, + visibleExtendTimeHigherThanMeetingTimeError: false, extendTime: 5, }; } @@ -182,6 +187,10 @@ class BreakoutRoom extends PureComponent { this.setState({ visibleExtendTimeForm: true }); } + showExtendTimeHigherThanMeetingTimeError(show) { + this.setState({ visibleExtendTimeHigherThanMeetingTimeError: show }); + } + resetExtendTimeForm() { this.setState({ visibleExtendTimeForm: false, extendTime: 5 }); } @@ -366,9 +375,9 @@ class BreakoutRoom extends PureComponent { renderDuration() { const { - intl, breakoutRooms, amIModerator, isMeteorConnected, extendBreakoutsTime, + intl, breakoutRooms, amIModerator, isMeteorConnected, extendBreakoutsTime, isExtendTimeHigherThanMeetingRemaining, } = this.props; - const { extendTime, visibleExtendTimeForm } = this.state; + const { extendTime, visibleExtendTimeForm, visibleExtendTimeHigherThanMeetingTimeError } = this.state; return (