Merge pull request #7337 from pedrobmarin/set-lock-settings-on-meeting-create

Allow passing of breakout and lock settings on meeting create
This commit is contained in:
Anton Georgiev 2019-05-03 10:56:11 -04:00 committed by GitHub
commit 66ed4014e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 542 additions and 87 deletions

View File

@ -61,7 +61,8 @@ trait CreateBreakoutRoomsCmdMsgHdlr extends RightsManagementTrait {
msg.body.durationInMinutes,
liveMeeting.props.password.moderatorPass,
liveMeeting.props.password.viewerPass,
presId, presSlide, msg.body.record
presId, presSlide, msg.body.record,
liveMeeting.props.breakoutProps.privateChatEnabled
)
val event = buildCreateBreakoutRoomSysCmdMsg(liveMeeting.props.meetingProp.intId, roomDetail)

View File

@ -11,7 +11,7 @@ import org.bigbluebutton.core.apps.users._
import org.bigbluebutton.core.apps.whiteboard.ClientToServerLatencyTracerMsgHdlr
import org.bigbluebutton.core.domain._
import org.bigbluebutton.core.util.TimeUtil
import org.bigbluebutton.common2.domain.DefaultProps
import org.bigbluebutton.common2.domain.{ DefaultProps, LockSettingsProps }
import org.bigbluebutton.core.api._
import org.bigbluebutton.core.apps._
import org.bigbluebutton.core.apps.caption.CaptionApp2x
@ -23,7 +23,7 @@ import org.bigbluebutton.core.apps.sharednotes.SharedNotesApp2x
import org.bigbluebutton.core.apps.whiteboard.WhiteboardApp2x
import org.bigbluebutton.core.bus._
import org.bigbluebutton.core.models._
import org.bigbluebutton.core2.MeetingStatus2x
import org.bigbluebutton.core2.{ MeetingStatus2x, Permissions }
import org.bigbluebutton.core2.message.handlers._
import org.bigbluebutton.core2.message.handlers.meeting._
import org.bigbluebutton.common2.msgs._
@ -177,6 +177,8 @@ class MeetingActor(
// Set webcamsOnlyForModerator property in case we didn't after meeting creation
MeetingStatus2x.setWebcamsOnlyForModerator(liveMeeting.status, liveMeeting.props.usersProp.webcamsOnlyForModerator)
initLockSettings(liveMeeting, liveMeeting.props.lockSettingsProps)
/** *****************************************************************/
// Helper to create fake users for testing (ralam jan 5, 2018)
//object FakeTestData extends FakeTestData
@ -225,6 +227,23 @@ class MeetingActor(
case _ => // do nothing
}
private def initLockSettings(liveMeeting: LiveMeeting, lockSettingsProp: LockSettingsProps): Unit = {
val settings = Permissions(
disableCam = lockSettingsProp.disableCam,
disableMic = lockSettingsProp.disableMic,
disablePrivChat = lockSettingsProp.disablePrivateChat,
disablePubChat = lockSettingsProp.disablePublicChat,
lockedLayout = lockSettingsProp.lockedLayout,
lockOnJoin = lockSettingsProp.lockOnJoin,
lockOnJoinConfigurable = lockSettingsProp.lockOnJoinConfigurable
)
MeetingStatus2x.initializePermissions(liveMeeting.status)
MeetingStatus2x.setPermissions(liveMeeting.status, settings)
}
private def updateInactivityTracker(state: MeetingState2x): MeetingState2x = {
val tracker = state.inactivityTracker.updateLastActivityTimestamp(TimeUtil.timeNowInMs())
state.update(tracker)

View File

@ -124,6 +124,11 @@ class AnalyticsActor extends Actor with ActorLogging {
// Recording
case m: RecordingChapterBreakSysMsg => logMessage(msg)
case m: GetLockSettingsRespMsg => logMessage(msg)
case m: ChangeLockSettingsInMeetingCmdMsg => logMessage(msg)
case m: GetLockSettingsReqMsg => logMessage(msg)
case m: LockSettingsNotInitializedRespMsg => logMessage(msg)
case _ => // ignore message
}
}

View File

@ -9,7 +9,15 @@ case class DurationProps(duration: Int, createdTime: Long, createdDate: String,
case class MeetingProp(name: String, extId: String, intId: String, isBreakout: Boolean)
case class BreakoutProps(parentId: String, sequence: Int, freeJoin: Boolean, breakoutRooms: Vector[String])
case class BreakoutProps(
parentId: String,
sequence: Int,
freeJoin: Boolean,
breakoutRooms: Vector[String],
enabled: Boolean,
record: Boolean,
privateChatEnabled: Boolean
)
case class PasswordProp(moderatorPass: String, viewerPass: String)
@ -25,10 +33,29 @@ case class MetadataProp(metadata: collection.immutable.Map[String, String])
case class ScreenshareProps(screenshareConf: String, red5ScreenshareIp: String, red5ScreenshareApp: String)
case class DefaultProps(meetingProp: MeetingProp, breakoutProps: BreakoutProps,
durationProps: DurationProps, password: PasswordProp,
recordProp: RecordProp, welcomeProp: WelcomeProp, voiceProp: VoiceProp,
usersProp: UsersProp, metadataProp: MetadataProp, screenshareProps: ScreenshareProps)
case class LockSettingsProps(
disableCam: Boolean,
disableMic: Boolean,
disablePrivateChat: Boolean,
disablePublicChat: Boolean,
lockedLayout: Boolean,
lockOnJoin: Boolean,
lockOnJoinConfigurable: Boolean
)
case class DefaultProps(
meetingProp: MeetingProp,
breakoutProps: BreakoutProps,
durationProps: DurationProps,
password: PasswordProp,
recordProp: RecordProp,
welcomeProp: WelcomeProp,
voiceProp: VoiceProp,
usersProp: UsersProp,
metadataProp: MetadataProp,
screenshareProps: ScreenshareProps,
lockSettingsProps: LockSettingsProps
)
case class StartEndTimeStatus(startTime: Long, endTime: Long)
case class RecordingStatus(isRecording: Boolean)

View File

@ -42,9 +42,22 @@ case class CreateBreakoutRoomSysCmdMsg(
body: CreateBreakoutRoomSysCmdMsgBody
) extends BbbCoreMsg
case class CreateBreakoutRoomSysCmdMsgBody(meetingId: String, room: BreakoutRoomDetail)
case class BreakoutRoomDetail(breakoutMeetingId: String, name: String, parentId: String, sequence: Integer, freeJoin: Boolean,
dialNumber: String, voiceConfId: String, durationInMinutes: Int, moderatorPassword: String,
viewerPassword: String, sourcePresentationId: String, sourcePresentationSlide: Int, record: Boolean)
case class BreakoutRoomDetail(
breakoutMeetingId: String,
name: String,
parentId: String,
sequence: Integer,
freeJoin: Boolean,
dialNumber: String,
voiceConfId: String,
durationInMinutes: Int,
moderatorPassword: String,
viewerPassword: String,
sourcePresentationId: String,
sourcePresentationSlide: Int,
record: Boolean,
privateChatEnabled: Boolean
)
/**
* Sent by client to request to create breakout rooms.

View File

@ -55,6 +55,18 @@ public class ApiParams {
public static final String WEBCAMS_ONLY_FOR_MODERATOR = "webcamsOnlyForModerator";
public static final String WELCOME = "welcome";
public static final String BREAKOUT_ROOMS_ENABLED = "breakoutRoomsEnabled";
public static final String BREAKOUT_ROOMS_RECORD = "breakoutRoomsRecord";
public static final String BREAKOUT_ROOMS_PRIVATE_CHAT_ENABLED = "breakoutRoomsPrivateChatEnabled";
public static final String LOCK_SETTINGS_DISABLE_CAM = "lockSettingsDisableCam";
public static final String LOCK_SETTINGS_DISABLE_MIC = "lockSettingsDisableMic";
public static final String LOCK_SETTINGS_DISABLE_PRIVATE_CHAT = "lockSettingsDisablePrivateChat";
public static final String LOCK_SETTINGS_DISABLE_PUBLIC_CHAT = "lockSettingsDisablePublicChat";
public static final String LOCK_SETTINGS_LOCKED_LAYOUT = "lockSettingsLockedLayout";
public static final String LOCK_SETTINGS_LOCK_ON_JOIN = "lockSettingsLockOnJoin";
public static final String LOCK_SETTINGS_LOCK_ON_JOIN_CONFIGURABLE = "lockSettingsLockOnJoinConfigurable";
private ApiParams() {
throw new IllegalStateException("ApiParams is a utility class. Instanciation is forbidden.");
}

View File

@ -315,7 +315,9 @@ public class MeetingService implements MessageListener {
m.getDialNumber(), m.getMaxUsers(), m.getMaxInactivityTimeoutMinutes(), m.getWarnMinutesBeforeMax(),
m.getMeetingExpireIfNoUserJoinedInMinutes(), m.getmeetingExpireWhenLastUserLeftInMinutes(),
m.getUserInactivityInspectTimerInMinutes(), m.getUserInactivityThresholdInMinutes(),
m.getUserActivitySignResponseDelayInMinutes(), m.getMuteOnStart(), m.getAllowModsToUnmuteUsers(), keepEvents);
m.getUserActivitySignResponseDelayInMinutes(), m.getMuteOnStart(), m.getAllowModsToUnmuteUsers(), keepEvents,
m.breakoutRoomsParams,
m.lockSettingsParams);
}
private String formatPrettyDate(Long timestamp) {

View File

@ -46,6 +46,8 @@ import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.bigbluebutton.api.domain.BreakoutRoomsParams;
import org.bigbluebutton.api.domain.LockSettingsParams;
import org.bigbluebutton.api.domain.Meeting;
import org.bigbluebutton.api.util.ParamsUtil;
import org.slf4j.Logger;
@ -92,6 +94,18 @@ public class ParamsProcessorUtil {
private boolean defaultMuteOnStart = false;
private boolean defaultAllowModsToUnmuteUsers = false;
private boolean defaultBreakoutRoomsEnabled;
private boolean defaultBreakoutRoomsRecord;
private boolean defaultbreakoutRoomsPrivateChatEnabled;
private boolean defaultLockSettingsDisableCam;
private boolean defaultLockSettingsDisableMic;
private boolean defaultLockSettingsDisablePrivateChat;
private boolean defaultLockSettingsDisablePublicChat;
private boolean defaultLockSettingsLockedLayout;
private boolean defaultLockSettingsLockOnJoin;
private boolean defaultLockSettingsLockOnJoinConfigurable;
private String defaultConfigXML = null;
private Long maxPresentationFileUpload = 30000000L; // 30MB
@ -207,7 +221,83 @@ public class ParamsProcessorUtil {
return metas;
}
private BreakoutRoomsParams processBreakoutRoomsParams(Map<String, String> params) {
Boolean breakoutRoomsEnabled = defaultBreakoutRoomsEnabled;
String breakoutRoomsEnabledParam = params.get(ApiParams.BREAKOUT_ROOMS_ENABLED);
if (!StringUtils.isEmpty(breakoutRoomsEnabledParam)) {
breakoutRoomsEnabled = Boolean.parseBoolean(breakoutRoomsEnabledParam);
}
Boolean breakoutRoomsRecord = defaultBreakoutRoomsRecord;
String breakoutRoomsRecordParam = params.get(ApiParams.BREAKOUT_ROOMS_RECORD);
if (!StringUtils.isEmpty(breakoutRoomsRecordParam)) {
breakoutRoomsRecord = Boolean.parseBoolean(breakoutRoomsRecordParam);
}
Boolean breakoutRoomsPrivateChatEnabled = defaultbreakoutRoomsPrivateChatEnabled;
String breakoutRoomsPrivateChatEnabledParam = params.get(ApiParams.BREAKOUT_ROOMS_PRIVATE_CHAT_ENABLED);
if (!StringUtils.isEmpty(breakoutRoomsPrivateChatEnabledParam)) {
breakoutRoomsPrivateChatEnabled = Boolean.parseBoolean(breakoutRoomsPrivateChatEnabledParam);
}
return new BreakoutRoomsParams(breakoutRoomsEnabled,
breakoutRoomsRecord,
breakoutRoomsPrivateChatEnabled);
}
private LockSettingsParams processLockSettingsParams(Map<String, String> params) {
Boolean lockSettingsDisableCam = defaultLockSettingsDisableCam;
String lockSettingsDisableCamParam = params.get(ApiParams.LOCK_SETTINGS_DISABLE_CAM);
if (!StringUtils.isEmpty(lockSettingsDisableCamParam)) {
lockSettingsDisableCam = Boolean.parseBoolean(lockSettingsDisableCamParam);
}
Boolean lockSettingsDisableMic = defaultLockSettingsDisableMic;
String lockSettingsDisableMicParam = params.get(ApiParams.LOCK_SETTINGS_DISABLE_MIC);
if (!StringUtils.isEmpty(lockSettingsDisableMicParam)) {
lockSettingsDisableMic = Boolean.parseBoolean(lockSettingsDisableMicParam);
}
Boolean lockSettingsDisablePrivateChat = defaultLockSettingsDisablePrivateChat;
String lockSettingsDisablePrivateChatParam = params.get(ApiParams.LOCK_SETTINGS_DISABLE_PRIVATE_CHAT);
if (!StringUtils.isEmpty(lockSettingsDisablePrivateChatParam)) {
lockSettingsDisablePrivateChat = Boolean.parseBoolean(lockSettingsDisablePrivateChatParam);
}
Boolean lockSettingsDisablePublicChat = defaultLockSettingsDisablePublicChat;
String lockSettingsDisablePublicChatParam = params.get(ApiParams.LOCK_SETTINGS_DISABLE_PUBLIC_CHAT);
if (!StringUtils.isEmpty(lockSettingsDisablePublicChatParam)) {
lockSettingsDisablePublicChat = Boolean.parseBoolean(lockSettingsDisablePublicChatParam);
}
Boolean lockSettingsLockedLayout = defaultLockSettingsLockedLayout;
String lockSettingsLockedLayoutParam = params.get(ApiParams.LOCK_SETTINGS_LOCKED_LAYOUT);
if (!StringUtils.isEmpty(lockSettingsLockedLayoutParam)) {
lockSettingsLockedLayout = Boolean.parseBoolean(lockSettingsLockedLayoutParam);
}
Boolean lockSettingsLockOnJoin = defaultLockSettingsLockOnJoin;
String lockSettingsLockOnJoinParam = params.get(ApiParams.LOCK_SETTINGS_LOCK_ON_JOIN);
if (!StringUtils.isEmpty(lockSettingsLockOnJoinParam)) {
lockSettingsLockOnJoin = Boolean.parseBoolean(lockSettingsLockOnJoinParam);
}
Boolean lockSettingsLockOnJoinConfigurable = defaultLockSettingsLockOnJoinConfigurable;
String lockSettingsLockOnJoinConfigurableParam = params.get(ApiParams.LOCK_SETTINGS_LOCK_ON_JOIN_CONFIGURABLE);
if (!StringUtils.isEmpty(lockSettingsLockOnJoinConfigurableParam)) {
lockSettingsLockOnJoinConfigurable = Boolean.parseBoolean(lockSettingsLockOnJoinConfigurableParam);
}
return new LockSettingsParams(lockSettingsDisableCam,
lockSettingsDisableMic,
lockSettingsDisablePrivateChat,
lockSettingsDisablePublicChat,
lockSettingsLockedLayout,
lockSettingsLockOnJoin,
lockSettingsLockOnJoinConfigurable);
}
public Meeting processCreateParams(Map<String, String> params) {
String meetingName = params.get(ApiParams.NAME);
@ -308,7 +398,11 @@ public class ParamsProcessorUtil {
if (!StringUtils.isEmpty(params.get(ApiParams.GUEST_POLICY))) {
guestPolicy = params.get(ApiParams.GUEST_POLICY);
}
BreakoutRoomsParams breakoutParams = processBreakoutRoomsParams(params);
LockSettingsParams lockSettingsParams = processLockSettingsParams(params);
// Collect metadata for this meeting that the third-party app wants to
// store if meeting is recorded.
Map<String, String> meetingInfo = processMetaParam(params);
@ -352,6 +446,8 @@ public class ParamsProcessorUtil {
.withWelcomeMessageTemplate(welcomeMessageTemplate)
.withWelcomeMessage(welcomeMessage).isBreakout(isBreakout)
.withGuestPolicy(guestPolicy)
.withBreakoutRoomsParams(breakoutParams)
.withLockSettingsParams(lockSettingsParams)
.build();
String configXML = getDefaultConfigXML();
@ -959,4 +1055,43 @@ public class ParamsProcessorUtil {
return filters;
}
public void setBreakoutRoomsEnabled(Boolean breakoutRoomsEnabled) {
this.defaultBreakoutRoomsEnabled = breakoutRoomsEnabled;
}
public void setBreakoutRoomsRecord(Boolean breakoutRoomsRecord) {
this.defaultBreakoutRoomsRecord = breakoutRoomsRecord;
}
public void setBreakoutRoomsPrivateChatEnabled(Boolean breakoutRoomsPrivateChatEnabled) {
this.defaultbreakoutRoomsPrivateChatEnabled = breakoutRoomsPrivateChatEnabled;
}
public void setLockSettingsDisableCam(Boolean lockSettingsDisableCam) {
this.defaultLockSettingsDisableCam = lockSettingsDisableCam;
}
public void setLockSettingsDisableMic(Boolean lockSettingsDisableMic) {
this.defaultLockSettingsDisableMic = lockSettingsDisableMic;
}
public void setLockSettingsDisablePrivateChat(Boolean lockSettingsDisablePrivateChat) {
this.defaultLockSettingsDisablePrivateChat = lockSettingsDisablePrivateChat;
}
public void setLockSettingsDisablePublicChat(Boolean lockSettingsDisablePublicChat) {
this.defaultLockSettingsDisablePublicChat = lockSettingsDisablePublicChat;
}
public void setLockSettingsLockedLayout(Boolean lockSettingsLockedLayout) {
this.defaultLockSettingsLockedLayout = lockSettingsLockedLayout;
}
public void setLockSettingsLockOnJoin(Boolean lockSettingsLockOnJoin) {
this.defaultLockSettingsLockOnJoin = lockSettingsLockOnJoin;
}
public void setLockSettingsLockOnJoinConfigurable(Boolean lockSettingsLockOnJoinConfigurable) {
this.defaultLockSettingsLockOnJoinConfigurable = lockSettingsLockOnJoinConfigurable;
}
}

View File

@ -0,0 +1,13 @@
package org.bigbluebutton.api.domain;
public class BreakoutRoomsParams {
public final Boolean enabled;
public final Boolean record;
public final Boolean privateChatEnabled;
public BreakoutRoomsParams(Boolean enabled, Boolean record, Boolean privateChatEnabled) {
this.enabled = enabled;
this.record = record;
this.privateChatEnabled = privateChatEnabled;
}
}

View File

@ -0,0 +1,27 @@
package org.bigbluebutton.api.domain;
public class LockSettingsParams {
public final Boolean disableCam;
public final Boolean disableMic;
public final Boolean disablePrivateChat;
public final Boolean disablePublicChat;
public final Boolean lockedLayout;
public final Boolean lockOnJoin;
public final Boolean lockOnJoinConfigurable;
public LockSettingsParams(Boolean disableCam,
Boolean disableMic,
Boolean disablePrivateChat,
Boolean disablePublicChat,
Boolean lockedLayout,
Boolean lockOnJoin,
Boolean lockOnJoinConfigurable) {
this.disableCam = disableCam;
this.disableMic = disableMic;
this.disablePrivateChat = disablePrivateChat;
this.disablePublicChat = disablePublicChat;
this.lockedLayout = lockedLayout;
this.lockOnJoin = lockOnJoin;
this.lockOnJoinConfigurable = lockOnJoinConfigurable;
}
}

View File

@ -27,6 +27,7 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.Lock;
import org.apache.commons.lang3.RandomStringUtils;
@ -88,6 +89,9 @@ public class Meeting {
private Integer userInactivityThresholdInMinutes = 30;
private Integer userActivitySignResponseDelayInMinutes = 5;
public final BreakoutRoomsParams breakoutRoomsParams;
public final LockSettingsParams lockSettingsParams;
public Meeting(Meeting.Builder builder) {
name = builder.name;
extMeetingId = builder.externalId;
@ -114,6 +118,8 @@ public class Meeting {
createdTime = builder.createdTime;
isBreakout = builder.isBreakout;
guestPolicy = builder.guestPolicy;
breakoutRoomsParams = builder.breakoutRoomsParams;
lockSettingsParams = builder.lockSettingsParams;
userCustomData = new HashMap<>();
@ -611,6 +617,8 @@ public class Meeting {
private long createdTime;
private boolean isBreakout;
private String guestPolicy;
private BreakoutRoomsParams breakoutRoomsParams;
private LockSettingsParams lockSettingsParams;
public Builder(String externalId, String internalId, long createTime) {
this.externalId = externalId;
@ -727,6 +735,16 @@ public class Meeting {
guestPolicy = policy;
return this;
}
public Builder withBreakoutRoomsParams(BreakoutRoomsParams params) {
breakoutRoomsParams = params;
return this;
}
public Builder withLockSettingsParams(LockSettingsParams params) {
lockSettingsParams = params;
return this;
}
public Meeting build() {
return new Meeting(this);

View File

@ -16,10 +16,22 @@ public class CreateBreakoutRoom implements IMessage {
public final String sourcePresentationId;
public final Integer sourcePresentationSlide;
public final Boolean record;
public final Boolean privateChatEnabled;
public CreateBreakoutRoom(String meetingId, String parentMeetingId, String name, Integer sequence, Boolean freeJoin,
String dialNumber, String voiceConfId, String viewerPassword, String moderatorPassword, Integer duration,
String sourcePresentationId, Integer sourcePresentationSlide, Boolean record) {
public CreateBreakoutRoom(String meetingId,
String parentMeetingId,
String name,
Integer sequence,
Boolean freeJoin,
String dialNumber,
String voiceConfId,
String viewerPassword,
String moderatorPassword,
Integer duration,
String sourcePresentationId,
Integer sourcePresentationSlide,
Boolean record,
Boolean privateChatEnabled) {
this.meetingId = meetingId;
this.parentMeetingId = parentMeetingId;
this.name = name;
@ -33,5 +45,6 @@ public class CreateBreakoutRoom implements IMessage {
this.sourcePresentationId = sourcePresentationId;
this.sourcePresentationSlide = sourcePresentationSlide;
this.record = record;
this.privateChatEnabled = privateChatEnabled;
}
}

View File

@ -2,6 +2,8 @@ package org.bigbluebutton.api2;
import java.util.Map;
import org.bigbluebutton.api.domain.BreakoutRoomsParams;
import org.bigbluebutton.api.domain.LockSettingsParams;
import org.bigbluebutton.api.messaging.converters.messages.DestroyMeetingMessage;
import org.bigbluebutton.api.messaging.converters.messages.EndMeetingMessage;
import org.bigbluebutton.api.messaging.converters.messages.PublishedRecordingMessage;
@ -27,7 +29,9 @@ public interface IBbbWebApiGWApp {
Integer userActivitySignResponseDelayInMinutes,
Boolean muteOnStart,
Boolean allowModsToUnmuteUsers,
Boolean keepEvents);
Boolean keepEvents,
BreakoutRoomsParams breakoutParams,
LockSettingsParams lockSettingsParams);
void registerUser(String meetingID, String internalUserId, String fullname, String role,
String externUserID, String authToken, String avatarURL,

View File

@ -3,14 +3,16 @@ package org.bigbluebutton.api2
import scala.collection.JavaConverters._
import akka.actor.ActorSystem
import akka.event.Logging
import org.bigbluebutton.api.domain.{ BreakoutRoomsParams, LockSettingsParams }
import org.bigbluebutton.api.messaging.converters.messages._
import org.bigbluebutton.api2.bus._
import org.bigbluebutton.api2.endpoint.redis.{ WebRedisSubscriberActor }
import org.bigbluebutton.api2.endpoint.redis.WebRedisSubscriberActor
import org.bigbluebutton.common2.redis.MessageSender
import org.bigbluebutton.api2.meeting.{ OldMeetingMsgHdlrActor, RegisterUser }
import org.bigbluebutton.common2.domain._
import org.bigbluebutton.common2.util.JsonUtil
import org.bigbluebutton.presentation.messages._
import scala.concurrent.duration._
import org.bigbluebutton.common2.redis._
import org.bigbluebutton.common2.bus._
@ -98,7 +100,9 @@ class BbbWebApiGWApp(
userActivitySignResponseDelayInMinutes: java.lang.Integer,
muteOnStart: java.lang.Boolean,
allowModsToUnmuteUsers: java.lang.Boolean,
keepEvents: java.lang.Boolean): Unit = {
keepEvents: java.lang.Boolean,
breakoutParams: BreakoutRoomsParams,
lockSettingsParams: LockSettingsParams): Unit = {
val meetingProp = MeetingProp(name = meetingName, extId = extMeetingId, intId = meetingId,
isBreakout = isBreakout.booleanValue())
@ -117,7 +121,17 @@ class BbbWebApiGWApp(
val password = PasswordProp(moderatorPass = moderatorPass, viewerPass = viewerPass)
val recordProp = RecordProp(record = recorded.booleanValue(), autoStartRecording = autoStartRecording.booleanValue(),
allowStartStopRecording = allowStartStopRecording.booleanValue(), keepEvents = keepEvents.booleanValue())
val breakoutProps = BreakoutProps(parentId = parentMeetingId, sequence = sequence.intValue(), freeJoin = freeJoin.booleanValue(), breakoutRooms = Vector())
val breakoutProps = BreakoutProps(
parentId = parentMeetingId,
sequence = sequence.intValue(),
freeJoin = freeJoin.booleanValue(),
breakoutRooms = Vector(),
enabled = breakoutParams.enabled.booleanValue(),
record = breakoutParams.record.booleanValue(),
privateChatEnabled = breakoutParams.privateChatEnabled.booleanValue()
)
val welcomeProp = WelcomeProp(welcomeMsgTemplate = welcomeMsgTemplate, welcomeMsg = welcomeMsg,
modOnlyMessage = modOnlyMessage)
val voiceProp = VoiceProp(telVoice = voiceBridge, voiceConf = voiceBridge, dialNumber = dialNumber, muteOnStart = muteOnStart.booleanValue())
@ -130,8 +144,29 @@ class BbbWebApiGWApp(
red5ScreenshareApp = screenshareRtmpBroadcastApp
)
val defaultProps = DefaultProps(meetingProp, breakoutProps, durationProps, password, recordProp, welcomeProp, voiceProp,
usersProp, metadataProp, screenshareProps)
val lockSettingsProps = LockSettingsProps(
disableCam = lockSettingsParams.disableCam.booleanValue(),
disableMic = lockSettingsParams.disableMic.booleanValue(),
disablePrivateChat = lockSettingsParams.disablePrivateChat.booleanValue(),
disablePublicChat = lockSettingsParams.disablePublicChat.booleanValue(),
lockedLayout = lockSettingsParams.lockedLayout.booleanValue(),
lockOnJoin = lockSettingsParams.lockOnJoin.booleanValue(),
lockOnJoinConfigurable = lockSettingsParams.lockOnJoinConfigurable.booleanValue()
)
val defaultProps = DefaultProps(
meetingProp,
breakoutProps,
durationProps,
password,
recordProp,
welcomeProp,
voiceProp,
usersProp,
metadataProp,
screenshareProps,
lockSettingsProps
)
//meetingManagerActorRef ! new CreateMeetingMsg(defaultProps)

View File

@ -80,7 +80,8 @@ class OldMeetingMsgHdlrActor(val olgMsgGW: OldMessageReceivedGW)
msg.body.room.durationInMinutes,
msg.body.room.sourcePresentationId,
msg.body.room.sourcePresentationSlide,
msg.body.room.record
msg.body.room.record,
msg.body.room.privateChatEnabled
))
}

View File

@ -28,12 +28,16 @@ package org.bigbluebutton.main.model.users
import flash.net.URLRequestMethod;
import flash.net.URLVariables;
import mx.utils.ObjectUtil;
import org.as3commons.logging.api.ILogger;
import org.as3commons.logging.api.getClassLogger;
import org.bigbluebutton.core.BBB;
import org.bigbluebutton.core.Options;
import org.bigbluebutton.core.UsersUtil;
import org.bigbluebutton.main.events.MeetingNotFoundEvent;
import org.bigbluebutton.main.model.users.events.ConnectionFailedEvent;
import org.bigbluebutton.modules.users.model.BreakoutRoomsOptions;
import org.bigbluebutton.util.i18n.ResourceUtil;
public class JoinService
@ -183,6 +187,28 @@ package org.bigbluebutton.main.model.users
apiResponse.muteOnStart = result.response.muteOnStart as Boolean;
apiResponse.customLogo = result.response.customLogoURL;
apiResponse.customCopyright = result.response.customCopyright;
var breakoutOptions: BreakoutRoomsOptions = Options.getOptions(BreakoutRoomsOptions) as BreakoutRoomsOptions;
if (result.response.hasOwnProperty("breakoutRooms")) {
logData.logCode = "override_breakout_rooms_settings";
logData.oldBreakoutSettings = ObjectUtil.copy(breakoutOptions);
// Overrive breakout options from config.xml with those passed on create API call
// ralam (mar 26, 2019)
if (result.response.breakoutRooms.hasOwnProperty("enabled")) {
breakoutOptions.enabled = result.response.breakoutRooms.enabled as Boolean;
}
if (result.response.breakoutRooms.hasOwnProperty("record")) {
breakoutOptions.record = result.response.breakoutRooms.record as Boolean;
}
if (result.response.breakoutRooms.hasOwnProperty("privateChatEnabled")) {
breakoutOptions.privateChateEnabled = result.response.breakoutRooms.privateChatEnabled as Boolean;
}
logData.newBreakoutSettings = breakoutOptions;
LOGGER.info(JSON.stringify(logData));
}
if (_resultListener != null) _resultListener(true, apiResponse);
}

View File

@ -11,11 +11,11 @@ export default function toggleLockSettings(credentials, meeting) {
check(meetingId, String);
check(requesterUserId, String);
check(meeting.lockSettingsProp, {
check(meeting.lockSettingsProps, {
disableCam: Boolean,
disableMic: Boolean,
disablePrivChat: Boolean,
disablePubChat: Boolean,
disablePrivateChat: Boolean,
disablePublicChat: Boolean,
lockedLayout: Boolean,
lockOnJoin: Boolean,
lockOnJoinConfigurable: Boolean,
@ -23,13 +23,13 @@ export default function toggleLockSettings(credentials, meeting) {
});
const payload = {
disableCam: meeting.lockSettingsProp.disableCam,
disableMic: meeting.lockSettingsProp.disableMic,
disablePrivChat: meeting.lockSettingsProp.disablePrivChat,
disablePubChat: meeting.lockSettingsProp.disablePubChat,
lockedLayout: meeting.lockSettingsProp.lockedLayout,
lockOnJoin: meeting.lockSettingsProp.lockOnJoin,
lockOnJoinConfigurable: meeting.lockSettingsProp.lockOnJoinConfigurable,
disableCam: meeting.lockSettingsProps.disableCam,
disableMic: meeting.lockSettingsProps.disableMic,
disablePrivChat: meeting.lockSettingsProps.disablePrivateChat,
disablePubChat: meeting.lockSettingsProps.disablePublicChat,
lockedLayout: meeting.lockSettingsProps.lockedLayout,
lockOnJoin: meeting.lockSettingsProps.lockOnJoin,
lockOnJoinConfigurable: meeting.lockSettingsProps.lockOnJoinConfigurable,
setBy: requesterUserId,
};

View File

@ -16,6 +16,9 @@ export default function addMeeting(meeting) {
freeJoin: Boolean,
breakoutRooms: Array,
parentId: String,
enabled: Boolean,
record: Boolean,
privateChatEnabled: Boolean,
},
meetingProp: {
intId: String,
@ -68,6 +71,15 @@ export default function addMeeting(meeting) {
screenshareConf: String,
},
metadataProp: Object,
lockSettingsProps: {
disableCam: Boolean,
disableMic: Boolean,
disablePrivateChat: Boolean,
disablePublicChat: Boolean,
lockOnJoin: Boolean,
lockOnJoinConfigurable: Boolean,
lockedLayout: Boolean,
},
});
const newMeeting = meeting;
@ -76,16 +88,7 @@ export default function addMeeting(meeting) {
meetingId,
};
const lockSettingsProp = {
disableCam: false,
disableMic: false,
disablePrivChat: false,
disablePubChat: false,
lockOnJoin: true,
lockOnJoinConfigurable: false,
lockedLayout: false,
setBy: 'temp',
};
newMeeting.lockSettingsProps = Object.assign(meeting.lockSettingsProps, { setBy: 'temp' });
const meetingEnded = false;
@ -109,7 +112,6 @@ export default function addMeeting(meeting) {
$set: Object.assign({
meetingId,
meetingEnded,
lockSettingsProp,
}, flat(newMeeting, {
safe: true,
})),

View File

@ -15,13 +15,33 @@ export default function changeLockSettings(meetingId, payload) {
setBy: Match.Maybe(String),
});
const {
disableCam,
disableMic,
disablePrivChat,
disablePubChat,
lockedLayout,
lockOnJoin,
lockOnJoinConfigurable,
setBy,
} = payload;
const selector = {
meetingId,
};
const modifier = {
$set: {
lockSettingsProp: payload,
lockSettingsProps: {
disableCam,
disableMic,
disablePrivateChat: disablePrivChat,
disablePublicChat: disablePubChat,
lockedLayout,
lockOnJoin,
lockOnJoinConfigurable,
setBy,
},
},
};

View File

@ -93,6 +93,10 @@ const intlMessages = defineMessages({
id: 'app.createBreakoutRoom.addRoomTime',
description: 'aria label for btn to increase room time',
},
record: {
id: 'app.createBreakoutRoom.record',
description: 'label for checkbox to allow record',
},
});
const MIN_BREAKOUT_ROOMS = 2;
@ -108,6 +112,7 @@ const propTypes = {
getBreakouts: PropTypes.func.isRequired,
sendInvitation: PropTypes.func.isRequired,
mountModal: PropTypes.func.isRequired,
isBreakoutRecordable: PropTypes.bool.isRequired,
};
class BreakoutRoom extends Component {
@ -127,7 +132,7 @@ class BreakoutRoom extends Component {
this.renderUserItemByRoom = this.renderUserItemByRoom.bind(this);
this.renderRoomsGrid = this.renderRoomsGrid.bind(this);
this.renderBreakoutForm = this.renderBreakoutForm.bind(this);
this.renderFreeJoinCheck = this.renderFreeJoinCheck.bind(this);
this.renderCheckboxes = this.renderCheckboxes.bind(this);
this.renderRoomSortList = this.renderRoomSortList.bind(this);
this.renderDesktop = this.renderDesktop.bind(this);
this.renderMobile = this.renderMobile.bind(this);
@ -136,6 +141,7 @@ class BreakoutRoom extends Component {
this.renderTitle = this.renderTitle.bind(this);
this.handleDismiss = this.handleDismiss.bind(this);
this.setInvitationConfig = this.setInvitationConfig.bind(this);
this.setRecord = this.setRecord.bind(this);
this.blurDurationTime = this.blurDurationTime.bind(this);
this.removeRoomUsers = this.removeRoomUsers.bind(this);
@ -149,6 +155,7 @@ class BreakoutRoom extends Component {
roomSelected: 0,
preventClosing: true,
valid: true,
record: false,
};
this.breakoutFormId = _.uniqueId('breakout-form-');
@ -191,6 +198,7 @@ class BreakoutRoom extends Component {
const {
users,
freeJoin,
record,
} = this.state;
if (users.length === this.getUserByRoom(0).length && !freeJoin) {
@ -209,7 +217,7 @@ class BreakoutRoom extends Component {
sequence: value,
}));
createBreakoutRoom(rooms, durationTime, freeJoin);
createBreakoutRoom(rooms, durationTime, record);
Session.set('isUserListOpen', true);
}
@ -275,6 +283,10 @@ class BreakoutRoom extends Component {
this.setState({ freeJoin: e.target.checked });
}
setRecord(e) {
this.setState({ record: e.target.checked });
}
getUserByRoom(room) {
const { users } = this.state;
return users.filter(user => user.room === room);
@ -490,21 +502,44 @@ class BreakoutRoom extends Component {
);
}
renderFreeJoinCheck() {
const { intl, isInvitation } = this.props;
renderCheckboxes() {
const { intl, isInvitation, isBreakoutRecordable } = this.props;
if (isInvitation) return null;
const { freeJoin } = this.state;
const {
freeJoin,
record,
} = this.state;
return (
<label htmlFor="freeJoinCheckbox" className={styles.freeJoinLabel} key={this.freeJoinId}>
<input
type="checkbox"
className={styles.freeJoinCheckbox}
onChange={this.setFreeJoin}
checked={freeJoin}
aria-label={intl.formatMessage(intlMessages.freeJoinLabel)}
/>
<span aria-hidden>{intl.formatMessage(intlMessages.freeJoinLabel)}</span>
</label>
<div className={styles.checkBoxesContainer}>
<label htmlFor="freeJoinCheckbox" className={styles.freeJoinLabel} key={this.freeJoinId}>
<input
type="checkbox"
id="freeJoinCheckbox"
className={styles.freeJoinCheckbox}
onChange={this.setFreeJoin}
checked={freeJoin}
aria-label={intl.formatMessage(intlMessages.freeJoinLabel)}
/>
<span aria-hidden>{intl.formatMessage(intlMessages.freeJoinLabel)}</span>
</label>
{
isBreakoutRecordable ? (
<label htmlFor="recordBreakoutCheckbox" className={styles.freeJoinLabel} key={this.freeJoinId}>
<input
id="recordBreakoutCheckbox"
type="checkbox"
className={styles.freeJoinCheckbox}
onChange={this.setRecord}
checked={record}
aria-label={intl.formatMessage(intlMessages.record)}
/>
<span aria-hidden>
{intl.formatMessage(intlMessages.record)}
</span>
</label>
) : null
}
</div>
);
}
@ -578,7 +613,7 @@ class BreakoutRoom extends Component {
renderDesktop() {
return [
this.renderBreakoutForm(),
this.renderFreeJoinCheck(),
this.renderCheckboxes(),
this.renderRoomsGrid(),
];
}
@ -596,7 +631,7 @@ class BreakoutRoom extends Component {
return [
this.renderBreakoutForm(),
this.renderFreeJoinCheck(),
this.renderCheckboxes(),
this.renderButtonSetLevel(2, intl.formatMessage(intlMessages.nextLabel)),
];
}

View File

@ -289,4 +289,9 @@ input[type="number"]::-webkit-outer-spin-button, input[type="number"]::-webkit-i
.dontShow {
display: none;
}
.checkBoxesContainer {
display: flex;
flex-direction: row;
}

View File

@ -30,8 +30,10 @@ export default {
meetingName: () => Meetings.findOne({ meetingId: Auth.meetingID }).meetingProp.name,
users: () => Users.find({ connectionStatus: 'online', meetingId: Auth.meetingID }).fetch(),
hasBreakoutRoom: () => Breakouts.find({ parentMeetingId: Auth.meetingID }).fetch().length > 0,
isBreakoutEnabled: () => Meetings.findOne({ meetingId: Auth.meetingID }).breakoutProps.enabled,
isBreakoutRecordable: () => Meetings.findOne({ meetingId: Auth.meetingID }).breakoutProps.record,
toggleRecording: () => makeCall('toggleRecording'),
createBreakoutRoom: (numberOfRooms, durationInMinutes, freeJoin = true, record = false) => makeCall('createBreakoutRoom', numberOfRooms, durationInMinutes, freeJoin, record),
createBreakoutRoom: (numberOfRooms, durationInMinutes, record = false) => makeCall('createBreakoutRoom', numberOfRooms, durationInMinutes, record),
sendInvitation: (breakoutId, userId) => makeCall('requestJoinURL', { breakoutId, userId }),
getBreakouts,
getUsersNotAssigned,

View File

@ -35,7 +35,7 @@ const audioLocked = () => {
const User = mapUser(Users.findOne({ userId }));
const Meeting = Meetings.findOne({ meetingId: Auth.meetingID });
const lockSetting = Meeting.lockSettingsProp;
const lockSetting = Meeting.lockSettingsProps;
const audioLock = lockSetting ? lockSetting.disableMic : false;
return audioLock && User.isLocked;

View File

@ -136,14 +136,14 @@ const isChatLocked = (receiverID) => {
const meeting = Meetings.findOne({});
const user = Users.findOne({ userId: Auth.userID });
if (meeting.lockSettingsProp !== undefined) {
if (meeting.lockSettingsProps !== undefined) {
if (mapUser(user).isLocked) {
if (isPublic) {
return meeting.lockSettingsProp.disablePubChat;
return meeting.lockSettingsProps.disablePublicChat;
}
const receivingUser = Users.findOne({ userId: receiverID });
const receiverIsMod = receivingUser && receivingUser.role === ROLE_MODERATOR;
return !receiverIsMod && meeting.lockSettingsProp.disablePrivChat;
return !receiverIsMod && meeting.lockSettingsProps.disablePrivateChat;
}
}

View File

@ -95,9 +95,9 @@ class LockViewersComponent extends React.PureComponent {
<div className={cx(styles.formElement, styles.pullContentRight)}>
<Toggle
icons={false}
defaultChecked={meeting.lockSettingsProp.disableCam}
defaultChecked={meeting.lockSettingsProps.disableCam}
onChange={() => {
meeting.lockSettingsProp.disableCam = !meeting.lockSettingsProp.disableCam;
meeting.lockSettingsProps.disableCam = !meeting.lockSettingsProps.disableCam;
toggleLockSettings(meeting);
}}
ariaLabel={intl.formatMessage(intlMessages.webcamLabel)}
@ -139,9 +139,9 @@ class LockViewersComponent extends React.PureComponent {
<div className={cx(styles.formElement, styles.pullContentRight)}>
<Toggle
icons={false}
defaultChecked={meeting.lockSettingsProp.disableMic}
defaultChecked={meeting.lockSettingsProps.disableMic}
onChange={() => {
meeting.lockSettingsProp.disableMic = !meeting.lockSettingsProp.disableMic;
meeting.lockSettingsProps.disableMic = !meeting.lockSettingsProps.disableMic;
toggleLockSettings(meeting);
}}
ariaLabel={intl.formatMessage(intlMessages.microphoneLable)}
@ -161,9 +161,9 @@ class LockViewersComponent extends React.PureComponent {
<div className={cx(styles.formElement, styles.pullContentRight)}>
<Toggle
icons={false}
defaultChecked={meeting.lockSettingsProp.disablePubChat}
defaultChecked={meeting.lockSettingsProps.disablePublicChat}
onChange={() => {
meeting.lockSettingsProp.disablePubChat = !meeting.lockSettingsProp.disablePubChat;
meeting.lockSettingsProps.disablePublicChat = !meeting.lockSettingsProps.disablePublicChat;
toggleLockSettings(meeting);
}}
ariaLabel={intl.formatMessage(intlMessages.publicChatLabel)}
@ -183,9 +183,9 @@ class LockViewersComponent extends React.PureComponent {
<div className={cx(styles.formElement, styles.pullContentRight)}>
<Toggle
icons={false}
defaultChecked={meeting.lockSettingsProp.disablePrivChat}
defaultChecked={meeting.lockSettingsProps.disablePrivateChat}
onChange={() => {
meeting.lockSettingsProp.disablePrivChat = !meeting.lockSettingsProp.disablePrivChat;
meeting.lockSettingsProps.disablePrivateChat = !meeting.lockSettingsProps.disablePrivateChat;
toggleLockSettings(meeting);
}}
ariaLabel={intl.formatMessage(intlMessages.privateChatLable)}

View File

@ -267,13 +267,13 @@ const isMeetingLocked = (id) => {
const meeting = Meetings.findOne({ meetingId: id });
let isLocked = false;
if (meeting.lockSettingsProp !== undefined) {
const lockSettings = meeting.lockSettingsProp;
if (meeting.lockSettingsProps !== undefined) {
const lockSettings = meeting.lockSettingsProps;
if (lockSettings.disableCam
|| lockSettings.disableMic
|| lockSettings.disablePrivChat
|| lockSettings.disablePubChat) {
|| lockSettings.disablePrivateChat
|| lockSettings.disablePublicChat) {
isLocked = true;
}
}

View File

@ -52,7 +52,7 @@ class UserListItem extends PureComponent {
requestUserInformation,
} = this.props;
const { meetingId, lockSettingsProp } = meeting;
const { meetingId, lockSettingsProps } = meeting;
const contents = (
<UserDropdown
@ -71,7 +71,7 @@ class UserListItem extends PureComponent {
isBreakoutRoom,
isMeetingLocked,
meetingId,
lockSettingsProp,
lockSettingsProps,
normalizeEmojiName,
removeUser,
setEmojiStatus,

View File

@ -206,7 +206,7 @@ class UserDropdown extends PureComponent {
removeUser,
toggleVoice,
changeRole,
lockSettingsProp,
lockSettingsProps,
hasPrivateChatBetweenUsers,
toggleUserLock,
requestUserInformation,
@ -230,12 +230,12 @@ class UserDropdown extends PureComponent {
allowedToChangeUserLockStatus,
} = actionPermissions;
const { disablePrivChat } = lockSettingsProp;
const { disablePrivateChat } = lockSettingsProps;
const enablePrivateChat = currentUser.isModerator
? allowedToChatPrivately
: allowedToChatPrivately
&& (!(currentUser.isLocked && disablePrivChat)
&& (!(currentUser.isLocked && disablePrivateChat)
|| hasPrivateChatBetweenUsers(currentUser, user)
|| user.isModerator);

View File

@ -25,6 +25,8 @@ const propTypes = {
users: PropTypes.arrayOf(Object).isRequired,
meetingIsBreakout: PropTypes.bool.isRequired,
hasBreakoutRoom: PropTypes.bool.isRequired,
isBreakoutEnabled: PropTypes.bool.isRequired,
isBreakoutRecordable: PropTypes.bool.isRequired,
};
const intlMessages = defineMessages({
@ -152,11 +154,13 @@ class UserOptions extends PureComponent {
handleCreateBreakoutRoomClick(isInvitation) {
const {
mountModal,
isBreakoutRecordable,
} = this.props;
return mountModal(
<BreakoutRoom
{...{
isBreakoutRecordable,
isInvitation,
}}
/>,
@ -173,6 +177,7 @@ class UserOptions extends PureComponent {
toggleMuteAllUsersExceptPresenter,
meetingIsBreakout,
hasBreakoutRoom,
isBreakoutEnabled,
getUsersNotAssigned,
isUserModerator,
users,
@ -180,7 +185,8 @@ class UserOptions extends PureComponent {
const canCreateBreakout = isUserModerator
&& !meetingIsBreakout
&& !hasBreakoutRoom;
&& !hasBreakoutRoom
&& isBreakoutEnabled;
const canInviteUsers = isUserModerator
&& !meetingIsBreakout

View File

@ -35,6 +35,8 @@ const UserOptionsContainer = withTracker((props) => {
meetingIsBreakout: Service.meetingIsBreakout(),
getUsersNotAssigned: Service.getUsersNotAssigned,
hasBreakoutRoom: Service.hasBreakoutRoom(),
isBreakoutEnabled: Service.isBreakoutEnabled(),
isBreakoutRecordable: Service.isBreakoutRecordable(),
users: Service.users(),
userListService,
};

View File

@ -105,7 +105,7 @@ class VideoService {
isLocked() {
const m = Meetings.findOne({ meetingId: Auth.meetingID }) || {};
return m.lockSettingsProp ? m.lockSettingsProp.disableCam : false;
return m.lockSettingsProps ? m.lockSettingsProps.disableCam : false;
}
userId() {

View File

@ -562,6 +562,7 @@
"app.createBreakoutRoom.joinAudio": "Join audio",
"app.createBreakoutRoom.returnAudio": "Return audio",
"app.createBreakoutRoom.confirm": "Create",
"app.createBreakoutRoom.record": "Record",
"app.createBreakoutRoom.numberOfRooms": "Number of rooms",
"app.createBreakoutRoom.durationInMinutes": "Duration (minutes)",
"app.createBreakoutRoom.randomlyAssign": "Randomly assign",

View File

@ -307,3 +307,17 @@ screenshareRtmpBroadcastApp=video-broadcast
# The suffix of our verto screenshare conference.
# Convention is {voiceConf}-SCREENSHARE
screenshareConfSuffix=-SCREENSHARE
# Default settings for breakout rooms
breakoutRoomsEnabled=true
breakoutRoomsRecord=false
breakoutRoomsPrivateChatEnabled=true
# Default Lock Settings
lockSettingsDisableCam=false
lockSettingsDisableMic=false
lockSettingsDisablePrivateChat=false
lockSettingsDisablePublicChat=false
lockSettingsLockedLayout=false
lockSettingsLockOnJoin=true
lockSettingsLockOnJoinConfigurable=false

View File

@ -132,6 +132,16 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<property name="clientLogoutTimerInMinutes" value="${clientLogoutTimerInMinutes}"/>
<property name="muteOnStart" value="${muteOnStart}"/>
<property name="allowModsToUnmuteUsers" value="${allowModsToUnmuteUsers}"/>
<property name="breakoutRoomsEnabled" value="${breakoutRoomsEnabled}"/>
<property name="breakoutRoomsRecord" value="${breakoutRoomsRecord}"/>
<property name="breakoutRoomsPrivateChatEnabled" value="${breakoutRoomsPrivateChatEnabled}"/>
<property name="lockSettingsDisableCam" value="${lockSettingsDisableCam}"/>
<property name="lockSettingsDisableMic" value="${lockSettingsDisableMic}"/>
<property name="lockSettingsDisablePrivateChat" value="${lockSettingsDisablePrivateChat}"/>
<property name="lockSettingsDisablePublicChat" value="${lockSettingsDisablePublicChat}"/>
<property name="lockSettingsLockedLayout" value="${lockSettingsLockedLayout}"/>
<property name="lockSettingsLockOnJoin" value="${lockSettingsLockOnJoin}"/>
<property name="lockSettingsLockOnJoinConfigurable" value="${lockSettingsLockOnJoinConfigurable}"/>
</bean>
<import resource="doc-conversion.xml"/>

View File

@ -1518,6 +1518,13 @@ class ApiController {
logoutUrl us.logoutUrl
defaultLayout us.defaultLayout
avatarURL us.avatarURL
if (meeting.breakoutRoomsParams != null) {
breakoutRooms {
enabled meeting.breakoutRoomsParams.enabled
record meeting.breakoutRoomsParams.record
privateChatEnabled meeting.breakoutRoomsParams.privateChatEnabled
}
}
customdata (
meeting.getUserCustomData(us.externUserID).collect { k, v ->
["$k": v]