Stundenaufzeichnung/src/routes/+page.server.ts

260 lines
6.5 KiB
TypeScript
Raw Normal View History

2025-03-25 15:25:04 +01:00
import type { PageServerLoad, Actions } from "./$types";
2025-06-05 14:32:12 +02:00
import { SQLiteError } from "bun:sqlite";
2025-03-25 15:25:04 +01:00
2025-06-05 14:32:12 +02:00
import type { FileProperties } from "$lib/server/docstore"
2025-03-25 15:25:04 +01:00
import type { RecordEntry, EstimatesEntry } from "$lib/db_types";
import { fail, redirect } from '@sveltejs/kit';
2025-06-05 14:32:12 +02:00
import { toInt, parseDate, isTimeValidHHMM } from "$lib/util"
2025-03-25 15:25:04 +01:00
import { getRecordFiles } from "$lib/server/docstore";
export const load: PageServerLoad = async ({ locals }) => {
2025-06-05 14:32:12 +02:00
if (!locals.user) {
return fail(403, { message: "Unauthorized user" });
}
2025-03-25 15:25:04 +01:00
2025-06-05 14:32:12 +02:00
let records = locals.user.get_entries().map((v) => ({ entry: v, parsedDate: parseDate(v.date) ?? new Date(0) }));
let estimates = locals.user.get_estimates()
let documents = (await getRecordFiles(locals.user)).map((v) => { return { year: toInt(v.identifier.substring(0, 4)), month: toInt(v.identifier.substring(5, 7)), file: v }; });
2025-03-25 15:25:04 +01:00
2025-06-05 14:32:12 +02:00
let records_grouped: Map<number, Map<number, RecordEntry[]>> = new Map()
Map.groupBy(records, (v) => { return v.parsedDate.getFullYear() } ).forEach((value, key, _) => {
let month_map: Map<number, RecordEntry[]> = new Map()
Map.groupBy(value, (v) => v.parsedDate.getMonth()).forEach((value, key, _) => {
// remove parsed date
month_map.set(key, value.map((v) => v.entry));
2025-03-25 15:25:04 +01:00
});
2025-06-05 14:32:12 +02:00
records_grouped.set(key, month_map);
2025-03-25 15:25:04 +01:00
});
2025-06-05 14:32:12 +02:00
let estimates_grouped: Map<number, Map<number, number>>= new Map();
Map.groupBy(estimates, (v) => { return v.year }).forEach((value, key, _) => {
2025-03-25 15:25:04 +01:00
let arr = value.map((v) => [
{ key: ((v.quarter - 1) * 3 + 2), value: v["estimate_2"] },
{ key: ((v.quarter - 1) * 3 + 1), value: v["estimate_1"] },
{ key: ((v.quarter - 1) * 3 + 0), value: v["estimate_0"] },
]).flat();
2025-06-05 14:32:12 +02:00
let m: Map<number, number> = new Map();
Map.groupBy(arr, (e) => e.key).forEach((value, key, _) => {
m.set(key, value[0].value);
2025-03-25 15:25:04 +01:00
})
2025-06-05 14:32:12 +02:00
estimates_grouped.set(key, m);
2025-03-25 15:25:04 +01:00
})
2025-06-05 14:32:12 +02:00
let documents_grouped: Map<number, Map<number, FileProperties>> = new Map();
Map.groupBy(documents, (v) => v.year ).forEach((value, key, _) => {
let m: Map<number, FileProperties> = new Map()
Map.groupBy(value, (v) => v.month).forEach((value, key, _) => {
m.set(key, value.map((v) => v.file)[0]);
2025-03-25 15:25:04 +01:00
})
2025-06-05 14:32:12 +02:00
documents_grouped.set(key, m);
2025-03-25 15:25:04 +01:00
})
return {
2025-03-25 15:25:04 +01:00
records: records_grouped,
estimates: estimates_grouped,
documents: documents_grouped
};
}
export const actions = {
new_entry: async ({locals, request}) => {
2025-06-05 14:32:12 +02:00
if (!locals.user) {
return fail(403, { message: "Unauthorized user" })
}
const ok = "ok";
const missing = "missing";
const invalid = "invalid";
const data = await request.formData();
2025-06-05 14:32:12 +02:00
let date = data.get("date") as string;
let start = data.get("start") as string;
let end = data.get("end") as string;
let comment = data.get("comment") as string;
2025-06-05 14:32:12 +02:00
let return_obj: Map<string, { status: string, value: string }> = new Map(Object.entries({
date : {
status: ok,
value: date
},
start : {
status: ok,
value: start
},
end : {
status: ok,
value: end
},
comment : {
status: ok,
value: comment
},
2025-06-05 14:32:12 +02:00
}))
if (date == null) {
2025-06-05 14:32:12 +02:00
return_obj.get("date")!.status = missing;
} else if (parseDate(date) == null) {
2025-06-05 14:32:12 +02:00
return_obj.get("date")!.status = invalid;
}
if (start == null) {
2025-06-05 14:32:12 +02:00
return_obj.get("start")!.status = missing;
} else if (!isTimeValidHHMM(start)) {
2025-06-05 14:32:12 +02:00
return_obj.get("start")!.status = invalid;
}
if (end == null) {
2025-06-05 14:32:12 +02:00
return_obj.get("end")!.status = missing;
} else if (!isTimeValidHHMM(end)) {
2025-06-05 14:32:12 +02:00
return_obj.get("end")!.status = invalid;
}
2025-06-05 14:32:12 +02:00
if ([...return_obj.values()].some((v) => { return v.status != ok; })) {
return fail(400, { new_entry: return_obj });
}
let res = locals.user.insert_entry(date, start, end, comment);
if (!res) {
return fail(500, { })
}
2025-06-05 14:32:12 +02:00
return { success: true, new_entry: return_obj };
},
edit_entry: async ({locals, request}) => {
2025-06-05 14:32:12 +02:00
if (!locals.user) {
return fail(403, { message: "Unauthorized user" })
}
const ok = "ok";
const missing = "missing";
const invalid = "invalid";
const data = await request.formData();
2025-06-05 14:32:12 +02:00
let id = data.get("id") as string;
let date = data.get("date") as string;
let start = data.get("start") as string;
let end = data.get("end") as string;
let comment = data.get("comment") as string;
2025-06-05 14:32:12 +02:00
let return_obj : Map<string, { status: string, value: string }> = new Map(Object.entries({
id: {
status: ok,
value: id,
},
date : {
status: ok,
value: date
},
start : {
status: ok,
value: start
},
end : {
status: ok,
value: end
},
comment : {
status: ok,
value: comment
},
2025-06-05 14:32:12 +02:00
}))
if (id == null) {
2025-06-05 14:32:12 +02:00
return_obj.get("id")!.status = missing;
} else if (isNaN(toInt(id))) {
2025-06-05 14:32:12 +02:00
return_obj.get("id")!.status = invalid;
}
if (date == null) {
2025-06-05 14:32:12 +02:00
return_obj.get("date")!.status = missing;
} else if (parseDate(date) == null) {
2025-06-05 14:32:12 +02:00
return_obj.get("date")!.status = invalid;
}
if (start == null) {
2025-06-05 14:32:12 +02:00
return_obj.get("start")!.status = missing;
} else if (!isTimeValidHHMM(start)) {
2025-06-05 14:32:12 +02:00
return_obj.get("start")!.status = invalid;
}
if (end == null) {
2025-06-05 14:32:12 +02:00
return_obj.get("end")!.status = missing;
} else if (!isTimeValidHHMM(end)) {
2025-06-05 14:32:12 +02:00
return_obj.get("end")!.status = invalid;
}
2025-06-05 14:32:12 +02:00
if ([...return_obj.values()].some((v) => { return v.status != ok; })) {
return fail(400, { edit_entry: return_obj });
}
2025-06-05 14:32:12 +02:00
let user_id = toInt(id);
2025-03-25 15:25:04 +01:00
2025-06-05 14:32:12 +02:00
let current = locals.user.get_entry(user_id);
if (!current) {
2025-06-05 14:32:12 +02:00
return fail(404, { edit_entry: return_obj });
}
2025-06-05 14:32:12 +02:00
if (current.id == user_id && current.date == date && current.start == start && current.end == end && current.comment == comment) {
return { success: false, edit_entry: return_obj }
}
let res = false;
try {
2025-06-05 14:32:12 +02:00
res = locals.user.update_entry(user_id, date, start, end, comment);
} catch (e) {
if (!(e instanceof SQLiteError)) {
throw e;
}
}
if (!res) {
return fail(500, { })
}
redirect(303, '/');
return { success: true };
},
2025-03-25 15:25:04 +01:00
remove_entry: async ({ locals, request })=> {
2025-06-05 14:32:12 +02:00
if (!locals.user) {
return fail(403, { message: "Unauthorized user" })
}
2025-03-25 15:25:04 +01:00
const data = await request.formData();
2025-06-05 14:32:12 +02:00
let id = data.get("id") as string;
2025-03-25 15:25:04 +01:00
if (id == null) {
return fail(400, { id: id });
}
2025-06-05 14:32:12 +02:00
let user_id = toInt(id);
if (isNaN(user_id)) {
2025-03-25 15:25:04 +01:00
return fail(400, { id: id });
}
let res = false;
try {
2025-06-05 14:32:12 +02:00
res = locals.user.remove_entry(user_id);
2025-03-25 15:25:04 +01:00
} catch (e) {
if (!(e instanceof SQLiteError)) {
throw e;
}
}
if (!res) {
return fail(500, { });
}
return { success: true }
}
} satisfies Actions;