Ajout de la gestion des images avec scan, suppression et mise à jour des mesures dans la base de données
This commit is contained in:
106
routes/api.js
106
routes/api.js
@@ -12,6 +12,7 @@ const dbTester = require('../test/tester');
|
|||||||
const cors = require('cors'); // Import the cors package
|
const cors = require('cors'); // Import the cors package
|
||||||
const projectManager = require('../src/project/projectManager.js');
|
const projectManager = require('../src/project/projectManager.js');
|
||||||
const measureManager = require('../src/measure/measureManager.js');
|
const measureManager = require('../src/measure/measureManager.js');
|
||||||
|
const fileWatcher = require('../src/data/filewatcher.js');
|
||||||
|
|
||||||
router.use(cors({
|
router.use(cors({
|
||||||
origin: ['http://127.0.0.1:5500', 'http://localhost:5500', 'http://localhost:3000'],
|
origin: ['http://127.0.0.1:5500', 'http://localhost:5500', 'http://localhost:3000'],
|
||||||
@@ -260,6 +261,20 @@ router.get('/measurements/:id', (req, res) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get('/measurements/:projectId/:orderId', async (req, res) => {
|
||||||
|
const projectId = req.params.projectId;
|
||||||
|
const orderId = req.params.orderId;
|
||||||
|
if (!projectId || isNaN(projectId) || !orderId || isNaN(orderId)) {
|
||||||
|
return res.status(400).json({ error: 'Invalid project ID or order ID' });
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const measurement = await measureManager.getMeasurement(projectId, orderId);
|
||||||
|
res.json(measurement);
|
||||||
|
} catch (error) {
|
||||||
|
serverError.sendError('Error getting measurement:', res, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @swagger
|
* @swagger
|
||||||
* /measurements:
|
* /measurements:
|
||||||
@@ -272,12 +287,12 @@ router.get('/measurements/:id', (req, res) => {
|
|||||||
* description: Internal server error
|
* description: Internal server error
|
||||||
*/
|
*/
|
||||||
router.post('/measurements', (req, res) => {
|
router.post('/measurements', (req, res) => {
|
||||||
const { project_id, timestamp, image_path, temperature, humidity, completed } = req.body;
|
const { project_id, timestamp, image_path, temperature, humidity} = req.body;
|
||||||
if (!project_id || !timestamp || !image_path || !temperature || !humidity || !completed) {
|
if (!project_id || !timestamp || !image_path || !temperature || !humidity) {
|
||||||
return res.status(400).json({ error: 'All fields are required' });
|
return res.status(400).json({ error: 'All fields are required' });
|
||||||
}
|
}
|
||||||
const query = 'INSERT INTO public.measurements (project_id, timestamp, image_path, temperature, humidity, completed) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id';
|
const query = 'INSERT INTO public.measurements (project_id, timestamp, image_path, temperature, humidity) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id';
|
||||||
db.query(query, [project_id, timestamp, image_path, temperature, humidity, completed], (err, results) => {
|
db.query(query, [project_id, timestamp, image_path, temperature, humidity], (err, results) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
serverError.sendError('Erreur lors de l\'ajout de la mesure:', res, err);
|
serverError.sendError('Erreur lors de l\'ajout de la mesure:', res, err);
|
||||||
}
|
}
|
||||||
@@ -305,21 +320,31 @@ router.post('/measurements', (req, res) => {
|
|||||||
* 500:
|
* 500:
|
||||||
* description: Internal server error
|
* description: Internal server error
|
||||||
*/
|
*/
|
||||||
router.delete('/measurements/:id', (req, res) => {
|
router.delete('/measurements/:id', async (req, res) => {
|
||||||
const measurementId = req.params.id;
|
const measurementId = req.params.id;
|
||||||
if (!measurementId || isNaN(measurementId)) {
|
if (!measurementId || isNaN(measurementId)) {
|
||||||
return res.status(400).json({ error: 'Invalid measurement ID' });
|
return res.status(400).json({ error: 'Invalid measurement ID' });
|
||||||
}
|
}
|
||||||
const query = 'DELETE FROM public.measurements WHERE id = $1 RETURNING id';
|
try {
|
||||||
db.query(query, [measurementId], (err, results) => {
|
const measurement = await measureManager.deleteMeasurement(measurementId);
|
||||||
if (err) {
|
res.status(200).json({ message: 'Measurement deleted successfully', id: measurementId });
|
||||||
serverError.sendError('Erreur lors de la suppression de la mesure:', res, err);
|
} catch (error) {
|
||||||
}
|
serverError.sendError('Error deleting measurement:', res, error);
|
||||||
if (results.rowCount === 0) {
|
}
|
||||||
return res.status(404).json({ error: 'Aucune mesure trouvée avec cet ID.' });
|
});
|
||||||
}
|
|
||||||
res.status(200).json({ message: 'Mesure supprimée avec succès', id: measurementId });
|
router.delete('/measurements/:projectId/:orderId', async (req, res) => {
|
||||||
});
|
const projectId = req.params.projectId;
|
||||||
|
const orderId = req.params.orderId;
|
||||||
|
if (!projectId || isNaN(projectId) || !orderId || isNaN(orderId)) {
|
||||||
|
return res.status(400).json({ error: 'Invalid project ID or order ID' });
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const measurement = await measureManager.deleteMeasurementByOrderId(projectId, orderId);
|
||||||
|
res.status(200).json({ message: 'Measurement deleted successfully', id: measurement.id });
|
||||||
|
} catch (error) {
|
||||||
|
serverError.sendError('Error deleting measurement:', res, error);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -561,7 +586,6 @@ const upload = multer({ storage: multer.memoryStorage() });
|
|||||||
* 500:
|
* 500:
|
||||||
* description: Internal server error
|
* description: Internal server error
|
||||||
*/
|
*/
|
||||||
|
|
||||||
router.post('/upload', upload.single('image'), async (req, res) => {
|
router.post('/upload', upload.single('image'), async (req, res) => {
|
||||||
const { projectId, orderId } = req.body;
|
const { projectId, orderId } = req.body;
|
||||||
const image = req.file; // Multer adds the file to req.file
|
const image = req.file; // Multer adds the file to req.file
|
||||||
@@ -578,4 +602,54 @@ router.post('/upload', upload.single('image'), async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /uploadmeasurement:
|
||||||
|
* post:
|
||||||
|
* description: Use to upload a measurement with an image
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* multipart/form-data:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* image:
|
||||||
|
* type: string
|
||||||
|
* format: binary
|
||||||
|
* projectId:
|
||||||
|
* type: integer
|
||||||
|
* timestamp:
|
||||||
|
* type: string
|
||||||
|
* format: date-time
|
||||||
|
* temperature:
|
||||||
|
* type: number
|
||||||
|
* humidity:
|
||||||
|
* type: number
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Measurement uploaded successfully
|
||||||
|
* 400:
|
||||||
|
* description: All fields are required
|
||||||
|
* 500:
|
||||||
|
* description: Internal server error
|
||||||
|
*/
|
||||||
|
router.post('/uploadmeasurement', upload.single('image'), async (req, res) => {
|
||||||
|
const { projectId, timestamp, temperature, humidity } = req.body;
|
||||||
|
const image = req.file; // Multer adds the file to req.file
|
||||||
|
|
||||||
|
if (!image || !projectId || !timestamp || !temperature || !humidity) {
|
||||||
|
return res.status(400).json({ error: 'All fields are required' });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const nextOrderId = await measureManager.getNextOrderId(projectId);
|
||||||
|
const imagePath = await measureManager.uploadMeasureImage(image, projectId, nextOrderId);
|
||||||
|
const measurement = await measureManager.addMeasureToProject(projectId, timestamp, imagePath, temperature, humidity, nextOrderId);
|
||||||
|
res.json({ message: 'Measurement uploaded successfully', path: imagePath, id: measurement.id });
|
||||||
|
} catch (error) {
|
||||||
|
serverError.sendError('Error uploading measurement:', res, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
42
src/data/filewatcher.js
Normal file
42
src/data/filewatcher.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import db from '../../db.js';
|
||||||
|
import path from 'path';
|
||||||
|
import storageManager from '../data/storageManager.js';
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
|
async function checkAndRemoveInvalidEntries() {
|
||||||
|
console.log('Checking for invalid entries...');
|
||||||
|
try {
|
||||||
|
const measurementsRes = await db.query('SELECT id, path FROM measurements');
|
||||||
|
console.log('Fetched measurements:', measurementsRes.rows);
|
||||||
|
for (const row of measurementsRes.rows) {
|
||||||
|
console.log('Checking file path:', row.path);
|
||||||
|
if (!fs.existsSync(row.path)) {
|
||||||
|
// Remove invalid entry
|
||||||
|
await db.query('DELETE FROM measurements WHERE id = $1', [row.id]);
|
||||||
|
console.log(`Deleted invalid measurement entry with id: ${row.id}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan all images in storage
|
||||||
|
const allImages = await storageManager.scanAllImages();
|
||||||
|
console.log('Scanned all images:', allImages);
|
||||||
|
for (const imagePath of allImages) {
|
||||||
|
const entryRes = await db.query('SELECT id FROM measurements WHERE path = $1', [imagePath]);
|
||||||
|
if (entryRes.rows.length === 0) {
|
||||||
|
// Remove the file if the entry does not exist
|
||||||
|
fs.unlinkSync(imagePath);
|
||||||
|
console.log(`Deleted file at path: ${imagePath} as its database entry does not exist`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error checking and removing invalid entries:', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Run the check periodically
|
||||||
|
setInterval(checkAndRemoveInvalidEntries, 10000); // Every second
|
||||||
|
|
||||||
|
// Initial run
|
||||||
|
checkAndRemoveInvalidEntries();
|
||||||
@@ -19,6 +19,27 @@ function deleteFolder(name){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function scanAllImages(dir = 'storage') {
|
||||||
|
const projectDir = path.join(PROJECTS_DIR, dir);
|
||||||
|
let results = [];
|
||||||
|
|
||||||
|
function scanDirectory(directory) {
|
||||||
|
const files = fs.readdirSync(directory);
|
||||||
|
files.forEach(file => {
|
||||||
|
const filePath = path.join(directory, file);
|
||||||
|
const stat = fs.statSync(filePath);
|
||||||
|
if (stat.isDirectory()) {
|
||||||
|
scanDirectory(filePath);
|
||||||
|
} else if (file.endsWith('.jpg')) {
|
||||||
|
results.push(filePath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
scanDirectory(projectDir);
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
function saveFile(filePath, content) {
|
function saveFile(filePath, content) {
|
||||||
// Ensure content is a buffer
|
// Ensure content is a buffer
|
||||||
if (Buffer.isBuffer(content)) {
|
if (Buffer.isBuffer(content)) {
|
||||||
@@ -28,16 +49,23 @@ function saveFile(filePath, content) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function getFile(name){
|
function getFile(name){
|
||||||
const filePath = path.join(PROJECTS_DIR, `${name}`);
|
const filePath = path.join(PROJECTS_DIR, `${name}`);
|
||||||
return fs
|
return fs
|
||||||
.readFileSync(filePath);
|
.readFileSync(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function deleteFile(name){
|
||||||
|
const filePath = path.join(PROJECTS_DIR, `${name}`);
|
||||||
|
if (fs.existsSync(filePath))
|
||||||
|
fs.rmSync(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
createFolder,
|
createFolder,
|
||||||
deleteFolder,
|
deleteFolder,
|
||||||
|
scanAllImages,
|
||||||
saveFile,
|
saveFile,
|
||||||
getFile
|
getFile,
|
||||||
|
deleteFile
|
||||||
};
|
};
|
||||||
@@ -11,21 +11,77 @@ async function uploadMeasureImage(image, projectId, orderId) {
|
|||||||
return imagePath;
|
return imagePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function getMeasureImage(projectId, orderId) {
|
async function getMeasureImage(projectId, orderId) {
|
||||||
const projectPath = `${projectId}`;
|
const projectPath = `${projectId}`;
|
||||||
const imagePath = `${projectPath}/${orderId}.jpg`;
|
const imagePath = `${projectPath}/${orderId}.jpg`;
|
||||||
return storageManager.getFile(imagePath);
|
return storageManager.getFile(imagePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addMeasureToProject(projectId, timestamp, imagePath, temperature, humidity, completed) {
|
async function getNextOrderId(projectId) {
|
||||||
const query = 'INSERT INTO public.measurements (project_id, timestamp, image_path, temperature, humidity, completed) VALUES ($1, $2, $3, $4, $5, $6) RETURNING *';
|
const query = 'SELECT MAX(order_id) FROM public.measurements WHERE project_id = $1';
|
||||||
const values = [projectId, timestamp, imagePath, temperature, humidity, completed];
|
const values = [projectId];
|
||||||
|
const res = await db.query(query, values);
|
||||||
|
return res.rows[0].max + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addMeasureToProject(projectId, orderId, timestamp, path, temperature, humidity) {
|
||||||
|
const query = 'INSERT INTO public.measurements (project_id, timestamp, path, temperature, humidity, order_id) VALUES ($1, $2, $3, $4, $5, $6) RETURNING *';
|
||||||
|
const values = [projectId, orderId, timestamp, path, temperature, humidity];
|
||||||
|
const res = await db.query(query, values);
|
||||||
|
return res.rows[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getMeasurements(projectId) {
|
||||||
|
const query = 'SELECT * FROM public.measurements WHERE project_id = $1';
|
||||||
|
const values = [projectId];
|
||||||
|
const res = await db.query(query, values);
|
||||||
|
return res.rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getMeasurement(projectId, orderId) {
|
||||||
|
const query = 'SELECT * FROM public.measurements WHERE project_id = $1 AND order_id = $2';
|
||||||
|
const values = [projectId, orderId];
|
||||||
|
const res = await db.query(query, values);
|
||||||
|
return res.rows[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getMeasurementById(id) {
|
||||||
|
const query = 'SELECT * FROM public.measurements WHERE id = $1';
|
||||||
|
const values = [id];
|
||||||
|
const res = await db.query(query, values);
|
||||||
|
return res.rows[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateMeasurement(projectId, orderId, timestamp, path, temperature, humidity) {
|
||||||
|
const query = 'UPDATE public.measurements SET timestamp = $3, path = $4, temperature = $5, humidity = $6 WHERE project_id = $1 AND order_id = $2 RETURNING *';
|
||||||
|
const values = [projectId, orderId, timestamp, path, temperature, humidity];
|
||||||
|
const res = await db.query(query, values);
|
||||||
|
return res.rows[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateMeasurementById(id, timestamp, path, temperature, humidity) {
|
||||||
|
const query = 'UPDATE public.measurements SET timestamp = $2, path = $3, temperature = $4, humidity = $5 WHERE id = $1 RETURNING *';
|
||||||
|
const values = [id, timestamp, path, temperature, humidity];
|
||||||
|
const res = await db.query(query, values);
|
||||||
|
return res.rows[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteMeasurement(id) {
|
||||||
|
const query = 'DELETE FROM public.measurements WHERE id = $1';
|
||||||
|
const values = [id];
|
||||||
const res = await db.query(query, values);
|
const res = await db.query(query, values);
|
||||||
return res.rows[0];
|
return res.rows[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
uploadMeasureImage,
|
uploadMeasureImage,
|
||||||
addMeasureToProject
|
addMeasureToProject,
|
||||||
|
getNextOrderId,
|
||||||
|
getMeasurements,
|
||||||
|
getMeasurement,
|
||||||
|
updateMeasurement,
|
||||||
|
deleteMeasurement,
|
||||||
|
getMeasureImage,
|
||||||
|
getMeasurementById,
|
||||||
|
updateMeasurementById
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user