Benutzeranlage direkt aus Mitarbeiterprofil ermöglichen
This commit is contained in:
@@ -451,6 +451,116 @@ export default async function adminRoutes(server: FastifyInstance) {
|
||||
}
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// POST /admin/profiles/:profileId/create-user
|
||||
// -------------------------------------------------------------
|
||||
server.post("/admin/profiles/:profileId/create-user", async (req, reply) => {
|
||||
try {
|
||||
const currentUser = await requireAdmin(req, reply);
|
||||
if (!currentUser) return;
|
||||
|
||||
const { profileId } = req.params as { profileId: string };
|
||||
const body = req.body as { email?: string };
|
||||
|
||||
const email = body.email?.trim().toLowerCase();
|
||||
if (!email) {
|
||||
return reply.code(400).send({ error: "email required" });
|
||||
}
|
||||
|
||||
const [profile] = await server.db
|
||||
.select({
|
||||
id: authProfiles.id,
|
||||
tenant_id: authProfiles.tenant_id,
|
||||
user_id: authProfiles.user_id,
|
||||
first_name: authProfiles.first_name,
|
||||
last_name: authProfiles.last_name,
|
||||
email: authProfiles.email,
|
||||
})
|
||||
.from(authProfiles)
|
||||
.where(eq(authProfiles.id, profileId))
|
||||
.limit(1);
|
||||
|
||||
if (!profile) {
|
||||
return reply.code(404).send({ error: "Profile not found" });
|
||||
}
|
||||
|
||||
if (profile.user_id) {
|
||||
return reply.code(409).send({ error: "Profile already linked to a user" });
|
||||
}
|
||||
|
||||
const existingUsers = await server.db
|
||||
.select({ id: authUsers.id })
|
||||
.from(authUsers)
|
||||
.where(eq(authUsers.email, email))
|
||||
.limit(1);
|
||||
|
||||
if (existingUsers.length) {
|
||||
return reply.code(409).send({ error: "User with this email already exists" });
|
||||
}
|
||||
|
||||
const initialPassword = generateRandomPassword(14);
|
||||
const passwordHash = await hashPassword(initialPassword);
|
||||
|
||||
const result = await server.db.transaction(async (tx) => {
|
||||
const [createdUser] = await tx
|
||||
.insert(authUsers)
|
||||
.values({
|
||||
email,
|
||||
passwordHash,
|
||||
is_admin: false,
|
||||
multiTenant: true,
|
||||
must_change_password: true,
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
.returning({
|
||||
id: authUsers.id,
|
||||
email: authUsers.email,
|
||||
must_change_password: authUsers.must_change_password,
|
||||
is_admin: authUsers.is_admin,
|
||||
multiTenant: authUsers.multiTenant,
|
||||
created_at: authUsers.created_at,
|
||||
});
|
||||
|
||||
await tx
|
||||
.insert(authTenantUsers)
|
||||
.values({
|
||||
tenant_id: profile.tenant_id,
|
||||
user_id: createdUser.id,
|
||||
created_by: currentUser.id,
|
||||
});
|
||||
|
||||
const [updatedProfile] = await tx
|
||||
.update(authProfiles)
|
||||
.set({
|
||||
user_id: createdUser.id,
|
||||
email,
|
||||
})
|
||||
.where(eq(authProfiles.id, profile.id))
|
||||
.returning({
|
||||
id: authProfiles.id,
|
||||
tenant_id: authProfiles.tenant_id,
|
||||
user_id: authProfiles.user_id,
|
||||
first_name: authProfiles.first_name,
|
||||
last_name: authProfiles.last_name,
|
||||
email: authProfiles.email,
|
||||
});
|
||||
|
||||
return {
|
||||
user: createdUser,
|
||||
profile: updatedProfile,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
...result,
|
||||
initialPassword,
|
||||
};
|
||||
} catch (err) {
|
||||
console.error("ERROR /admin/profiles/:profileId/create-user:", err);
|
||||
return reply.code(500).send({ error: "Internal Server Error" });
|
||||
}
|
||||
});
|
||||
|
||||
server.post("/admin/customers/:customerId/invite-portal-user", async (req, reply) => {
|
||||
try {
|
||||
const currentUser = await requireAdmin(req, reply);
|
||||
|
||||
Reference in New Issue
Block a user