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:
Shaun Hamilton
2021-08-17 18:31:25 +01:00
committed by GitHub
parent 63340dc55c
commit 5806c3047d
3 changed files with 94 additions and 14 deletions

View File

@ -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']);

View File

@ -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',

View File

@ -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 {