Merge pull request #15845 from JoVictorNunes/improved-error-screen-messages-backport

[2.5] improvement: error screen messages and logs
This commit is contained in:
Ramón Souza 2022-10-17 14:24:56 -03:00 committed by GitHub
commit 8968f1c91a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 124 additions and 18 deletions

View File

@ -11,6 +11,7 @@ import userActivitySign from './methods/userActivitySign';
import userLeftMeeting from './methods/userLeftMeeting';
import changePin from './methods/changePin';
import setRandomUser from './methods/setRandomUser';
import setExitReason from './methods/setExitReason';
Meteor.methods({
setEmojiStatus,
@ -25,4 +26,5 @@ Meteor.methods({
userLeftMeeting,
changePin,
setRandomUser,
setExitReason,
});

View File

@ -0,0 +1,21 @@
import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger';
import { extractCredentials } from '/imports/api/common/server/helpers';
import setUserExitReason from '/imports/api/users/server/modifiers/setUserExitReason';
export default function setExitReason(reason) {
try {
const { meetingId, requesterUserId } = extractCredentials(this.userId);
// Unauthenticated user, just ignore and go ahead.
if (!meetingId || !requesterUserId) return;
check(meetingId, String);
check(requesterUserId, String);
check(reason, String);
setUserExitReason(meetingId, requesterUserId, reason);
} catch (err) {
Logger.error(`Exception while invoking method setExitReason ${err.stack}`);
}
};

View File

@ -45,7 +45,20 @@ export default function userLeaving(meetingId, userId, connectionId) {
ClientConnections.removeClientConnection(`${meetingId}--${userId}`, connectionId);
Logger.info(`User '${userId}' is leaving meeting '${meetingId}'`);
let reason;
if (user.loggedOut) {
// User explicitly requested logout.
reason = 'logout';
} else if (user.exitReason) {
// User didn't requested logout but exited graciously.
reason = user.exitReason;
} else {
// User didn't exit graciously (disconnection).
reason = 'disconnection';
}
Logger.info(`User '${userId}' is leaving meeting '${meetingId}' reason=${reason}`);
RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, userId, payload);
} catch (err) {
Logger.error(`Exception while invoking method userLeaving ${err.stack}`);

View File

@ -0,0 +1,25 @@
import Logger from '/imports/startup/server/logger';
import Users from '/imports/api/users';
export default function setUserExitReason(meetingId, userId, reason) {
const selector = {
meetingId,
userId,
};
const modifier = {
$set: {
exitReason: reason,
},
};
try {
const numberAffected = Users.update(selector, modifier);
if (numberAffected) {
Logger.info(`Set exit reason userId=${userId} meeting=${meetingId}`);
}
} catch (err) {
Logger.error(`Setting user exit reason: ${err}`);
}
};

View File

@ -26,6 +26,7 @@ import DebugWindow from '/imports/ui/components/debug-window/component';
import { ACTIONS, PANELS } from '../../ui/components/layout/enums';
import { isChatEnabled } from '/imports/ui/services/features';
import MediaService from '/imports/ui/components/media/service';
import { makeCall } from '/imports/ui/services/api';
const CHAT_CONFIG = Meteor.settings.public.chat;
const PUBLIC_CHAT_ID = CHAT_CONFIG.public_id;
@ -319,6 +320,10 @@ class Base extends Component {
});
}
static async setExitReason(reason) {
return await makeCall('setExitReason', reason);
}
renderByState() {
const { updateLoadingState } = this;
const stateControls = { updateLoadingState };
@ -332,7 +337,6 @@ class Base extends Component {
meetingEndedReason,
meetingIsBreakout,
subscriptionsReady,
User,
} = this.props;
if ((loading || !subscriptionsReady) && !meetingHasEnded && meetingExist) {
@ -340,30 +344,39 @@ class Base extends Component {
}
if (ejected) {
return (<MeetingEnded code="403" ejectedReason={ejectedReason} />);
return (
<MeetingEnded
code="403"
ejectedReason={ejectedReason}
callback={() => Base.setExitReason('ejected')}
/>
);
}
if ((meetingHasEnded || User?.loggedOut) && meetingIsBreakout) {
window.close();
if (meetingHasEnded && meetingIsBreakout) {
Base.setExitReason('breakoutEnded').finally(() => {
Meteor.disconnect();
window.close();
});
return null;
}
if (((meetingHasEnded && !meetingIsBreakout)) || (codeError && User?.loggedOut)) {
if (meetingHasEnded && !meetingIsBreakout) {
return (
<MeetingEnded
code={codeError}
endedReason={meetingEndedReason}
ejectedReason={ejectedReason}
callback={() => Base.setExitReason('meetingEnded')}
/>
);
}
if (codeError && !meetingHasEnded) {
// 680 is set for the codeError when the user requests a logout
// 680 is set for the codeError when the user requests a logout.
if (codeError !== '680') {
return (<ErrorScreen code={codeError} />);
return (<ErrorScreen code={codeError} callback={() => Base.setExitReason('error')} />);
}
return (<MeetingEnded code={codeError} />);
return (<MeetingEnded code={codeError} callback={() => Base.setExitReason('logout')} />);
}
return (<AppContainer {...this.props} baseControls={stateControls} />);
@ -454,7 +467,7 @@ export default withTracker(() => {
const connectionIdUpdateTime = User?.connectionIdUpdateTime;
if (currentConnectionId && currentConnectionId !== connectionID && connectionIdUpdateTime > connectionAuthTime) {
Session.set('codeError', 403);
Session.set('codeError', '409');
Session.set('errorMessageDescription', 'joined_another_window_reason')
}

View File

@ -150,7 +150,16 @@ export default injectIntl(withModalMounter(withTracker(({ intl, baseControls })
setTimeout(() => {
const queryCurrentUser = Users.find({ userId: Auth.userID, meetingId: Auth.meetingID });
if (queryCurrentUser.count() === 0) {
endMeeting(403, userData.ejectedReason || null);
if (userData.ejected) {
endMeeting('403', userData.ejectedReason);
} else {
// Either authentication process hasn't finished yet or user did authenticate but Users
// collection is unsynchronized. In both cases user may be able to rejoin.
const description = Auth.isAuthenticating || Auth.loggedIn
? 'able_to_rejoin_user_disconnected_reason'
: null;
endMeeting('503', description);
}
}
}, delayForReconnection);
},

View File

@ -8,6 +8,9 @@ import logger from '/imports/startup/client/logger';
import Styled from './styles';
const intlMessages = defineMessages({
503: {
id: 'app.error.503',
},
500: {
id: 'app.error.500',
defaultMessage: 'Oops, something went wrong',
@ -15,6 +18,9 @@ const intlMessages = defineMessages({
410: {
id: 'app.error.410',
},
409: {
id: 'app.error.409',
},
408: {
id: 'app.error.408',
},
@ -55,6 +61,9 @@ const intlMessages = defineMessages({
not_enough_permission_eject_reason: {
id: 'app.meeting.logout.permissionEjectReason',
},
able_to_rejoin_user_disconnected_reason: {
id: 'app.error.disconnected.rejoin',
},
});
const propTypes = {
@ -65,15 +74,18 @@ const propTypes = {
};
const defaultProps = {
code: 500,
code: '500',
callback: async () => {},
};
class ErrorScreen extends PureComponent {
componentDidMount() {
const { code } = this.props;
const log = code === 403 ? 'warn' : 'error';
const { code, callback } = this.props;
const log = code === '403' ? 'warn' : 'error';
AudioManager.exitAudio();
Meteor.disconnect();
callback().finally(() => {
Meteor.disconnect();
});
logger[log]({ logCode: 'startup_client_usercouldnotlogin_error' }, `User could not log in HTML5, hit ${code}`);
}
@ -92,7 +104,7 @@ class ErrorScreen extends PureComponent {
let errorMessageDescription = Session.get('errorMessageDescription');
if (code === 403 && errorMessageDescription in intlMessages) {
if (errorMessageDescription in intlMessages) {
errorMessageDescription = intl.formatMessage(intlMessages[errorMessageDescription]);
}

View File

@ -116,6 +116,7 @@ const propTypes = {
const defaultProps = {
ejectedReason: null,
endedReason: null,
callback: async () => {},
};
class MeetingEnded extends PureComponent {
@ -159,7 +160,9 @@ class MeetingEnded extends PureComponent {
AudioManager.exitAudio();
Storage.removeItem('getEchoTest');
Storage.removeItem('isFirstJoin');
Meteor.disconnect();
this.props.callback().finally(() => {
Meteor.disconnect();
});
}
setSelectedStar(starNumber) {

View File

@ -223,10 +223,15 @@ class Auth {
}
this.loggedIn = false;
this.isAuthenticating = true;
return this.validateAuthToken()
.then(() => {
this.loggedIn = true;
this.uniqueClientSession = `${this.sessionToken}-${Math.random().toString(36).substring(6)}`;
})
.finally(() => {
this.isAuthenticating = false;
});
}

View File

@ -598,8 +598,11 @@
"app.error.403": "You have been removed from the meeting",
"app.error.404": "Not found",
"app.error.408": "Authentication failed",
"app.error.409": "Conflict",
"app.error.410": "Meeting has ended",
"app.error.500": "Ops, something went wrong",
"app.error.503": "You have been disconnected",
"app.error.disconnected.rejoin": "You are able to refresh the page to rejoin.",
"app.error.userLoggedOut": "User has an invalid sessionToken due to log out",
"app.error.ejectedUser": "User has an invalid sessionToken due to ejection",
"app.error.joinedAnotherWindow": "This session seems to be opened in another browser window.",