Files
FEDEO/backend/src/routes/auth/user.ts
flfeders 4ffafef3f1
All checks were successful
Build and Release FEDEO / verify (push) Successful in 1m5s
Build and Release FEDEO / build-and-release (push) Successful in 6m53s
feat(admin): archive users and their profiles permanently
2026-10-15 14:22:12 +02:00

133 lines
4.6 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { FastifyInstance } from "fastify"
import { eq, and, isNull } from "drizzle-orm"
import {
authUsers,
authProfiles,
} from "../../../db/schema"
export default async function userRoutes(server: FastifyInstance) {
// -------------------------------------------------------------
// GET /user/:id
// -------------------------------------------------------------
server.get("/user/:id", async (req, reply) => {
try {
const authUser = req.user
const { id } = req.params as { id: string }
if (!authUser) {
return reply.code(401).send({ error: "Unauthorized" })
}
// 1️⃣ User laden
const [user] = await server.db
.select({
id: authUsers.id,
email: authUsers.email,
created_at: authUsers.created_at,
must_change_password: authUsers.must_change_password,
})
.from(authUsers)
.where(eq(authUsers.id, id))
if (!user) {
return reply.code(404).send({ error: "User not found" })
}
// 2️⃣ Profil im Tenant
let profile = null
if (authUser.tenant_id) {
const [profileRow] = await server.db
.select()
.from(authProfiles)
.where(
and(
eq(authProfiles.user_id, id),
eq(authProfiles.tenant_id, authUser.tenant_id)
)
)
profile = profileRow || null
}
return { user, profile }
} catch (err: any) {
console.error("/user/:id ERROR", err)
return reply.code(500).send({ error: err.message || "Internal error" })
}
})
// -------------------------------------------------------------
// PUT /user/:id/profile
// -------------------------------------------------------------
server.put("/user/:id/profile", async (req, reply) => {
try {
const { id } = req.params as { id: string }
const { data } = req.body as { data?: Record<string, any> }
if (!req.user?.tenant_id) {
return reply.code(401).send({ error: "Unauthorized" })
}
if (!data || typeof data !== "object") {
return reply.code(400).send({ error: "data object required" })
}
// 1️⃣ Profil für diesen Tenant laden (damit wir die ID kennen)
const [profile] = await server.db
.select()
.from(authProfiles)
.where(
and(
eq(authProfiles.user_id, id),
eq(authProfiles.tenant_id, req.user.tenant_id),
isNull(authProfiles.archived_at)
)
)
if (!profile) {
return reply.code(404).send({ error: "Profile not found in tenant" })
}
// 2️⃣ Timestamp-Felder normalisieren (falls welche drin sind)
const normalizeDate = (val: any) => {
if (!val) return null
const d = new Date(val)
return isNaN(d.getTime()) ? null : d
}
const updateData: any = { ...data }
for (const key of ["archived_at", "user_id", "tenant_id", "id"]) delete updateData[key]
// bekannte Date-Felder prüfen
if (data.entry_date !== undefined)
updateData.entry_date = normalizeDate(data.entry_date)
if (data.birthday !== undefined)
updateData.birthday = normalizeDate(data.birthday)
if (data.created_at !== undefined)
updateData.created_at = normalizeDate(data.created_at)
updateData.updated_at = new Date()
// 3️⃣ Update durchführen
const [updatedProfile] = await server.db
.update(authProfiles)
.set(updateData)
.where(and(eq(authProfiles.id, profile.id), isNull(authProfiles.archived_at)))
.returning()
if (!updatedProfile) return reply.code(404).send({ error: "Profile not found in tenant" })
return { profile: updatedProfile }
} catch (err: any) {
console.error("PUT /user/:id/profile ERROR", err)
return reply.code(500).send({ error: err.message || "Internal server error" })
}
})
}