const axios = require('axios'); const config = require('../config'); const logger = require('../utils/logger'); class NocoDBService { constructor() { this.apiUrl = config.nocodb.apiUrl; this.apiToken = config.nocodb.apiToken; this.projectId = config.nocodb.projectId; this.timeout = 10000; // 10 seconds // Create axios instance with defaults this.client = axios.create({ baseURL: this.apiUrl, timeout: this.timeout, headers: { 'xc-token': this.apiToken, 'Content-Type': 'application/json' } }); // Add response interceptor for error handling this.client.interceptors.response.use( response => response, error => { logger.error('NocoDB API Error:', { message: error.message, url: error.config?.url, method: error.config?.method, status: error.response?.status, data: error.response?.data }); throw error; } ); } // Build table URL getTableUrl(tableId) { return `/db/data/v1/${this.projectId}/${tableId}`; } // Get all records from a table async getAll(tableId, params = {}) { const url = this.getTableUrl(tableId); const response = await this.client.get(url, { params }); return response.data; } // Get single record async getById(tableId, recordId) { const url = `${this.getTableUrl(tableId)}/${recordId}`; const response = await this.client.get(url); return response.data; } // Create record async create(tableId, data) { const url = this.getTableUrl(tableId); const response = await this.client.post(url, data); return response.data; } // Update record async update(tableId, recordId, data) { const url = `${this.getTableUrl(tableId)}/${recordId}`; const response = await this.client.patch(url, data); return response.data; } // Delete record async delete(tableId, recordId) { const url = `${this.getTableUrl(tableId)}/${recordId}`; const response = await this.client.delete(url); return response.data; } // Get locations with proper filtering async getLocations(params = {}) { const defaultParams = { limit: 1000, offset: 0, ...params }; return this.getAll(config.nocodb.tableId, defaultParams); } // Get user by email async getUserByEmail(email) { if (!config.nocodb.loginSheetId) { throw new Error('Login sheet not configured'); } const response = await this.getAll(config.nocodb.loginSheetId, { where: `(Email,eq,${email})`, limit: 1 }); return response.list?.[0] || null; } // Get latest settings async getLatestSettings() { if (!config.nocodb.settingsSheetId) { return null; } const response = await this.getAll(config.nocodb.settingsSheetId, { sort: '-created_at', limit: 1 }); return response.list?.[0] || null; } // Get settings with walk sheet data async getWalkSheetSettings() { if (!config.nocodb.settingsSheetId) { return null; } const response = await this.getAll(config.nocodb.settingsSheetId, { sort: '-created_at', limit: 20 }); // Find first row with walk sheet data const settings = response.list?.find(row => row.walk_sheet_title || row.walk_sheet_subtitle || row.walk_sheet_footer || row.qr_code_1_url || row.qr_code_2_url || row.qr_code_3_url ) || response.list?.[0]; return settings || null; } } // Export singleton instance module.exports = new NocoDBService();