feat(reactions): add user reaction
add user-reaction collection add emoji picker for user reaction in the user list add options to enable/disable user-reaction add a way to pass style to emoji-picker component
This commit is contained in:
parent
e79ebb720b
commit
d28b93a586
@ -29,6 +29,7 @@ import clearVoiceCallStates from '/imports/api/voice-call-states/server/modifier
|
||||
import clearVideoStreams from '/imports/api/video-streams/server/modifiers/clearVideoStreams';
|
||||
import clearAuthTokenValidation from '/imports/api/auth-token-validation/server/modifiers/clearAuthTokenValidation';
|
||||
import clearUsersPersistentData from '/imports/api/users-persistent-data/server/modifiers/clearUsersPersistentData';
|
||||
import clearReactions from '/imports/api/user-reaction/server/modifiers/clearReactions';
|
||||
|
||||
import clearWhiteboardMultiUser from '/imports/api/whiteboard-multi-user/server/modifiers/clearWhiteboardMultiUser';
|
||||
import Metrics from '/imports/startup/server/metrics';
|
||||
@ -67,6 +68,7 @@ export default async function meetingHasEnded(meetingId) {
|
||||
clearWhiteboardMultiUser(meetingId),
|
||||
clearScreenshare(meetingId),
|
||||
clearUsersPersistentData(meetingId),
|
||||
clearReactions(meetingId),
|
||||
]);
|
||||
await Metrics.removeMeeting(meetingId);
|
||||
return Logger.info(`Cleared Meetings with id ${meetingId}`);
|
||||
|
14
bigbluebutton-html5/imports/api/user-reaction/index.js
Normal file
14
bigbluebutton-html5/imports/api/user-reaction/index.js
Normal file
@ -0,0 +1,14 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
|
||||
const expireSeconds = Meteor.settings.public.userReaction.expire;
|
||||
const UserReaction = new Mongo.Collection('user-reaction');
|
||||
|
||||
if (Meteor.isServer) {
|
||||
// TTL indexes are special single-field indexes to automatically remove documents
|
||||
// from a collection after a certain amount of time.
|
||||
// A single-field with only a date is necessary to this special single-field index, because
|
||||
// compound indexes do not support TTL.
|
||||
UserReaction._ensureIndex({ creationDate: 1 }, { expireAfterSeconds: expireSeconds });
|
||||
}
|
||||
|
||||
export default UserReaction;
|
@ -0,0 +1,2 @@
|
||||
import './methods';
|
||||
import './publishers';
|
@ -0,0 +1,6 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import setUserReaction from './methods/setUserReaction';
|
||||
|
||||
Meteor.methods({
|
||||
setUserReaction,
|
||||
});
|
@ -0,0 +1,13 @@
|
||||
import { check } from 'meteor/check';
|
||||
import { extractCredentials } from '/imports/api/common/server/helpers';
|
||||
import addUserReaction from '/imports/api/user-reaction/server/modifiers/addUserReaction';
|
||||
|
||||
export default function setUserReaction(reaction) {
|
||||
check(reaction, String);
|
||||
const { meetingId, requesterUserId } = extractCredentials(this.userId);
|
||||
|
||||
check(meetingId, String);
|
||||
check(requesterUserId, String);
|
||||
|
||||
addUserReaction(meetingId, requesterUserId, reaction);
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
import UserReaction from '/imports/api/user-reaction';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import { check } from 'meteor/check';
|
||||
|
||||
export default function addUserReaction(meetingId, userId, reaction) {
|
||||
check(meetingId, String);
|
||||
check(userId, String);
|
||||
check(reaction, String);
|
||||
|
||||
const selector = {
|
||||
creationDate: new Date(),
|
||||
meetingId,
|
||||
userId,
|
||||
};
|
||||
|
||||
const modifier = {
|
||||
$set: {
|
||||
meetingId,
|
||||
userId,
|
||||
reaction,
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
UserReaction.remove({ meetingId, userId });
|
||||
const { numberAffected } = UserReaction.upsert(selector, modifier);
|
||||
|
||||
if (numberAffected) {
|
||||
Logger.verbose(`Added user reaction meetingId=${meetingId} userId=${userId}`);
|
||||
}
|
||||
} catch (err) {
|
||||
Logger.error(`Adding user reaction: ${err}`);
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
import UserReaction from '/imports/api/user-reaction';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
|
||||
export default function clearReactions(meetingId) {
|
||||
const selector = {};
|
||||
|
||||
if (meetingId) {
|
||||
selector.meetingId = meetingId;
|
||||
}
|
||||
|
||||
try {
|
||||
const numberAffected = UserReaction.remove(selector);
|
||||
|
||||
if (numberAffected) {
|
||||
if (meetingId) {
|
||||
Logger.info(`Removed UserReaction (${meetingId})`);
|
||||
} else {
|
||||
Logger.info('Removed UserReaction (all)');
|
||||
}
|
||||
} else {
|
||||
Logger.warn('Removing UserReaction nonaffected');
|
||||
}
|
||||
} catch (err) {
|
||||
Logger.error(`Removing UserReaction: ${err}`);
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import UserReaction from '/imports/api/user-reaction';
|
||||
import { extractCredentials } from '/imports/api/common/server/helpers';
|
||||
|
||||
function userReaction() {
|
||||
if (!this.userId) {
|
||||
return UserReaction.find({ meetingId: '' });
|
||||
}
|
||||
|
||||
const { meetingId, requesterUserId } = extractCredentials(this.userId);
|
||||
|
||||
check(meetingId, String);
|
||||
check(requesterUserId, String);
|
||||
|
||||
Logger.info(`Publishing user reaction for ${meetingId} ${requesterUserId}`);
|
||||
|
||||
return UserReaction.find({ meetingId });
|
||||
}
|
||||
|
||||
function publish(...args) {
|
||||
const boundUserReaction = userReaction.bind(this);
|
||||
return boundUserReaction(...args);
|
||||
}
|
||||
|
||||
Meteor.publish('user-reaction', publish);
|
@ -10,6 +10,7 @@ const propTypes = {
|
||||
description: PropTypes.string,
|
||||
accessKey: PropTypes.string,
|
||||
tabIndex: PropTypes.number,
|
||||
disabled: PropTypes.bool,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
@ -18,6 +19,7 @@ const defaultProps = {
|
||||
description: '',
|
||||
tabIndex: 0,
|
||||
accessKey: null,
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
const messages = defineMessages({
|
||||
@ -62,6 +64,7 @@ class DropdownListItem extends Component {
|
||||
className,
|
||||
style,
|
||||
intl,
|
||||
disabled,
|
||||
'data-test': dataTest,
|
||||
} = this.props;
|
||||
|
||||
@ -71,8 +74,8 @@ class DropdownListItem extends Component {
|
||||
<Styled.Item
|
||||
id={id}
|
||||
ref={injectRef}
|
||||
onClick={onClick}
|
||||
onKeyDown={onKeyDown}
|
||||
onClick={disabled ? () => {} : onClick}
|
||||
onKeyDown={disabled ? () => {} : onKeyDown}
|
||||
tabIndex={tabIndex}
|
||||
aria-labelledby={this.labelID}
|
||||
aria-describedby={this.descID}
|
||||
|
@ -23,7 +23,7 @@ const SUBSCRIPTIONS = [
|
||||
'local-settings', 'users-typing', 'record-meetings', 'video-streams',
|
||||
'connection-status', 'voice-call-states', 'external-video-meetings', 'breakouts', 'breakouts-history',
|
||||
'pads', 'pads-sessions', 'pads-updates', 'notifications', 'audio-captions',
|
||||
'layout-meetings',
|
||||
'layout-meetings', 'user-reaction',
|
||||
];
|
||||
const {
|
||||
localBreakoutsSync,
|
||||
|
@ -4,6 +4,7 @@ import VoiceUsers from '/imports/api/voice-users';
|
||||
import GroupChat from '/imports/api/group-chat';
|
||||
import Breakouts from '/imports/api/breakouts';
|
||||
import Meetings from '/imports/api/meetings';
|
||||
import UserReaction from '/imports/api/user-reaction';
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
import Storage from '/imports/ui/services/storage/session';
|
||||
import { EMOJI_STATUSES } from '/imports/utils/statuses';
|
||||
@ -198,6 +199,25 @@ const addIsSharingWebcam = (users) => {
|
||||
});
|
||||
};
|
||||
|
||||
const addUserReaction = (users) => {
|
||||
const usersReactions = UserReaction.find({
|
||||
meetingId: Auth.meetingID,
|
||||
}).fetch();
|
||||
|
||||
return users.map((user) => {
|
||||
let reaction = '';
|
||||
const obj = usersReactions.find(us => us.userId === user.userId);
|
||||
if (obj !== undefined) {
|
||||
({ reaction } = obj);
|
||||
}
|
||||
|
||||
return {
|
||||
...user,
|
||||
reaction,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const getUsers = () => {
|
||||
let users = Users
|
||||
.find({
|
||||
@ -215,7 +235,7 @@ const getUsers = () => {
|
||||
}
|
||||
}
|
||||
|
||||
return addIsSharingWebcam(addWhiteboardAccess(users)).sort(sortUsers);
|
||||
return addIsSharingWebcam(addUserReaction(addWhiteboardAccess(users))).sort(sortUsers);
|
||||
};
|
||||
|
||||
const formatUsers = (contextUsers, videoUsers, whiteboardUsers) => {
|
||||
|
@ -0,0 +1,43 @@
|
||||
import UserReaction from '/imports/api/user-reaction';
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
import { makeCall } from '/imports/ui/services/api';
|
||||
import { getFromMeetingSettingsAsBoolean } from '/imports/ui/services/meeting-settings';
|
||||
|
||||
const ENABLED = Meteor.settings.public.userReaction.enabled;
|
||||
|
||||
const isEnabled = () => getFromMeetingSettingsAsBoolean('enable-user-reaction', ENABLED);
|
||||
|
||||
const setUserReaction = (reaction) => {
|
||||
if (isEnabled()) {
|
||||
makeCall('setUserReaction', reaction);
|
||||
}
|
||||
};
|
||||
|
||||
const getUserReaction = (userId) => {
|
||||
const reaction = UserReaction.findOne(
|
||||
{
|
||||
meetingId: Auth.meetingID,
|
||||
userId,
|
||||
},
|
||||
{
|
||||
fields:
|
||||
{
|
||||
reaction: 1,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!reaction) {
|
||||
return {
|
||||
reaction: 'none',
|
||||
};
|
||||
}
|
||||
|
||||
return reaction;
|
||||
};
|
||||
|
||||
export default {
|
||||
getUserReaction,
|
||||
setUserReaction,
|
||||
isEnabled,
|
||||
};
|
@ -546,6 +546,9 @@ public:
|
||||
frequentEmojiSortOnClick: false
|
||||
# e.g.: disableEmojis: ['1F595','1F922']
|
||||
disableEmojis: []
|
||||
userReaction:
|
||||
enabled: true
|
||||
expire: 60
|
||||
notes:
|
||||
enabled: true
|
||||
id: notes
|
||||
|
@ -29,6 +29,7 @@ import '/imports/api/pads/server';
|
||||
import '/imports/api/guest-users/server';
|
||||
import '/imports/api/local-settings/server';
|
||||
import '/imports/api/voice-call-states/server';
|
||||
import '/imports/api/user-reaction/server';
|
||||
|
||||
// Commons
|
||||
import '/imports/api/log-client/server';
|
||||
|
Loading…
Reference in New Issue
Block a user