fix(client): 🐛 do not allow private resumes to be viewable or downloadable through the link

This commit is contained in:
Amruth Pillai
2023-07-12 15:59:22 +02:00
parent 5ef4bfcb6b
commit 1c2d796c50
121 changed files with 3193 additions and 2068 deletions

View File

@ -18,7 +18,7 @@ const CustomCSS = () => {
const dispatch = useAppDispatch();
const customCSS: CustomCSSType = useAppSelector((state) =>
get(state.resume.present, 'metadata.css', {} as CustomCSSType)
get(state.resume.present, 'metadata.css', {} as CustomCSSType),
);
const handleChange = (value: string | undefined) => {
@ -27,7 +27,7 @@ const CustomCSS = () => {
return (
<>
<Heading path="metadata.css" name={t<string>('builder.rightSidebar.sections.css.heading')} isHideable />
<Heading path="metadata.css" name={t('builder.rightSidebar.sections.css.heading')} isHideable />
<Editor
height="200px"

View File

@ -20,12 +20,12 @@ const Export = () => {
const pdfListItemText = {
normal: {
primary: t<string>('builder.rightSidebar.sections.export.pdf.normal.primary'),
secondary: t<string>('builder.rightSidebar.sections.export.pdf.normal.secondary'),
primary: t('builder.rightSidebar.sections.export.pdf.normal.primary'),
secondary: t('builder.rightSidebar.sections.export.pdf.normal.secondary'),
},
loading: {
primary: t<string>('builder.rightSidebar.sections.export.pdf.loading.primary'),
secondary: t<string>('builder.rightSidebar.sections.export.pdf.loading.secondary'),
primary: t('builder.rightSidebar.sections.export.pdf.loading.primary'),
secondary: t('builder.rightSidebar.sections.export.pdf.loading.secondary'),
},
};
@ -55,7 +55,7 @@ const Export = () => {
return (
<>
<Heading path="metadata.export" name={t<string>('builder.rightSidebar.sections.export.heading')} />
<Heading path="metadata.export" name={t('builder.rightSidebar.sections.export.heading')} />
<List sx={{ padding: 0 }}>
<ListItem sx={{ padding: 0 }}>
@ -63,8 +63,8 @@ const Export = () => {
<Schema />
<ListItemText
primary={t<string>('builder.rightSidebar.sections.export.json.primary')}
secondary={t<string>('builder.rightSidebar.sections.export.json.secondary')}
primary={t('builder.rightSidebar.sections.export.json.primary')}
secondary={t('builder.rightSidebar.sections.export.json.secondary')}
/>
</ListItemButton>
</ListItem>

View File

@ -1,6 +1,6 @@
.page {
@apply relative border pl-4 pb-4 dark:border-neutral-100/10;
@apply rounded bg-neutral-100 dark:bg-neutral-800;
@apply relative border pl-4 pb-4 dark:border-zinc-100/10;
@apply rounded bg-zinc-100 dark:bg-zinc-900;
.delete {
@apply opacity-50 hover:opacity-75;
@ -28,14 +28,14 @@
.base {
@apply absolute inset-0 w-4/5;
@apply rounded bg-neutral-200 dark:bg-neutral-700;
@apply rounded bg-zinc-200 dark:bg-zinc-800;
}
}
.section {
@apply relative my-3 w-full px-4 py-2;
@apply cursor-move break-all rounded text-xs capitalize;
@apply bg-neutral-800/90 text-neutral-50 dark:bg-neutral-50/90 dark:text-neutral-800;
@apply bg-zinc-900/90 text-zinc-50 dark:bg-zinc-50/90 dark:text-zinc-900;
&.disabled {
@apply opacity-60;

View File

@ -60,9 +60,9 @@ const Layout = () => {
<>
<Heading
path="metadata.layout"
name={t<string>('builder.rightSidebar.sections.layout.heading')}
name={t('builder.rightSidebar.sections.layout.heading')}
action={
<Tooltip title={t<string>('builder.rightSidebar.sections.layout.tooltip.reset-layout')}>
<Tooltip title={t('builder.rightSidebar.sections.layout.tooltip.reset-layout')}>
<IconButton onClick={handleResetLayout}>
<Restore />
</IconButton>
@ -76,14 +76,14 @@ const Layout = () => {
<div key={pageIndex} className={styles.page}>
<div className="flex items-center justify-between pr-3">
<p className={styles.heading}>
{t<string>('builder.common.glossary.page')} {pageIndex + 1}
{t('builder.common.glossary.page')} {pageIndex + 1}
</p>
<div className={clsx(styles.delete, { hidden: pageIndex === 0 })}>
<Tooltip
title={
t<string>('builder.common.actions.delete', {
token: t<string>('builder.common.glossary.page'),
t('builder.common.actions.delete', {
token: t('builder.common.glossary.page'),
}) as string
}
>
@ -136,7 +136,7 @@ const Layout = () => {
<div className="flex items-center justify-end">
<Button variant="outlined" startIcon={<Add />} onClick={handleAddPage}>
{t<string>('builder.common.actions.add', { token: t<string>('builder.common.glossary.page') })}
{t('builder.common.actions.add', { token: t('builder.common.glossary.page') })}
</Button>
</div>
</DragDropContext>

View File

@ -3,7 +3,7 @@
.section {
@apply grid gap-2 rounded p-6;
@apply bg-neutral-100 dark:bg-neutral-800;
@apply bg-zinc-100 dark:bg-zinc-900;
h2 {
@apply inline-flex items-center gap-2 text-base font-medium;

View File

@ -12,53 +12,51 @@ const Links = () => {
return (
<>
<Heading path="metadata.links" name={t<string>('builder.rightSidebar.sections.links.heading')} />
<Heading path="metadata.links" name={t('builder.rightSidebar.sections.links.heading')} />
<div className={styles.container}>
<div className={styles.section}>
<h2>
<Savings fontSize="small" />
{t<string>('builder.rightSidebar.sections.links.donate.heading')}
{t('builder.rightSidebar.sections.links.donate.heading')}
</h2>
<p>{t<string>('builder.rightSidebar.sections.links.donate.body')}</p>
<p>{t('builder.rightSidebar.sections.links.donate.body')}</p>
<a href={DONATION_URL} target="_blank" rel="noreferrer">
<Button startIcon={<Coffee />}>{t<string>('builder.rightSidebar.sections.links.donate.button')}</Button>
<Button startIcon={<Coffee />}>{t('builder.rightSidebar.sections.links.donate.button')}</Button>
</a>
</div>
<div className={styles.section}>
<h2>
<BugReport fontSize="small" />
{t<string>('builder.rightSidebar.sections.links.bugs-features.heading')}
{t('builder.rightSidebar.sections.links.bugs-features.heading')}
</h2>
<p>{t<string>('builder.rightSidebar.sections.links.bugs-features.body')}</p>
<p>{t('builder.rightSidebar.sections.links.bugs-features.body')}</p>
<a href={GITHUB_ISSUES_URL} target="_blank" rel="noreferrer">
<Button startIcon={<GitHub />}>
{t<string>('builder.rightSidebar.sections.links.bugs-features.button')}
</Button>
<Button startIcon={<GitHub />}>{t('builder.rightSidebar.sections.links.bugs-features.button')}</Button>
</a>
</div>
<div>
<a href={GITHUB_URL} target="_blank" rel="noreferrer">
<Button variant="text" startIcon={<Link />}>
{t<string>('builder.rightSidebar.sections.links.github')}
{t('builder.rightSidebar.sections.links.github')}
</Button>
</a>
<a href={REDDIT_URL} target="_blank" rel="noreferrer">
<Button variant="text" startIcon={<Link />}>
{t<string>('builder.rightSidebar.sections.links.reddit')}
{t('builder.rightSidebar.sections.links.reddit')}
</Button>
</a>
<a href={DOCS_URL} target="_blank" rel="noreferrer">
<Button variant="text" startIcon={<Link />}>
{t<string>('builder.rightSidebar.sections.links.docs')}
{t('builder.rightSidebar.sections.links.docs')}
</Button>
</a>
</div>

View File

@ -55,7 +55,7 @@ const Settings = () => {
const themeString = useMemo(() => (isDarkMode ? 'Matte Black Everything' : 'As bright as your future'), [isDarkMode]);
const { mutateAsync: loadSampleDataMutation } = useMutation<Resume, ServerError, LoadSampleDataParams>(
loadSampleData
loadSampleData,
);
const { mutateAsync: resetResumeMutation } = useMutation<Resume, ServerError, ResetResumeParams>(resetResume);
@ -96,13 +96,13 @@ const Settings = () => {
return (
<>
<Heading path="metadata.settings" name={t<string>('builder.rightSidebar.sections.settings.heading')} />
<Heading path="metadata.settings" name={t('builder.rightSidebar.sections.settings.heading')} />
<List disablePadding>
{/* Global Settings */}
<>
<ListSubheader disableSticky className="rounded">
{t<string>('builder.rightSidebar.sections.settings.global.heading')}
{t('builder.rightSidebar.sections.settings.global.heading')}
</ListSubheader>
<ListItem>
@ -110,7 +110,7 @@ const Settings = () => {
<Palette />
</ListItemIcon>
<ListItemText
primary={t<string>('builder.rightSidebar.sections.settings.global.theme.primary')}
primary={t('builder.rightSidebar.sections.settings.global.theme.primary')}
secondary={themeString}
/>
<ThemeSwitch checked={isDarkMode} onChange={(_, value: boolean) => handleSetTheme(value)} />
@ -119,8 +119,8 @@ const Settings = () => {
<ListItem className="flex-col">
<ListItemText
className="w-full"
primary={t<string>('builder.rightSidebar.sections.settings.global.date.primary')}
secondary={t<string>('builder.rightSidebar.sections.settings.global.date.secondary')}
primary={t('builder.rightSidebar.sections.settings.global.date.primary')}
secondary={t('builder.rightSidebar.sections.settings.global.date.secondary')}
/>
<Autocomplete<string, false, true, false>
disableClearable
@ -135,8 +135,8 @@ const Settings = () => {
<ListItem className="flex-col">
<ListItemText
className="w-full"
primary={t<string>('builder.rightSidebar.sections.settings.global.language.primary')}
secondary={t<string>('builder.rightSidebar.sections.settings.global.language.secondary')}
primary={t('builder.rightSidebar.sections.settings.global.language.primary')}
secondary={t('builder.rightSidebar.sections.settings.global.language.secondary')}
/>
<Autocomplete<Language, false, true, false>
disableClearable
@ -160,14 +160,14 @@ const Settings = () => {
{/* Page Settings */}
<>
<ListSubheader disableSticky className="rounded">
{t<string>('builder.rightSidebar.sections.settings.page.heading')}
{t('builder.rightSidebar.sections.settings.page.heading')}
</ListSubheader>
<ListItem className="flex-col">
<ListItemText
className="w-full"
primary={t<string>('builder.rightSidebar.sections.settings.page.format.primary')}
secondary={t<string>('builder.rightSidebar.sections.settings.page.format.secondary')}
primary={t('builder.rightSidebar.sections.settings.page.format.primary')}
secondary={t('builder.rightSidebar.sections.settings.page.format.secondary')}
/>
<Autocomplete<PageConfig['format'], false, true, false>
disableClearable
@ -182,11 +182,11 @@ const Settings = () => {
<ListItem>
<ListItemText
primary={t<string>('builder.rightSidebar.sections.settings.page.orientation.primary')}
primary={t('builder.rightSidebar.sections.settings.page.orientation.primary')}
secondary={
pages.length === 1
? t<string>('builder.rightSidebar.sections.settings.page.orientation.disabled')
: t<string>('builder.rightSidebar.sections.settings.page.orientation.secondary')
? t('builder.rightSidebar.sections.settings.page.orientation.disabled')
: t('builder.rightSidebar.sections.settings.page.orientation.secondary')
}
/>
<Switch
@ -199,8 +199,8 @@ const Settings = () => {
<ListItem>
<ListItemText
primary={t<string>('builder.rightSidebar.sections.settings.page.break-line.primary')}
secondary={t<string>('builder.rightSidebar.sections.settings.page.break-line.secondary')}
primary={t('builder.rightSidebar.sections.settings.page.break-line.primary')}
secondary={t('builder.rightSidebar.sections.settings.page.break-line.secondary')}
/>
<Switch color="secondary" checked={breakLine} onChange={() => dispatch(togglePageBreakLine())} />
</ListItem>
@ -209,7 +209,7 @@ const Settings = () => {
{/* Resume Settings */}
<>
<ListSubheader disableSticky className="rounded">
{t<string>('builder.rightSidebar.sections.settings.resume.heading')}
{t('builder.rightSidebar.sections.settings.resume.heading')}
</ListSubheader>
<ListItem disableGutters>
@ -218,8 +218,8 @@ const Settings = () => {
<Anchor />
</ListItemIcon>
<ListItemText
primary={t<string>('builder.rightSidebar.sections.settings.resume.sample.primary')}
secondary={t<string>('builder.rightSidebar.sections.settings.resume.sample.secondary')}
primary={t('builder.rightSidebar.sections.settings.resume.sample.primary')}
secondary={t('builder.rightSidebar.sections.settings.resume.sample.secondary')}
/>
</ListItemButton>
</ListItem>
@ -231,11 +231,9 @@ const Settings = () => {
</ListItemIcon>
<ListItemText
primary={
confirmReset
? 'Are you sure?'
: t<string>('builder.rightSidebar.sections.settings.resume.reset.primary')
confirmReset ? 'Are you sure?' : t('builder.rightSidebar.sections.settings.resume.reset.primary')
}
secondary={t<string>('builder.rightSidebar.sections.settings.resume.reset.secondary')}
secondary={t('builder.rightSidebar.sections.settings.resume.reset.secondary')}
/>
</ListItemButton>
</ListItem>

View File

@ -29,19 +29,19 @@ const Sharing = () => {
await navigator.clipboard.writeText(text);
toast.success(t<string>('common.toast.success.resume-link-copied'));
toast.success(t('common.toast.success.resume-link-copied'));
};
return (
<>
<Heading path="metadata.sharing" name={t<string>('builder.rightSidebar.sections.sharing.heading')} />
<Heading path="metadata.sharing" name={t('builder.rightSidebar.sections.sharing.heading')} />
<List sx={{ padding: 0 }}>
<ListItem className="flex flex-col" sx={{ padding: 0 }}>
<div className="flex w-full items-center justify-between">
<ListItemText
primary={t<string>('builder.rightSidebar.sections.sharing.visibility.title')}
secondary={t<string>('builder.rightSidebar.sections.sharing.visibility.subtitle')}
primary={t('builder.rightSidebar.sections.sharing.visibility.title')}
secondary={t('builder.rightSidebar.sections.sharing.visibility.subtitle')}
/>
<Switch color="secondary" checked={isPublic} onChange={(_, value) => handleSetVisibility(value)} />
</div>
@ -63,7 +63,7 @@ const Sharing = () => {
<div className="mt-1 flex w-full">
<FormControlLabel
label={t<string>('builder.rightSidebar.sections.sharing.short-url.label')}
label={t('builder.rightSidebar.sections.sharing.short-url.label')}
control={
<Checkbox className="mr-1" checked={showShortUrl} onChange={(_, value) => setShowShortUrl(value)} />
}

View File

@ -24,7 +24,7 @@ const Templates = () => {
return (
<>
<Heading path="metadata.templates" name={t<string>('builder.rightSidebar.sections.templates.heading')} />
<Heading path="metadata.templates" name={t('builder.rightSidebar.sections.templates.heading')} />
<div className={styles.container}>
{Object.values(templateMap).map((template) => (

View File

@ -17,7 +17,7 @@ const Theme = () => {
const dispatch = useAppDispatch();
const { background, text, primary } = useAppSelector<ThemeConfig>((state) =>
get(state.resume.present, 'metadata.theme')
get(state.resume.present, 'metadata.theme'),
);
const handleChange = (property: string, color: string) => {
@ -26,7 +26,7 @@ const Theme = () => {
return (
<>
<Heading path="metadata.theme" name={t<string>('builder.rightSidebar.sections.theme.heading')} />
<Heading path="metadata.theme" name={t('builder.rightSidebar.sections.theme.heading')} />
<div className={styles.container}>
<div className={styles.colorOptions}>
@ -36,18 +36,18 @@ const Theme = () => {
</div>
<ColorPicker
label={t<string>('builder.rightSidebar.sections.theme.form.primary.label')}
label={t('builder.rightSidebar.sections.theme.form.primary.label')}
color={primary}
className="col-span-2"
onChange={(color) => handleChange('primary', color)}
/>
<ColorPicker
label={t<string>('builder.rightSidebar.sections.theme.form.background.label')}
label={t('builder.rightSidebar.sections.theme.form.background.label')}
color={background}
onChange={(color) => handleChange('background', color)}
/>
<ColorPicker
label={t<string>('builder.rightSidebar.sections.theme.form.text.label')}
label={t('builder.rightSidebar.sections.theme.form.text.label')}
color={text}
onChange={(color) => handleChange('text', color)}
/>

View File

@ -46,7 +46,7 @@ const Widgets: React.FC<WidgetProps> = ({ label, category }) => {
setResumeState({
path: `metadata.typography.${property}.${category}`,
value: property === 'family' ? (value as Font).family : value,
})
}),
);
};
@ -64,7 +64,7 @@ const Widgets: React.FC<WidgetProps> = ({ label, category }) => {
step={1}
marks={[
{ value: 12, label: '12px' },
{ value: 24, label: t<string>('builder.rightSidebar.sections.typography.form.font-size.label') },
{ value: 24, label: t('builder.rightSidebar.sections.typography.form.font-size.label') },
{ value: 36, label: '36px' },
]}
valueLabelDisplay="auto"
@ -82,10 +82,7 @@ const Widgets: React.FC<WidgetProps> = ({ label, category }) => {
value={fonts.find((font) => font.family === family[category])}
onChange={(_, font: Font | null) => handleChange('family', font)}
renderInput={(params) => (
<TextField
{...params}
label={t<string>('builder.rightSidebar.sections.typography.form.font-family.label')}
/>
<TextField {...params} label={t('builder.rightSidebar.sections.typography.form.font-family.label')} />
)}
/>
</div>
@ -98,13 +95,10 @@ const Typography = () => {
return (
<>
<Heading path="metadata.typography" name={t<string>('builder.rightSidebar.sections.typography.heading')} />
<Heading path="metadata.typography" name={t('builder.rightSidebar.sections.typography.heading')} />
<Widgets
label={t<string>('builder.rightSidebar.sections.typography.widgets.headings.label')}
category="heading"
/>
<Widgets label={t<string>('builder.rightSidebar.sections.typography.widgets.body.label')} category="body" />
<Widgets label={t('builder.rightSidebar.sections.typography.widgets.headings.label')} category="heading" />
<Widgets label={t('builder.rightSidebar.sections.typography.widgets.body.label')} category="body" />
</>
);
};