157 lines
4.8 KiB
TypeScript
157 lines
4.8 KiB
TypeScript
// src/routes/resources/history.ts
|
|
import { FastifyInstance } from "fastify";
|
|
|
|
const columnMap: Record<string, string> = {
|
|
customers: "customer",
|
|
vendors: "vendor",
|
|
projects: "project",
|
|
plants: "plant",
|
|
contracts: "contract",
|
|
contacts: "contact",
|
|
tasks: "task",
|
|
vehicles: "vehicle",
|
|
events: "event",
|
|
files: "file",
|
|
products: "product",
|
|
inventoryitems: "inventoryitem",
|
|
inventoryitemgroups: "inventoryitemgroup",
|
|
absencerequests: "absencerequest",
|
|
checks: "check",
|
|
costcentres: "costcentre",
|
|
ownaccounts: "ownaccount",
|
|
documentboxes: "documentbox",
|
|
hourrates: "hourrate",
|
|
services: "service",
|
|
roles: "role",
|
|
};
|
|
|
|
export default async function resourceHistoryRoutes(server: FastifyInstance) {
|
|
server.get<{
|
|
Params: { resource: string; id: string }
|
|
}>("/resource/:resource/:id/history", {
|
|
schema: {
|
|
tags: ["History"],
|
|
summary: "Get history entries for a resource",
|
|
params: {
|
|
type: "object",
|
|
required: ["resource", "id"],
|
|
properties: {
|
|
resource: { type: "string" },
|
|
id: { type: "string" },
|
|
},
|
|
},
|
|
},
|
|
}, async (req, reply) => {
|
|
const { resource, id } = req.params;
|
|
|
|
const column = columnMap[resource];
|
|
if (!column) {
|
|
return reply.code(400).send({ error: `History not supported for resource '${resource}'` });
|
|
}
|
|
|
|
const { data, error } = await server.supabase
|
|
.from("historyitems")
|
|
.select("*")
|
|
.eq(column, id)
|
|
.order("created_at", { ascending: true });
|
|
|
|
if (error) {
|
|
server.log.error(error);
|
|
return reply.code(500).send({ error: "Failed to fetch history" });
|
|
}
|
|
|
|
const {data:users, error:usersError} = await server.supabase
|
|
.from("auth_users")
|
|
.select("*, auth_profiles(*), tenants!auth_tenant_users(*)")
|
|
|
|
const filteredUsers = (users ||[]).filter(i => i.tenants.find((t:any) => t.id === req.user?.tenant_id))
|
|
|
|
const dataCombined = data.map(historyitem => {
|
|
return {
|
|
...historyitem,
|
|
created_by_profile: filteredUsers.find(i => i.id === historyitem.created_by) ? filteredUsers.find(i => i.id === historyitem.created_by).auth_profiles[0] : null
|
|
}
|
|
})
|
|
|
|
|
|
|
|
return dataCombined;
|
|
});
|
|
|
|
// Neuen HistoryItem anlegen
|
|
server.post<{
|
|
Params: { resource: string; id: string };
|
|
Body: {
|
|
text: string;
|
|
old_val?: string | null;
|
|
new_val?: string | null;
|
|
config?: Record<string, any>;
|
|
};
|
|
}>("/resource/:resource/:id/history", {
|
|
schema: {
|
|
tags: ["History"],
|
|
summary: "Create new history entry",
|
|
params: {
|
|
type: "object",
|
|
properties: {
|
|
resource: { type: "string" },
|
|
id: { type: "string" }
|
|
},
|
|
required: ["resource", "id"]
|
|
},
|
|
body: {
|
|
type: "object",
|
|
properties: {
|
|
text: { type: "string" },
|
|
old_val: { type: "string", nullable: true },
|
|
new_val: { type: "string", nullable: true },
|
|
config: { type: "object", nullable: true }
|
|
},
|
|
required: ["text"]
|
|
},
|
|
response: {
|
|
201: {
|
|
type: "object",
|
|
properties: {
|
|
id: { type: "number" },
|
|
text: { type: "string" },
|
|
created_at: { type: "string" },
|
|
created_by: { type: "string" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}, async (req, reply) => {
|
|
const { resource, id } = req.params;
|
|
const { text, old_val, new_val, config } = req.body;
|
|
|
|
const userId = (req.user as any)?.user_id;
|
|
|
|
|
|
const fkField = columnMap[resource];
|
|
if (!fkField) {
|
|
return reply.code(400).send({ error: `Unknown resource: ${resource}` });
|
|
}
|
|
|
|
const { data, error } = await server.supabase
|
|
.from("historyitems")
|
|
.insert({
|
|
text,
|
|
[fkField]: id,
|
|
oldVal: old_val || null,
|
|
newVal: new_val || null,
|
|
config: config || null,
|
|
tenant: (req.user as any)?.tenant_id,
|
|
created_by: userId
|
|
})
|
|
.select()
|
|
.single();
|
|
|
|
if (error) {
|
|
return reply.code(500).send({ error: error.message });
|
|
}
|
|
|
|
return reply.code(201).send(data);
|
|
});
|
|
}
|