fix: Only dismiss the modal when masquerading as specific learner (#759)

if the user is masquerading as a specific learner, then dismiss the modal and do not post back and save the Honor Code signature

Co-authored-by: Simon Chen <schen@edX-C02FW0GUML85.local>
This commit is contained in:
Simon Chen
2021-12-02 10:08:49 -05:00
committed by GitHub
parent fba300bc5c
commit 436c05487a
3 changed files with 88 additions and 14 deletions

View File

@@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { useDispatch } from 'react-redux';
import { getConfig, history } from '@edx/frontend-platform';
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { ActionRow, Alert, Button } from '@edx/paragon';
@@ -11,13 +12,23 @@ import messages from './messages';
function HonorCode({ intl, courseId }) {
const dispatch = useDispatch();
const { isMasquerading } = useModel('coursewareMeta', courseId);
const coursewareMetaData = useModel('coursewareMeta', courseId);
const authUser = getAuthenticatedUser();
const siteName = getConfig().SITE_NAME;
const honorCodeUrl = `${getConfig().TERMS_OF_SERVICE_URL}#honor-code`;
const handleCancel = () => history.push(`/course/${courseId}/home`);
const handleAgree = () => dispatch(saveIntegritySignature(courseId, isMasquerading));
const handleAgree = () => dispatch(
// If the request is made by a staff user masquerading as a specific learner,
// don't actually create a signature for them on the backend.
// Only the modal dialog will be dismissed.
// Otherwise, even for staff users, we want to record the signature.
saveIntegritySignature(
courseId,
coursewareMetaData.isMasquerading && coursewareMetaData.username !== authUser.username,
),
);
return (
<Alert variant="light" aria-live="off">

View File

@@ -1,8 +1,11 @@
import React from 'react';
import { history } from '@edx/frontend-platform';
import MockAdapter from 'axios-mock-adapter';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { getConfig, history } from '@edx/frontend-platform';
import { Factory } from 'rosie';
import {
fireEvent, initializeTestStore, render, screen,
authenticatedUser, fireEvent, initializeTestStore, render, screen, waitFor,
} from '../../../../setupTest';
import HonorCode from './HonorCode';
@@ -14,20 +17,80 @@ jest.mock('@edx/frontend-platform', () => ({
}));
describe('Honor Code', () => {
let axiosMock;
let store;
let honorCodePostUrl;
const mockData = {};
beforeAll(async () => {
store = await initializeTestStore();
const { courseware } = store.getState();
mockData.courseId = courseware.courseId;
});
async function setupStoreState(coursewareMetaOptions) {
if (coursewareMetaOptions) {
const courseMetadata = Factory.build(
'courseMetadata',
coursewareMetaOptions,
);
store = await initializeTestStore({ courseMetadata });
} else {
store = await initializeTestStore();
}
const storeState = store.getState();
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
mockData.courseId = storeState.courseware.courseId;
honorCodePostUrl = `${getConfig().LMS_BASE_URL}/api/agreements/v1/integrity_signature/${mockData.courseId}`;
}
it('cancel button links to course home ', () => {
it('cancel button links to course home ', async () => {
await setupStoreState();
render(<HonorCode {...mockData} />);
const cancelButton = screen.getByText('Cancel');
fireEvent.click(cancelButton);
expect(history.push).toHaveBeenCalledWith(`/course/${mockData.courseId}/home`);
});
it('calls to save integrity_signature when agreeing', async () => {
await setupStoreState({ username: authenticatedUser.username });
render(<HonorCode {...mockData} />);
const agreeButton = screen.getByText('I agree');
fireEvent.click(agreeButton);
await waitFor(() => {
expect(axiosMock.history.post.length).toBe(1);
expect(axiosMock.history.post[0].url).toBe(honorCodePostUrl);
});
});
it('still calls to save integrity_signature if masquerading', async () => {
await setupStoreState(
{
is_staff: false,
original_user_is_staff: true,
username: authenticatedUser.username,
},
);
render(<HonorCode {...mockData} />);
const agreeButton = screen.getByText('I agree');
fireEvent.click(agreeButton);
await waitFor(() => {
expect(axiosMock.history.post.length).toBe(1);
expect(axiosMock.history.post[0].url).toBe(honorCodePostUrl);
});
});
it('will not call to save integrity_signature if masquerading a specific student', async () => {
await setupStoreState(
{
is_staff: false,
original_user_is_staff: true,
username: 'otheruser',
},
);
render(<HonorCode {...mockData} />);
const agreeButton = screen.getByText('I agree');
fireEvent.click(agreeButton);
await waitFor(() => {
expect(axiosMock.history.post.length).toBe(0);
});
});
afterEach(async () => {
axiosMock.resetHistory();
});
});

View File

@@ -306,9 +306,9 @@ export function saveSequencePosition(courseId, sequenceId, activeUnitIndex) {
export function saveIntegritySignature(courseId, isMasquerading) {
return async (dispatch) => {
try {
// If the request is made by a staff user masquerading as a learner,
// don't actually create a signature for them on the backend. Only
// frontend state will be updated.
// If the request is made by a staff user masquerading as a specific learner,
// don't actually create a signature for them on the backend,
// only the modal dialog will be dismissed
if (!isMasquerading) {
await postIntegritySignature(courseId);
}