mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2025-12-30 03:03:06 -05:00
fix(api): handle 4XX errors get-public-profile (#55205)
Co-authored-by: Mrugesh Mohapatra <1884376+raisedadead@users.noreply.github.com>
This commit is contained in:
@@ -22,11 +22,6 @@ import {
|
||||
setAccessTokenToResponse,
|
||||
removeCookies
|
||||
} from '../../server/utils/getSetAccessToken';
|
||||
import {
|
||||
normaliseUserFields,
|
||||
getProgress,
|
||||
publicUserProps
|
||||
} from '../../server/utils/publicUserProps';
|
||||
import { saveUser, observeMethod } from '../../server/utils/rx.js';
|
||||
import { getEmailSender } from '../../server/utils/url-utils';
|
||||
import {
|
||||
@@ -744,116 +739,6 @@ export default function initializeUser(User) {
|
||||
);
|
||||
};
|
||||
|
||||
function prepUserForPublish(user, profileUI) {
|
||||
const {
|
||||
about,
|
||||
calendar,
|
||||
completedChallenges,
|
||||
isDonating,
|
||||
joinDate,
|
||||
location,
|
||||
name,
|
||||
points,
|
||||
portfolio,
|
||||
username,
|
||||
yearsTopContributor
|
||||
} = user;
|
||||
const {
|
||||
isLocked = true,
|
||||
showAbout = false,
|
||||
showCerts = false,
|
||||
showDonation = false,
|
||||
showHeatMap = false,
|
||||
showLocation = false,
|
||||
showName = false,
|
||||
showPoints = false,
|
||||
showPortfolio = false,
|
||||
showTimeLine = false
|
||||
} = profileUI;
|
||||
|
||||
if (isLocked) {
|
||||
return {
|
||||
isLocked,
|
||||
profileUI,
|
||||
username
|
||||
};
|
||||
}
|
||||
return {
|
||||
...user,
|
||||
about: showAbout ? about : '',
|
||||
calendar: showHeatMap ? calendar : {},
|
||||
completedChallenges: (function () {
|
||||
if (showTimeLine) {
|
||||
return showCerts
|
||||
? completedChallenges
|
||||
: completedChallenges.filter(
|
||||
({ challengeType }) => challengeType !== 7
|
||||
);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
})(),
|
||||
isDonating: showDonation ? isDonating : null,
|
||||
joinDate: showAbout ? joinDate : '',
|
||||
location: showLocation ? location : '',
|
||||
name: showName ? name : '',
|
||||
points: showPoints ? points : null,
|
||||
portfolio: showPortfolio ? portfolio : [],
|
||||
yearsTopContributor: yearsTopContributor
|
||||
};
|
||||
}
|
||||
|
||||
User.getPublicProfile = function getPublicProfile(username, cb) {
|
||||
return User.findOne$({ where: { username } })
|
||||
.flatMap(user => {
|
||||
if (!user) {
|
||||
return Observable.of({});
|
||||
}
|
||||
const { completedChallenges, progressTimestamps, profileUI } = user;
|
||||
const allUser = {
|
||||
..._.pick(user, publicUserProps),
|
||||
points: progressTimestamps.length,
|
||||
completedChallenges,
|
||||
...getProgress(progressTimestamps),
|
||||
...normaliseUserFields(user),
|
||||
joinDate: user.id.getTimestamp()
|
||||
};
|
||||
|
||||
const publicUser = prepUserForPublish(allUser, profileUI);
|
||||
|
||||
return Observable.of({
|
||||
entities: {
|
||||
user: {
|
||||
[user.username]: {
|
||||
...publicUser
|
||||
}
|
||||
}
|
||||
},
|
||||
result: user.username
|
||||
});
|
||||
})
|
||||
.subscribe(user => cb(null, user), cb);
|
||||
};
|
||||
|
||||
User.remoteMethod('getPublicProfile', {
|
||||
accepts: {
|
||||
arg: 'username',
|
||||
type: 'string',
|
||||
required: true
|
||||
},
|
||||
returns: [
|
||||
{
|
||||
arg: 'user',
|
||||
type: 'object',
|
||||
root: true
|
||||
}
|
||||
],
|
||||
http: {
|
||||
path: '/get-public-profile',
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
User.giveBrowniePoints = function giveBrowniePoints(
|
||||
receiver,
|
||||
giver,
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import { pick } from 'lodash';
|
||||
import { getRedirectParams } from '../utils/redirection';
|
||||
import { deprecatedEndpoint } from '../utils/disabled-endpoints';
|
||||
import {
|
||||
getProgress,
|
||||
normaliseUserFields,
|
||||
publicUserProps
|
||||
} from '../utils/publicUserProps';
|
||||
|
||||
module.exports = function (app) {
|
||||
const router = app.loopback.Router();
|
||||
@@ -10,6 +16,7 @@ module.exports = function (app) {
|
||||
router.get('/unsubscribe/:email', unsubscribeDeprecated);
|
||||
router.get('/ue/:unsubscribeId', unsubscribeById);
|
||||
router.get('/resubscribe/:unsubscribeId', resubscribe);
|
||||
router.get('/api/users/get-public-profile', blockUserAgent, getPublicProfile);
|
||||
|
||||
app.use(router);
|
||||
|
||||
@@ -105,4 +112,118 @@ module.exports = function (app) {
|
||||
.catch(next);
|
||||
});
|
||||
}
|
||||
|
||||
const blockedUserAgentParts = ['python', 'google-apps-script', 'curl'];
|
||||
|
||||
function blockUserAgent(req, res, next) {
|
||||
const userAgent = req.headers['user-agent'];
|
||||
|
||||
if (
|
||||
!userAgent ||
|
||||
blockedUserAgentParts.some(ua => userAgent.toLowerCase().includes(ua))
|
||||
) {
|
||||
return res
|
||||
.status(400)
|
||||
.send(
|
||||
'This endpoint is no longer available outside of the freeCodeCamp ecosystem'
|
||||
);
|
||||
}
|
||||
|
||||
return next();
|
||||
}
|
||||
|
||||
async function getPublicProfile(req, res) {
|
||||
const { username } = req.query;
|
||||
if (!username) {
|
||||
return res.status(400).json({ error: 'No username provided' });
|
||||
}
|
||||
|
||||
const user = await User.findOne({ where: { username } });
|
||||
|
||||
if (!user) {
|
||||
return res.status(404).json({ error: 'User not found' });
|
||||
}
|
||||
|
||||
const { completedChallenges, progressTimestamps, profileUI } = user;
|
||||
const allUser = {
|
||||
...pick(user, publicUserProps),
|
||||
points: progressTimestamps.length,
|
||||
completedChallenges,
|
||||
...getProgress(progressTimestamps),
|
||||
...normaliseUserFields(user),
|
||||
joinDate: user.id.getTimestamp()
|
||||
};
|
||||
|
||||
const publicUser = prepUserForPublish(allUser, profileUI);
|
||||
|
||||
return res.json({
|
||||
entities: {
|
||||
user: {
|
||||
[user.username]: {
|
||||
...publicUser
|
||||
}
|
||||
}
|
||||
},
|
||||
result: user.username
|
||||
});
|
||||
}
|
||||
|
||||
function prepUserForPublish(user, profileUI) {
|
||||
const {
|
||||
about,
|
||||
calendar,
|
||||
completedChallenges,
|
||||
isDonating,
|
||||
joinDate,
|
||||
location,
|
||||
name,
|
||||
points,
|
||||
portfolio,
|
||||
username,
|
||||
yearsTopContributor
|
||||
} = user;
|
||||
const {
|
||||
isLocked = true,
|
||||
showAbout = false,
|
||||
showCerts = false,
|
||||
showDonation = false,
|
||||
showHeatMap = false,
|
||||
showLocation = false,
|
||||
showName = false,
|
||||
showPoints = false,
|
||||
showPortfolio = false,
|
||||
showTimeLine = false
|
||||
} = profileUI;
|
||||
|
||||
if (isLocked) {
|
||||
return {
|
||||
isLocked,
|
||||
profileUI,
|
||||
username
|
||||
};
|
||||
}
|
||||
return {
|
||||
...user,
|
||||
about: showAbout ? about : '',
|
||||
calendar: showHeatMap ? calendar : {},
|
||||
completedChallenges: (function () {
|
||||
if (showTimeLine) {
|
||||
return showCerts
|
||||
? completedChallenges
|
||||
: completedChallenges.filter(
|
||||
({ challengeType }) => challengeType !== 7
|
||||
);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
})(),
|
||||
isDonating: showDonation ? isDonating : null,
|
||||
joinDate: showAbout ? joinDate : '',
|
||||
location: showLocation ? location : '',
|
||||
name: showName ? name : '',
|
||||
points: showPoints ? points : null,
|
||||
portfolio: showPortfolio ? portfolio : [],
|
||||
yearsTopContributor: yearsTopContributor
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -43,7 +43,6 @@ function bootUser(app) {
|
||||
const deleteMsUsername = createDeleteMsUsername(app);
|
||||
const postSubmitSurvey = createPostSubmitSurvey(app);
|
||||
const deleteUserSurveys = createDeleteUserSurveys(app);
|
||||
|
||||
api.get('/account', sendNonUserToHome, deprecatedEndpoint);
|
||||
api.get('/account/unlink/:social', sendNonUserToHome, getUnlinkSocial);
|
||||
api.get('/user/get-session-user', getSessionUser);
|
||||
@@ -532,4 +531,5 @@ function createPostReportUserProfile(app) {
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export default bootUser;
|
||||
|
||||
Reference in New Issue
Block a user