add script update org and sync keycloak, setup time run cronjob
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m26s
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m26s
This commit is contained in:
parent
911d9b6bc5
commit
b714dfe239
7 changed files with 1694 additions and 15 deletions
|
|
@ -832,3 +832,142 @@ export async function resetPassword(username: string) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateUserAttributes(
|
||||
userId: string,
|
||||
attributes: Record<string, string[]>,
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
// Get existing user data to preserve other attributes
|
||||
const existingUser = await getUser(userId);
|
||||
|
||||
if (!existingUser) {
|
||||
console.error(`User ${userId} not found in Keycloak`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Merge existing attributes with new attributes
|
||||
// IMPORTANT: Spread all existing user fields to preserve firstName, lastName, email, etc.
|
||||
// The Keycloak PUT endpoint performs a full update, so we must include all fields
|
||||
const updatedAttributes = {
|
||||
...existingUser,
|
||||
attributes: {
|
||||
...(existingUser.attributes || {}),
|
||||
...attributes,
|
||||
},
|
||||
};
|
||||
|
||||
console.log(
|
||||
`[updateUserAttributes] Sending to Keycloak:`,
|
||||
JSON.stringify(updatedAttributes, null, 2),
|
||||
);
|
||||
|
||||
const res = await fetch(`${KC_URL}/admin/realms/${KC_REALMS}/users/${userId}`, {
|
||||
headers: {
|
||||
authorization: `Bearer ${await getToken()}`,
|
||||
"content-type": "application/json",
|
||||
},
|
||||
method: "PUT",
|
||||
body: JSON.stringify(updatedAttributes),
|
||||
}).catch((e) => {
|
||||
console.error(`[updateUserAttributes] Network error:`, e);
|
||||
return null;
|
||||
});
|
||||
|
||||
if (!res) {
|
||||
console.error(`[updateUserAttributes] No response from Keycloak`);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!res.ok) {
|
||||
const errorText = await res.text();
|
||||
console.error(`[updateUserAttributes] Keycloak Error (${res.status}):`, errorText);
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log(`[updateUserAttributes] Successfully updated attributes for user ${userId}`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(`[updateUserAttributes] Error updating attributes for user ${userId}:`, error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getAllUsersPaginated(
|
||||
search: string = "",
|
||||
batchSize: number = 100,
|
||||
): Promise<
|
||||
| Array<{
|
||||
id: string;
|
||||
username: string;
|
||||
firstName?: string;
|
||||
lastName?: string;
|
||||
email?: string;
|
||||
enabled: boolean;
|
||||
}>
|
||||
| false
|
||||
> {
|
||||
const allUsers: any[] = [];
|
||||
let first = 0;
|
||||
let hasMore = true;
|
||||
|
||||
while (hasMore) {
|
||||
const res = await fetch(
|
||||
`${KC_URL}/admin/realms/${KC_REALMS}/users?first=${first}&max=${batchSize}${search ? `&search=${search}` : ""}`,
|
||||
{
|
||||
headers: {
|
||||
authorization: `Bearer ${await getToken()}`,
|
||||
"content-type": `application/json`,
|
||||
},
|
||||
},
|
||||
).catch((e) => console.log("Keycloak Error: ", e));
|
||||
|
||||
if (!res) return false;
|
||||
if (!res.ok) {
|
||||
const errorText = await res.text();
|
||||
console.error("Keycloak Error Response: ", errorText);
|
||||
return false;
|
||||
}
|
||||
|
||||
const rawText = await res.text();
|
||||
|
||||
try {
|
||||
const batch = JSON.parse(rawText) as any[];
|
||||
|
||||
if (batch.length === 0) {
|
||||
hasMore = false;
|
||||
} else {
|
||||
allUsers.push(...batch);
|
||||
first += batch.length;
|
||||
hasMore = batch.length === batchSize;
|
||||
|
||||
// Log progress for large datasets
|
||||
if (allUsers.length % 500 === 0) {
|
||||
console.log(`[getAllUsersPaginated] Fetched ${allUsers.length} users so far...`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[getAllUsersPaginated] Failed to parse JSON response at offset ${first}:`);
|
||||
console.error(
|
||||
`[getAllUsersPaginated] Response preview (first 500 chars):`,
|
||||
rawText.substring(0, 500),
|
||||
);
|
||||
console.error(
|
||||
`[getAllUsersPaginated] Response preview (last 200 chars):`,
|
||||
rawText.slice(-200),
|
||||
);
|
||||
throw new Error(`Failed to parse Keycloak response as JSON at batch starting at ${first}.`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`[getAllUsersPaginated] Total users fetched: ${allUsers.length}`);
|
||||
|
||||
return allUsers.map((v: any) => ({
|
||||
id: v.id,
|
||||
username: v.username,
|
||||
firstName: v.firstName,
|
||||
lastName: v.lastName,
|
||||
email: v.email,
|
||||
enabled: v.enabled === true || v.enabled === "true",
|
||||
}));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue