mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-20 12:03:11 -04:00
feat(api/client): use server response as flash msg for c# (#51551)
Co-authored-by: Shaun Hamilton <shauhami020@gmail.com> Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
@@ -701,7 +701,9 @@ function createMsTrophyChallengeCompleted(app) {
|
||||
});
|
||||
|
||||
if (!msUser || !msUser.msUsername) {
|
||||
throw new Error('Microsoft username not found.');
|
||||
return res
|
||||
.status(403)
|
||||
.json({ type: 'error', message: 'flash.ms.trophy.err-1' });
|
||||
}
|
||||
|
||||
const { msUsername } = msUser;
|
||||
@@ -711,15 +713,24 @@ function createMsTrophyChallengeCompleted(app) {
|
||||
);
|
||||
|
||||
if (!challenge) {
|
||||
throw new Error('Challenge not found');
|
||||
return res
|
||||
.status(400)
|
||||
.json({ type: 'error', message: 'flash.ms.trophy.err-2' });
|
||||
}
|
||||
|
||||
const { msTrophyId = '' } = challenge;
|
||||
const msTrophyApiUrl = `https://learn.microsoft.com/api/gamestatus/achievements/${msTrophyId}?username=${msUsername}&locale=en-us`;
|
||||
const msApiRes = await fetch(msTrophyApiUrl);
|
||||
const msTrophyJson = await msApiRes.json();
|
||||
|
||||
if (!msApiRes.ok) {
|
||||
throw new Error('Unable to validate trophy');
|
||||
if (!msApiRes.ok || msTrophyJson.awardType !== 'Trophy') {
|
||||
return res.status(403).json({
|
||||
type: 'error',
|
||||
message: 'flash.ms.trophy.err-3',
|
||||
variables: {
|
||||
msUsername
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const completedChallenge = pick(body, ['id']);
|
||||
@@ -751,9 +762,10 @@ function createMsTrophyChallengeCompleted(app) {
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
log(e);
|
||||
return res.status(500).json({
|
||||
type: 'error',
|
||||
message: e.message
|
||||
message: 'flash.ms.trophy.err-4'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -123,9 +123,10 @@ function createPostMsUsername(app) {
|
||||
const { msTranscriptUrl } = req.body;
|
||||
|
||||
if (!msTranscriptUrl) {
|
||||
return res
|
||||
.status(400)
|
||||
.send('Please include a Microsoft transcript URL in request');
|
||||
return res.status(400).json({
|
||||
type: 'error',
|
||||
message: 'flash.ms.transcript.link-err-1'
|
||||
});
|
||||
}
|
||||
|
||||
const msTranscriptId = msTranscriptUrl.split('/').pop();
|
||||
@@ -135,19 +136,17 @@ function createPostMsUsername(app) {
|
||||
const msApiRes = await fetch(msTranscriptApiUrl);
|
||||
|
||||
if (!msApiRes.ok) {
|
||||
res.status(500);
|
||||
throw new Error(
|
||||
'An error occurred trying to get your Microsoft transcript'
|
||||
);
|
||||
return res
|
||||
.status(404)
|
||||
.json({ type: 'error', message: 'flash.ms.transcript.link-err-2' });
|
||||
}
|
||||
|
||||
const { userName } = await msApiRes.json();
|
||||
|
||||
if (!userName) {
|
||||
res.status(500);
|
||||
throw new Error(
|
||||
'An error occured trying to link your Microsoft account'
|
||||
);
|
||||
return res
|
||||
.status(500)
|
||||
.json({ type: 'error', message: 'flash.ms.transcript.link-err-3' });
|
||||
}
|
||||
|
||||
// Don't create if username is used by another fCC account
|
||||
@@ -156,7 +155,9 @@ function createPostMsUsername(app) {
|
||||
});
|
||||
|
||||
if (usernameUsed) {
|
||||
throw new Error('That username is already used');
|
||||
return res
|
||||
.status(403)
|
||||
.json({ type: 'error', message: 'flash.ms.transcript.link-err-4' });
|
||||
}
|
||||
|
||||
await MsUsername.destroyAll({ userId: req.user.id });
|
||||
@@ -169,25 +170,27 @@ function createPostMsUsername(app) {
|
||||
});
|
||||
|
||||
if (!newMsUsername?.id) {
|
||||
res.status(500);
|
||||
throw new Error(
|
||||
'An error occured trying to link your Microsoft account'
|
||||
);
|
||||
return res
|
||||
.status(500)
|
||||
.json({ type: 'error', message: 'flash.ms.transcript.link-err-5' });
|
||||
}
|
||||
|
||||
return res.json({ msUsername: userName });
|
||||
} catch (e) {
|
||||
log(e);
|
||||
return res.send(e.message);
|
||||
return res
|
||||
.status(500)
|
||||
.json({ type: 'error', message: 'flash.ms.transcript.link-err-6' });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function deleteMsUsernameResponse(req, res) {
|
||||
if (!req.msUsernameDeleted) {
|
||||
return res
|
||||
.status(500)
|
||||
.send('An error occurred trying to unlink your Microsoft username');
|
||||
return res.status(500).json({
|
||||
type: 'error',
|
||||
message: 'flash.ms.transcript.unlink-err'
|
||||
});
|
||||
}
|
||||
|
||||
return res.send({ msUsername: null });
|
||||
|
||||
@@ -718,12 +718,26 @@
|
||||
"challenge-submit-too-big": "Sorry, you cannot submit your code. Your code is {{user-size}} bytes. We allow a maximum of {{max-size}} bytes. Please make your code smaller and try again or request assistance on https://forum.freecodecamp.org",
|
||||
"invalid-update-flag": "You are attempting to access forbidden resources. Please request assistance on https://forum.freecodecamp.org if this is a valid request.",
|
||||
"generate-exam-error": "An error occurred trying to generate your exam.",
|
||||
"ms-trophy-err": "We were unable to verify your trophy from Microsoft's learning platform.",
|
||||
"ms-trophy-verified": "Your trophy from Microsoft's learning platform was verified.",
|
||||
"ms-linked": "Your Microsoft username been linked to your freeCodeCamp account.",
|
||||
"ms-link-err": "An error occurred trying to link your Microsoft username to your freeCodeCamp account.",
|
||||
"ms-unlinked": "The link to your Microsoft username has been removed.",
|
||||
"ms-unlink-err": "An error occurred trying to remove the link to your Microsoft username."
|
||||
"ms": {
|
||||
"transcript": {
|
||||
"link-err-1": "Please include a Microsoft transcript URL in the request.",
|
||||
"link-err-2": "Something went wrong trying to get your transcript from Microsoft.",
|
||||
"link-err-3": "A username was not found in your Microsoft transcript.",
|
||||
"link-err-4": "That Microsoft username is being used by another freeCodeCamp account.",
|
||||
"link-err-5": "Something went wrong trying to save your Microsoft account.",
|
||||
"link-err-6": "Something went wrong trying to link your Microsoft username to your freeCodeCamp account.",
|
||||
"linked": "Your Microsoft username has been linked to your freeCodeCamp account.",
|
||||
"unlinked": "The link to your Microsoft username has been removed.",
|
||||
"unlink-err": "Something went wrong trying to remove the link to your Microsoft username."
|
||||
},
|
||||
"trophy": {
|
||||
"err-1": "We could not find a Microsoft username associated with your freeCodeCamp account.",
|
||||
"err-2": "You are trying to submit a challenge that does not appear to be a trophy challenge.",
|
||||
"err-3": "It appears that the Microsoft user \"{{msUsername}}\" has not earned this trophy.",
|
||||
"err-4": "Something went wrong trying to verify your trophy. Please check and try again.",
|
||||
"verified": "Your trophy from Microsoft's learning platform was verified."
|
||||
}
|
||||
}
|
||||
},
|
||||
"validation": {
|
||||
"max-characters": "There is a maximum limit of 288 characters, you have {{charsLeft}} left",
|
||||
|
||||
@@ -20,11 +20,13 @@ function Flash({ flashMessage, removeFlashMessage }: FlashProps): JSX.Element {
|
||||
removeFlashMessage();
|
||||
}
|
||||
|
||||
const flashStyle = type === 'error' ? 'danger' : type;
|
||||
|
||||
return (
|
||||
<TransitionGroup>
|
||||
<CSSTransition classNames='flash-message' key={id} timeout={500}>
|
||||
<Alert
|
||||
bsStyle={type}
|
||||
bsStyle={flashStyle}
|
||||
className='flash-message'
|
||||
closeLabel={t('buttons.close')}
|
||||
onDismiss={handleClose}
|
||||
|
||||
@@ -18,12 +18,20 @@ export enum FlashMessages {
|
||||
IncompleteSteps = 'flash.incomplete-steps',
|
||||
LocalCodeSaved = 'flash.local-code-saved',
|
||||
LocalCodeSaveError = 'flash.local-code-save-error',
|
||||
MsLinked = 'flash.ms-linked',
|
||||
MsLinkErr = 'flash.ms-link-err',
|
||||
MsTrophyErr = 'flash.ms-trophy-err',
|
||||
MsTrophyVerified = 'flash.ms-trophy-verified',
|
||||
MsUnlinked = 'flash.ms-unlinked',
|
||||
MsUnlinkErr = 'flash.ms-unlink-err',
|
||||
MsTranscriptErr1 = 'flash.ms.transcript.link-err-1',
|
||||
MsTranscriptErr2 = 'flash.ms.transcript.link-err-2',
|
||||
MsTranscriptErr3 = 'flash.ms.transcript.link-err-3',
|
||||
MsTranscriptErr4 = 'flash.ms.transcript.link-err-4',
|
||||
MsTranscriptErr5 = 'flash.ms.transcript.link-err-5',
|
||||
MsTranscriptErr6 = 'flash.ms.transcript.link-err-6',
|
||||
MsTranscriptLinked = 'flash.ms.transcript.linked',
|
||||
MsTranscriptUnlinked = 'flash.ms.transcript.unlinked',
|
||||
MsTranscriptUnlinkErr = 'flash.ms.transcript.unlink-err',
|
||||
MsTrophyErr1 = 'flash.ms.trophy.err-1',
|
||||
MsTrophyErr2 = 'flash.ms.trophy.err-2',
|
||||
MsTrophyErr3 = 'flash.ms.trophy.err-3',
|
||||
MsTrophyErr4 = 'flash.ms.trophy.err-4',
|
||||
MsTrophyVerified = 'flash.ms.trophy.verified',
|
||||
NameNeeded = 'flash.name-needed',
|
||||
None = '',
|
||||
NotEligible = 'flash.not-eligible',
|
||||
|
||||
@@ -8,19 +8,19 @@ import { setMsUsername, setIsProcessing } from './actions';
|
||||
const message = {
|
||||
linked: {
|
||||
type: 'success',
|
||||
message: FlashMessages.MsLinked
|
||||
message: FlashMessages.MsTranscriptLinked
|
||||
},
|
||||
linkErr: {
|
||||
type: 'danger',
|
||||
message: FlashMessages.MsLinkErr
|
||||
message: FlashMessages.MsTranscriptErr6
|
||||
},
|
||||
unlinked: {
|
||||
type: 'info',
|
||||
message: FlashMessages.MsUnlinked
|
||||
message: FlashMessages.MsTranscriptUnlinked
|
||||
},
|
||||
unlinkErr: {
|
||||
type: 'danger',
|
||||
message: FlashMessages.MsUnlinkErr
|
||||
message: FlashMessages.MsTranscriptUnlinkErr
|
||||
}
|
||||
};
|
||||
|
||||
@@ -28,12 +28,14 @@ function* linkMsUsernameSaga({ payload: { msTranscriptUrl } }) {
|
||||
try {
|
||||
const { data } = yield call(postMsUsername, { msTranscriptUrl });
|
||||
|
||||
if (data && Object.prototype.hasOwnProperty.call(data, 'msUsername')) {
|
||||
yield put(setIsProcessing(false));
|
||||
|
||||
if (data?.message) {
|
||||
yield put(createFlashMessage(data));
|
||||
} else if (data?.msUsername) {
|
||||
yield put(setMsUsername(data.msUsername));
|
||||
yield put(setIsProcessing(false));
|
||||
yield put(createFlashMessage(message.linked));
|
||||
} else {
|
||||
yield put(setIsProcessing(false));
|
||||
yield put(createFlashMessage(message.linkErr));
|
||||
}
|
||||
} catch {
|
||||
@@ -46,7 +48,12 @@ function* unlinkMsUsernameSaga() {
|
||||
try {
|
||||
const { data } = yield call(deleteMsUsername);
|
||||
|
||||
if (data && Object.prototype.hasOwnProperty.call(data, 'msUsername')) {
|
||||
if (data?.message) {
|
||||
yield put(createFlashMessage(data));
|
||||
} else if (
|
||||
data &&
|
||||
Object.prototype.hasOwnProperty.call(data, 'msUsername')
|
||||
) {
|
||||
yield put(setMsUsername(data.msUsername));
|
||||
yield put(createFlashMessage(message.unlinked));
|
||||
} else {
|
||||
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
import { createFlashMessage } from '../../../components/Flash/redux';
|
||||
import {
|
||||
standardErrorMessage,
|
||||
msTrophyError,
|
||||
msTrophyVerified
|
||||
} from '../../../utils/error-messages';
|
||||
import {
|
||||
@@ -58,7 +57,7 @@ function postChallenge(update, username) {
|
||||
const saveChallenge = postUpdate$(update).pipe(
|
||||
retry(3),
|
||||
switchMap(({ data }) => {
|
||||
const { savedChallenges, points, type, examResults } = data;
|
||||
const { savedChallenges, points, message, examResults } = data;
|
||||
const payloadWithClientProperties = {
|
||||
...omit(update.payload, ['files'])
|
||||
};
|
||||
@@ -85,8 +84,8 @@ function postChallenge(update, username) {
|
||||
submitChallengeComplete()
|
||||
];
|
||||
|
||||
if (challengeType === challengeTypes.msTrophy && type === 'error') {
|
||||
actions = [createFlashMessage(msTrophyError), submitChallengeError()];
|
||||
if (message && challengeType === challengeTypes.msTrophy) {
|
||||
actions = [createFlashMessage(data), submitChallengeError()];
|
||||
} else if (challengeType === challengeTypes.msTrophy) {
|
||||
actions.push(createFlashMessage(msTrophyVerified));
|
||||
}
|
||||
|
||||
@@ -5,11 +5,6 @@ export const standardErrorMessage = {
|
||||
message: FlashMessages.WentWrong
|
||||
};
|
||||
|
||||
export const msTrophyError = {
|
||||
type: 'danger',
|
||||
message: FlashMessages.MsTrophyErr
|
||||
};
|
||||
|
||||
export const reallyWeirdErrorMessage = {
|
||||
type: 'danger',
|
||||
message: FlashMessages.ReallyWeird
|
||||
|
||||
@@ -33,6 +33,20 @@ const toneUrls = {
|
||||
[FlashMessages.IncompleteSteps]: TRY_AGAIN,
|
||||
[FlashMessages.LocalCodeSaved]: CHAL_COMP,
|
||||
[FlashMessages.LocalCodeSaveError]: TRY_AGAIN,
|
||||
[FlashMessages.MsTranscriptErr1]: TRY_AGAIN,
|
||||
[FlashMessages.MsTranscriptErr2]: TRY_AGAIN,
|
||||
[FlashMessages.MsTranscriptErr3]: TRY_AGAIN,
|
||||
[FlashMessages.MsTranscriptErr4]: TRY_AGAIN,
|
||||
[FlashMessages.MsTranscriptErr5]: TRY_AGAIN,
|
||||
[FlashMessages.MsTranscriptErr6]: TRY_AGAIN,
|
||||
[FlashMessages.MsTranscriptLinked]: CHAL_COMP,
|
||||
[FlashMessages.MsTranscriptUnlinked]: CHAL_COMP,
|
||||
[FlashMessages.MsTranscriptUnlinkErr]: TRY_AGAIN,
|
||||
[FlashMessages.MsTrophyErr1]: TRY_AGAIN,
|
||||
[FlashMessages.MsTrophyErr2]: TRY_AGAIN,
|
||||
[FlashMessages.MsTrophyErr3]: TRY_AGAIN,
|
||||
[FlashMessages.MsTrophyErr4]: TRY_AGAIN,
|
||||
[FlashMessages.MsTrophyVerified]: CHAL_COMP,
|
||||
[FlashMessages.NameNeeded]: TRY_AGAIN,
|
||||
// [FlashMessages.None]: '',
|
||||
[FlashMessages.NotEligible]: TRY_AGAIN,
|
||||
|
||||
Reference in New Issue
Block a user