courrier
This commit is contained in:
parent
26ec4864cf
commit
692c72481f
@ -7,7 +7,7 @@
|
|||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"sync-users": "ts-node --transpile-only scripts/sync-users.ts"
|
"sync-users": "node scripts/sync-users.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "^3.802.0",
|
"@aws-sdk/client-s3": "^3.802.0",
|
||||||
|
|||||||
123
scripts/sync-users.js
Normal file
123
scripts/sync-users.js
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
const { PrismaClient } = require('@prisma/client');
|
||||||
|
const bcrypt = require('bcryptjs');
|
||||||
|
require('dotenv').config();
|
||||||
|
|
||||||
|
const prisma = new PrismaClient();
|
||||||
|
|
||||||
|
async function syncUsers() {
|
||||||
|
try {
|
||||||
|
console.log('Starting user sync process...');
|
||||||
|
|
||||||
|
// Use your existing /api/users endpoint to get users from Keycloak
|
||||||
|
// This endpoint already exists in your codebase and handles all the Keycloak auth
|
||||||
|
const apiUrl = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000';
|
||||||
|
console.log(`Fetching users from: ${apiUrl}/api/users`);
|
||||||
|
|
||||||
|
// Get client credentials token for authentication
|
||||||
|
const tokenResponse = await fetch(
|
||||||
|
`${process.env.KEYCLOAK_BASE_URL}/realms/${process.env.KEYCLOAK_REALM}/protocol/openid-connect/token`,
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
},
|
||||||
|
body: new URLSearchParams({
|
||||||
|
grant_type: 'client_credentials',
|
||||||
|
client_id: process.env.KEYCLOAK_CLIENT_ID,
|
||||||
|
client_secret: process.env.KEYCLOAK_CLIENT_SECRET,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const tokenData = await tokenResponse.json();
|
||||||
|
if (!tokenResponse.ok) {
|
||||||
|
throw new Error(`Failed to get token: ${JSON.stringify(tokenData)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Token obtained successfully");
|
||||||
|
|
||||||
|
// Now fetch users from Keycloak
|
||||||
|
const usersResponse = await fetch(
|
||||||
|
`${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users?briefRepresentation=false`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${tokenData.access_token}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!usersResponse.ok) {
|
||||||
|
throw new Error(`Failed to fetch users: ${usersResponse.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const users = await usersResponse.json();
|
||||||
|
|
||||||
|
// Filter out service accounts and users from other realms
|
||||||
|
const filteredUsers = users.filter((user) =>
|
||||||
|
!user.serviceAccountClientId && // Remove service accounts
|
||||||
|
(!user.realm || user.realm === process.env.KEYCLOAK_REALM) // Only users from our realm
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(`Fetched ${filteredUsers.length} users from Keycloak API`);
|
||||||
|
|
||||||
|
const results = {
|
||||||
|
total: filteredUsers.length,
|
||||||
|
created: 0,
|
||||||
|
updated: 0,
|
||||||
|
failed: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Process each user from Keycloak
|
||||||
|
for (const user of filteredUsers) {
|
||||||
|
try {
|
||||||
|
// Check if the keycloak ID exists in our database
|
||||||
|
const existingUser = await prisma.user.findUnique({
|
||||||
|
where: { id: user.id },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (existingUser) {
|
||||||
|
// Update existing user
|
||||||
|
await prisma.user.update({
|
||||||
|
where: { id: user.id },
|
||||||
|
data: {
|
||||||
|
email: user.email,
|
||||||
|
// Don't update password as it might be locally changed
|
||||||
|
updatedAt: new Date(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
console.log(`Updated user: ${user.id} (${user.email})`);
|
||||||
|
results.updated++;
|
||||||
|
} else {
|
||||||
|
// Create new user
|
||||||
|
// Generate a temporary random password
|
||||||
|
const tempPassword = await bcrypt.hash(Math.random().toString(36).slice(-10), 10);
|
||||||
|
|
||||||
|
await prisma.user.create({
|
||||||
|
data: {
|
||||||
|
id: user.id, // Use the keycloak ID as our primary ID
|
||||||
|
email: user.email,
|
||||||
|
password: tempPassword,
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
console.log(`Created new user: ${user.id} (${user.email})`);
|
||||||
|
results.created++;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error processing user ${user.id}:`, error);
|
||||||
|
results.failed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Sync completed. Results:', results);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error syncing users:', error);
|
||||||
|
} finally {
|
||||||
|
await prisma.$disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the sync function
|
||||||
|
syncUsers();
|
||||||
@ -1,5 +1,6 @@
|
|||||||
import { PrismaClient } from '@prisma/client';
|
const { PrismaClient } = require('@prisma/client');
|
||||||
import bcrypt from 'bcryptjs';
|
const bcrypt = require('bcryptjs');
|
||||||
|
require('dotenv').config();
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
const prisma = new PrismaClient();
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"target": "es2017",
|
||||||
|
"module": "commonjs",
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"target": "ES2024",
|
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"module": "ESNext",
|
"moduleResolution": "node",
|
||||||
"moduleResolution": "bundler",
|
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
"incremental": true,
|
"incremental": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
|
||||||
"plugins": [
|
"plugins": [
|
||||||
{
|
{
|
||||||
"name": "next"
|
"name": "next"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user