Allow updating remote timetables with permission

This commit is contained in:
2023-06-20 20:22:51 +02:00
parent 5d9317ac01
commit 41c0d329fb
5 changed files with 91 additions and 5 deletions

View File

@ -82,6 +82,34 @@ export async function getTimetable(req, res) {
});
}
// Edit timetable API endpoint (/api/timetable)
// Updates a remote timetable with the requested data
export async function putTimetable(req, res) {
const timetableId = parseInt(req.query.id);
const data = req.body.data;
if (
!(await hasPermission(req.locals.session, "timetable.update", timetableId))
) {
res.status(401).send({
success: false,
error: "missing_permission",
message: "You don't have permission to update this timetable!",
});
return;
}
await prisma.timetable.update({
where: {
id: timetableId,
},
data: {
data,
title: req.body.title,
},
});
res.status(201).send();
}
// Helper function for converting a date string
// (eg. "2022-06-02" or "1654128000000") to a
// unix timestamp

View File

@ -8,6 +8,7 @@ import {
getSubstitutions,
getHistory,
getClasses,
putTimetable,
getInfo,
putKey,
deleteKey,
@ -63,6 +64,7 @@ app.get("/api/info", getInfo);
app.put("/api/key", putKey);
app.delete("/api/key", deleteKey);
app.get("/api/timetable", getTimetable);
app.put("/api/timetable", putTimetable);
app.get("/api/substitutions", getSubstitutions);
app.get("/api/history", getHistory);
app.get("/api/classes", getClasses);

View File

@ -7,11 +7,12 @@ import {
TrashIcon,
AlertCircleIcon,
CopyIcon,
UploadCloudIcon,
} from "lucide-vue-next";
import { DownloadIcon } from "lucide-vue-next";
defineProps(["timetable", "editable", "selected"]);
defineEmits(["click", "edit", "delete", "copy", "export"]);
defineProps(["timetable", "editable", "remote", "selected"]);
defineEmits(["click", "edit", "delete", "copy", "export", "upload"]);
const deleteConfirm = ref(false);
@ -38,7 +39,8 @@ watch(deleteConfirm, (value) => {
<div class="buttons">
<DownloadIcon @click="$emit('export')" />
<Edit2Icon v-if="editable" @click="$emit('edit')" />
<Edit2Icon v-if="editable && !remote" @click="$emit('edit')" />
<UploadCloudIcon v-if="editable && remote" @click="$emit('upload')" />
<CopyIcon @click="$emit('copy')" />
<TrashIcon
v-if="editable && !deleteConfirm"

14
src/permission.js Normal file
View File

@ -0,0 +1,14 @@
import { sessionInfo } from "@/store";
export function hasPermission(permission, forValue) {
let hasPermission = false;
for (const perm of sessionInfo.value.permissions) {
if (perm == permission) hasPermission = true;
else if (perm == permission + ":" + forValue) hasPermission = true;
}
return hasPermission;
}
export function canEditTimetable(id) {
return hasPermission("timetable.update", id);
}

View File

@ -1,9 +1,18 @@
<script setup>
import TimetableCard from "@/components/settings/timetable-card.vue";
import { timetables, localTimetables, timetableId } from "@/store";
import {
timetable,
timetables,
localTimetables,
timetableId,
baseUrl,
fetchTimetables,
} from "@/store";
import { canEditTimetable } from "@/permission";
import { PlusIcon, PaperclipIcon } from "lucide-vue-next";
import { toRaw, ref } from "vue";
import download from "downloadjs";
import { loading, loadingProgress } from "@/store";
function copyTimetable(timetable) {
const newTimetable = structuredClone(toRaw(timetable));
@ -47,6 +56,34 @@ function exportTimetable(timetable) {
"application/json"
);
}
async function uploadTimetable(id) {
loadingProgress.value = 0.1;
loading.value = true;
const timetableData = timetable.value;
const response = await fetch(
baseUrl + "/timetable?id=" + encodeURIComponent(id),
{
method: "put",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(timetableData),
}
);
if (response.status != 201) {
alert("Failed uploading timetable!");
} else {
loadingProgress.value = 0.5;
await fetchTimetables();
timetableId.value = id;
}
loadingProgress.value = 1;
loading.value = false;
}
</script>
<template>
@ -59,6 +96,7 @@ function exportTimetable(timetable) {
:timetable="timetable"
:selected="timetableId == timetable.id"
:editable="true"
:remote="false"
@click="timetableId = timetable.id"
@edit="$router.push('timetable/edit/' + timetable.id)"
@copy="copyTimetable(timetable)"
@ -92,10 +130,12 @@ function exportTimetable(timetable) {
:key="timetable.id"
:timetable="timetable"
:selected="timetableId == timetable.id"
:editable="false"
:editable="canEditTimetable(timetable.id)"
:remote="true"
@click="timetableId = timetable.id"
@copy="copyTimetable(timetable)"
@export="exportTimetable(timetable)"
@upload="uploadTimetable(timetable.id)"
/>
</div>
</div>