v1.6.5: fix attendance unique constraint, schema sync, seed script
- Change attendance idx_attendance_user_date from unique to index (allow multiple shifts per day) - Reset migrations to single baseline init migration - Add seed script with admin user (admin/admin) - Update CLAUDE.md with migration workflow documentation - Various frontend fixes (queries, pages, hooks) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,12 @@ export default async function tripsRoutes(
|
||||
const query = request.query as Record<string, unknown>;
|
||||
const { page, limit, skip, order } = parsePagination(query);
|
||||
const authData = request.authData!;
|
||||
const isAdmin = authData.permissions.includes("trips.admin");
|
||||
const hasTripsAccess =
|
||||
authData.permissions.includes("trips.manage") ||
|
||||
authData.permissions.includes("trips.record") ||
|
||||
authData.permissions.includes("trips.history");
|
||||
if (!hasTripsAccess) return error(reply, "Nedostatečná oprávnění", 403);
|
||||
const isAdmin = authData.permissions.includes("trips.manage");
|
||||
|
||||
const where: Record<string, unknown> = {};
|
||||
if (!isAdmin) where.user_id = authData.userId;
|
||||
@@ -107,7 +112,7 @@ export default async function tripsRoutes(
|
||||
// GET /api/admin/trips/print — print data for trip report
|
||||
fastify.get(
|
||||
"/print",
|
||||
{ preHandler: requirePermission("trips.admin") },
|
||||
{ preHandler: requirePermission("trips.manage") },
|
||||
async (request, reply) => {
|
||||
const query = request.query as Record<string, unknown>;
|
||||
const filterUserId = query.user_id ? Number(query.user_id) : null;
|
||||
@@ -182,7 +187,7 @@ export default async function tripsRoutes(
|
||||
// Matches PHP: COALESCE(MAX(end_km), vehicle.initial_km, 0)
|
||||
fastify.get<{ Params: { vehicleId: string } }>(
|
||||
"/last-km/:vehicleId",
|
||||
{ preHandler: requirePermission("trips.view") },
|
||||
{ preHandler: requirePermission("trips.manage") },
|
||||
async (request, reply) => {
|
||||
const vehicleId = parseInt(request.params.vehicleId, 10);
|
||||
if (isNaN(vehicleId)) return error(reply, "Neplatné ID vozidla", 400);
|
||||
@@ -213,6 +218,11 @@ export default async function tripsRoutes(
|
||||
const body = parsed.data;
|
||||
const authData = request.authData!;
|
||||
|
||||
const canRecord =
|
||||
authData.permissions.includes("trips.manage") ||
|
||||
authData.permissions.includes("trips.record");
|
||||
if (!canRecord) return error(reply, "Nedostatečná oprávnění", 403);
|
||||
|
||||
if (body.end_km < body.start_km) {
|
||||
return error(reply, "Konečný stav km nesmí být menší než počáteční", 400);
|
||||
}
|
||||
@@ -274,7 +284,7 @@ export default async function tripsRoutes(
|
||||
if (!existing) return error(reply, "Jízda nenalezena", 404);
|
||||
|
||||
// Ownership check — same as DELETE handler
|
||||
const isAdmin = authData.permissions.includes("trips.admin");
|
||||
const isAdmin = authData.permissions.includes("trips.manage");
|
||||
if (existing.user_id !== authData.userId && !isAdmin) {
|
||||
return error(reply, "Nemáte oprávnění upravit tuto jízdu", 403);
|
||||
}
|
||||
@@ -332,7 +342,7 @@ export default async function tripsRoutes(
|
||||
if (!existing) return error(reply, "Jízda nenalezena", 404);
|
||||
|
||||
// Allow users to delete their own trips, admins can delete any
|
||||
const isAdmin = authData.permissions.includes("trips.admin");
|
||||
const isAdmin = authData.permissions.includes("trips.manage");
|
||||
if (existing.user_id !== authData.userId && !isAdmin) {
|
||||
return error(reply, "Nemáte oprávnění smazat tuto jízdu", 403);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user