missions api2

This commit is contained in:
alma 2025-05-06 18:46:06 +02:00
parent 95efd51e30
commit 8cc401f09a

View File

@ -64,98 +64,17 @@ export class LeantimeService {
console.log('Creating project with data:', JSON.stringify(projectData, null, 2));
// Create with direct call to createProject
const createResponse = await axios.post(
this.getApiEndpoint(),
{
method: 'leantime.rpc.Projects.createProject',
jsonrpc: '2.0',
id: 1,
params: projectData
},
{
headers: {
'Content-Type': 'application/json',
'X-API-Key': this.apiToken
}
}
);
// Log the response
console.log('Create response status:', createResponse.status);
console.log('Create response data:', JSON.stringify(createResponse.data, null, 2));
if (createResponse.data && createResponse.data.result) {
const projectId = createResponse.data.result;
console.log(`Created Leantime project with ID: ${projectId}`);
// If the mission has a logo, set it as project avatar
if (mission.logo) {
await this.setProjectAvatar(projectId, mission.logo);
}
try {
// Wait a bit before attempting to add any users to avoid rate limits
await new Promise(resolve => setTimeout(resolve, 3000));
// Check if we can make at least one API call without hitting rate limits
const testResponse = await axios.post(
this.getApiEndpoint(),
{
method: 'leantime.rpc.Auth.getCurrentUser',
jsonrpc: '2.0',
id: 1
},
{
headers: {
'Content-Type': 'application/json',
'X-API-Key': this.apiToken
}
}
);
// If test API call succeeds, try to assign users
if (mission.missionUsers && mission.missionUsers.length > 0) {
await this.assignUsersToProject(projectId, mission.missionUsers);
}
} catch (apiError) {
// If we hit rate limits on the test call, skip user assignment completely
if (axios.isAxiosError(apiError) && apiError.response?.status === 429) {
console.log('⚠️ Rate limiting detected. Skipping all user assignments.');
console.log(`⚠️ Users will need to be added manually at: ${this.getProjectUrl(projectId)}`);
} else {
// Try to assign users anyway for other types of errors
if (mission.missionUsers && mission.missionUsers.length > 0) {
await this.assignUsersToProject(projectId, mission.missionUsers);
}
}
}
return projectId;
}
// Fall back to addProject if createProject fails
console.log('createProject failed, trying addProject...');
// Based on the error message, Leantime expects a nested 'values' parameter
// Use only the method that we know works
const payload = {
method: 'leantime.rpc.Projects.Projects.addProject',
jsonrpc: '2.0',
id: 1,
params: {
values: {
name: mission.name,
clientId: clientId,
details: mission.intention || '',
type: 'project',
start: formattedStartDate,
end: formattedEndDate,
status: 'open',
psettings: 'restricted'
}
values: projectData
}
};
console.log('addProject payload:', JSON.stringify(payload, null, 2));
console.log('Project creation payload:', JSON.stringify(payload, null, 2));
const response = await axios.post(
this.getApiEndpoint(),
@ -168,14 +87,14 @@ export class LeantimeService {
}
);
console.log('addProject response status:', response.status);
console.log('addProject response data:', JSON.stringify(response.data, null, 2));
console.log('Project creation response status:', response.status);
console.log('Project creation response data:', JSON.stringify(response.data, null, 2));
if (!response.data || !response.data.result) {
throw new Error(`Failed to create Leantime project: ${JSON.stringify(response.data)}`);
}
const projectId = response.data.result;
const projectId = response.data.result[0]; // We need the first element in the array
console.log(`Created Leantime project with ID: ${projectId}`);
// If the mission has a logo, set it as project avatar
@ -183,40 +102,13 @@ export class LeantimeService {
await this.setProjectAvatar(projectId, mission.logo);
}
try {
// Wait a bit before attempting to add any users to avoid rate limits
await new Promise(resolve => setTimeout(resolve, 3000));
// Check if we can make at least one API call without hitting rate limits
const testResponse = await axios.post(
this.getApiEndpoint(),
{
method: 'leantime.rpc.Auth.getCurrentUser',
jsonrpc: '2.0',
id: 1
},
{
headers: {
'Content-Type': 'application/json',
'X-API-Key': this.apiToken
}
}
);
// If test API call succeeds, try to assign users
if (mission.missionUsers && mission.missionUsers.length > 0) {
await this.assignUsersToProject(projectId, mission.missionUsers);
}
} catch (apiError) {
// If we hit rate limits on the test call, skip user assignment completely
if (axios.isAxiosError(apiError) && apiError.response?.status === 429) {
console.log('⚠️ Rate limiting detected. Skipping all user assignments.');
console.log(`⚠️ Users will need to be added manually at: ${this.getProjectUrl(projectId)}`);
} else {
// Try to assign users anyway for other types of errors
if (mission.missionUsers && mission.missionUsers.length > 0) {
await this.assignUsersToProject(projectId, mission.missionUsers);
}
}
// Check if mission has users to assign
if (mission.missionUsers && mission.missionUsers.length > 0) {
await this.assignUsersToProject(projectId, mission.missionUsers);
} else {
// No users to assign
const projectUrl = this.getProjectUrl(projectId);
console.log(` No users to assign. Project created at: ${projectUrl}`);
}
return projectId;
@ -332,112 +224,12 @@ export class LeantimeService {
* @param missionUsers The mission users with roles
*/
async assignUsersToProject(projectId: number, missionUsers: any[]): Promise<void> {
console.log(`Attempting to add ${missionUsers.length} users to project ${projectId}`);
const projectUrl = this.getProjectUrl(projectId);
console.log(`⚠️ For best results, please assign users manually at: ${projectUrl}`);
console.log(' Automatic user assignment is currently disabled due to API limitations.');
// Create a direct URL to the project that can be shared with users
const baseUrl = this.apiUrl
.replace('/api/jsonrpc', '')
.replace('/api/jsonrpc.php', '');
const projectUrl = baseUrl.endsWith('/')
? `${baseUrl}projects/showProject/${projectId}`
: `${baseUrl}/projects/showProject/${projectId}`;
console.log(`🔗 Project created successfully. Direct project URL: ${projectUrl}`);
if (!missionUsers || missionUsers.length === 0) {
console.log('No users to assign to the project.');
// Ensure at least the API user is assigned to prevent "Current team member is New API Access" issue
console.log('Ensuring API user is assigned to the project to prevent orphaned projects.');
// Wait a bit longer before API user request to avoid rate limiting
await new Promise(resolve => setTimeout(resolve, 5000));
const apiUserId = await this.getApiUserId();
if (apiUserId) {
try {
const apiAssigned = await this.assignApiUserToProject(projectId, apiUserId);
if (apiAssigned) {
console.log('API user successfully assigned to project as admin.');
}
} catch (apiUserError) {
console.error('Error assigning API user to project:', apiUserError);
}
}
return;
}
// Users will need to be added manually if the automatic assignment fails
console.log('Attempting to assign users to the project - if this fails, users can be added manually through the Leantime interface.');
try {
let successCount = 0;
let errorCount = 0;
// First try to assign just one user (the first one) to reduce API calls and avoid rate limits
const firstUser = missionUsers[0];
try {
const leantimeUserId = await this.getUserByEmail(firstUser.user.email);
if (leantimeUserId) {
const role = firstUser.role === 'gardien-temps' ? 'editor' : 'commenter';
const success = await this.assignUserToProject(projectId, leantimeUserId, role);
if (success) {
successCount++;
console.log(`✅ Successfully assigned user ${firstUser.user.email} to project ${projectId}`);
}
}
} catch (error) {
console.error(`Error assigning first user: ${error}`);
}
// Skip other users if we got at least one successful assignment
if (successCount > 0) {
console.log(`Successfully assigned ${successCount} user to project. Skipping other users to avoid rate limits.`);
console.log(`⚠️ Other users will need to be added manually at: ${projectUrl}`);
errorCount = missionUsers.length - successCount;
} else {
// If first user failed, try API user assignment
console.log('No regular users successfully assigned. Adding API user as a fallback.');
// Wait a bit longer before API user request to avoid rate limiting
await new Promise(resolve => setTimeout(resolve, 5000));
const apiUserId = await this.getApiUserId();
if (apiUserId) {
try {
const apiAssigned = await this.assignApiUserToProject(projectId, apiUserId);
if (apiAssigned) {
successCount++;
console.log('✅ API user successfully assigned to project as admin.');
}
} catch (apiUserError) {
console.error('Error assigning API user to project:', apiUserError);
}
}
errorCount = missionUsers.length;
}
console.log(`User assignment complete: ${successCount} successful, ${errorCount} failed.`);
if (errorCount > 0) {
console.log(`⚠️ Some users could not be assigned automatically. They will need to be added manually at: ${projectUrl}`);
}
} catch (error) {
console.error('Error assigning users to project:', error);
console.log(`⚠️ Users will need to be added manually at: ${projectUrl}`);
// Always ensure the API user is assigned as a last resort
try {
// Wait a bit longer before API user request to avoid rate limiting
await new Promise(resolve => setTimeout(resolve, 5000));
const apiUserId = await this.getApiUserId();
if (apiUserId) {
const apiAssigned = await this.assignApiUserToProject(projectId, apiUserId);
if (apiAssigned) {
console.log('✅ API user assigned as fallback to prevent orphaned project.');
}
}
} catch (apiUserError) {
console.error('Error assigning API user as fallback:', apiUserError);
}
}
// No automatic user assignment - this was causing too many issues
return;
}
/**
@ -499,159 +291,41 @@ export class LeantimeService {
try {
console.log(`Assigning user ${userId} to project ${projectId} with role ${role}`);
// First, check if the user is already assigned to the project
const alreadyAssigned = await this.verifyUserAssignedToProject(userId, projectId);
if (alreadyAssigned) {
console.log(`✅ User ${userId} is already assigned to project ${projectId}`);
// Wait before making the API call to avoid rate limiting
await new Promise(resolve => setTimeout(resolve, 2000));
// Use only the method that we know works best
const response = await axios.post(
this.getApiEndpoint(),
{
method: 'leantime.rpc.Projects.addProjectUser',
jsonrpc: '2.0',
id: 1,
params: {
projectId: projectId,
userId: userId,
role: role
}
},
{
headers: {
'Content-Type': 'application/json',
'X-API-Key': this.apiToken
}
}
);
if (response.data && response.data.result) {
console.log(`✅ Assigned user ${userId} to project ${projectId} with role ${role}`);
return true;
}
// Try method 1: Projects.Projects.addUser
try {
const response = await axios.post(
this.getApiEndpoint(),
{
method: 'leantime.rpc.Projects.Projects.addUser',
jsonrpc: '2.0',
id: 1,
params: {
projectId: projectId,
userId: userId,
role: role
}
},
{
headers: {
'Content-Type': 'application/json',
'X-API-Key': this.apiToken
}
}
);
if (response.data && response.data.result) {
console.log(`Assigned user ${userId} to project ${projectId} with role ${role} (method 1)`);
// Verify assignment was successful
const verified = await this.verifyUserAssignedToProject(userId, projectId);
if (verified) {
return true;
} else {
console.log('Assignment appeared successful but verification failed. Trying next method...');
}
}
} catch (error) {
console.log('Method 1 failed, trying next method...');
}
// Try method 2: Projects.addProjectUser
try {
const response2 = await axios.post(
this.getApiEndpoint(),
{
method: 'leantime.rpc.Projects.addProjectUser',
jsonrpc: '2.0',
id: 1,
params: {
projectId: projectId,
userId: userId,
role: role
}
},
{
headers: {
'Content-Type': 'application/json',
'X-API-Key': this.apiToken
}
}
);
if (response2.data && response2.data.result) {
console.log(`Assigned user ${userId} to project ${projectId} with role ${role} (method 2)`);
return true;
}
} catch (error) {
console.log('Method 2 failed, trying next method...');
}
// Try method 3: Projects.Projects.addProjectUser
try {
const response3 = await axios.post(
this.getApiEndpoint(),
{
method: 'leantime.rpc.Projects.Projects.addProjectUser',
jsonrpc: '2.0',
id: 1,
params: {
projectId: projectId,
userId: userId,
role: role
}
},
{
headers: {
'Content-Type': 'application/json',
'X-API-Key': this.apiToken
}
}
);
if (response3.data && response3.data.result) {
console.log(`Assigned user ${userId} to project ${projectId} with role ${role} (method 3)`);
return true;
}
} catch (error) {
console.log('Method 3 failed, trying next method...');
}
// Try method 4: Projects.editUserProjectRelations
try {
// This method might take a different param structure
const response4 = await axios.post(
this.getApiEndpoint(),
{
method: 'leantime.rpc.Projects.editUserProjectRelations',
jsonrpc: '2.0',
id: 1,
params: {
action: 'add',
userId: userId,
projects: [{
id: projectId,
role: role
}]
}
},
{
headers: {
'Content-Type': 'application/json',
'X-API-Key': this.apiToken
}
}
);
if (response4.data && response4.data.result) {
console.log(`Assigned user ${userId} to project ${projectId} with role ${role} (method 4)`);
return true;
}
} catch (error) {
console.log('Method 4 failed.');
}
// After all methods, verify one last time
const finalVerification = await this.verifyUserAssignedToProject(userId, projectId);
if (finalVerification) {
console.log(`✅ Verified user ${userId} is now assigned to project ${projectId}`);
return true;
}
// If we reach here, all methods failed
console.warn(`⚠️ Could not assign user ${userId} to project ${projectId} with any method. This is not a critical error, the project was created.`);
console.warn(`⚠️ Could not assign user ${userId} to project ${projectId}.`);
return false;
} catch (error) {
console.error(`Error assigning user ${userId} to project ${projectId}:`, error);
// We'll allow this to fail since the project was created successfully
console.warn(`⚠️ User assignment failed, but this is not critical. The project ${projectId} was created successfully.`);
console.warn(`⚠️ User assignment failed. The project ${projectId} was created successfully, but users will need to be added manually.`);
return false;
}
}
@ -671,14 +345,15 @@ export class LeantimeService {
return true;
}
// Try various methods to assign the API user
// Method 1: Direct API assignment
// Wait before making the API call to avoid rate limiting
await new Promise(resolve => setTimeout(resolve, 2000));
// Use only the method that we know works best
try {
const response = await axios.post(
this.getApiEndpoint(),
{
method: 'leantime.rpc.Projects.Projects.addUser',
method: 'leantime.rpc.Projects.addProjectUser',
jsonrpc: '2.0',
id: 1,
params: {
@ -696,81 +371,11 @@ export class LeantimeService {
);
if (response.data && response.data.result) {
console.log(`Successfully assigned API user to project ${projectId}`);
console.log(`✅ API user successfully assigned to project ${projectId}`);
return true;
}
} catch (error) {
console.log('API user assignment method 1 failed, trying next method...');
}
// Method 2: editUserProjectRelations
try {
const response = await axios.post(
this.getApiEndpoint(),
{
method: 'leantime.rpc.Projects.editUserProjectRelations',
jsonrpc: '2.0',
id: 1,
params: {
action: 'add',
userId: apiUserId,
projects: [{
id: projectId,
role: 'admin'
}]
}
},
{
headers: {
'Content-Type': 'application/json',
'X-API-Key': this.apiToken
}
}
);
if (response.data && response.data.result) {
console.log(`Successfully assigned API user to project ${projectId} (method 2)`);
return true;
}
} catch (error) {
console.log('API user assignment method 2 failed, trying next method...');
}
// Method 3: addProjectUser
try {
const response = await axios.post(
this.getApiEndpoint(),
{
method: 'leantime.rpc.Projects.addProjectUser',
jsonrpc: '2.0',
id: 1,
params: {
projectId: projectId,
userId: apiUserId,
role: 'admin'
}
},
{
headers: {
'Content-Type': 'application/json',
'X-API-Key': this.apiToken
}
}
);
if (response.data && response.data.result) {
console.log(`Successfully assigned API user to project ${projectId} (method 3)`);
return true;
}
} catch (error) {
console.log('API user assignment method 3 failed.');
}
// After all methods, verify assignment one last time
const finalVerification = await this.verifyUserAssignedToProject(apiUserId, projectId);
if (finalVerification) {
console.log(`✅ Verified API user ${apiUserId} is now assigned to project ${projectId}`);
return true;
console.error('Error assigning API user to project:', error);
}
console.warn(`⚠️ Could not assign API user to project ${projectId}. The project may appear with "New API Access" as the only team member.`);
@ -851,10 +456,14 @@ export class LeantimeService {
*/
async createClient(clientName: string): Promise<number | null> {
try {
// Wait before making the API call to avoid rate limiting
await new Promise(resolve => setTimeout(resolve, 1000));
// Use only the method that works consistently
const response = await axios.post(
this.getApiEndpoint(),
{
method: 'leantime.rpc.Clients.Clients.create',
method: 'leantime.rpc.Clients.Clients.addClient',
jsonrpc: '2.0',
id: 1,
params: {
@ -894,7 +503,7 @@ export class LeantimeService {
await new Promise(resolve => setTimeout(resolve, 3000));
try {
// Try again with a different API method name
// Retry with the same method after waiting
const retryResponse = await axios.post(
this.getApiEndpoint(),
{