mirror of
https://github.com/danbulant/Portfolio
synced 2026-05-27 14:02:14 +00:00
refactor: massive refactor of ssr and ssr api
This commit is contained in:
parent
4f32b244cf
commit
245fd6de80
8 changed files with 145 additions and 144 deletions
|
|
@ -1,13 +1,17 @@
|
||||||
import type { AdminLogin } from "$lib/stores/admin";
|
import type { AdminLogin } from '$lib/stores/admin';
|
||||||
import type { CandidateData, CandidatePreview, CreateCandidate, CreateCandidateLogin } from "$lib/stores/candidate";
|
import type {
|
||||||
import axios from "axios";
|
CandidateData,
|
||||||
import { API_URL, errorHandler, type Fetch } from ".";
|
CandidatePreview,
|
||||||
|
CreateCandidate,
|
||||||
|
CreateCandidateLogin
|
||||||
|
} from '$lib/stores/candidate';
|
||||||
|
import axios from 'axios';
|
||||||
|
import { API_URL, errorHandler, type Fetch } from '.';
|
||||||
|
|
||||||
// Login as admin /admin/login
|
// Login as admin /admin/login
|
||||||
export const apiLogin = async (data: AdminLogin): Promise<number> => {
|
export const apiLogin = async (data: AdminLogin): Promise<number> => {
|
||||||
try {
|
try {
|
||||||
const res = await axios.post(API_URL + '/admin/login', data, { withCredentials: true });
|
await axios.post(API_URL + '/admin/login', data, { withCredentials: true });
|
||||||
return data.adminId;
|
return data.adminId;
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
throw errorHandler(e, 'Login failed');
|
throw errorHandler(e, 'Login failed');
|
||||||
|
|
@ -17,97 +21,92 @@ export const apiLogin = async (data: AdminLogin): Promise<number> => {
|
||||||
// Create new candidate /admin/create
|
// Create new candidate /admin/create
|
||||||
// return created candidate's applicationId, personalIdNumber and password
|
// return created candidate's applicationId, personalIdNumber and password
|
||||||
export const apiCreateCandidate = async (data: CreateCandidate): Promise<CreateCandidateLogin> => {
|
export const apiCreateCandidate = async (data: CreateCandidate): Promise<CreateCandidateLogin> => {
|
||||||
try {
|
try {
|
||||||
const res = await axios.post(API_URL + '/admin/create', data, { withCredentials: true });
|
const res = await axios.post(API_URL + '/admin/create', data, { withCredentials: true });
|
||||||
return res.data;
|
return res.data;
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
throw errorHandler(e, 'Candidate creation failed');
|
throw errorHandler(e, 'Candidate creation failed');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// Reset candidate password /admin/candidate/{id}/reset_password
|
// Reset candidate password /admin/candidate/{id}/reset_password
|
||||||
export const apiResetCandidatePassword = async (id: number): Promise<CreateCandidateLogin> => {
|
export const apiResetCandidatePassword = async (id: number): Promise<CreateCandidateLogin> => {
|
||||||
try {
|
try {
|
||||||
const res = await axios.post(API_URL + '/admin/candidate/' + id + '/reset_password',
|
const res = await axios.post(
|
||||||
{},
|
API_URL + '/admin/candidate/' + id + '/reset_password',
|
||||||
{ withCredentials: true }
|
{},
|
||||||
);
|
{ withCredentials: true }
|
||||||
return res.data;
|
);
|
||||||
} catch (e: any) {
|
return res.data;
|
||||||
throw errorHandler(e, 'Candidate creation failed');
|
} catch (e: any) {
|
||||||
}
|
throw errorHandler(e, 'Candidate creation failed');
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const apiGetCandidatePortfolio = async (id: number): Promise<Blob> => {
|
export const apiGetCandidatePortfolio = async (id: number): Promise<Blob> => {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(API_URL + '/admin/candidate/' + id + '/portfolio', {
|
const res = await fetch(API_URL + '/admin/candidate/' + id + '/portfolio', {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
credentials: 'include',
|
credentials: 'include'
|
||||||
});
|
});
|
||||||
return await res.blob();
|
return await res.blob();
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
throw errorHandler(e, 'Candidate portfolio failed');
|
throw errorHandler(e, 'Candidate portfolio failed');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// SSR compatible
|
// SSR compatible
|
||||||
// Logout as admin /admin/logout
|
// Logout as admin /admin/logout
|
||||||
export const apiLogout = async (fetchSsr?: Fetch) => {
|
export const apiLogout = async (fetchSsr?: Fetch) => {
|
||||||
|
const apiFetch = fetchSsr || fetch;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (fetchSsr) {
|
const res = await apiFetch(API_URL + '/admin/logout', {
|
||||||
const res = await fetchSsr(API_URL + '/admin/logout', {
|
method: 'POST',
|
||||||
method: 'POST',
|
credentials: 'include'
|
||||||
credentials: 'include'
|
});
|
||||||
});
|
return await res.text();
|
||||||
return await res.text();
|
} catch (e) {
|
||||||
}
|
|
||||||
const res = await axios.post(API_URL + '/admin/logout', { withCredentials: true });
|
|
||||||
return res.data;
|
|
||||||
} catch (e: any) {
|
|
||||||
throw errorHandler(e, 'Logout failed');
|
throw errorHandler(e, 'Logout failed');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// SSR compatible
|
// SSR compatible
|
||||||
// List all candidates /admin/list/candidates
|
// List all candidates /admin/list/candidates
|
||||||
export const apiListCandidates = async (fetchSsr?: Fetch, field?: string): Promise<[CandidatePreview]> => {
|
export const apiListCandidates = async (
|
||||||
|
fetchSsr?: Fetch,
|
||||||
|
field?: string
|
||||||
|
): Promise<Array<CandidatePreview>> => {
|
||||||
|
const apiFetch = fetchSsr || fetch;
|
||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
if (field) {
|
if (field) {
|
||||||
params.append('field', field);
|
params.append('field', field);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (fetchSsr) {
|
const res = await apiFetch(API_URL + '/admin/list/candidates?' + params.toString(), {
|
||||||
const res = await fetchSsr(API_URL + '/admin/list/candidates?' + params.toString(), {
|
method: 'GET',
|
||||||
method: 'GET',
|
credentials: 'include'
|
||||||
credentials: 'include'
|
|
||||||
});
|
|
||||||
return await res.json();
|
|
||||||
}
|
|
||||||
const res = await axios.get(API_URL + '/admin/list/candidates?' + params.toString(), {
|
|
||||||
withCredentials: true
|
|
||||||
});
|
});
|
||||||
return res.data;
|
if (res.status != 200) {
|
||||||
} catch (e: any) {
|
throw Error(await res.text());
|
||||||
throw errorHandler(e, 'Failed to fetch submission progress');
|
}
|
||||||
|
return await res.json();
|
||||||
|
} catch (e) {
|
||||||
|
throw errorHandler(e, 'List candidates failed');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// SSR compatible
|
// SSR compatible
|
||||||
// Get candidate data /admin/candidate/{id}
|
// Get candidate data /admin/candidate/{id}
|
||||||
export const apiFetchCandidate = async (id: number, fetchSsr?: Fetch): Promise<CandidateData> => {
|
export const apiFetchCandidate = async (id: number, fetchSsr?: Fetch): Promise<CandidateData> => {
|
||||||
try {
|
const apiFetch = fetchSsr || fetch;
|
||||||
if (fetchSsr) {
|
try {
|
||||||
const res = await fetchSsr(API_URL + '/admin/candidate/' + id, {
|
const res = await apiFetch(API_URL + '/admin/candidate/' + id, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
credentials: 'include'
|
credentials: 'include'
|
||||||
});
|
|
||||||
return await res.json();
|
|
||||||
}
|
|
||||||
const res = await axios.get(API_URL + '/admin/candidate/' + id, {
|
|
||||||
withCredentials: true
|
|
||||||
});
|
});
|
||||||
return res.data;
|
return await res.json();
|
||||||
} catch (e: any) {
|
} catch (e) {
|
||||||
throw errorHandler(e, 'Failed to fetch candidate data');
|
throw errorHandler(e, 'Failed to fetch candidate data');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
|
||||||
|
|
@ -6,64 +6,66 @@ import DOMPurify from 'isomorphic-dompurify';
|
||||||
|
|
||||||
// SSR Compatible
|
// SSR Compatible
|
||||||
export const apiLogout = async (fetchSsr?: Fetch) => {
|
export const apiLogout = async (fetchSsr?: Fetch) => {
|
||||||
|
const apiFetch = fetchSsr || fetch;
|
||||||
try {
|
try {
|
||||||
fetchSsr
|
const res = await apiFetch(API_URL + '/candidate/logout', {
|
||||||
? await fetchSsr(API_URL + '/candidate/logout', { method: 'POST', credentials: 'include' })
|
method: 'POST',
|
||||||
: await axios.post(API_URL + '/candidate/logout', { withCredentials: true });
|
credentials: 'include'
|
||||||
} catch (e: any) {
|
});
|
||||||
|
return await res.json();
|
||||||
|
} catch (e) {
|
||||||
throw errorHandler(e, 'Logout failed');
|
throw errorHandler(e, 'Logout failed');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// SSR Compatible
|
// SSR Compatible
|
||||||
export const apiFetchDetails = async (fetchSsr?: Fetch): Promise<CandidateData> => {
|
export const apiFetchDetails = async (fetchSsr?: Fetch): Promise<CandidateData> => {
|
||||||
|
const apiFetch = fetchSsr || fetch;
|
||||||
try {
|
try {
|
||||||
if (fetchSsr) {
|
const res = await apiFetch(API_URL + '/candidate/details', {
|
||||||
const res = await fetchSsr(API_URL + '/candidate/details', {
|
method: 'GET',
|
||||||
method: 'GET',
|
credentials: 'include'
|
||||||
credentials: 'include'
|
});
|
||||||
});
|
if (res.status != 200) {
|
||||||
if (res.status != 200) {
|
throw new Error(await res.text());
|
||||||
throw new Error(await res.text());
|
|
||||||
}
|
|
||||||
return await res.json();
|
|
||||||
}
|
}
|
||||||
const res = await axios.get(API_URL + '/candidate/details', { withCredentials: true });
|
return await res.json();
|
||||||
return res.data;
|
} catch (e) {
|
||||||
} catch (e: any) {
|
throw errorHandler(e, 'Fetch details failed');
|
||||||
console.log(e);
|
|
||||||
throw errorHandler(e, 'Failed to fill details');
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// SSR Compatible
|
// SSR Compatible
|
||||||
export const apiFetchSubmissionProgress = async (fetchSsr?: Fetch): Promise<SubmissionProgress> => {
|
export const apiFetchSubmissionProgress = async (fetchSsr?: Fetch): Promise<SubmissionProgress> => {
|
||||||
|
const apiFetch = fetchSsr || fetch;
|
||||||
try {
|
try {
|
||||||
if (fetchSsr) {
|
const res = await apiFetch(API_URL + '/candidate/portfolio/submission_progress', {
|
||||||
const res = await fetchSsr(API_URL + '/candidate/portfolio/submission_progress', {
|
method: 'GET',
|
||||||
method: 'GET',
|
credentials: 'include'
|
||||||
credentials: 'include'
|
|
||||||
});
|
|
||||||
if (res.status != 200) {
|
|
||||||
throw Error(await res.text());
|
|
||||||
}
|
|
||||||
return await res.json();
|
|
||||||
}
|
|
||||||
const res = await axios.get(API_URL + '/candidate/portfolio/submission_progress', {
|
|
||||||
withCredentials: true
|
|
||||||
});
|
});
|
||||||
return res.data;
|
if (res.status != 200) {
|
||||||
} catch (e: any) {
|
throw Error(await res.text());
|
||||||
|
}
|
||||||
|
return await res.json();
|
||||||
|
} catch (e) {
|
||||||
throw errorHandler(e, 'Failed to fetch submission progress');
|
throw errorHandler(e, 'Failed to fetch submission progress');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const apiWhoami = async (): Promise<string> => {
|
export const apiWhoami = async (fetchSsr?: Fetch): Promise<string> => {
|
||||||
|
const apiFetch = fetchSsr || fetch;
|
||||||
try {
|
try {
|
||||||
const res = await axios.get(`${API_URL}/whoami`);
|
console.log(API_URL + '/candidate/whoami');
|
||||||
return res.data;
|
const res = await apiFetch(API_URL + '/candidate/whoami', {
|
||||||
} catch (e: any) {
|
method: 'GET',
|
||||||
throw errorHandler(e, 'Whoami failed');
|
credentials: 'include'
|
||||||
|
});
|
||||||
|
if (res.status != 200) {
|
||||||
|
throw Error(await res.text());
|
||||||
|
}
|
||||||
|
return await res.text();
|
||||||
|
} catch (e) {
|
||||||
|
throw errorHandler(e, 'Failed to fetch whoami');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -77,10 +79,11 @@ export const apiLogin = async (data: CandidateLogin): Promise<number> => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const apiFillDetails = async (data: CandidateData): Promise<CandidateData> => {
|
export const apiFillDetails = async (data: CandidateData): Promise<CandidateData> => {
|
||||||
Object.keys(data).forEach(key => {
|
Object.keys(data).forEach((key) => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
data[key] = DOMPurify.sanitize(data[key]);
|
data[key] = DOMPurify.sanitize(data[key]);
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
const res = await axios.post(API_URL + '/candidate/details', data, { withCredentials: true });
|
const res = await axios.post(API_URL + '/candidate/details', data, { withCredentials: true });
|
||||||
return res.data;
|
return res.data;
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@ export type Fetch = (input: RequestInfo, init?: RequestInit) => Promise<Response
|
||||||
export const API_URL = 'http://localhost:8000';
|
export const API_URL = 'http://localhost:8000';
|
||||||
|
|
||||||
export interface ApiError {
|
export interface ApiError {
|
||||||
error: AxiosError;
|
error: AxiosError | unknown;
|
||||||
msg: string;
|
msg: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const errorHandler = (error: AxiosError, msg: string): ApiError => {
|
export const errorHandler = (error: AxiosError | unknown, msg: string): ApiError => {
|
||||||
return { error, msg };
|
return { error, msg };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,13 @@ import type { PageServerLoad } from './$types';
|
||||||
|
|
||||||
export const load: PageServerLoad = async ({ fetch }) => {
|
export const load: PageServerLoad = async ({ fetch }) => {
|
||||||
let candidatePreview: Array<CandidatePreview> = [{}];
|
let candidatePreview: Array<CandidatePreview> = [{}];
|
||||||
try {
|
|
||||||
candidatePreview = await apiListCandidates(fetch);
|
candidatePreview =
|
||||||
} catch (e) {
|
(await apiListCandidates(fetch).catch((e) => {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
})) || [];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
preview: candidatePreview,
|
preview: candidatePreview
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,16 @@
|
||||||
import type { LayoutServerLoad } from './$types';
|
import type { LayoutServerLoad } from './$types';
|
||||||
|
|
||||||
import { redirect } from '@sveltejs/kit';
|
import { redirect } from '@sveltejs/kit';
|
||||||
|
import { apiWhoami } from '$lib/@api/candidate';
|
||||||
|
|
||||||
export const load: LayoutServerLoad = ({ cookies }) => {
|
export const load: LayoutServerLoad = async ({ cookies, fetch }) => {
|
||||||
const isAuthenticated = cookies.get('id');
|
const isAuthenticated = cookies.get('id');
|
||||||
if (!isAuthenticated) {
|
|
||||||
throw redirect(302, '/auth/login');
|
if (isAuthenticated) {
|
||||||
|
await apiWhoami(fetch).catch((e) => {
|
||||||
|
throw redirect(302, '/auth/logout');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw redirect(302, '/auth/logout');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
import { apiFetchDetails, apiFetchSubmissionProgress } from '$lib/@api/candidate';
|
|
||||||
import type { CandidateData } from '$lib/stores/candidate';
|
|
||||||
import { redirect } from '@sveltejs/kit';
|
|
||||||
import type { LayoutServerLoad } from './$types';
|
|
||||||
|
|
||||||
export const load: LayoutServerLoad = async ({ fetch }) => {
|
|
||||||
let details: CandidateData;
|
|
||||||
try {
|
|
||||||
details = await apiFetchDetails(fetch);
|
|
||||||
} catch (e: any) {
|
|
||||||
if (e.code === 401) {
|
|
||||||
throw redirect(302, '/auth/login');
|
|
||||||
} else {
|
|
||||||
throw redirect(302, '/register');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let submissionProgress;
|
|
||||||
try {
|
|
||||||
submissionProgress = await apiFetchSubmissionProgress(fetch);
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
candidate: details,
|
|
||||||
submission: {
|
|
||||||
...submissionProgress
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { apiFetchDetails, apiFetchSubmissionProgress } from '$lib/@api/candidate';
|
||||||
|
import type { CandidateData } from '$lib/stores/candidate';
|
||||||
|
import { redirect } from '@sveltejs/kit';
|
||||||
|
import type { PageServerLoad } from './$types';
|
||||||
|
|
||||||
|
export const load: PageServerLoad = async ({ fetch }) => {
|
||||||
|
const details: CandidateData = await apiFetchDetails(fetch).catch((e) => {
|
||||||
|
console.error(e);
|
||||||
|
throw redirect(302, '/register');
|
||||||
|
});
|
||||||
|
|
||||||
|
const submissionProgress = await apiFetchSubmissionProgress(fetch).catch((e) => {
|
||||||
|
console.log(e);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
candidate: details,
|
||||||
|
submission: {
|
||||||
|
...submissionProgress
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -4,7 +4,9 @@ import { redirect } from '@sveltejs/kit';
|
||||||
import { apiLogout } from '$lib/@api/candidate';
|
import { apiLogout } from '$lib/@api/candidate';
|
||||||
|
|
||||||
export const load: PageServerLoad = async ({ fetch, cookies }) => {
|
export const load: PageServerLoad = async ({ fetch, cookies }) => {
|
||||||
await apiLogout(fetch);
|
await apiLogout(fetch).catch(() => {
|
||||||
|
// TODO: Handle error
|
||||||
|
});
|
||||||
|
|
||||||
cookies.delete('id', { path: '/' });
|
cookies.delete('id', { path: '/' });
|
||||||
cookies.delete('key', { path: '/' });
|
cookies.delete('key', { path: '/' });
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue