Skip to content

Commit

Permalink
Added file upload and deletion to edit page (Closes #340)
Browse files Browse the repository at this point in the history
  • Loading branch information
netcodedev committed Sep 25, 2023
1 parent 615f55c commit 6cb2f60
Show file tree
Hide file tree
Showing 2 changed files with 204 additions and 123 deletions.
37 changes: 34 additions & 3 deletions src/routes/(protectedRoutes)/edit/[id]/+page.server.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { db } from '$lib/server/db';
import { error, redirect } from '@sveltejs/kit';
import { z } from 'zod';
import path from 'path';
import fs from 'fs/promises';
import fsSync from 'fs';

const filterSchema = z.object({
subjectArea: z
Expand Down Expand Up @@ -63,10 +66,12 @@ export async function load({ params, locals }) {
if (data[0].author !== locals.session.cas.user) {
throw error(403, 'Nicht authorisiert');
}

const directoryPath = path.join(process.cwd(), 'static', 'uploads', params.id);
let files = await fsSync.existsSync(directoryPath) ? await fs.readdir(directoryPath) : [];
return {
data: data[0],
errors: returnError
errors: returnError,
files
};
}

Expand All @@ -75,7 +80,9 @@ export const actions = {
const affiliation = locals.session.cas.attributes.eduPersonAffiliation;
const isEmployee = affiliation[0]._text == 'employee' || affiliation[1]._text == 'employee';
if (!isEmployee) throw redirect(303, '/');
const formData = Object.fromEntries(await request.formData());

const rawFormData = await request.formData();
const formData = Object.fromEntries(rawFormData);

// Convert thesisType_* fields to single array 'thesisType: []'
formData.thesisType = [];
Expand All @@ -91,11 +98,29 @@ export const actions = {
formData.supervisor = parseCSV(formData.supervisor);
formData.lastUpdatedAt = new Date();
formData.createdAt = new Date(formData.createdAt);
delete formData.files;
try {
if (!formData.draft) {
filterSchema.parse(formData);
}
db.merge(`topics:${params.id}`, formData);
const files = rawFormData.getAll('files');
const cwd = process.cwd();
for(const file of files) {
const filePath = path.join(
cwd,
'static',
'uploads',
params.id,
file.name
);
try {
await fs.mkdir(path.dirname(filePath), { recursive: true });
await fs.writeFile(filePath, Buffer.from(await file.arrayBuffer()));
} catch (error) {
console.error(error);
}
}
} catch (error) {
formData.draft = 'true';
db.merge(`topics:${params.id}`, formData);
Expand All @@ -110,6 +135,12 @@ export const actions = {
} else {
throw redirect(303, '/profile/topics');
}
},
deleteFile: async ({ params, request }) => {
const directoryPath = path.join(process.cwd(), 'static', 'uploads', params.id);
const { file } = Object.fromEntries(await request.formData());
await fs.unlink(path.join(directoryPath, file));
throw redirect(303, `/edit/${params.id}`);
}
};

Expand Down
290 changes: 170 additions & 120 deletions src/routes/(protectedRoutes)/edit/[id]/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,147 +1,197 @@
<script>
import { Input, Textarea } from '$lib/components';
import PDFIcon from 'svelte-material-icons/FilePdfBox.svelte';
import Delete from 'svelte-material-icons/Delete.svelte';
export let data;
let thesisType = [
{ id: 'Bachelor', text: 'Bachelor Thesis', checked: data.data.thesisType.includes('Bachelor') },
{ id: 'Master', text: 'Master Thesis', checked: data.data.thesisType.includes('Master') }
];
let files;
</script>

<form
action="?/updateTopic"
method="POST"
id="createTopic"
class="card shadow-xl bg-base-100 p-5 m-5">
<h2 class="text-3xl font-bold mx-5 my-3">Thema erstellen</h2>
<div id="createTopic" class="card shadow-xl bg-base-100 p-5 m-5">
<form
action="?/updateTopic"
enctype="multipart/form-data"
method="POST">
<h2 class="text-3xl font-bold mx-5 my-3">Thema erstellen</h2>

<div class="w-full flex justify-start flex-wrap">
<div class="mr-5">
<div class="w-full flex justify-start flex-wrap">
<div class="mr-5">
<div>
{#each thesisType as tType}
<div class="form-control">
<label class="label justify-start cursor-pointer">
<input
type="checkbox"
class="checkbox"
name="thesisType_{tType.id}"
checked={tType.checked ? 'checked' : ''} />
<span class="label-text ml-2">{tType.text}</span>
</label>
</div>
{/each}
</div>
<label class="label font-medium pb-1" for="thesisType">
{#if data?.errors?.thesisType}
<span class="label-text-alt text-error">*{data?.errors?.thesisType}*</span>
{/if}
</label>
</div>
<div class="mr-5">
<Input
id="subjectArea"
value={data.data.subjectArea}
label="Fachbereich"
suggestions
placeholder="Fachbereich"
errorMsg={data?.errors?.subjectArea ?? ''} />
</div>
<div class="mr-5">
<Input
id="areaOfExpertise"
value={data.data.areaOfExpertise}
label="Fachgebiet"
suggestions
placeholder="Fachgebiet"
errorMsg={data?.errors?.areaOfExpertise ?? ''} />
</div>
<div>
{#each thesisType as tType}
<div class="form-control">
<label class="label justify-start cursor-pointer">
<input
type="checkbox"
class="checkbox"
name="thesisType_{tType.id}"
checked={tType.checked ? 'checked' : ''} />
<span class="label-text ml-2">{tType.text}</span>
</label>
</div>
{/each}
<Input
id="specialization"
value={data.data.specialization}
label="Spezialisierung"
suggestions
csv
placeholder="Spezialisierung"
errorMsg={data?.errors?.specialization ?? ''} />
</div>
<label class="label font-medium pb-1" for="thesisType">
{#if data?.errors?.thesisType}
<span class="label-text-alt text-error">*{data?.errors?.thesisType}*</span>
{/if}
</label>
</div>
<div class="mr-5">
<Input
id="subjectArea"
value={data.data.subjectArea}
label="Fachbereich"
suggestions
placeholder="Fachbereich"
errorMsg={data?.errors?.subjectArea ?? ''} />
</div>
<div class="mr-5">
<Input
id="areaOfExpertise"
value={data.data.areaOfExpertise}
label="Fachgebiet"
suggestions
placeholder="Fachgebiet"
errorMsg={data?.errors?.areaOfExpertise ?? ''} />
</div>
<div>
<Input
id="specialization"
value={data.data.specialization}
label="Spezialisierung"
suggestions
csv
placeholder="Spezialisierung"
errorMsg={data?.errors?.specialization ?? ''} />
</div>
</div>

<Input
id="title"
label="Titel"
placeholder="Titel"
value={data.data.title}
errorMsg={data?.errors?.title ?? ''} />
<Textarea
id="description"
label="Beschreibung"
placeholder="Beschreibung des Themas"
value={data.data.description}
errorMsg={data?.errors?.description ?? ''} />
<Input
id="title"
label="Titel"
placeholder="Titel"
value={data.data.title}
errorMsg={data?.errors?.title ?? ''} />
<Textarea
id="description"
label="Beschreibung"
placeholder="Beschreibung des Themas"
value={data.data.description}
errorMsg={data?.errors?.description ?? ''} />

<div class="w-full flex justify-start flex-wrap">
<div class="mr-5">
<Input
id="professor"
label="Leitende(r) Professor*in"
placeholder="Leitende(r) Professor*in"
value={data.data.professor}
suggestions
errorMsg={data?.errors?.professor ?? ''} />
</div>
<div class="mr-5">
<Input
id="supervisor"
label="Betreuende Personen"
placeholder="Betreuende Personen"
value={data.data.supervisor}
suggestions
csv
errorMsg={data?.errors?.supervisor ?? ''} />
<div class="w-full flex justify-start flex-wrap">
<div class="mr-5">
<Input
id="professor"
label="Leitende(r) Professor*in"
placeholder="Leitende(r) Professor*in"
value={data.data.professor}
suggestions
errorMsg={data?.errors?.professor ?? ''} />
</div>
<div class="mr-5">
<Input
id="supervisor"
label="Betreuende Personen"
placeholder="Betreuende Personen"
value={data.data.supervisor}
suggestions
csv
errorMsg={data?.errors?.supervisor ?? ''} />
</div>

<div class="mr-5">
<Input
id="technologies"
label="Zu verwendende Technologien"
placeholder="Java, Python, C++ ..."
value={data.data.technologies}
suggestions
csv
errorMsg={data?.errors?.technologies ?? ''} />
</div>
<div>
<Input
id="email"
label="E-Mail Kontakt"
placeholder="me@tu-darmstadt.de"
type="mail"
value={data.data.email}
suggestions
errorMsg={data?.errors?.email ?? ''} />
</div>
</div>

<div class="mr-5">
<Input
id="technologies"
label="Zu verwendende Technologien"
placeholder="Java, Python, C++ ..."
value={data.data.technologies}
suggestions
csv
errorMsg={data?.errors?.technologies ?? ''} />
<Textarea
id="other"
label="Sonstiges"
placeholder="Sonstige Informationen"
value={data.data.other} />
<div class="mb-3">
<div class="form-control w-full max-w-xs">
<label class="label" for="pdfUpload">
<span class="label-text">PDF Dateien hochladen</span>
</label>
<input bind:files name="files" id="pdfUpload" type="file" multiple class="file-input file-input-bordered w-full max-w-xs" accept="application/pdf"/>
{#if files && files.length > 0}
<h2>Ausgewählte Dateien:</h2>
{#each files as file}
<div class="flex justify-between mb-1">
<span>{file.name}</span>
</div>
{/each}
{/if}
</div>
</div>
<input type="hidden" name="createdAt" value={data.data.createdAt} />
<input type="hidden" name="lastUpdatedAt" value={data.data.lastUpdatedAt} />
<div class="flex justify-end">
<button type="submit" class="btn btn-outline mr-5" name="draft" value="true">
Entwurf speichern
</button>
<button type="submit" class="btn btn-primary">Veröffentlichen</button>
</div>
</form>
{#if data.files.length > 0}
<div>
<Input
id="email"
label="E-Mail Kontakt"
placeholder="me@tu-darmstadt.de"
type="mail"
value={data.data.email}
suggestions
errorMsg={data?.errors?.email ?? ''} />
<h2 class="mb-3">Dateien</h2>
<div>
{#each data.files as file}
<form class="flex justify-between mb-2">
<a
href="/uploads/{data.data.id.split(":")[1]}/{file}"
class="btn btn-primary btn-sm mr-2"
title="Datei herunterladen">
<span class="text-3xl"><PDFIcon /></span>
{file}
</a>
<button
class="btn btn-error btn-sm btn-circle text-white"
type="submit"
formaction="?/deleteFile"
formmethod="POST"
name="file"
value="{file}">
<span class="text-xl"><Delete /></span>
</button>
</form>
{#if data.files.indexOf(file) != data.files.length - 1}
<hr class="mb-2 border-t border-b-0">
{/if}
{/each}
</div>
</div>
</div>

<Textarea
id="other"
label="Sonstiges"
placeholder="Sonstige Informationen"
value={data.data.other} />
<input type="hidden" name="createdAt" value={data.data.createdAt} />
<input type="hidden" name="lastUpdatedAt" value={data.data.lastUpdatedAt} />
<div class="flex justify-end">
<button type="submit" class="btn btn-outline mr-5" name="draft" value="true">
Entwurf speichern
</button>
<button type="submit" class="btn btn-primary">Veröffentlichen</button>
</div>
</form>

{/if}
</div>
<style lang="scss">
@media (min-width: 1440px) {
form#createTopic {
div#createTopic {
margin-left: calc(50% - 700px);
width: 1400px;
text-align: left;
Expand Down

0 comments on commit 6cb2f60

Please sign in to comment.