610 lines
18 KiB
TypeScript
610 lines
18 KiB
TypeScript
/**
|
|
* LibreBooking API Test Script
|
|
*
|
|
* Testet alle wichtigen API-Endpunkte mit echten Credentials
|
|
*/
|
|
|
|
import * as https from 'https';
|
|
import * as http from 'http';
|
|
|
|
const BASE_URL = 'https://librebooking.zell-cloud.de';
|
|
const USERNAME = 'sebastian.zell@zell-aufmass.de';
|
|
const PASSWORD = 'wanUQ4uVqU6lfP';
|
|
|
|
interface Session {
|
|
sessionToken: string;
|
|
userId: number;
|
|
}
|
|
|
|
interface TestResult {
|
|
name: string;
|
|
success: boolean;
|
|
data?: any;
|
|
error?: string;
|
|
}
|
|
|
|
const results: TestResult[] = [];
|
|
|
|
/**
|
|
* HTTP Request Helper
|
|
*/
|
|
function makeRequest(
|
|
method: string,
|
|
path: string,
|
|
body?: any,
|
|
session?: Session,
|
|
qs?: Record<string, string>
|
|
): Promise<any> {
|
|
return new Promise((resolve, reject) => {
|
|
const url = new URL(path, BASE_URL);
|
|
|
|
if (qs) {
|
|
Object.entries(qs).forEach(([key, value]) => {
|
|
if (value) url.searchParams.append(key, value);
|
|
});
|
|
}
|
|
|
|
const headers: Record<string, string> = {
|
|
'Content-Type': 'application/json',
|
|
};
|
|
|
|
if (session) {
|
|
headers['X-Booked-SessionToken'] = session.sessionToken;
|
|
headers['X-Booked-UserId'] = session.userId.toString();
|
|
}
|
|
|
|
const options = {
|
|
method,
|
|
hostname: url.hostname,
|
|
path: url.pathname + url.search,
|
|
headers,
|
|
};
|
|
|
|
const httpModule = url.protocol === 'https:' ? https : http;
|
|
|
|
const req = httpModule.request(options, (res) => {
|
|
let data = '';
|
|
res.on('data', (chunk) => { data += chunk; });
|
|
res.on('end', () => {
|
|
try {
|
|
if (data) {
|
|
resolve(JSON.parse(data));
|
|
} else {
|
|
resolve({ success: true });
|
|
}
|
|
} catch (e) {
|
|
resolve({ rawData: data });
|
|
}
|
|
});
|
|
});
|
|
|
|
req.on('error', (error) => {
|
|
reject(error);
|
|
});
|
|
|
|
if (body) {
|
|
req.write(JSON.stringify(body));
|
|
}
|
|
|
|
req.end();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test Authentication
|
|
*/
|
|
async function testAuthentication(): Promise<Session> {
|
|
console.log('\n=== 1. Testing Authentication ===');
|
|
try {
|
|
const response = await makeRequest(
|
|
'POST',
|
|
'/Web/Services/index.php/Authentication/Authenticate',
|
|
{ username: USERNAME, password: PASSWORD }
|
|
);
|
|
|
|
if (response.isAuthenticated) {
|
|
console.log('✅ Authentication successful');
|
|
console.log(` Session Token: ${response.sessionToken.substring(0, 20)}...`);
|
|
console.log(` User ID: ${response.userId}`);
|
|
console.log(` Session Expires: ${response.sessionExpires}`);
|
|
results.push({ name: 'Authentication', success: true, data: { userId: response.userId } });
|
|
return { sessionToken: response.sessionToken, userId: response.userId };
|
|
} else {
|
|
throw new Error('Authentication failed');
|
|
}
|
|
} catch (error: any) {
|
|
console.log('❌ Authentication failed:', error.message);
|
|
results.push({ name: 'Authentication', success: false, error: error.message });
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test Get Reservations
|
|
*/
|
|
async function testGetReservations(session: Session): Promise<void> {
|
|
console.log('\n=== 2. Testing Get Reservations ===');
|
|
try {
|
|
// Test without date filters (should return next 2 weeks)
|
|
const response = await makeRequest(
|
|
'GET',
|
|
'/Web/Services/index.php/Reservations/',
|
|
undefined,
|
|
session
|
|
);
|
|
|
|
console.log(`✅ Reservations fetched: ${response.reservations?.length || 0} found`);
|
|
|
|
if (response.reservations && response.reservations.length > 0) {
|
|
const res = response.reservations[0];
|
|
console.log(` Example: ${res.title || 'No title'} (${res.referenceNumber})`);
|
|
console.log(` Start: ${res.startDate}`);
|
|
console.log(` Resource: ${res.resourceName}`);
|
|
}
|
|
|
|
results.push({ name: 'Get Reservations (no filter)', success: true, data: { count: response.reservations?.length || 0 } });
|
|
|
|
// Test with date filter (Feb 7-14, 2026)
|
|
console.log('\n Testing with date filter (2026-02-07 to 2026-02-14)...');
|
|
const responseFiltered = await makeRequest(
|
|
'GET',
|
|
'/Web/Services/index.php/Reservations/',
|
|
undefined,
|
|
session,
|
|
{
|
|
startDateTime: '2026-02-07T00:00:00',
|
|
endDateTime: '2026-02-14T23:59:59'
|
|
}
|
|
);
|
|
|
|
console.log(`✅ Filtered reservations: ${responseFiltered.reservations?.length || 0} found`);
|
|
results.push({ name: 'Get Reservations (date filter)', success: true, data: { count: responseFiltered.reservations?.length || 0 } });
|
|
|
|
} catch (error: any) {
|
|
console.log('❌ Get Reservations failed:', error.message);
|
|
results.push({ name: 'Get Reservations', success: false, error: error.message });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test Get Resources
|
|
*/
|
|
async function testGetResources(session: Session): Promise<number | null> {
|
|
console.log('\n=== 3. Testing Get Resources ===');
|
|
try {
|
|
const response = await makeRequest(
|
|
'GET',
|
|
'/Web/Services/index.php/Resources/',
|
|
undefined,
|
|
session
|
|
);
|
|
|
|
console.log(`✅ Resources fetched: ${response.resources?.length || 0} found`);
|
|
|
|
let firstResourceId: number | null = null;
|
|
if (response.resources && response.resources.length > 0) {
|
|
const res = response.resources[0];
|
|
firstResourceId = res.resourceId;
|
|
console.log(` Example: ${res.name} (ID: ${res.resourceId})`);
|
|
console.log(` Schedule ID: ${res.scheduleId}`);
|
|
console.log(` Custom Attributes: ${res.customAttributes?.length || 0}`);
|
|
|
|
if (res.customAttributes && res.customAttributes.length > 0) {
|
|
res.customAttributes.forEach((attr: any) => {
|
|
console.log(` - ${attr.label}: ${attr.value || '(no value)'}`);
|
|
});
|
|
}
|
|
}
|
|
|
|
results.push({ name: 'Get Resources', success: true, data: { count: response.resources?.length || 0 } });
|
|
return firstResourceId;
|
|
|
|
} catch (error: any) {
|
|
console.log('❌ Get Resources failed:', error.message);
|
|
results.push({ name: 'Get Resources', success: false, error: error.message });
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test Get Single Resource (with custom attributes)
|
|
*/
|
|
async function testGetSingleResource(session: Session, resourceId: number): Promise<void> {
|
|
console.log('\n=== 4. Testing Get Single Resource (with custom attributes) ===');
|
|
try {
|
|
const response = await makeRequest(
|
|
'GET',
|
|
`/Web/Services/index.php/Resources/${resourceId}`,
|
|
undefined,
|
|
session
|
|
);
|
|
|
|
console.log(`✅ Resource fetched: ${response.name}`);
|
|
console.log(` Custom Attributes: ${response.customAttributes?.length || 0}`);
|
|
|
|
if (response.customAttributes && response.customAttributes.length > 0) {
|
|
response.customAttributes.forEach((attr: any) => {
|
|
console.log(` - ID: ${attr.id}, Label: ${attr.label}, Value: ${attr.value || '(no value)'}`);
|
|
});
|
|
}
|
|
|
|
results.push({ name: 'Get Single Resource', success: true, data: { customAttributes: response.customAttributes?.length || 0 } });
|
|
|
|
} catch (error: any) {
|
|
console.log('❌ Get Single Resource failed:', error.message);
|
|
results.push({ name: 'Get Single Resource', success: false, error: error.message });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test Get Users
|
|
*/
|
|
async function testGetUsers(session: Session): Promise<number | null> {
|
|
console.log('\n=== 5. Testing Get Users ===');
|
|
try {
|
|
const response = await makeRequest(
|
|
'GET',
|
|
'/Web/Services/index.php/Users/',
|
|
undefined,
|
|
session
|
|
);
|
|
|
|
console.log(`✅ Users fetched: ${response.users?.length || 0} found`);
|
|
|
|
let firstUserId: number | null = null;
|
|
if (response.users && response.users.length > 0) {
|
|
const user = response.users[0];
|
|
firstUserId = user.id;
|
|
console.log(` Example: ${user.firstName} ${user.lastName} (ID: ${user.id})`);
|
|
}
|
|
|
|
results.push({ name: 'Get Users', success: true, data: { count: response.users?.length || 0 } });
|
|
return firstUserId;
|
|
|
|
} catch (error: any) {
|
|
console.log('❌ Get Users failed:', error.message);
|
|
results.push({ name: 'Get Users', success: false, error: error.message });
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test Get Single User (with custom attributes)
|
|
*/
|
|
async function testGetSingleUser(session: Session, userId: number): Promise<void> {
|
|
console.log('\n=== 6. Testing Get Single User (with custom attributes) ===');
|
|
try {
|
|
const response = await makeRequest(
|
|
'GET',
|
|
`/Web/Services/index.php/Users/${userId}`,
|
|
undefined,
|
|
session
|
|
);
|
|
|
|
console.log(`✅ User fetched: ${response.firstName} ${response.lastName}`);
|
|
console.log(` Custom Attributes: ${response.customAttributes?.length || 0}`);
|
|
|
|
if (response.customAttributes && response.customAttributes.length > 0) {
|
|
response.customAttributes.forEach((attr: any) => {
|
|
console.log(` - ID: ${attr.id}, Label: ${attr.label}, Value: ${attr.value || '(no value)'}`);
|
|
});
|
|
}
|
|
|
|
results.push({ name: 'Get Single User', success: true, data: { customAttributes: response.customAttributes?.length || 0 } });
|
|
|
|
} catch (error: any) {
|
|
console.log('❌ Get Single User failed:', error.message);
|
|
results.push({ name: 'Get Single User', success: false, error: error.message });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test Get Schedules
|
|
*/
|
|
async function testGetSchedules(session: Session): Promise<void> {
|
|
console.log('\n=== 7. Testing Get Schedules ===');
|
|
try {
|
|
const response = await makeRequest(
|
|
'GET',
|
|
'/Web/Services/index.php/Schedules/',
|
|
undefined,
|
|
session
|
|
);
|
|
|
|
console.log(`✅ Schedules fetched: ${response.schedules?.length || 0} found`);
|
|
|
|
if (response.schedules && response.schedules.length > 0) {
|
|
const schedule = response.schedules[0];
|
|
console.log(` Example: ${schedule.name} (ID: ${schedule.id})`);
|
|
}
|
|
|
|
results.push({ name: 'Get Schedules', success: true, data: { count: response.schedules?.length || 0 } });
|
|
|
|
} catch (error: any) {
|
|
console.log('❌ Get Schedules failed:', error.message);
|
|
results.push({ name: 'Get Schedules', success: false, error: error.message });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test Get Attributes by Category
|
|
*/
|
|
async function testGetAttributes(session: Session): Promise<void> {
|
|
console.log('\n=== 8. Testing Get Attributes by Category ===');
|
|
|
|
const categories = [
|
|
{ id: 1, name: 'Reservation' },
|
|
{ id: 2, name: 'User' },
|
|
{ id: 4, name: 'Resource' },
|
|
{ id: 5, name: 'Resource Type' },
|
|
];
|
|
|
|
for (const cat of categories) {
|
|
try {
|
|
const response = await makeRequest(
|
|
'GET',
|
|
`/Web/Services/index.php/Attributes/Category/${cat.id}`,
|
|
undefined,
|
|
session
|
|
);
|
|
|
|
console.log(`✅ ${cat.name} Attributes: ${response.attributes?.length || 0} found`);
|
|
|
|
if (response.attributes && response.attributes.length > 0) {
|
|
response.attributes.forEach((attr: any) => {
|
|
console.log(` - ID: ${attr.id}, Label: ${attr.label}, Type: ${attr.type}, Required: ${attr.required}`);
|
|
});
|
|
}
|
|
|
|
results.push({ name: `Get Attributes (${cat.name})`, success: true, data: { count: response.attributes?.length || 0 } });
|
|
|
|
} catch (error: any) {
|
|
console.log(`❌ Get ${cat.name} Attributes failed:`, error.message);
|
|
results.push({ name: `Get Attributes (${cat.name})`, success: false, error: error.message });
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test Create, Update, Delete Reservation
|
|
*/
|
|
async function testReservationCRUD(session: Session, resourceId: number): Promise<void> {
|
|
console.log('\n=== 9. Testing Reservation CRUD ===');
|
|
|
|
// Create
|
|
console.log(' Creating test reservation...');
|
|
try {
|
|
const createResponse = await makeRequest(
|
|
'POST',
|
|
'/Web/Services/index.php/Reservations/',
|
|
{
|
|
title: 'API Test Reservation',
|
|
description: 'Created by n8n node test script',
|
|
resourceId: resourceId,
|
|
startDateTime: '2026-02-07T10:00:00',
|
|
endDateTime: '2026-02-07T11:00:00',
|
|
userId: session.userId,
|
|
termsAccepted: true,
|
|
allowParticipation: false,
|
|
},
|
|
session
|
|
);
|
|
|
|
if (createResponse.referenceNumber) {
|
|
console.log(`✅ Reservation created: ${createResponse.referenceNumber}`);
|
|
results.push({ name: 'Create Reservation', success: true, data: { referenceNumber: createResponse.referenceNumber } });
|
|
|
|
const refNum = createResponse.referenceNumber;
|
|
|
|
// Get the created reservation
|
|
console.log(' Fetching created reservation...');
|
|
const getResponse = await makeRequest(
|
|
'GET',
|
|
`/Web/Services/index.php/Reservations/${refNum}`,
|
|
undefined,
|
|
session
|
|
);
|
|
console.log(`✅ Reservation fetched: ${getResponse.title}`);
|
|
console.log(` Custom Attributes: ${getResponse.customAttributes?.length || 0}`);
|
|
if (getResponse.customAttributes && getResponse.customAttributes.length > 0) {
|
|
getResponse.customAttributes.forEach((attr: any) => {
|
|
console.log(` - ID: ${attr.id}, Label: ${attr.label}, Value: ${attr.value || '(no value)'}`);
|
|
});
|
|
}
|
|
results.push({ name: 'Get Created Reservation', success: true });
|
|
|
|
// Update
|
|
console.log(' Updating reservation...');
|
|
const updateResponse = await makeRequest(
|
|
'POST',
|
|
`/Web/Services/index.php/Reservations/${refNum}?updateScope=this`,
|
|
{
|
|
title: 'API Test Reservation UPDATED',
|
|
description: 'Updated by n8n node test script',
|
|
resourceId: resourceId,
|
|
startDateTime: '2026-02-07T10:00:00',
|
|
endDateTime: '2026-02-07T12:00:00',
|
|
termsAccepted: true,
|
|
allowParticipation: false,
|
|
},
|
|
session
|
|
);
|
|
console.log(`✅ Reservation updated`);
|
|
results.push({ name: 'Update Reservation', success: true });
|
|
|
|
// Delete
|
|
console.log(' Deleting reservation...');
|
|
const deleteResponse = await makeRequest(
|
|
'DELETE',
|
|
`/Web/Services/index.php/Reservations/${refNum}?updateScope=this`,
|
|
undefined,
|
|
session
|
|
);
|
|
console.log(`✅ Reservation deleted`);
|
|
results.push({ name: 'Delete Reservation', success: true });
|
|
|
|
} else {
|
|
console.log('❌ Create Reservation failed - no reference number returned');
|
|
console.log(' Response:', JSON.stringify(createResponse, null, 2));
|
|
results.push({ name: 'Create Reservation', success: false, error: JSON.stringify(createResponse) });
|
|
}
|
|
|
|
} catch (error: any) {
|
|
console.log('❌ Reservation CRUD failed:', error.message);
|
|
results.push({ name: 'Reservation CRUD', success: false, error: error.message });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test Groups
|
|
*/
|
|
async function testGetGroups(session: Session): Promise<void> {
|
|
console.log('\n=== 10. Testing Get Groups ===');
|
|
try {
|
|
const response = await makeRequest(
|
|
'GET',
|
|
'/Web/Services/index.php/Groups/',
|
|
undefined,
|
|
session
|
|
);
|
|
|
|
console.log(`✅ Groups fetched: ${response.groups?.length || 0} found`);
|
|
|
|
if (response.groups && response.groups.length > 0) {
|
|
const group = response.groups[0];
|
|
console.log(` Example: ${group.name} (ID: ${group.id})`);
|
|
}
|
|
|
|
results.push({ name: 'Get Groups', success: true, data: { count: response.groups?.length || 0 } });
|
|
|
|
} catch (error: any) {
|
|
console.log('❌ Get Groups failed:', error.message);
|
|
results.push({ name: 'Get Groups', success: false, error: error.message });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test Accessories
|
|
*/
|
|
async function testGetAccessories(session: Session): Promise<void> {
|
|
console.log('\n=== 11. Testing Get Accessories ===');
|
|
try {
|
|
const response = await makeRequest(
|
|
'GET',
|
|
'/Web/Services/index.php/Accessories/',
|
|
undefined,
|
|
session
|
|
);
|
|
|
|
console.log(`✅ Accessories fetched: ${response.accessories?.length || 0} found`);
|
|
|
|
if (response.accessories && response.accessories.length > 0) {
|
|
const acc = response.accessories[0];
|
|
console.log(` Example: ${acc.name} (ID: ${acc.id})`);
|
|
}
|
|
|
|
results.push({ name: 'Get Accessories', success: true, data: { count: response.accessories?.length || 0 } });
|
|
|
|
} catch (error: any) {
|
|
console.log('❌ Get Accessories failed:', error.message);
|
|
results.push({ name: 'Get Accessories', success: false, error: error.message });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test SignOut
|
|
*/
|
|
async function testSignOut(session: Session): Promise<void> {
|
|
console.log('\n=== 12. Testing Sign Out ===');
|
|
try {
|
|
await makeRequest(
|
|
'POST',
|
|
'/Web/Services/index.php/Authentication/SignOut',
|
|
{
|
|
userId: session.userId,
|
|
sessionToken: session.sessionToken,
|
|
}
|
|
);
|
|
console.log('✅ Sign Out successful');
|
|
results.push({ name: 'Sign Out', success: true });
|
|
|
|
} catch (error: any) {
|
|
console.log('❌ Sign Out failed:', error.message);
|
|
results.push({ name: 'Sign Out', success: false, error: error.message });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Print Summary
|
|
*/
|
|
function printSummary(): void {
|
|
console.log('\n========================================');
|
|
console.log(' TEST SUMMARY');
|
|
console.log('========================================');
|
|
|
|
const passed = results.filter(r => r.success).length;
|
|
const failed = results.filter(r => !r.success).length;
|
|
|
|
console.log(`\nTotal Tests: ${results.length}`);
|
|
console.log(`✅ Passed: ${passed}`);
|
|
console.log(`❌ Failed: ${failed}`);
|
|
|
|
if (failed > 0) {
|
|
console.log('\nFailed Tests:');
|
|
results.filter(r => !r.success).forEach(r => {
|
|
console.log(` - ${r.name}: ${r.error}`);
|
|
});
|
|
}
|
|
|
|
console.log('\n========================================\n');
|
|
}
|
|
|
|
/**
|
|
* Main Test Runner
|
|
*/
|
|
async function runTests(): Promise<void> {
|
|
console.log('========================================');
|
|
console.log(' LibreBooking API Test Suite');
|
|
console.log(` URL: ${BASE_URL}`);
|
|
console.log(` User: ${USERNAME}`);
|
|
console.log('========================================');
|
|
|
|
try {
|
|
// Authentication
|
|
const session = await testAuthentication();
|
|
|
|
// Get operations
|
|
await testGetReservations(session);
|
|
const resourceId = await testGetResources(session);
|
|
if (resourceId) {
|
|
await testGetSingleResource(session, resourceId);
|
|
}
|
|
|
|
const userId = await testGetUsers(session);
|
|
if (userId) {
|
|
await testGetSingleUser(session, userId);
|
|
}
|
|
|
|
await testGetSchedules(session);
|
|
await testGetAttributes(session);
|
|
await testGetGroups(session);
|
|
await testGetAccessories(session);
|
|
|
|
// CRUD operations
|
|
if (resourceId) {
|
|
await testReservationCRUD(session, resourceId);
|
|
}
|
|
|
|
// Sign out
|
|
await testSignOut(session);
|
|
|
|
} catch (error: any) {
|
|
console.log('\n❌ Test suite failed:', error.message);
|
|
}
|
|
|
|
printSummary();
|
|
}
|
|
|
|
// Run tests
|
|
runTests().catch(console.error);
|