115 lines
4.0 KiB
TypeScript
115 lines
4.0 KiB
TypeScript
import { withBerthQueue } from '~/server/utils/operation-lock';
|
|
import { getNocoDbConfiguration } from '~/server/utils/nocodb';
|
|
import { requireAuth } from '~/server/utils/auth';
|
|
import {
|
|
BerthStatus,
|
|
BerthArea,
|
|
SidePontoon,
|
|
MooringType,
|
|
CleatType,
|
|
CleatCapacity,
|
|
BollardType,
|
|
BollardCapacity,
|
|
Access
|
|
} from '~/utils/types';
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
console.log('[update-berth] Request received');
|
|
|
|
// Check authentication (x-tag header OR Keycloak session)
|
|
await requireAuth(event);
|
|
|
|
try {
|
|
const body = await readBody(event);
|
|
const { berthId, updates } = body;
|
|
console.log('[update-berth] Request body:', { berthId, updates });
|
|
|
|
if (!berthId || !updates) {
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: "berthId and updates object are required"
|
|
});
|
|
}
|
|
|
|
// Validate enum fields
|
|
const validEnumFields: Record<string, string[]> = {
|
|
'Status': Object.values(BerthStatus),
|
|
'Area': Object.values(BerthArea),
|
|
'Side Pontoon': Object.values(SidePontoon),
|
|
'Mooring Type': Object.values(MooringType),
|
|
'Cleat Type': Object.values(CleatType),
|
|
'Cleat Capacity': Object.values(CleatCapacity),
|
|
'Bollard Type': Object.values(BollardType),
|
|
'Bollard Capacity': Object.values(BollardCapacity),
|
|
'Access': Object.values(Access)
|
|
};
|
|
|
|
// Validate enum values
|
|
for (const [field, value] of Object.entries(updates)) {
|
|
if (validEnumFields[field] && value !== null && value !== undefined) {
|
|
if (!validEnumFields[field].includes(value as string)) {
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: `Invalid value for ${field}: ${value}. Must be one of: ${validEnumFields[field].join(', ')}`
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handle measurement conversions
|
|
// If metric values are being updated, convert them to imperial for storage
|
|
const measurementFields = ['Nominal Boat Size', 'Water Depth', 'Length', 'Width', 'Depth'];
|
|
const processedUpdates = { ...updates };
|
|
|
|
for (const field of measurementFields) {
|
|
if (processedUpdates[field] !== undefined) {
|
|
const value = processedUpdates[field];
|
|
if (typeof value === 'string') {
|
|
// Parse user input and convert metric to imperial if needed
|
|
const cleanInput = value.replace(/[^\d.]/g, '');
|
|
const numericValue = parseFloat(cleanInput);
|
|
|
|
if (!isNaN(numericValue)) {
|
|
const isMetric = value.toLowerCase().includes('m') && !value.toLowerCase().includes('ft');
|
|
if (isMetric) {
|
|
// Convert metric to imperial for NocoDB storage
|
|
const imperial = numericValue / 0.3048;
|
|
processedUpdates[field] = parseFloat(imperial.toFixed(2));
|
|
console.log(`[update-berth] Converted ${field} from ${numericValue}m to ${processedUpdates[field]}ft`);
|
|
} else {
|
|
// Assume imperial, store as is
|
|
processedUpdates[field] = numericValue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Use queuing system to handle concurrent updates
|
|
return await withBerthQueue(berthId, async () => {
|
|
const config = getNocoDbConfiguration();
|
|
const berthsTableId = "mczgos9hr3oa9qc";
|
|
|
|
const url = `${config.url}/api/v2/tables/${berthsTableId}/records/${berthId}`;
|
|
console.log('[update-berth] URL:', url);
|
|
console.log('[update-berth] Processed updates:', processedUpdates);
|
|
|
|
const result = await $fetch(url, {
|
|
method: 'PATCH',
|
|
headers: {
|
|
"xc-token": config.token,
|
|
},
|
|
body: processedUpdates,
|
|
});
|
|
|
|
console.log('[update-berth] Successfully updated berth:', berthId);
|
|
return result;
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error('[update-berth] Error occurred:', error);
|
|
console.error('[update-berth] Error details:', error instanceof Error ? error.message : 'Unknown error');
|
|
throw error;
|
|
}
|
|
});
|