Skip to content

Commit

Permalink
Merge branch 'main' into bilalqamar95/frontend-platform-upgrade
Browse files Browse the repository at this point in the history
  • Loading branch information
BilalQamar95 authored Jan 1, 2024
2 parents b38d524 + 8457727 commit da07c8b
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 29 deletions.
73 changes: 68 additions & 5 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
##########################
frontend-lib-special-exams
=================================
##########################

*******
Purpose
*******
This is a react library responsible for extending learning app with special exams functionality, e.g. proctored/timed exams.

Set up instructions
--------------------------
***************
Getting Started
***************

Installation
============

1. Clone your new repo:

Expand All @@ -17,15 +26,69 @@ Set up instructions

``cd frontend-lib-special-exams && npm install``

*******************
Build Process Notes
-------------------
*******************

**Production Build**

The production build is created with ``npm run build``.

*********************
Internationalization
--------------------
*********************

Please see `edx/frontend-platform's i18n module <https://edx.github.io/frontend-platform/module-Internationalization.html>`_ for documentation on internationalization. The documentation explains how to use it, and the `How To <https://github.com/edx/frontend-i18n/blob/master/docs/how_tos/i18n.rst>`_ has more detail.

************
Contributing
************

Contributions are very welcome. Please read `How To Contribute`_ for details.

.. _How To Contribute: https://openedx.org/r/how-to-contribute

This project is currently accepting all types of contributions, bug fixes,
security fixes, maintenance work, or new features. However, please make sure
to have a discussion about your new feature idea with the maintainers prior to
beginning development to maximize the chances of your change being accepted.
You can start a conversation by creating a new issue on this repo summarizing
your idea.

************
Getting Help
************

If you're having trouble, we have discussion forums at
https://discuss.openedx.org where you can connect with others in the community.

Our real-time conversations are on Slack. You can request a `Slack
invitation`_, then join our `community Slack workspace`_. Because this is a
frontend repository, the best place to discuss it would be in the `#wg-frontend
channel`_.

For anything non-trivial, the best path is to open an issue in this repository
with as many details about the issue you are facing as you can provide.

https://github.com/openedx/frontend-lib-special-exams/issues

For more information about these options, see the `Getting Help`_ page.

.. _Slack invitation: https://openedx.org/slack
.. _community Slack workspace: https://openedx.slack.com/
.. _#wg-frontend channel: https://openedx.slack.com/archives/C04BM6YC7A6
.. _Getting Help: https://openedx.org/community/connect

****************************
The Open edX Code of Conduct
****************************

All community members are expected to follow the `Open edX Code of Conduct`_.

.. _Open edX Code of Conduct: https://openedx.org/code-of-conduct/

**************************
Reporting Security Issues
**************************

Please do not report security issues in public. Please email [email protected].
5 changes: 5 additions & 0 deletions src/data/__snapshots__/redux.test.jsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ Object {
"provider_name": "",
"provider_tech_support_email": "",
"provider_tech_support_phone": "",
"provider_tech_support_url": "",
},
"timeIsOver": false,
},
Expand Down Expand Up @@ -129,6 +130,7 @@ Object {
"provider_name": "",
"provider_tech_support_email": "",
"provider_tech_support_phone": "",
"provider_tech_support_url": "",
},
"timeIsOver": false,
},
Expand All @@ -148,6 +150,7 @@ Object {
"provider_name": "",
"provider_tech_support_email": "",
"provider_tech_support_phone": "",
"provider_tech_support_url": "",
}
`;

Expand Down Expand Up @@ -302,6 +305,7 @@ Object {
"provider_name": "",
"provider_tech_support_email": "",
"provider_tech_support_phone": "",
"provider_tech_support_url": "",
},
"timeIsOver": false,
},
Expand Down Expand Up @@ -370,6 +374,7 @@ Object {
"provider_name": "",
"provider_tech_support_email": "",
"provider_tech_support_phone": "",
"provider_tech_support_url": "",
},
"timeIsOver": false,
},
Expand Down
4 changes: 3 additions & 1 deletion src/data/messages/proctorio.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
* vendor-specific integrations long term. As of now these events
* will trigger on ANY lti integration, not just Proctorio.
*/
import { getConfig } from '@edx/frontend-platform';

export async function checkAppStatus() {
return new Promise((resolve, reject) => {
const handleResponse = event => {
if (event.origin === window.location.origin) {
if (event.origin === getConfig().EXAMS_BASE_URL) {
window.removeEventListener('message', handleResponse);
if (event?.data?.active) {
resolve();
Expand Down
4 changes: 2 additions & 2 deletions src/data/redux.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -1152,7 +1152,7 @@ describe('Data layer integration tests', () => {
await new Promise(process.nextTick);
const handleResponseCb = mockAddEventListener.mock.calls[0][1];
axiosMock.onPut(`${createUpdateAttemptURL}/${proctoredAttempt.attempt_id}`).reply(200, { exam_attempt_id: proctoredAttempt.attempt_id });
handleResponseCb({ origin: 'https://edx.example.com', data: { active: false } });
handleResponseCb({ origin: 'http://localhost:18740', data: { active: false } });

await new Promise(process.nextTick);
const request = axiosMock.history.put[0];
Expand All @@ -1171,7 +1171,7 @@ describe('Data layer integration tests', () => {

await new Promise(process.nextTick);
const handleResponseCb = mockAddEventListener.mock.calls[0][1];
handleResponseCb({ origin: 'https://edx.example.com', data: { active: true } });
handleResponseCb({ origin: 'http://localhost:18740', data: { active: true } });

await new Promise(process.nextTick);
expect(axiosMock.history.put.length).toBe(0);
Expand Down
1 change: 1 addition & 0 deletions src/data/slice.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const examSlice = createSlice({
},
provider_tech_support_email: '',
provider_tech_support_phone: '',
provider_tech_support_url: '',
provider_name: '',
learner_notification_from_email: '',
integration_specific_email: '',
Expand Down
42 changes: 41 additions & 1 deletion src/instructions/Instructions.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,7 @@ describe('SequenceExamWrapper', () => {
expect(screen.getByText('You have submitted this proctored exam for review')).toBeInTheDocument();
});

it('Shows correct download instructions for LTI provider if attempt status is created', () => {
it('Shows correct download instructions for LTI provider if attempt status is created, with support email and phone', () => {
store.getState = () => ({
examState: Factory.build('examState', {
activeAttempt: {},
Expand Down Expand Up @@ -760,6 +760,46 @@ describe('SequenceExamWrapper', () => {
expect(screen.getByText('Start Exam')).toBeInTheDocument();
});

it('Shows correct download instructions for LTI provider if attempt status is created with support URL', () => {
store.getState = () => ({
examState: Factory.build('examState', {
activeAttempt: {},
proctoringSettings: Factory.build('proctoringSettings', {
provider_name: 'LTI Provider',
provider_tech_support_email: '[email protected]',
provider_tech_support_phone: '+123456789',
provider_tech_support_url: 'www.example.com',
}),
exam: Factory.build('exam', {
is_proctored: true,
type: ExamType.PROCTORED,
attempt: Factory.build('attempt', {
attempt_status: ExamStatus.CREATED,
}),
}),
}),
});

render(
<ExamStateProvider>
<Instructions>
<div>Sequence</div>
</Instructions>
</ExamStateProvider>,
{ store },
);

expect(screen.getByText(
'If you have issues relating to proctoring, you can contact LTI Provider technical support by visiting',
{ exact: false },
)).toBeInTheDocument();
expect(screen.getByRole('link', { name: 'www.example.com in a new tab' })).toHaveAttribute('href', 'www.example.com');

expect(screen.getByText('Set up and start your proctored exam.')).toBeInTheDocument();
expect(screen.getByText('Start System Check')).toBeInTheDocument();
expect(screen.getByText('Start Exam')).toBeInTheDocument();
});

it('Hides support contact info on download instructions for LTI provider if not provided', () => {
store.getState = () => ({
examState: Factory.build('examState', {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,47 +1,70 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import { Hyperlink } from '@edx/paragon';

const LtiProviderExamInstructions = ({
providerName, supportEmail, supportPhone,
}) => (
<>
<p>
<FormattedMessage
id="exam.DownloadSoftwareProctoredExamInstructions.text1"
defaultMessage={'Note: As part of the proctored exam setup, you '
+ 'will be asked to verify your identity. Before you begin, make '
+ 'sure you are on a computer with a webcam, and that you have a '
+ 'valid form of photo identification such as a driver’s license or passport.'}
/>
</p>
{supportEmail && supportPhone && (
<p>
providerName, supportEmail, supportPhone, supportURL,
}) => {
const supportURLHyperlink = (chunks) => (
<Hyperlink destination={chunks} target="_blank">
{chunks}
</Hyperlink>
);

const getSupportText = () => {
// We assume that an LTI-based provider will either have a supportURL or a supportEmail and supportPhone.
// In the unlikely event a provider has all three, we prioritize the supportURL.
if (supportURL) {
return (
<FormattedMessage
id="exam.DownloadSoftwareProctoredExamInstructions.supportText"
id="exam.DownloadSoftwareProctoredExamInstructions.LTI.supportText.URL"
defaultMessage={'If you have issues relating to proctoring, you can contact '
+ '{providerName} technical support by emailing {supportEmail} or by calling {supportPhone}.'}
+ '{providerName} technical support by visiting <a>{supportURL}</a>.'}
values={{
providerName,
supportURL,
a: supportURLHyperlink,
}}
/>
);
}
if (supportEmail && supportPhone) {
return (
<FormattedMessage
id="exam.DownloadSoftwareProctoredExamInstructions.LTI.supportText.EmailPhone"
defaultMessage={'If you have issues relating to proctoring, you can contact '
+ '{providerName} technical support by emailing {supportEmail} or by calling {supportPhone}.'}
values={{
providerName,
supportEmail,
supportPhone,
}}
/>
</p>
)}
</>
);
);
}
return null;
};

return (
<p>
{getSupportText()}
</p>
);
};

LtiProviderExamInstructions.propTypes = {
providerName: PropTypes.string,
supportEmail: PropTypes.string,
supportPhone: PropTypes.string,
supportURL: PropTypes.string,
};

LtiProviderExamInstructions.defaultProps = {
providerName: '',
supportEmail: '',
supportPhone: '',
supportURL: '',
};

export default LtiProviderExamInstructions;
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const DownloadSoftwareProctoredExamInstructions = ({ intl, skipProctoredExam })
provider_name: providerName,
provider_tech_support_email: supportEmail,
provider_tech_support_phone: supportPhone,
provider_tech_support_url: supportURL,
exam_proctoring_backend: proctoringBackend,
} = proctoringSettings;
const examHasLtiProvider = !useLegacyAttemptApi;
Expand Down Expand Up @@ -81,6 +82,7 @@ const DownloadSoftwareProctoredExamInstructions = ({ intl, skipProctoredExam })
providerName={providerName}
supportEmail={supportEmail}
supportPhone={supportPhone}
supportURL={supportURL}
/>
);
}
Expand Down

0 comments on commit da07c8b

Please sign in to comment.