Replace all async reads and writes to the JSON database with the sync reads and writes to prevent a data corruption race condition where two requests are processed at the same time and write to the same file, or one reads while the other writes causing read of partially written data.
77 lines
2.1 KiB
TypeScript
77 lines
2.1 KiB
TypeScript
/*
|
|
SPDX-FileCopyrightText: © 2025 Hornwitser <code@hornwitser.no>
|
|
SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*/
|
|
import { readUsers, writeUsers } from "~/server/database";
|
|
import { DateTime, Info } from "~/shared/utils/luxon";
|
|
import { apiAccountPatchSchema } from "~/shared/types/api";
|
|
import { z } from "zod/v4-mini";
|
|
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
const session = await requireServerSessionWithUser(event);
|
|
const { success, error, data: patch } = apiAccountPatchSchema.safeParse(await readBody(event));
|
|
if (!success) {
|
|
throw createError({
|
|
status: 400,
|
|
statusText: "Bad Request",
|
|
message: z.prettifyError(error),
|
|
});
|
|
}
|
|
|
|
if (patch.timezone?.length) {
|
|
const zone = Info.normalizeZone(patch.timezone);
|
|
if (!zone.isValid) {
|
|
throw createError({
|
|
status: 400,
|
|
message: `Invalid timezone: the zone "${patch.timezone} is not supported`,
|
|
});
|
|
}
|
|
}
|
|
if (patch.locale?.length) {
|
|
const locale = DateTime.local({ locale: patch.locale }).resolvedLocaleOptions().locale;
|
|
if (locale !== patch.locale) {
|
|
throw createError({
|
|
status: 400,
|
|
message: `Invalid locale: the locale "${patch.locale}" is not supported (was treated as "${locale}")`
|
|
});
|
|
}
|
|
}
|
|
|
|
const users = readUsers();
|
|
const account = users.find(user => user.id === session.accountId);
|
|
if (!account) {
|
|
throw Error("Account does not exist");
|
|
}
|
|
|
|
if (patch.interestedEventIds !== undefined) {
|
|
if (patch.interestedEventIds.length) {
|
|
account.interestedEventIds = patch.interestedEventIds;
|
|
} else {
|
|
delete account.interestedEventIds;
|
|
}
|
|
}
|
|
if (patch.interestedEventSlotIds !== undefined) {
|
|
if (patch.interestedEventSlotIds.length) {
|
|
account.interestedEventSlotIds = patch.interestedEventSlotIds;
|
|
} else {
|
|
delete account.interestedEventSlotIds;
|
|
}
|
|
}
|
|
if (patch.timezone !== undefined) {
|
|
if (patch.timezone)
|
|
account.timezone = patch.timezone;
|
|
else
|
|
delete account.timezone;
|
|
}
|
|
if (patch.locale !== undefined) {
|
|
if (patch.locale)
|
|
account.locale = patch.locale;
|
|
else
|
|
delete account.locale;
|
|
}
|
|
writeUsers(users);
|
|
|
|
// Update Schedule counts.
|
|
await updateScheduleInterestedCounts(users);
|
|
})
|