add user leantime api

This commit is contained in:
Alma 2025-04-10 20:19:28 +02:00
parent 9a51d8cd88
commit dc0021dc91
2 changed files with 404 additions and 1 deletions

View File

@ -200,6 +200,57 @@ function validateUsername(username: string): { isValid: boolean; error?: string
return { isValid: true }; return { isValid: true };
} }
// Helper function to create user in Leantime
async function createLeantimeUser(userData: {
username: string;
firstName: string;
lastName: string;
email: string;
}): Promise<{ success: boolean; error?: string }> {
try {
const response = await fetch('https://agilite.slm-lab.net/api/jsonrpc', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.LEANTIME_TOKEN}`,
},
body: JSON.stringify({
method: 'leantime.rpc.Users.Users.addUser',
jsonrpc: '2.0',
id: 1,
params: {
values: {
firstname: userData.firstName,
lastname: userData.lastName,
username: userData.username,
email: userData.email,
status: 'active',
role: 'user', // Default role in Leantime
}
}
})
});
const data = await response.json();
if (!response.ok || !data.result) {
console.error('Leantime user creation failed:', data);
return {
success: false,
error: 'Failed to create user in Leantime'
};
}
return { success: true };
} catch (error) {
console.error('Error creating Leantime user:', error);
return {
success: false,
error: 'Error creating user in Leantime'
};
}
}
export async function POST(req: Request) { export async function POST(req: Request) {
const session = await getServerSession(authOptions); const session = await getServerSession(authOptions);
@ -257,7 +308,7 @@ export async function POST(req: Request) {
); );
} }
// Create the user // Create the user in Keycloak
const createResponse = await fetch( const createResponse = await fetch(
`${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users`, `${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users`,
{ {
@ -356,6 +407,20 @@ export async function POST(req: Request) {
); );
} }
// Create user in Leantime
const leantimeResult = await createLeantimeUser({
username: data.username,
firstName: data.firstName,
lastName: data.lastName,
email: data.email,
});
if (!leantimeResult.success) {
console.error("Leantime user creation failed:", leantimeResult.error);
// We don't return an error here since Keycloak user was created successfully
// We just log the error and continue
}
return NextResponse.json({ return NextResponse.json({
success: true, success: true,
user: { user: {

View File

@ -0,0 +1,338 @@
{
"name": "Keycloak User Creation",
"nodes": [
{
"parameters": {
"path": "create-user",
"options": {
"responseMode": "lastNode",
"responseData": "allEntries"
}
},
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [
100,
300
],
"webhookId": "create-user-webhook"
},
{
"parameters": {
"url": "https://connect.slm-lab.net/admin/realms/cercle/users",
"options": {},
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"nodeCredentialType": "httpHeaderAuth",
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "={{$node[\"Get Admin Token\"].json[\"access_token\"]}}"
}
]
}
},
"name": "HTTP Request",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
500,
300
]
},
{
"parameters": {
"url": "https://connect.slm-lab.net/realms/cercle/protocol/openid-connect/token",
"options": {},
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"nodeCredentialType": "httpHeaderAuth",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/x-www-form-urlencoded"
}
]
},
"bodyParameters": {
"parameters": [
{
"name": "grant_type",
"value": "client_credentials"
},
{
"name": "client_id",
"value": "lab"
},
{
"name": "client_secret",
"value": "LwgeE1ntADD20OuWC88S3pR0EaO7FtO4"
}
]
}
},
"name": "Get Admin Token",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
300,
300
]
},
{
"parameters": {
"conditions": {
"string": [
{
"value1": "={{$json[\"isValid\"]}}",
"value2": "false"
}
]
}
},
"name": "IF",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
300,
500
]
},
{
"parameters": {
"functionCode": "// Validate username according to Keycloak requirements\nconst username = $input.item.json.username;\n\n// Keycloak username requirements:\n// - Only alphanumeric characters, dots (.), hyphens (-), and underscores (_)\n// - Must start with a letter or number\n// - Must be between 3 and 255 characters\nconst usernameRegex = /^[a-zA-Z0-9][a-zA-Z0-9._-]{2,254}$/;\n\nif (!usernameRegex.test(username)) {\n return {\n isValid: false,\n error: \"Le nom d'utilisateur doit commencer par une lettre ou un chiffre, ne contenir que des lettres, chiffres, points, tirets et underscores, et faire entre 3 et 255 caractères\"\n };\n}\n\nreturn { isValid: true };"
},
"name": "Validate Username",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
300,
400
]
},
{
"parameters": {
"url": "https://connect.slm-lab.net/admin/realms/cercle/roles",
"options": {}
},
"name": "Get Available Roles",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
500,
400
]
},
{
"parameters": {
"functionCode": "// Filter valid roles\nconst requestedRoles = $input.item.json.roles || [];\nconst availableRoles = $input.item.json.roles;\n\nconst validRoles = requestedRoles.filter(roleName => \n availableRoles.some(r => r.name === roleName)\n);\n\nif (validRoles.length === 0) {\n return {\n isValid: false,\n error: \"Aucun rôle valide n'a été spécifié\"\n };\n}\n\nreturn {\n isValid: true,\n validRoles: validRoles,\n roleObjects: validRoles.map(roleName => \n availableRoles.find(r => r.name === roleName)\n )\n};"
},
"name": "Validate Roles",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
700,
400
]
},
{
"parameters": {
"url": "https://connect.slm-lab.net/admin/realms/cercle/users",
"options": {},
"body": {
"username": "={{$input.item.json.username}}",
"enabled": true,
"emailVerified": true,
"firstName": "={{$input.item.json.firstName}}",
"lastName": "={{$input.item.json.lastName}}",
"email": "={{$input.item.json.email}}",
"credentials": [
{
"type": "password",
"value": "={{$input.item.json.password}}",
"temporary": false
}
]
}
},
"name": "Create User",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
900,
400
]
},
{
"parameters": {
"url": "https://connect.slm-lab.net/admin/realms/cercle/users?username={{$input.item.json.username}}",
"options": {}
},
"name": "Get Created User",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
1100,
400
]
},
{
"parameters": {
"url": "https://connect.slm-lab.net/admin/realms/cercle/users/{{$input.item.json[0].id}}/role-mappings/realm",
"options": {},
"body": "={{$input.item.json.roleObjects}}"
},
"name": "Assign Roles",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
1300,
400
]
},
{
"parameters": {
"functionCode": "// Format success response\nreturn {\n success: true,\n user: {\n ...$input.item.json[0],\n roles: $input.item.json.validRoles\n }\n};"
},
"name": "Format Response",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
1500,
400
]
},
{
"parameters": {
"functionCode": "// Format error response\nreturn {\n success: false,\n error: $input.item.json.error\n};"
},
"name": "Format Error",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
500,
600
]
}
],
"connections": {
"Webhook": {
"main": [
[
{
"node": "Get Admin Token",
"type": "main",
"index": 0
}
]
]
},
"Get Admin Token": {
"main": [
[
{
"node": "HTTP Request",
"type": "main",
"index": 0
},
{
"node": "Validate Username",
"type": "main",
"index": 0
}
]
]
},
"Validate Username": {
"main": [
[
{
"node": "IF",
"type": "main",
"index": 0
}
]
]
},
"IF": {
"main": [
[
{
"node": "Format Error",
"type": "main",
"index": 0
}
],
[
{
"node": "Get Available Roles",
"type": "main",
"index": 0
}
]
]
},
"Get Available Roles": {
"main": [
[
{
"node": "Validate Roles",
"type": "main",
"index": 0
}
]
]
},
"Validate Roles": {
"main": [
[
{
"node": "Create User",
"type": "main",
"index": 0
}
]
]
},
"Create User": {
"main": [
[
{
"node": "Get Created User",
"type": "main",
"index": 0
}
]
]
},
"Get Created User": {
"main": [
[
{
"node": "Assign Roles",
"type": "main",
"index": 0
}
]
]
},
"Assign Roles": {
"main": [
[
{
"node": "Format Response",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"version": 1
}