Merge pull request #10458 from pedrobmarin/avatar-image
Support for avatar images
This commit is contained in:
commit
d5450af5df
@ -56,7 +56,7 @@ trait RegisterUserReqMsgHdlr {
|
||||
val g = GuestApprovedVO(regUser.id, GuestStatus.ALLOW)
|
||||
UsersApp.approveOrRejectGuest(liveMeeting, outGW, g, SystemUser.ID)
|
||||
case GuestStatus.WAIT =>
|
||||
val guest = GuestWaiting(regUser.id, regUser.name, regUser.role, regUser.guest, regUser.authed)
|
||||
val guest = GuestWaiting(regUser.id, regUser.name, regUser.role, regUser.guest, regUser.avatarURL, regUser.authed)
|
||||
addGuestToWaitingForApproval(guest, liveMeeting.guestsWaiting)
|
||||
notifyModeratorsOfGuestWaiting(Vector(guest), liveMeeting.users2x, liveMeeting.props.meetingProp.intId)
|
||||
case GuestStatus.DENY =>
|
||||
|
@ -51,7 +51,7 @@ class GuestsWaiting {
|
||||
def setGuestPolicy(policy: GuestPolicy) = guestPolicy = policy
|
||||
}
|
||||
|
||||
case class GuestWaiting(intId: String, name: String, role: String, guest: Boolean, authenticated: Boolean)
|
||||
case class GuestWaiting(intId: String, name: String, role: String, guest: Boolean, avatar: String, authenticated: Boolean)
|
||||
case class GuestPolicy(policy: String, setBy: String)
|
||||
|
||||
object GuestPolicyType {
|
||||
|
@ -44,7 +44,7 @@ object MsgBuilder {
|
||||
val envelope = BbbCoreEnvelope(GetGuestsWaitingApprovalRespMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(GetGuestsWaitingApprovalRespMsg.NAME, meetingId, userId)
|
||||
|
||||
val guestsWaiting = guests.map(g => GuestWaitingVO(g.intId, g.name, g.role, g.guest, g.authenticated))
|
||||
val guestsWaiting = guests.map(g => GuestWaitingVO(g.intId, g.name, g.role, g.guest, g.avatar, g.authenticated))
|
||||
val body = GetGuestsWaitingApprovalRespMsgBody(guestsWaiting)
|
||||
val event = GetGuestsWaitingApprovalRespMsg(header, body)
|
||||
|
||||
@ -56,7 +56,7 @@ object MsgBuilder {
|
||||
val envelope = BbbCoreEnvelope(GuestsWaitingForApprovalEvtMsg.NAME, routing)
|
||||
val header = BbbClientMsgHeader(GuestsWaitingForApprovalEvtMsg.NAME, meetingId, userId)
|
||||
|
||||
val guestsWaiting = guests.map(g => GuestWaitingVO(g.intId, g.name, g.role, g.guest, g.authenticated))
|
||||
val guestsWaiting = guests.map(g => GuestWaitingVO(g.intId, g.name, g.role, g.guest, g.avatar, g.authenticated))
|
||||
val body = GuestsWaitingForApprovalEvtMsgBody(guestsWaiting)
|
||||
val event = GuestsWaitingForApprovalEvtMsg(header, body)
|
||||
|
||||
|
@ -20,13 +20,13 @@ trait FakeTestData {
|
||||
val guest1 = createUserVoiceAndCam(liveMeeting, Roles.VIEWER_ROLE, guest = true, authed = true, CallingWith.WEBRTC, muted = false,
|
||||
talking = false, listenOnly = false)
|
||||
Users2x.add(liveMeeting.users2x, guest1)
|
||||
val guestWait1 = GuestWaiting(guest1.intId, guest1.name, guest1.role, guest1.guest, guest1.authed)
|
||||
val guestWait1 = GuestWaiting(guest1.intId, guest1.name, guest1.role, guest1.guest, "", guest1.authed)
|
||||
GuestsWaiting.add(liveMeeting.guestsWaiting, guestWait1)
|
||||
|
||||
val guest2 = createUserVoiceAndCam(liveMeeting, Roles.VIEWER_ROLE, guest = true, authed = true, CallingWith.FLASH, muted = false,
|
||||
talking = false, listenOnly = false)
|
||||
Users2x.add(liveMeeting.users2x, guest2)
|
||||
val guestWait2 = GuestWaiting(guest2.intId, guest2.name, guest2.role, guest2.guest, guest2.authed)
|
||||
val guestWait2 = GuestWaiting(guest2.intId, guest2.name, guest2.role, guest2.guest, "", guest2.authed)
|
||||
GuestsWaiting.add(liveMeeting.guestsWaiting, guestWait2)
|
||||
|
||||
val vu1 = FakeUserGenerator.createFakeVoiceOnlyUser(CallingWith.PHONE, muted = false, talking = false, listenOnly = false)
|
||||
|
@ -19,7 +19,7 @@ case class GetGuestsWaitingApprovalRespMsg(
|
||||
body: GetGuestsWaitingApprovalRespMsgBody
|
||||
) extends BbbCoreMsg
|
||||
case class GetGuestsWaitingApprovalRespMsgBody(guests: Vector[GuestWaitingVO])
|
||||
case class GuestWaitingVO(intId: String, name: String, role: String, guest: Boolean, authenticated: Boolean)
|
||||
case class GuestWaitingVO(intId: String, name: String, role: String, guest: Boolean, avatar: String, authenticated: Boolean)
|
||||
|
||||
/**
|
||||
* Message sent to client for list of guest waiting for approval. This is sent when
|
||||
|
@ -923,7 +923,7 @@ public class MeetingService implements MessageListener {
|
||||
} else {
|
||||
if (message.userId.startsWith("v_")) {
|
||||
// A dial-in user joined the meeting. Dial-in users by convention has userId that starts with "v_".
|
||||
User vuser = new User(message.userId, message.userId, message.name, "DIAL-IN-USER", "no-avatar-url",
|
||||
User vuser = new User(message.userId, message.userId, message.name, "DIAL-IN-USER", "",
|
||||
true, GuestPolicy.ALLOW, "DIAL-IN");
|
||||
vuser.setVoiceJoined(true);
|
||||
m.userJoined(vuser);
|
||||
|
@ -78,6 +78,7 @@ public class ParamsProcessorUtil {
|
||||
private Boolean moderatorsJoinViaHTML5Client;
|
||||
private Boolean attendeesJoinViaHTML5Client;
|
||||
private Boolean allowRequestsWithoutSession;
|
||||
private Boolean useDefaultAvatar = false;
|
||||
private String defaultAvatarURL;
|
||||
private String defaultConfigURL;
|
||||
private String defaultGuestPolicy;
|
||||
@ -464,6 +465,8 @@ public class ParamsProcessorUtil {
|
||||
externalMeetingId = externalHash + "-" + timeStamp;
|
||||
}
|
||||
|
||||
String avatarURL = useDefaultAvatar ? defaultAvatarURL : "";
|
||||
|
||||
// Create the meeting with all passed in parameters.
|
||||
Meeting meeting = new Meeting.Builder(externalMeetingId,
|
||||
internalMeetingId, createTime).withName(meetingName)
|
||||
@ -474,7 +477,7 @@ public class ParamsProcessorUtil {
|
||||
.withBannerText(bannerText).withBannerColor(bannerColor)
|
||||
.withTelVoice(telVoice).withWebVoice(webVoice)
|
||||
.withDialNumber(dialNumber)
|
||||
.withDefaultAvatarURL(defaultAvatarURL)
|
||||
.withDefaultAvatarURL(avatarURL)
|
||||
.withAutoStartRecording(autoStartRec)
|
||||
.withAllowStartStopRecording(allowStartStoptRec)
|
||||
.withWebcamsOnlyForModerator(webcamsOnlyForMod)
|
||||
@ -952,6 +955,10 @@ public class ParamsProcessorUtil {
|
||||
this.webcamsOnlyForModerator = webcamsOnlyForModerator;
|
||||
}
|
||||
|
||||
public void setUseDefaultAvatar(Boolean value) {
|
||||
this.useDefaultAvatar = value;
|
||||
}
|
||||
|
||||
public void setdefaultAvatarURL(String url) {
|
||||
this.defaultAvatarURL = url;
|
||||
}
|
||||
|
@ -126,6 +126,7 @@ class MessageListItem extends Component {
|
||||
className={styles.avatar}
|
||||
color={user.color}
|
||||
moderator={user.isModerator}
|
||||
avatar={user.avatar}
|
||||
>
|
||||
{user.name.toLowerCase().slice(0, 2)}
|
||||
</UserAvatar>
|
||||
|
@ -50,13 +50,18 @@ const mapGroupMessage = (message) => {
|
||||
const sender = Users.findOne({ userId: message.sender },
|
||||
{
|
||||
fields: {
|
||||
color: 1, role: 1, name: 1, connectionStatus: 1,
|
||||
color: 1,
|
||||
role: 1,
|
||||
name: 1,
|
||||
avatar: 1,
|
||||
connectionStatus: 1,
|
||||
},
|
||||
});
|
||||
const {
|
||||
color,
|
||||
role,
|
||||
name,
|
||||
avatar,
|
||||
connectionStatus,
|
||||
} = sender;
|
||||
|
||||
@ -64,6 +69,7 @@ const mapGroupMessage = (message) => {
|
||||
color,
|
||||
isModerator: role === ROLE_MODERATOR,
|
||||
name,
|
||||
avatar,
|
||||
isOnline: connectionStatus === CONNECTION_STATUS_ONLINE,
|
||||
};
|
||||
|
||||
|
@ -84,8 +84,9 @@ class ConnectionStatusComponent extends PureComponent {
|
||||
<div className={styles.left}>
|
||||
<div className={styles.avatar}>
|
||||
<UserAvatar
|
||||
className={styles.icon}
|
||||
className={cx({ [styles.initials]: conn.avatar.length === 0 })}
|
||||
you={conn.you}
|
||||
avatar={conn.avatar}
|
||||
moderator={conn.moderator}
|
||||
color={conn.color}
|
||||
>
|
||||
|
@ -82,7 +82,7 @@
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.icon {
|
||||
.initials {
|
||||
min-width: 2.25rem;
|
||||
height: 2.25rem;
|
||||
}
|
||||
|
@ -87,6 +87,7 @@ const getConnectionStatus = () => {
|
||||
userId: 1,
|
||||
name: 1,
|
||||
role: 1,
|
||||
avatar: 1,
|
||||
color: 1,
|
||||
connectionStatus: 1,
|
||||
},
|
||||
@ -96,6 +97,7 @@ const getConnectionStatus = () => {
|
||||
userId,
|
||||
name,
|
||||
role,
|
||||
avatar,
|
||||
color,
|
||||
connectionStatus: userStatus,
|
||||
} = user;
|
||||
@ -105,6 +107,7 @@ const getConnectionStatus = () => {
|
||||
if (status) {
|
||||
result.push({
|
||||
name,
|
||||
avatar,
|
||||
offline: userStatus === 'offline',
|
||||
you: Auth.userID === userId,
|
||||
moderator: role === ROLE_MODERATOR,
|
||||
|
@ -14,6 +14,8 @@ const propTypes = {
|
||||
voice: PropTypes.bool,
|
||||
noVoice: PropTypes.bool,
|
||||
color: PropTypes.string,
|
||||
emoji: PropTypes.bool,
|
||||
avatar: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
@ -26,6 +28,8 @@ const defaultProps = {
|
||||
voice: false,
|
||||
noVoice: false,
|
||||
color: '#000',
|
||||
emoji: false,
|
||||
avatar: '',
|
||||
className: null,
|
||||
};
|
||||
|
||||
@ -38,6 +42,8 @@ const UserAvatar = ({
|
||||
listenOnly,
|
||||
color,
|
||||
voice,
|
||||
emoji,
|
||||
avatar,
|
||||
noVoice,
|
||||
className,
|
||||
}) => (
|
||||
@ -60,14 +66,27 @@ const UserAvatar = ({
|
||||
>
|
||||
|
||||
<div className={cx({
|
||||
[styles.talking]: (talking && !muted),
|
||||
[styles.talking]: (talking && !muted && avatar.length === 0),
|
||||
})}
|
||||
/>
|
||||
|
||||
|
||||
<div className={styles.content}>
|
||||
{children}
|
||||
</div>
|
||||
{avatar.length !== 0 && !emoji
|
||||
? (
|
||||
<div className={styles.image}>
|
||||
<img
|
||||
className={cx(styles.img, {
|
||||
[styles.circle]: !moderator,
|
||||
[styles.square]: moderator,
|
||||
})}
|
||||
src={avatar}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className={styles.content}>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
);
|
||||
|
||||
|
@ -13,7 +13,8 @@
|
||||
|
||||
.avatar {
|
||||
position: relative;
|
||||
padding-bottom: 2rem;
|
||||
height: 2.25rem;
|
||||
min-width: 2.25rem;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
font-size: .85rem;
|
||||
@ -166,6 +167,25 @@
|
||||
@include indicatorStyles();
|
||||
}
|
||||
|
||||
.image {
|
||||
display: flex;
|
||||
height: 2rem;
|
||||
width: 2rem;
|
||||
|
||||
.img {
|
||||
object-fit: cover;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.circle {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.square {
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
color: var(--user-avatar-text);
|
||||
top: 50%;
|
||||
|
@ -12,11 +12,14 @@ const defaultProps = {
|
||||
};
|
||||
|
||||
const ChatAvatar = (props) => {
|
||||
const { color, name, isModerator } = props;
|
||||
const {
|
||||
color, name, avatar, isModerator,
|
||||
} = props;
|
||||
return (
|
||||
|
||||
<UserAvatar
|
||||
moderator={isModerator}
|
||||
avatar={avatar}
|
||||
color={color}
|
||||
>
|
||||
{name.toLowerCase().slice(0, 2)}
|
||||
|
@ -96,6 +96,7 @@ const ChatListItem = (props) => {
|
||||
<ChatAvatar
|
||||
isModerator={chat.isModerator}
|
||||
color={chat.color}
|
||||
avatar={chat.avatar}
|
||||
name={chat.name.toLowerCase().slice(0, 2)}
|
||||
/>
|
||||
)}
|
||||
|
@ -256,6 +256,7 @@ const getActiveChats = (chatID) => {
|
||||
const activeChat = op;
|
||||
activeChat.unreadCounter = UnreadMessages.count(op.userId);
|
||||
activeChat.name = op.name;
|
||||
activeChat.avatar = op.avatar;
|
||||
activeChat.isModerator = op.role === ROLE_MODERATOR;
|
||||
activeChat.lastActivity = idsWithTimeStamp[`${op.userId}`];
|
||||
return activeChat;
|
||||
|
@ -538,6 +538,8 @@ class UserDropdown extends PureComponent {
|
||||
voice={voiceUser.isVoiceUser}
|
||||
noVoice={!voiceUser.isVoiceUser}
|
||||
color={user.color}
|
||||
emoji={user.emoji !== 'none'}
|
||||
avatar={user.avatar}
|
||||
>
|
||||
{
|
||||
userInBreakout
|
||||
|
@ -66,13 +66,14 @@ const getNameInitials = (name) => {
|
||||
return nameInitials.replace(/^\w/, c => c.toUpperCase());
|
||||
}
|
||||
|
||||
const renderGuestUserItem = (name, color, handleAccept, handleDeny, role, sequence, userId, intl) => (
|
||||
const renderGuestUserItem = (name, color, handleAccept, handleDeny, role, sequence, userId, avatar, intl) => (
|
||||
<div key={`userlist-item-${userId}`} className={styles.listItem}>
|
||||
<div key={`user-content-container-${userId}`} className={styles.userContentContainer}>
|
||||
<div key={`user-avatar-container-${userId}`} className={styles.userAvatar}>
|
||||
<UserAvatar
|
||||
key={`user-avatar-${userId}`}
|
||||
moderator={role === 'MODERATOR'}
|
||||
avatar={avatar}
|
||||
color={color}
|
||||
>
|
||||
{getNameInitials(name)}
|
||||
@ -123,6 +124,7 @@ const renderPendingUsers = (message, usersArray, action, intl) => {
|
||||
user.role,
|
||||
idx + 1,
|
||||
user.intId,
|
||||
user.avatar,
|
||||
intl,
|
||||
))}
|
||||
</div>
|
||||
|
@ -254,9 +254,8 @@ html5ClientUrl=${bigbluebutton.web.serverURL}/html5client/join
|
||||
# The url for where the guest will poll if approved to join or not.
|
||||
defaultGuestWaitURL=${bigbluebutton.web.serverURL}/client/guest-wait.html
|
||||
|
||||
# The default avatar image to display if nothing is passed on the JOIN API (avatarURL)
|
||||
# call. This avatar is displayed if the user isn't sharing the webcam and
|
||||
# the option (displayAvatar) is enabled in config.xml
|
||||
# The default avatar image to display.
|
||||
useDefaultAvatar=false
|
||||
defaultAvatarURL=${bigbluebutton.web.serverURL}/client/avatar.png
|
||||
|
||||
# The URL of the default configuration
|
||||
|
@ -133,6 +133,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
<property name="autoStartRecording" value="${autoStartRecording}"/>
|
||||
<property name="allowStartStopRecording" value="${allowStartStopRecording}"/>
|
||||
<property name="webcamsOnlyForModerator" value="${webcamsOnlyForModerator}"/>
|
||||
<property name="useDefaultAvatar" value="${useDefaultAvatar}"/>
|
||||
<property name="defaultAvatarURL" value="${defaultAvatarURL}"/>
|
||||
<property name="defaultConfigURL" value="${defaultConfigURL}"/>
|
||||
<property name="defaultGuestPolicy" value="${defaultGuestPolicy}"/>
|
||||
|
Loading…
Reference in New Issue
Block a user