freealberta/map/app/controllers/locationsController.js

272 lines
9.1 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 {
// Add debugging logs
logger.info('Session data:', {
authenticated: req.session.authenticated,
userId: req.session.userId,
userEmail: req.session.userEmail,
isAdmin: req.session.isAdmin
});
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) {
const boundsCheck = checkBounds(validation.latitude, validation.longitude);
if (!boundsCheck.valid) {
return res.status(400).json({
success: false,
error: boundsCheck.error
});
}
}
// Format geodata with string values to preserve precision
const geodata = `${validation.latitude};${validation.longitude}`;
// Prepare data for NocoDB - keep coordinates as strings
const finalData = {
geodata,
'Geo-Location': geodata,
latitude: validation.latitude,
longitude: validation.longitude,
...additionalData,
created_by_user: req.session.userEmail || 'anonymous' // Add fallback
};
logger.info('Final data being sent to NocoDB:', finalData);
logger.info('Creating new location:', {
lat: validation.latitude,
lng: validation.longitude,
user: req.session.userEmail
});
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);
// Add update tracking
updateData.last_updated_by_user = req.session.userEmail; // Changed from last_updated_by
logger.info(`Updating location ${locationId}`, {
user: req.session.userEmail
});
const response = await nocodbService.update(
config.nocodb.tableId,
locationId,
updateData
);
logger.info('Location updated successfully:', locationId);
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();