257 lines
8.5 KiB
JavaScript
257 lines
8.5 KiB
JavaScript
const nocodbService = require('../services/nocodb');
|
|
const logger = require('../utils/logger');
|
|
const config = require('../config');
|
|
const {
|
|
syncGeoFields,
|
|
validateCoordinates,
|
|
checkBounds,
|
|
extractId
|
|
} = require('../utils/helpers');
|
|
|
|
class LocationsController {
|
|
async getAll(req, res) {
|
|
try {
|
|
const { limit = 1000, offset = 0, where } = req.query;
|
|
|
|
const params = { limit, offset };
|
|
if (where) params.where = where;
|
|
|
|
logger.info('Fetching locations from NocoDB');
|
|
|
|
const response = await nocodbService.getLocations(params);
|
|
const locations = response.list || [];
|
|
|
|
// Process and validate locations
|
|
const validLocations = locations.filter(loc => {
|
|
loc = syncGeoFields(loc);
|
|
|
|
if (loc.latitude && loc.longitude) {
|
|
return true;
|
|
}
|
|
|
|
// Try to parse from geodata column
|
|
if (loc.geodata && typeof loc.geodata === 'string') {
|
|
const parts = loc.geodata.split(';');
|
|
if (parts.length === 2) {
|
|
loc.latitude = parseFloat(parts[0]);
|
|
loc.longitude = parseFloat(parts[1]);
|
|
return !isNaN(loc.latitude) && !isNaN(loc.longitude);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
});
|
|
|
|
logger.info(`Retrieved ${validLocations.length} valid locations out of ${locations.length} total`);
|
|
|
|
res.json({
|
|
success: true,
|
|
count: validLocations.length,
|
|
total: response.pageInfo?.totalRows || validLocations.length,
|
|
locations: validLocations
|
|
});
|
|
|
|
} catch (error) {
|
|
logger.error('Error fetching locations:', error.message);
|
|
|
|
if (error.response) {
|
|
res.status(error.response.status).json({
|
|
success: false,
|
|
error: 'Failed to fetch data from NocoDB',
|
|
details: error.response.data
|
|
});
|
|
} else if (error.code === 'ECONNABORTED') {
|
|
res.status(504).json({
|
|
success: false,
|
|
error: 'Request timeout'
|
|
});
|
|
} else {
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Internal server error'
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
async getById(req, res) {
|
|
try {
|
|
const location = await nocodbService.getById(
|
|
config.nocodb.tableId,
|
|
req.params.id
|
|
);
|
|
|
|
res.json({
|
|
success: true,
|
|
location
|
|
});
|
|
|
|
} catch (error) {
|
|
logger.error(`Error fetching location ${req.params.id}:`, error.message);
|
|
res.status(error.response?.status || 500).json({
|
|
success: false,
|
|
error: 'Failed to fetch location'
|
|
});
|
|
}
|
|
}
|
|
|
|
async create(req, res) {
|
|
try {
|
|
let locationData = { ...req.body };
|
|
locationData = syncGeoFields(locationData);
|
|
|
|
const { latitude, longitude, ...additionalData } = locationData;
|
|
|
|
// Validate coordinates
|
|
const validation = validateCoordinates(latitude, longitude);
|
|
if (!validation.valid) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: validation.error
|
|
});
|
|
}
|
|
|
|
// Check bounds if configured
|
|
if (config.map.bounds) {
|
|
if (!checkBounds(validation.latitude, validation.longitude, config.map.bounds)) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: 'Location is outside allowed bounds'
|
|
});
|
|
}
|
|
}
|
|
|
|
// Format geodata
|
|
const geodata = `${validation.latitude};${validation.longitude}`;
|
|
|
|
// Prepare data for NocoDB
|
|
const finalData = {
|
|
geodata,
|
|
'Geo-Location': geodata,
|
|
latitude: validation.latitude,
|
|
longitude: validation.longitude,
|
|
...additionalData,
|
|
created_at: new Date().toISOString(),
|
|
created_by: req.session.userEmail
|
|
};
|
|
|
|
logger.info('Creating new location:', {
|
|
lat: validation.latitude,
|
|
lng: validation.longitude
|
|
});
|
|
|
|
const response = await nocodbService.create(
|
|
config.nocodb.tableId,
|
|
finalData
|
|
);
|
|
|
|
logger.info('Location created successfully:', extractId(response));
|
|
|
|
res.status(201).json({
|
|
success: true,
|
|
location: response
|
|
});
|
|
|
|
} catch (error) {
|
|
logger.error('Error creating location:', error.message);
|
|
|
|
if (error.response) {
|
|
res.status(error.response.status).json({
|
|
success: false,
|
|
error: 'Failed to save location to NocoDB',
|
|
details: error.response.data
|
|
});
|
|
} else {
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Internal server error'
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
async update(req, res) {
|
|
try {
|
|
const locationId = req.params.id;
|
|
|
|
// Validate ID
|
|
if (!locationId || locationId === 'undefined' || locationId === 'null') {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: 'Invalid location ID'
|
|
});
|
|
}
|
|
|
|
let updateData = { ...req.body };
|
|
|
|
// Remove ID fields to avoid conflicts
|
|
delete updateData.ID;
|
|
delete updateData.Id;
|
|
delete updateData.id;
|
|
delete updateData._id;
|
|
|
|
// Sync geo fields
|
|
updateData = syncGeoFields(updateData);
|
|
|
|
updateData.last_updated_at = new Date().toISOString();
|
|
updateData.last_updated_by = req.session.userEmail;
|
|
|
|
logger.info(`Updating location ${locationId} by ${req.session.userEmail}`);
|
|
|
|
const response = await nocodbService.update(
|
|
config.nocodb.tableId,
|
|
locationId,
|
|
updateData
|
|
);
|
|
|
|
res.json({
|
|
success: true,
|
|
location: response
|
|
});
|
|
|
|
} catch (error) {
|
|
logger.error(`Error updating location ${req.params.id}:`, error.message);
|
|
|
|
res.status(error.response?.status || 500).json({
|
|
success: false,
|
|
error: 'Failed to update location',
|
|
details: error.response?.data?.message || error.message
|
|
});
|
|
}
|
|
}
|
|
|
|
async delete(req, res) {
|
|
try {
|
|
const locationId = req.params.id;
|
|
|
|
// Validate ID
|
|
if (!locationId || locationId === 'undefined' || locationId === 'null') {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: 'Invalid location ID'
|
|
});
|
|
}
|
|
|
|
await nocodbService.delete(
|
|
config.nocodb.tableId,
|
|
locationId
|
|
);
|
|
|
|
logger.info(`Location ${locationId} deleted by ${req.session.userEmail}`);
|
|
|
|
res.json({
|
|
success: true,
|
|
message: 'Location deleted successfully'
|
|
});
|
|
|
|
} catch (error) {
|
|
logger.error(`Error deleting location ${req.params.id}:`, error.message);
|
|
res.status(error.response?.status || 500).json({
|
|
success: false,
|
|
error: 'Failed to delete location'
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = new LocationsController(); |