fix(client): convert challengeFiles->files before sending to api (#43204)
* fix(client): convert challengeFiles->files before sending to api * update use of user.completeChallenges * parse response in ajax, pre-typing * add typing to getSessionUser * refactor: use Omit * fix: reorganise getSessionUser * refactor ajax for simplicity * refactor to be worse * allow for undefined completedChallenges Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com> Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
@ -83,11 +83,9 @@ export function buildUserUpdate(
|
|||||||
if (jsProjects.includes(challengeId)) {
|
if (jsProjects.includes(challengeId)) {
|
||||||
completedChallenge = {
|
completedChallenge = {
|
||||||
..._completedChallenge,
|
..._completedChallenge,
|
||||||
files: Object.keys(files)
|
files: files.map(file =>
|
||||||
.map(key => files[key])
|
pick(file, ['contents', 'key', 'index', 'name', 'path', 'ext'])
|
||||||
.map(file =>
|
)
|
||||||
pick(file, ['contents', 'key', 'index', 'name', 'path', 'ext'])
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
completedChallenge = omit(_completedChallenge, ['files']);
|
completedChallenge = omit(_completedChallenge, ['files']);
|
||||||
|
@ -67,7 +67,10 @@ function submitModern(type, state) {
|
|||||||
const { username } = userSelector(state);
|
const { username } = userSelector(state);
|
||||||
const challengeInfo = {
|
const challengeInfo = {
|
||||||
id,
|
id,
|
||||||
challengeFiles
|
files: challengeFiles.reduce(
|
||||||
|
(acc, { fileKey, ...curr }) => [...acc, { ...curr, key: fileKey }],
|
||||||
|
[]
|
||||||
|
)
|
||||||
};
|
};
|
||||||
const update = {
|
const update = {
|
||||||
endpoint: '/modern-challenge-completed',
|
endpoint: '/modern-challenge-completed',
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
import cookies from 'browser-cookies';
|
import cookies from 'browser-cookies';
|
||||||
import envData from '../../../config/env.json';
|
import envData from '../../../config/env.json';
|
||||||
|
|
||||||
import type { UserType } from '../redux/prop-types';
|
import type {
|
||||||
|
ChallengeFile,
|
||||||
|
CompletedChallenge,
|
||||||
|
UserType
|
||||||
|
} from '../redux/prop-types';
|
||||||
|
|
||||||
const { apiLocation } = envData;
|
const { apiLocation } = envData;
|
||||||
|
|
||||||
@ -51,16 +55,91 @@ async function request<T>(
|
|||||||
/** GET **/
|
/** GET **/
|
||||||
|
|
||||||
interface SessionUser {
|
interface SessionUser {
|
||||||
user: UserType;
|
user?: { [username: string]: UserType };
|
||||||
sessionMeta: { activeDonations: number };
|
sessionMeta: { activeDonations: number };
|
||||||
result: string;
|
|
||||||
}
|
|
||||||
export function getSessionUser(): Promise<SessionUser> {
|
|
||||||
return get('/user/get-session-user');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getUserProfile(username: string): Promise<UserType> {
|
type challengeFilesForFiles = {
|
||||||
return get(`/api/users/get-public-profile?username=${username}`);
|
files: Array<Omit<ChallengeFile, 'fileKey'> & { key: string }>;
|
||||||
|
} & Omit<CompletedChallenge, 'challengeFiles'>;
|
||||||
|
|
||||||
|
type ApiSessionResponse = Omit<SessionUser, 'user'>;
|
||||||
|
type ApiUser = {
|
||||||
|
user: {
|
||||||
|
[username: string]: ApiUserType;
|
||||||
|
};
|
||||||
|
result?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ApiUserType = Omit<UserType, 'completedChallenges'> & {
|
||||||
|
completedChallenges?: challengeFilesForFiles[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type UserResponseType = {
|
||||||
|
user: { [username: string]: UserType } | Record<string, never>;
|
||||||
|
result: string | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
function parseApiResponseToClientUser(data: ApiUser): UserResponseType {
|
||||||
|
const userData = data.user?.[data?.result ?? ''];
|
||||||
|
let completedChallenges: CompletedChallenge[] = [];
|
||||||
|
if (userData) {
|
||||||
|
completedChallenges =
|
||||||
|
userData.completedChallenges?.reduce(
|
||||||
|
(acc: CompletedChallenge[], curr: challengeFilesForFiles) => {
|
||||||
|
return [
|
||||||
|
...acc,
|
||||||
|
{
|
||||||
|
...curr,
|
||||||
|
challengeFiles: curr.files.map(({ key: fileKey, ...file }) => ({
|
||||||
|
...file,
|
||||||
|
fileKey
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
) ?? [];
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
user: { [data.result ?? '']: { ...userData, completedChallenges } },
|
||||||
|
result: data.result
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSessionUser(): Promise<SessionUser> {
|
||||||
|
const response: Promise<ApiUser & ApiSessionResponse> = get(
|
||||||
|
'/user/get-session-user'
|
||||||
|
);
|
||||||
|
// TODO: Once DB is migrated, no longer need to parse `files` -> `challengeFiles` etc.
|
||||||
|
return response.then(data => {
|
||||||
|
const { result, user } = parseApiResponseToClientUser(data);
|
||||||
|
return {
|
||||||
|
sessionMeta: data.sessionMeta,
|
||||||
|
result,
|
||||||
|
user
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserProfileResponse = {
|
||||||
|
entities: Omit<UserResponseType, 'result'>;
|
||||||
|
result: string | undefined;
|
||||||
|
};
|
||||||
|
export function getUserProfile(username: string): Promise<UserProfileResponse> {
|
||||||
|
const response: Promise<{ entities?: ApiUser; result?: string }> = get(
|
||||||
|
`/api/users/get-public-profile?username=${username}`
|
||||||
|
);
|
||||||
|
return response.then(data => {
|
||||||
|
const { result, user } = parseApiResponseToClientUser({
|
||||||
|
user: data.entities?.user ?? {},
|
||||||
|
result: data.result
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
entities: { user },
|
||||||
|
result
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Cert {
|
interface Cert {
|
||||||
|
Reference in New Issue
Block a user