Merge remote-tracking branch 'upstream/v3.0.x-release' into pres-graphql

This commit is contained in:
Ramón Souza 2023-10-04 08:04:35 -03:00
commit 128e89fc83
22 changed files with 217 additions and 87 deletions

View File

@ -18,7 +18,8 @@ case class MeetingLockSettingsDbModel(
hideUserList: Boolean, hideUserList: Boolean,
lockOnJoin: Boolean, lockOnJoin: Boolean,
lockOnJoinConfigurable: Boolean, lockOnJoinConfigurable: Boolean,
hideViewersCursor: Boolean hideViewersCursor: Boolean,
hideViewersAnnotation: Boolean
) )
class MeetingLockSettingsDbTableDef(tag: Tag) extends Table[MeetingLockSettingsDbModel](tag, "meeting_lockSettings") { class MeetingLockSettingsDbTableDef(tag: Tag) extends Table[MeetingLockSettingsDbModel](tag, "meeting_lockSettings") {
@ -32,10 +33,11 @@ class MeetingLockSettingsDbTableDef(tag: Tag) extends Table[MeetingLockSettingsD
val lockOnJoin = column[Boolean]("lockOnJoin") val lockOnJoin = column[Boolean]("lockOnJoin")
val lockOnJoinConfigurable = column[Boolean]("lockOnJoinConfigurable") val lockOnJoinConfigurable = column[Boolean]("lockOnJoinConfigurable")
val hideViewersCursor = column[Boolean]("hideViewersCursor") val hideViewersCursor = column[Boolean]("hideViewersCursor")
val hideViewersAnnotation = column[Boolean]("hideViewersAnnotation")
// def fk_meetingId: ForeignKeyQuery[MeetingDbTableDef, MeetingDbModel] = foreignKey("fk_meetingId", meetingId, TableQuery[MeetingDbTableDef])(_.meetingId) // def fk_meetingId: ForeignKeyQuery[MeetingDbTableDef, MeetingDbModel] = foreignKey("fk_meetingId", meetingId, TableQuery[MeetingDbTableDef])(_.meetingId)
override def * : ProvenShape[MeetingLockSettingsDbModel] = (meetingId, disableCam, disableMic, disablePrivateChat, disablePublicChat, disableNotes, hideUserList, lockOnJoin, lockOnJoinConfigurable, hideViewersCursor) <> (MeetingLockSettingsDbModel.tupled, MeetingLockSettingsDbModel.unapply) override def * : ProvenShape[MeetingLockSettingsDbModel] = (meetingId, disableCam, disableMic, disablePrivateChat, disablePublicChat, disableNotes, hideUserList, lockOnJoin, lockOnJoinConfigurable, hideViewersCursor, hideViewersAnnotation) <> (MeetingLockSettingsDbModel.tupled, MeetingLockSettingsDbModel.unapply)
} }
object MeetingLockSettingsDAO { object MeetingLockSettingsDAO {
@ -52,7 +54,8 @@ object MeetingLockSettingsDAO {
hideUserList = lockSettingsProps.hideUserList, hideUserList = lockSettingsProps.hideUserList,
lockOnJoin = lockSettingsProps.lockOnJoin, lockOnJoin = lockSettingsProps.lockOnJoin,
lockOnJoinConfigurable = lockSettingsProps.lockOnJoinConfigurable, lockOnJoinConfigurable = lockSettingsProps.lockOnJoinConfigurable,
hideViewersCursor = lockSettingsProps.hideViewersCursor hideViewersCursor = lockSettingsProps.hideViewersCursor,
hideViewersAnnotation = lockSettingsProps.hideViewersAnnotation,
) )
) )
).onComplete { ).onComplete {
@ -76,7 +79,8 @@ object MeetingLockSettingsDAO {
hideUserList = permissions.hideUserList, hideUserList = permissions.hideUserList,
lockOnJoin = permissions.lockOnJoin, lockOnJoin = permissions.lockOnJoin,
lockOnJoinConfigurable = permissions.lockOnJoinConfigurable, lockOnJoinConfigurable = permissions.lockOnJoinConfigurable,
hideViewersCursor = permissions.hideViewersCursor hideViewersCursor = permissions.hideViewersCursor,
hideViewersAnnotation = permissions.hideViewersAnnotation,
), ),
) )
).onComplete { ).onComplete {

View File

@ -3,7 +3,6 @@ package main
import ( import (
"fmt" "fmt"
"github.com/iMDT/bbb-graphql-middleware/internal/msgpatch" "github.com/iMDT/bbb-graphql-middleware/internal/msgpatch"
"github.com/iMDT/bbb-graphql-middleware/internal/rediscli"
"github.com/iMDT/bbb-graphql-middleware/internal/websrv" "github.com/iMDT/bbb-graphql-middleware/internal/websrv"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"net/http" "net/http"
@ -21,7 +20,7 @@ func main() {
msgpatch.ClearAllCaches() msgpatch.ClearAllCaches()
// Listen msgs from akka (for example to invalidate connection) // Listen msgs from akka (for example to invalidate connection)
go rediscli.StartRedisListener() go websrv.StartRedisListener()
// Websocket listener // Websocket listener
// set default port // set default port

View File

@ -1,13 +0,0 @@
package rediscli
import "github.com/redis/go-redis/v9"
var redisClient = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379",
Password: "",
DB: 0,
})
func GetRedisConn() *redis.Client {
return redisClient
}

View File

@ -1,49 +0,0 @@
package rediscli
import (
"context"
"encoding/json"
log "github.com/sirupsen/logrus"
"strings"
)
func StartRedisListener() {
log := log.WithField("_routine", "StartRedisListener")
var ctx = context.Background()
subscriber := GetRedisConn().Subscribe(ctx, "from-akka-apps-redis-channel")
for {
msg, err := subscriber.ReceiveMessage(ctx)
if err != nil {
log.Errorf("error: ", err)
}
// Skip parsing unnecessary messages
if !strings.Contains(msg.Payload, "InvalidateUserGraphqlConnectionSysMsg") {
continue
}
var message interface{}
if err := json.Unmarshal([]byte(msg.Payload), &message); err != nil {
panic(err)
}
messageAsMap := message.(map[string]interface{})
messageEnvelopeAsMap := messageAsMap["envelope"].(map[string]interface{})
messageType := messageEnvelopeAsMap["name"]
if messageType == "InvalidateUserGraphqlConnectionSysMsg" {
messageCoreAsMap := messageAsMap["core"].(map[string]interface{})
messageBodyAsMap := messageCoreAsMap["body"].(map[string]interface{})
sessionTokenToInvalidate := messageBodyAsMap["sessionToken"]
log.Debugf("Received invalidate request for sessionToken %v", sessionTokenToInvalidate)
//Not being used yet
//websrv.InvalidateSessionTokenConnections(sessionTokenToInvalidate.(string))
}
}
}

View File

@ -6,7 +6,6 @@ import (
"github.com/iMDT/bbb-graphql-middleware/internal/common" "github.com/iMDT/bbb-graphql-middleware/internal/common"
"github.com/iMDT/bbb-graphql-middleware/internal/hascli" "github.com/iMDT/bbb-graphql-middleware/internal/hascli"
"github.com/iMDT/bbb-graphql-middleware/internal/msgpatch" "github.com/iMDT/bbb-graphql-middleware/internal/msgpatch"
"github.com/iMDT/bbb-graphql-middleware/internal/rediscli"
"github.com/iMDT/bbb-graphql-middleware/internal/websrv/reader" "github.com/iMDT/bbb-graphql-middleware/internal/websrv/reader"
"github.com/iMDT/bbb-graphql-middleware/internal/websrv/writer" "github.com/iMDT/bbb-graphql-middleware/internal/websrv/writer"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -65,7 +64,7 @@ func ConnectionHandler(w http.ResponseWriter, r *http.Request) {
sessionTokenRemoved := BrowserConnections[browserConnectionId].SessionToken sessionTokenRemoved := BrowserConnections[browserConnectionId].SessionToken
delete(BrowserConnections, browserConnectionId) delete(BrowserConnections, browserConnectionId)
BrowserConnectionsMutex.Unlock() BrowserConnectionsMutex.Unlock()
go rediscli.SendUserGraphqlConnectionClosedSysMsg(sessionTokenRemoved, browserConnectionId) go SendUserGraphqlConnectionClosedSysMsg(sessionTokenRemoved, browserConnectionId)
log.Infof("connection removed") log.Infof("connection removed")
}() }()
@ -136,7 +135,7 @@ func InvalidateSessionTokenConnections(sessionTokenToInvalidate string) {
browserConnection.HasuraConnection.ContextCancelFunc() browserConnection.HasuraConnection.ContextCancelFunc()
log.Debugf("Processed invalidate request for sessionToken %v (hasura connection %v)", sessionTokenToInvalidate, browserConnection.HasuraConnection.Id) log.Debugf("Processed invalidate request for sessionToken %v (hasura connection %v)", sessionTokenToInvalidate, browserConnection.HasuraConnection.Id)
//go SendInvalidatedUserGraphqlConnectionEvtMsg(browserConnection.SessionToken) go SendUserGraphqlConnectionInvalidatedEvtMsg(browserConnection.SessionToken)
} }
} }
} }

View File

@ -2,7 +2,6 @@ package websrv
import ( import (
"context" "context"
"github.com/iMDT/bbb-graphql-middleware/internal/rediscli"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"sync" "sync"
) )
@ -36,7 +35,7 @@ func ConnectionInitHandler(browserConnectionId string, browserConnectionContext
browserConnection.SessionToken = sessionToken browserConnection.SessionToken = sessionToken
BrowserConnectionsMutex.Unlock() BrowserConnectionsMutex.Unlock()
go rediscli.SendUserGraphqlConnectionStablishedSysMsg(sessionToken, browserConnectionId) go SendUserGraphqlConnectionStablishedSysMsg(sessionToken, browserConnectionId)
break break
} }

View File

@ -1,12 +1,66 @@
package rediscli package websrv
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/redis/go-redis/v9"
log "github.com/sirupsen/logrus"
"strings"
"time" "time"
) )
var redisClient = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379",
Password: "",
DB: 0,
})
func GetRedisConn() *redis.Client {
return redisClient
}
func StartRedisListener() {
log := log.WithField("_routine", "StartRedisListener")
var ctx = context.Background()
subscriber := GetRedisConn().Subscribe(ctx, "from-akka-apps-redis-channel")
for {
msg, err := subscriber.ReceiveMessage(ctx)
if err != nil {
log.Errorf("error: ", err)
}
// Skip parsing unnecessary messages
if !strings.Contains(msg.Payload, "InvalidateUserGraphqlConnectionSysMsg") {
continue
}
var message interface{}
if err := json.Unmarshal([]byte(msg.Payload), &message); err != nil {
panic(err)
}
messageAsMap := message.(map[string]interface{})
messageEnvelopeAsMap := messageAsMap["envelope"].(map[string]interface{})
messageType := messageEnvelopeAsMap["name"]
if messageType == "InvalidateUserGraphqlConnectionSysMsg" {
messageCoreAsMap := messageAsMap["core"].(map[string]interface{})
messageBodyAsMap := messageCoreAsMap["body"].(map[string]interface{})
sessionTokenToInvalidate := messageBodyAsMap["sessionToken"]
log.Debugf("Received invalidate request for sessionToken %v", sessionTokenToInvalidate)
//Not being used yet
InvalidateSessionTokenConnections(sessionTokenToInvalidate.(string))
}
}
}
func getCurrTimeInMs() int64 { func getCurrTimeInMs() int64 {
currentTime := time.Now() currentTime := time.Now()
milliseconds := currentTime.UnixNano() / int64(time.Millisecond) milliseconds := currentTime.UnixNano() / int64(time.Millisecond)

View File

@ -158,7 +158,8 @@ create table "meeting_lockSettings" (
"hideUserList" boolean, "hideUserList" boolean,
"lockOnJoin" boolean, "lockOnJoin" boolean,
"lockOnJoinConfigurable" boolean, "lockOnJoinConfigurable" boolean,
"hideViewersCursor" boolean "hideViewersCursor" boolean,
"hideViewersAnnotation" boolean
); );
create index "idx_meeting_lockSettings_meetingId" on "meeting_lockSettings"("meetingId"); create index "idx_meeting_lockSettings_meetingId" on "meeting_lockSettings"("meetingId");
@ -172,6 +173,7 @@ SELECT
mls."disableNotes", mls."disableNotes",
mls."hideUserList", mls."hideUserList",
mls."hideViewersCursor", mls."hideViewersCursor",
mls."hideViewersAnnotation",
mup."webcamsOnlyForModerator", mup."webcamsOnlyForModerator",
CASE WHEN CASE WHEN
mls."disableCam" IS TRUE THEN TRUE mls."disableCam" IS TRUE THEN TRUE
@ -181,6 +183,7 @@ SELECT
WHEN mls."disableNotes" IS TRUE THEN TRUE WHEN mls."disableNotes" IS TRUE THEN TRUE
WHEN mls."hideUserList" IS TRUE THEN TRUE WHEN mls."hideUserList" IS TRUE THEN TRUE
WHEN mls."hideViewersCursor" IS TRUE THEN TRUE WHEN mls."hideViewersCursor" IS TRUE THEN TRUE
WHEN mls."hideViewersAnnotation" IS TRUE THEN TRUE
WHEN mup."webcamsOnlyForModerator" IS TRUE THEN TRUE WHEN mup."webcamsOnlyForModerator" IS TRUE THEN TRUE
ELSE FALSE ELSE FALSE
END "hasActiveLockSetting" END "hasActiveLockSetting"

View File

@ -18,6 +18,7 @@ select_permissions:
- hasActiveLockSetting - hasActiveLockSetting
- hideUserList - hideUserList
- hideViewersCursor - hideViewersCursor
- hideViewersAnnotation
- webcamsOnlyForModerator - webcamsOnlyForModerator
filter: filter:
meetingId: meetingId:

View File

@ -6,6 +6,16 @@ configuration:
custom_column_names: {} custom_column_names: {}
custom_name: pres_annotation_curr custom_name: pres_annotation_curr
custom_root_fields: {} custom_root_fields: {}
object_relationships:
- name: user
using:
manual_configuration:
column_mapping:
userId: userId
insertion_order: null
remote_table:
name: v_user_ref
schema: public
select_permissions: select_permissions:
- role: bbb_client - role: bbb_client
permission: permission:
@ -18,5 +28,26 @@ select_permissions:
- annotationInfo - annotationInfo
- lastUpdatedAt - lastUpdatedAt
filter: filter:
meetingId: _and:
_eq: X-Hasura-MeetingId - meetingId:
_eq: X-Hasura-UserId
- _or:
- meetingId:
_eq: X-Hasura-ModeratorInMeeting
- userId:
_eq: X-Hasura-LockedUserId
- meetingId:
_neq: X-Hasura-LockedInMeeting
- _exists:
_table:
name: v_meeting_lockSettings
schema: public
_where:
_and:
- meetingId:
_eq: X-Hasura-MeetingId
- hideViewersAnnotation:
_eq: false
- user:
isModerator:
_eq: true

View File

@ -6,6 +6,16 @@ configuration:
custom_column_names: {} custom_column_names: {}
custom_name: pres_annotation_history_curr custom_name: pres_annotation_history_curr
custom_root_fields: {} custom_root_fields: {}
object_relationships:
- name: user
using:
manual_configuration:
column_mapping:
userId: userId
insertion_order: null
remote_table:
name: v_user_ref
schema: public
select_permissions: select_permissions:
- role: bbb_client - role: bbb_client
permission: permission:
@ -17,5 +27,26 @@ select_permissions:
- sequence - sequence
- annotationInfo - annotationInfo
filter: filter:
meetingId: _and:
_eq: X-Hasura-MeetingId - meetingId:
_eq: X-Hasura-MeetingId
- _or:
- meetingId:
_eq: X-Hasura-ModeratorInMeeting
- userId:
_eq: X-Hasura-LockedUserId
- meetingId:
_neq: X-Hasura-LockedInMeeting
- _exists:
_table:
name: v_meeting_lockSettings
schema: public
_where:
_and:
- meetingId:
_eq: X-Hasura-MeetingId
- hideViewersAnnotation:
_eq: false
- user:
isModerator:
_eq: true

View File

@ -28,5 +28,26 @@ select_permissions:
- xPercent - xPercent
- yPercent - yPercent
filter: filter:
meetingId: _and:
_eq: X-Hasura-MeetingId - meetingId:
_eq: X-Hasura-MeetingId
- _or:
- user:
isModerator:
_eq: true
- meetingId:
_eq: X-Hasura-ModeratorInMeeting
- meetingId:
_neq: X-Hasura-LockedInMeeting
- userId:
_eq: X-Hasura-LockedUserId
- _exists:
_table:
name: v_meeting_lockSettings
schema: public
_where:
_and:
- meetingId:
_eq: X-Hasura-MeetingId
- hideViewersCursor:
_eq: false

View File

@ -85,6 +85,7 @@ const ChatMesssage: React.FC<ChatMessageProps> = ({
const sameSender = (previousMessage?.user?.userId const sameSender = (previousMessage?.user?.userId
|| lastSenderPreviousPage) === message?.user?.userId; || lastSenderPreviousPage) === message?.user?.userId;
const isSystemSender = message.messageType === ChatMessageType.BREAKOUT_ROOM;
const dateTime = new Date(message?.createdAt); const dateTime = new Date(message?.createdAt);
const messageContent: { const messageContent: {
name: string, name: string,
@ -123,12 +124,26 @@ const ChatMesssage: React.FC<ChatMessageProps> = ({
/> />
), ),
}; };
case ChatMessageType.BREAKOUT_ROOM:
return {
name: message.senderName,
color: '#0F70D7',
isModerator: true,
isSystemSender: true,
component: (
<ChatMessageTextContent
emphasizedMessage
text={message.message}
/>
),
};
case ChatMessageType.TEXT: case ChatMessageType.TEXT:
default: default:
return { return {
name: message.user?.name, name: message.user?.name,
color: message.user?.color, color: message.user?.color,
isModerator: message.user?.isModerator, isModerator: message.user?.isModerator,
isSystemSender: ChatMessageType.BREAKOUT_ROOM,
component: ( component: (
<ChatMessageTextContent <ChatMessageTextContent
emphasizedMessage={message?.user?.isModerator} emphasizedMessage={message?.user?.isModerator}
@ -139,14 +154,14 @@ const ChatMesssage: React.FC<ChatMessageProps> = ({
} }
}, []); }, []);
return ( return (
<ChatWrapper sameSender={sameSender} ref={messageRef}> <ChatWrapper isSystemSender={isSystemSender} sameSender={sameSender} ref={messageRef}>
{(!message?.user || !sameSender) && ( {(!message?.user || !sameSender) && (
<ChatAvatar <ChatAvatar
avatar={message.user?.avatar} avatar={message.user?.avatar}
color={messageContent.color} color={messageContent.color}
moderator={messageContent.isModerator} moderator={messageContent.isModerator}
> >
{message.user?.avatar.length === 0 ? messageContent.name.toLowerCase().slice(0, 2) || '' : ''} {!message.user || message.user?.avatar.length === 0 ? messageContent.name.toLowerCase().slice(0, 2) || 'q' : 'a'}
</ChatAvatar> </ChatAvatar>
)} )}
<ChatContent sameSender={message?.user ? sameSender : false}> <ChatContent sameSender={message?.user ? sameSender : false}>

View File

@ -17,6 +17,7 @@ import {
interface ChatWrapperProps { interface ChatWrapperProps {
sameSender: boolean; sameSender: boolean;
isSystemSender: boolean;
} }
interface ChatContentProps { interface ChatContentProps {
@ -50,6 +51,12 @@ export const ChatWrapper = styled.div<ChatWrapperProps>`
margin: ${borderSize} ${borderSize} 0 0; margin: ${borderSize} ${borderSize} 0 0;
} }
font-size: ${fontSizeBase}; font-size: ${fontSizeBase};
${({ isSystemSender }) => isSystemSender && `
background-color: #fef9f1;
border-left: 2px solid #f5c67f;
border-radius: 0px 3px 3px 0px;
padding: 8px 2px;
`}
`; `;
export const ChatContent = styled.div<ChatContentProps>` export const ChatContent = styled.div<ChatContentProps>`
@ -118,7 +125,7 @@ export const ChatAvatar = styled.div<ChatAvatarProps>`
${({ moderator }) => moderator && ` ${({ moderator }) => moderator && `
border-radius: 5px; border-radius: 5px;
`} `}
// ================ image ================ // ================ image ================
${({ avatar, emoji, color }) => avatar?.length !== 0 && !emoji && css` ${({ avatar, emoji, color }) => avatar?.length !== 0 && !emoji && css`
background-image: url(${avatar}); background-image: url(${avatar});
@ -136,7 +143,7 @@ export const ChatAvatar = styled.div<ChatAvatarProps>`
justify-content: center; justify-content: center;
align-items:center; align-items:center;
// ================ content ================ // ================ content ================
& .react-loading-skeleton { & .react-loading-skeleton {
height: 2.25rem; height: 2.25rem;
width: 2.25rem; width: 2.25rem;

View File

@ -27,6 +27,8 @@ export const CHAT_MESSAGE_PUBLIC_SUBSCRIPTION = gql`
messageId messageId
createdAt createdAt
messageMetadata messageMetadata
senderName
senderRole
} }
} }
`; `;

View File

@ -10,5 +10,6 @@ export const enum ChatMessageType {
TEXT = 'default', TEXT = 'default',
POLL = 'poll', POLL = 'poll',
PRESENTATION = 'presentation', PRESENTATION = 'presentation',
CHAT_CLEAR = 'publicChatHistoryCleared' CHAT_CLEAR = 'publicChatHistoryCleared',
BREAKOUT_ROOM = 'breakoutRoomModeratorMsg',
} }

View File

@ -434,6 +434,7 @@ exports.dropAreaLeft = 'div[data-test="dropArea-contentLeft"]';
exports.dropAreaRight = 'div[data-test="dropArea-contentRight"]'; exports.dropAreaRight = 'div[data-test="dropArea-contentRight"]';
exports.dropAreaTop = 'div[data-test="dropArea-contentTop"]'; exports.dropAreaTop = 'div[data-test="dropArea-contentTop"]';
exports.dropAreaSidebarBottom = 'div[data-test="dropArea-sidebarContentBottom"]'; exports.dropAreaSidebarBottom = 'div[data-test="dropArea-sidebarContentBottom"]';
exports.selfViewDisableBtn = 'li[data-test="selfViewDisableBtn"]';
exports.videoQualitySelector = 'select[id="setQuality"]'; exports.videoQualitySelector = 'select[id="setQuality"]';
exports.webcamItemTalkingUser = 'div[data-test="webcamItemTalkingUser"]'; exports.webcamItemTalkingUser = 'div[data-test="webcamItemTalkingUser"]';

View File

@ -197,7 +197,7 @@ test.describe.parallel('User', () => {
}); });
// https://docs.bigbluebutton.org/2.6/release-tests.html#see-other-viewers-in-the-users-list // https://docs.bigbluebutton.org/2.6/release-tests.html#see-other-viewers-in-the-users-list
test('Lock See other viewers in the Users list', async ({ browser, context, page }) => { test('Lock See other viewers in the Users list @flaky', async ({ browser, context, page }) => {
const lockViewers = new LockViewers(browser, context); const lockViewers = new LockViewers(browser, context);
await lockViewers.initPages(page); await lockViewers.initPages(page);
await lockViewers.lockSeeOtherViewersUserList(); await lockViewers.lockSeeOtherViewersUserList();

View File

@ -86,6 +86,23 @@ class Webcam extends Page {
await expect(height).toBe(windowHeight); await expect(height).toBe(windowHeight);
} }
async disableSelfView() {
await this.waitAndClick(e.joinVideo);
await this.waitForSelector(e.noneBackgroundButton);
await uploadBackgroundVideoImage(this);
await this.waitAndClick(e.selectCustomBackground);
await sleep(1000);
await this.waitAndClick(e.startSharingWebcam);
await this.waitForSelector(e.webcamContainer);
await this.waitAndClick(e.dropdownWebcamButton);
await this.waitAndClick(e.selfViewDisableBtn);
const webcamVideoLocator = await this.getLocator(e.webcamConnecting);
await expect(webcamVideoLocator).toHaveScreenshot('disable-self-view.png');
}
async managingNewBackground() { async managingNewBackground() {
await this.waitAndClick(e.joinVideo); await this.waitAndClick(e.joinVideo);
await this.waitForSelector(e.noneBackgroundButton); await this.waitForSelector(e.noneBackgroundButton);

View File

@ -42,6 +42,12 @@ test.describe.parallel('Webcam', () => {
await webcam.webcamFullscreen(); await webcam.webcamFullscreen();
}); });
test('Disable Self-view', async ({ browser, page }) => {
const webcam = new Webcam(browser, page);
await webcam.init(true, true);
await webcam.disableSelfView();
});
test.describe('Webcam background', () => { test.describe('Webcam background', () => {
/* this test has the flaky tag because it is breaking due to a default video from chrome that /* this test has the flaky tag because it is breaking due to a default video from chrome that
is overlapping the virtual background. */ is overlapping the virtual background. */

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

@ -84,6 +84,7 @@ class ConnectionController {
"X-Hasura-Role" "bbb_client" "X-Hasura-Role" "bbb_client"
"X-Hasura-Locked" u.locked ? "true" : "false" "X-Hasura-Locked" u.locked ? "true" : "false"
"X-Hasura-LockedInMeeting" u.locked ? userSession.meetingID : "" "X-Hasura-LockedInMeeting" u.locked ? userSession.meetingID : ""
"X-Hasura-LockedUserId" u.locked ? userSession.internalUserId : ""
"X-Hasura-ModeratorInMeeting" u.isModerator() ? userSession.meetingID : "" "X-Hasura-ModeratorInMeeting" u.isModerator() ? userSession.meetingID : ""
"X-Hasura-PresenterInMeeting" u.isPresenter() ? userSession.meetingID : "" "X-Hasura-PresenterInMeeting" u.isPresenter() ? userSession.meetingID : ""
"X-Hasura-UserId" userSession.internalUserId "X-Hasura-UserId" userSession.internalUserId