Skip to content
Merged

PM-5516 #7236

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions __tests__/shared/components/SubmissionPage/Submit/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { resolveSubmissionMode } from 'components/SubmissionPage/Submit';

const topgearCommunitiesList = {
data: [
{
groupIds: ['wipro-group-id'],
mainSubdomain: 'topgear',
},
],
loadingUuid: '',
timestamp: Date.now(),
};

describe('resolveSubmissionMode', () => {
test('uses zip upload when submission_type metadata is zip', () => {
expect(resolveSubmissionMode(
[{ name: 'submission_type', value: 'zip' }],
['wipro-group-id'],
topgearCommunitiesList,
)).toEqual({
isLoadingCommunitiesList: false,
isUrlSubmission: false,
});
});

test('uses URL upload when submission_type metadata is url', () => {
expect(resolveSubmissionMode(
[{ name: 'submission_type', value: 'url' }],
[],
topgearCommunitiesList,
)).toEqual({
isLoadingCommunitiesList: false,
isUrlSubmission: true,
});
});

test('falls back to URL upload for Topgear groups when metadata is absent', () => {
expect(resolveSubmissionMode(
[],
['wipro-group-id'],
topgearCommunitiesList,
)).toEqual({
isLoadingCommunitiesList: false,
isUrlSubmission: true,
});
});

test('waits for communities list before applying the legacy group fallback', () => {
expect(resolveSubmissionMode(
[],
['wipro-group-id'],
{
data: [],
loadingUuid: '',
timestamp: 0,
},
)).toEqual({
isLoadingCommunitiesList: true,
isUrlSubmission: false,
});
});
});
8 changes: 7 additions & 1 deletion __tests__/shared/utils/terms.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,16 @@ describe('terms utils', () => {
expect(isNdaTerm({ title: 'Assignment Terms' })).toBe(false);
});

test('uses configured DocuSign template for NDA terms', () => {
test('uses terms-service DocuSign template for NDA terms when present', () => {
expect(getDocuSignTemplateIdForTerm({
docusignTemplateId: 'old-template-id',
title: 'Appirio NDA v2.0',
})).toBe('old-template-id');
});

test('uses configured DocuSign template for NDA terms without a template id', () => {
expect(getDocuSignTemplateIdForTerm({
title: 'Appirio NDA v2.0',
})).toBe(NEW_NDA_TEMPLATE_ID);
});

Expand Down
6 changes: 3 additions & 3 deletions config/backup-default.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ module.exports = {
* agreement flow. */
MOCK_TERMS_SERVICE: false,

/* Optional DocuSign template override for NDA-like terms. When set, the
* terms modal requests this template for terms whose title includes NDA or
* Non-Disclosure, even if the Terms API still returns an older template id.
/* Optional DocuSign template fallback for NDA-like terms. The terms modal
* prefers the template id returned by the Terms API because backend
* completion is persisted against that same template id.
*/
NDA_DOCUSIGN_TEMPLATE_ID: '400b989d-1c75-4889-b6f6-421e1f924709',

Expand Down
6 changes: 3 additions & 3 deletions config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ module.exports = {
* agreement flow. */
MOCK_TERMS_SERVICE: false,

/* Optional DocuSign template override for NDA-like terms. When set, the
* terms modal requests this template for terms whose title includes NDA or
* Non-Disclosure, even if the Terms API still returns an older template id.
/* Optional DocuSign template fallback for NDA-like terms. The terms modal
* prefers the template id returned by the Terms API because backend
* completion is persisted against that same template id.
*/
NDA_DOCUSIGN_TEMPLATE_ID: '400b989d-1c75-4889-b6f6-421e1f924709',

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
*
* Description:
* Component for uploading a file using Filestack Picker
* and Drag + Drop. Does not store the file contents in form. Instead,
* and Drag + Drop, or accepting a URL for Topgear submissions.
* Does not store the file contents in form. Instead,
* uploads file to S3 storage container and sets the
* S3 storage details to Redux store for submission.
*/
Expand Down
84 changes: 61 additions & 23 deletions src/shared/components/SubmissionPage/Submit/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
*
* Description:
* Page that is shown when a user is trying to submit a Submission.
* Allows user to upload Submission.zip file using a Filestack plugin.
* Allows users to submit either a standard zip upload or a Topgear URL,
* depending on challenge metadata and legacy Topgear group defaults.
*/
/* eslint-env browser */

Expand All @@ -21,6 +22,58 @@ import FilestackFilePicker from '../FilestackFilePicker';
import Uploading from '../Uploading';
import style from './styles.scss';

const SUBMISSION_TYPE_METADATA_FIELD = 'submission_type';
const SUBMISSION_TYPE_URL = 'url';
const SUBMISSION_TYPE_ZIP = 'zip';

/**
* Resolves which submission experience should be shown for the challenge.
* Explicit `submission_type` metadata wins over the historical Topgear group
* check. When the metadata is absent or invalid, the current fallback remains:
* Topgear/Wipro challenges use URL submission and all others use zip upload.
*
* @param {Array<Object>} metadata Challenge metadata entries.
* @param {Array<String>} groups Challenge group ids.
* @param {Object} communitiesList Loaded community metadata from Redux.
* @return {{isLoadingCommunitiesList: Boolean, isUrlSubmission: Boolean}}
*/
export function resolveSubmissionMode(metadata, groups, communitiesList) {
const submissionType = _.toLower(_.toString(_.get(
_.find(metadata, { name: SUBMISSION_TYPE_METADATA_FIELD }),
'value',
'',
)).trim());

if (submissionType === SUBMISSION_TYPE_ZIP || submissionType === SUBMISSION_TYPE_URL) {
return {
isLoadingCommunitiesList: false,
isUrlSubmission: submissionType === SUBMISSION_TYPE_URL,
};
}

if (_.isEmpty(groups)) {
return {
isLoadingCommunitiesList: false,
isUrlSubmission: false,
};
}

if (!communitiesList.timestamp) {
return {
isLoadingCommunitiesList: true,
isUrlSubmission: false,
};
}

const topGearCommunity = _.find(communitiesList.data, { mainSubdomain: 'topgear' });
const topGearGroupIds = _.get(topGearCommunity, 'groupIds', []);

return {
isLoadingCommunitiesList: false,
isUrlSubmission: _.some(groups, groupId => groupId && _.includes(topGearGroupIds, groupId)),
};
}

/**
* Submissions Page shown to develop challengers.
*/
Expand Down Expand Up @@ -137,31 +190,15 @@ class Submit extends React.Component {
setSubmissionFilestackData,
submitForm,
groups,
metadata,
} = this.props;

const id = 'file-picker-submission';

let isLoadingCommunitiesList = false;
let isChallengeBelongToTopgearGroup = false;
// check if challenge belong to any group
if (!_.isEmpty(groups)) {
// check if communitiesList is loaded
if (communitiesList.timestamp > 0) {
const topGearCommunity = _.find(communitiesList.data, { mainSubdomain: 'topgear' });
if (topGearCommunity) {
// check the group info match with group list
_.forOwn(groups, (value) => {
if (value && _.includes(topGearCommunity.groupIds, value)) {
isChallengeBelongToTopgearGroup = true;
return false;
}
return true;
});
}
} else {
isLoadingCommunitiesList = true;
}
}
const submissionMode = resolveSubmissionMode(metadata, groups, communitiesList);
const {
isLoadingCommunitiesList,
isUrlSubmission: isChallengeBelongToTopgearGroup,
} = submissionMode;

const submissionInstruction = isChallengeBelongToTopgearGroup ? (
<div>
Expand Down Expand Up @@ -427,6 +464,7 @@ Submit.propTypes = {
timestamp: PT.number.isRequired,
}).isRequired,
groups: PT.arrayOf(PT.shape()).isRequired,
metadata: PT.arrayOf(PT.shape()).isRequired,
isSubmitting: PT.bool.isRequired,
submitDone: PT.bool.isRequired,
errorMsg: PT.string,
Expand Down
1 change: 1 addition & 0 deletions src/shared/components/SubmissionPage/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ SubmissionsPage.propTypes = {
timestamp: PT.number.isRequired,
}).isRequired,
groups: PT.arrayOf(PT.shape()).isRequired,
metadata: PT.arrayOf(PT.shape()).isRequired,
track: PT.string.isRequired,
status: PT.string.isRequired,
submitForm: PT.func.isRequired,
Expand Down
2 changes: 2 additions & 0 deletions src/shared/containers/SubmissionPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ SubmissionsPageContainer.propTypes = {
status: PT.string.isRequired,
isRegistered: PT.bool.isRequired,
groups: PT.arrayOf(PT.shape()).isRequired,
metadata: PT.arrayOf(PT.shape()).isRequired,
errorMsg: PT.string.isRequired,
isSubmitting: PT.bool.isRequired,
submitDone: PT.bool.isRequired,
Expand Down Expand Up @@ -193,6 +194,7 @@ const mapStateToProps = (state, ownProps) => {
status: details.status,
isRegistered: details.isRegistered,
groups: details.groups,
metadata: details.metadata || [],
isSubmitting: submission.isSubmitting,
submitDone: submission.submitDone,
errorMsg: submission.submitErrorMsg,
Expand Down
10 changes: 7 additions & 3 deletions src/shared/utils/terms.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,18 @@ export function isNdaTerm(term = {}) {
* Resolves the DocuSign template id to use for a terms-service record.
*
* @param {Object|null} term terms-service record or details payload.
* @returns {String|Number|undefined} configured NDA template id for NDA terms,
* or the template id returned by terms-service for all other terms.
* @returns {String|Number|undefined} the template id returned by terms-service,
* or the configured NDA fallback when an NDA term has no template id.
*/
export function getDocuSignTemplateIdForTerm(term = {}) {
if (term && term.docusignTemplateId) {
return term.docusignTemplateId;
}

const configuredNdaTemplateId = config.NDA_DOCUSIGN_TEMPLATE_ID;
if (configuredNdaTemplateId && isNdaTerm(term)) {
return configuredNdaTemplateId;
}

return term ? term.docusignTemplateId : undefined;
return undefined;
}
Loading