Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| efaa49912e | |||
| bd9a9b70a1 | |||
| cbb18e0ca2 | |||
| a80193dadc | |||
| 33b55e0dc0 | |||
| f56c35c5f9 | |||
| 66d51f24d9 | |||
| 042ea5cc50 | |||
| 08fa489f4c | |||
| 83b7f14778 | |||
| 3f34fdeef3 | |||
| 4df3dae224 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,3 +2,4 @@ node_modules/
|
|||||||
info.log
|
info.log
|
||||||
storage/
|
storage/
|
||||||
uploads/
|
uploads/
|
||||||
|
package-lock.json
|
||||||
4
db.js
4
db.js
@@ -1,6 +1,6 @@
|
|||||||
const { Client } = require('pg');
|
const { Client } = require('pg');
|
||||||
|
|
||||||
const local = true;
|
const local = false;
|
||||||
// Connexion à la base de données PostgreSQL
|
// Connexion à la base de données PostgreSQL
|
||||||
const client = new Client({
|
const client = new Client({
|
||||||
host: local ? 'mikoshi' : '172.30.0.2',
|
host: local ? 'mikoshi' : '172.30.0.2',
|
||||||
@@ -16,7 +16,7 @@ function connectWithRetry() {
|
|||||||
console.error('Erreur de connexion à la base de données:', err);
|
console.error('Erreur de connexion à la base de données:', err);
|
||||||
setTimeout(connectWithRetry, 30000); // Réessayer après 30 secondes
|
setTimeout(connectWithRetry, 30000); // Réessayer après 30 secondes
|
||||||
} else {
|
} else {
|
||||||
console.log('Connecté à la base de données PostgreSQL.');
|
console.log('[DB] Connecté à la base de données PostgreSQL.');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const serverError = require('../utils/serverError');
|
|||||||
* summary: Retrieve a smile image
|
* summary: Retrieve a smile image
|
||||||
* responses:
|
* responses:
|
||||||
* 200:
|
* 200:
|
||||||
* description: Smile image retrieved successfully
|
* description: A smile image
|
||||||
* content:
|
* content:
|
||||||
* image/jpeg:
|
* image/jpeg:
|
||||||
* schema:
|
* schema:
|
||||||
@@ -23,67 +23,65 @@ const serverError = require('../utils/serverError');
|
|||||||
* description: Image not found
|
* description: Image not found
|
||||||
*/
|
*/
|
||||||
router.get('/smile', (req, res) => {
|
router.get('/smile', (req, res) => {
|
||||||
const imagePath = dbTester.getSmileImage();
|
const imagePath = dbTester.getSmileImage();
|
||||||
fs.access(imagePath, fs.constants.F_OK, (err) => {
|
fs.access(imagePath, fs.constants.F_OK, (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error('Image not found:', err);
|
console.error('Image not found:', err);
|
||||||
return res.status(404).json({ error: 'Image not found' });
|
return res.status(404).json({ error: 'Image not found' });
|
||||||
}
|
}
|
||||||
res.sendFile(imagePath);
|
res.sendFile(imagePath);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @swagger
|
* @swagger
|
||||||
* /images/{projectId}/{orderId}:
|
* /images/{projectId}/{orderId}:
|
||||||
* get:
|
* get:
|
||||||
* summary: Retrieve an image by project ID and order ID
|
* summary: Retrieve an image by project and order ID
|
||||||
* parameters:
|
* parameters:
|
||||||
* - in: path
|
* - in: path
|
||||||
* name: projectId
|
* name: projectId
|
||||||
* required: true
|
* required: true
|
||||||
* schema:
|
* schema:
|
||||||
* type: string
|
* type: string
|
||||||
* description: The ID of the project
|
* description: The project ID
|
||||||
* - in: path
|
* - in: path
|
||||||
* name: orderId
|
* name: orderId
|
||||||
* required: true
|
* required: true
|
||||||
* schema:
|
* schema:
|
||||||
* type: string
|
* type: string
|
||||||
* description: The ID of the order
|
* description: The order ID
|
||||||
* responses:
|
* responses:
|
||||||
* 200:
|
* 200:
|
||||||
* description: Image retrieved successfully
|
* description: An image file
|
||||||
* content:
|
* content:
|
||||||
* image/jpeg:
|
* application/octet-stream:
|
||||||
* schema:
|
* schema:
|
||||||
* type: string
|
* type: string
|
||||||
* format: binary
|
* format: binary
|
||||||
* 404:
|
* 404:
|
||||||
* description: Image not found
|
* description: Image not found
|
||||||
* 500:
|
|
||||||
* description: Internal server error
|
|
||||||
*/
|
*/
|
||||||
router.get('/images/:projectId/:orderId', (req, res) => {
|
router.get('/images/:projectId/:orderId', (req, res) => {
|
||||||
const projectId = req.params.projectId;
|
const projectId = req.params.projectId;
|
||||||
const orderId = req.params.orderId;
|
const orderId = req.params.orderId;
|
||||||
const query = 'SELECT path FROM public.measurements WHERE project_id = $1 AND order_id = $2';
|
const query = 'SELECT path FROM public.measurements WHERE project_id = $1 AND order_id = $2';
|
||||||
db.query(query, [projectId, orderId], (err, results) => {
|
db.query(query, [projectId, orderId], (err, results) => {
|
||||||
if (err) {
|
|
||||||
return serverError.sendError('Error getting image:', res, err);
|
|
||||||
}
|
|
||||||
if (results.rows.length === 0) {
|
|
||||||
return res.status(404).json({ error: 'Image not found' });
|
|
||||||
}
|
|
||||||
const imagePath = results.rows[0].path;
|
|
||||||
fs.access(imagePath, fs.constants.F_OK, (err) => {
|
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error('Image not found:', err);
|
return serverError.sendError('Error getting image:', res, err);
|
||||||
return res.status(404).json({ error: 'Image not found' });
|
|
||||||
}
|
}
|
||||||
res.download(imagePath);
|
if (results.rows.length === 0) {
|
||||||
});
|
return res.status(404).json({ error: 'Image not found' });
|
||||||
});
|
}
|
||||||
|
const imagePath = results.rows[0].path;
|
||||||
|
fs.access(imagePath, fs.constants.F_OK, (err) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('Image not found:', err);
|
||||||
|
return res.status(404).json({ error: 'Image not found' });
|
||||||
|
}
|
||||||
|
res.download(imagePath);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@@ -18,18 +18,32 @@ const serverError = require('../utils/serverError');
|
|||||||
* schema:
|
* schema:
|
||||||
* type: array
|
* type: array
|
||||||
* items:
|
* items:
|
||||||
* $ref: '#/components/schemas/Measurement'
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* id:
|
||||||
|
* type: integer
|
||||||
|
* project_id:
|
||||||
|
* type: integer
|
||||||
|
* timestamp:
|
||||||
|
* type: string
|
||||||
|
* format: date-time
|
||||||
|
* image_path:
|
||||||
|
* type: string
|
||||||
|
* temperature:
|
||||||
|
* type: number
|
||||||
|
* humidity:
|
||||||
|
* type: number
|
||||||
* 500:
|
* 500:
|
||||||
* description: Erreur serveur.
|
* description: Erreur serveur.
|
||||||
*/
|
*/
|
||||||
router.get('/measurements', (req, res) => {
|
router.get('/measurements', (req, res) => {
|
||||||
const query = 'SELECT * FROM public.measurements';
|
const query = 'SELECT * FROM public.measurements';
|
||||||
db.query(query, (err, results) => {
|
db.query(query, (err, results) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
serverError.sendError('Erreur lors de la récupération des mesures:', res, err);
|
serverError.sendError('Erreur lors de la récupération des mesures:', res, err);
|
||||||
}
|
}
|
||||||
res.json(results.rows);
|
res.json(results.rows);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,24 +65,38 @@ router.get('/measurements', (req, res) => {
|
|||||||
* content:
|
* content:
|
||||||
* application/json:
|
* application/json:
|
||||||
* schema:
|
* schema:
|
||||||
* $ref: '#/components/schemas/Measurement'
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* id:
|
||||||
|
* type: integer
|
||||||
|
* project_id:
|
||||||
|
* type: integer
|
||||||
|
* timestamp:
|
||||||
|
* type: string
|
||||||
|
* format: date-time
|
||||||
|
* image_path:
|
||||||
|
* type: string
|
||||||
|
* temperature:
|
||||||
|
* type: number
|
||||||
|
* humidity:
|
||||||
|
* type: number
|
||||||
* 400:
|
* 400:
|
||||||
* description: ID de mesure invalide.
|
* description: ID de mesure invalide.
|
||||||
* 500:
|
* 500:
|
||||||
* description: Erreur serveur.
|
* description: Erreur serveur.
|
||||||
*/
|
*/
|
||||||
router.get('/measurements/:id', (req, res) => {
|
router.get('/measurements/:id', (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 = 'SELECT * FROM public.measurements WHERE id = $1';
|
const query = 'SELECT * FROM public.measurements WHERE id = $1';
|
||||||
db.query(query, [measurementId], (err, results) => {
|
db.query(query, [measurementId], (err, results) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
serverError.sendError('Erreur lors de la récupération de la mesure:', res, err);
|
serverError.sendError('Erreur lors de la récupération de la mesure:', res, err);
|
||||||
}
|
}
|
||||||
res.json(results.rows);
|
res.json(results.rows);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -96,24 +124,38 @@ router.get('/measurements/:id', (req, res) => {
|
|||||||
* content:
|
* content:
|
||||||
* application/json:
|
* application/json:
|
||||||
* schema:
|
* schema:
|
||||||
* $ref: '#/components/schemas/Measurement'
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* id:
|
||||||
|
* type: integer
|
||||||
|
* project_id:
|
||||||
|
* type: integer
|
||||||
|
* timestamp:
|
||||||
|
* type: string
|
||||||
|
* format: date-time
|
||||||
|
* image_path:
|
||||||
|
* type: string
|
||||||
|
* temperature:
|
||||||
|
* type: number
|
||||||
|
* humidity:
|
||||||
|
* type: number
|
||||||
* 400:
|
* 400:
|
||||||
* description: ID de projet ou de commande invalide.
|
* description: ID de projet ou de commande invalide.
|
||||||
* 500:
|
* 500:
|
||||||
* description: Erreur serveur.
|
* description: Erreur serveur.
|
||||||
*/
|
*/
|
||||||
router.get('/measurements/:projectId/:orderId', async (req, res) => {
|
router.get('/measurements/:projectId/:orderId', async (req, res) => {
|
||||||
const projectId = req.params.projectId;
|
const projectId = req.params.projectId;
|
||||||
const orderId = req.params.orderId;
|
const orderId = req.params.orderId;
|
||||||
if (!projectId || isNaN(projectId) || !orderId || isNaN(orderId)) {
|
if (!projectId || isNaN(projectId) || !orderId || isNaN(orderId)) {
|
||||||
return res.status(400).json({ error: 'Invalid project ID or order ID' });
|
return res.status(400).json({ error: 'Invalid project ID or order ID' });
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const measurement = await measureManager.getMeasurement(projectId, orderId);
|
const measurement = await measureManager.getMeasurement(projectId, orderId);
|
||||||
res.json(measurement);
|
res.json(measurement);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
serverError.sendError('Error getting measurement:', res, error);
|
serverError.sendError('Error getting measurement:', res, error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -149,17 +191,17 @@ router.get('/measurements/:projectId/:orderId', async (req, res) => {
|
|||||||
* description: Erreur serveur.
|
* description: Erreur serveur.
|
||||||
*/
|
*/
|
||||||
router.post('/measurements', (req, res) => {
|
router.post('/measurements', (req, res) => {
|
||||||
const { project_id, timestamp, image_path, temperature, humidity } = req.body;
|
const { project_id, timestamp, image_path, temperature, humidity } = req.body;
|
||||||
if (!project_id || !timestamp || !image_path || !temperature || !humidity) {
|
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) VALUES ($1, $2, $3, $4, $5) RETURNING id';
|
const query = 'INSERT INTO public.measurements (project_id, timestamp, image_path, temperature, humidity) VALUES ($1, $2, $3, $4, $5) RETURNING id';
|
||||||
db.query(query, [project_id, timestamp, image_path, temperature, humidity], (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);
|
||||||
}
|
}
|
||||||
res.status(201).json({ message: 'Mesure ajoutée avec succès', id: results.rows[0].id });
|
res.status(201).json({ message: 'Mesure ajoutée avec succès', id: results.rows[0].id });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -184,16 +226,16 @@ router.post('/measurements', (req, res) => {
|
|||||||
* description: Erreur serveur.
|
* description: Erreur serveur.
|
||||||
*/
|
*/
|
||||||
router.delete('/measurements/:id', async (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' });
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const measurement = await measureManager.deleteMeasurement(measurementId);
|
const measurement = await measureManager.deleteMeasurement(measurementId);
|
||||||
res.status(200).json({ message: 'Measurement deleted successfully', id: measurementId });
|
res.status(200).json({ message: 'Measurement deleted successfully', id: measurementId });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
serverError.sendError('Error deleting measurement:', res, error);
|
serverError.sendError('Error deleting measurement:', res, error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -224,17 +266,17 @@ router.delete('/measurements/:id', async (req, res) => {
|
|||||||
* description: Erreur serveur.
|
* description: Erreur serveur.
|
||||||
*/
|
*/
|
||||||
router.delete('/measurements/:projectId/:orderId', async (req, res) => {
|
router.delete('/measurements/:projectId/:orderId', async (req, res) => {
|
||||||
const projectId = req.params.projectId;
|
const projectId = req.params.projectId;
|
||||||
const orderId = req.params.orderId;
|
const orderId = req.params.orderId;
|
||||||
if (!projectId || isNaN(projectId) || !orderId || isNaN(orderId)) {
|
if (!projectId || isNaN(projectId) || !orderId || isNaN(orderId)) {
|
||||||
return res.status(400).json({ error: 'Invalid project ID or order ID' });
|
return res.status(400).json({ error: 'Invalid project ID or order ID' });
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const measurement = await measureManager.deleteMeasurementByOrderId(projectId, orderId);
|
const measurement = await measureManager.deleteMeasurementByOrderId(projectId, orderId);
|
||||||
res.status(200).json({ message: 'Measurement deleted successfully', id: measurement.id });
|
res.status(200).json({ message: 'Measurement deleted successfully', id: measurement.id });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
serverError.sendError('Error deleting measurement:', res, error);
|
serverError.sendError('Error deleting measurement:', res, error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@@ -17,17 +17,17 @@ const serverError = require('../utils/serverError');
|
|||||||
* schema:
|
* schema:
|
||||||
* type: array
|
* type: array
|
||||||
* items:
|
* items:
|
||||||
* $ref: '#/components/schemas/Project'
|
* type: object
|
||||||
* 500:
|
* 500:
|
||||||
* description: Erreur serveur.
|
* description: Erreur serveur.
|
||||||
*/
|
*/
|
||||||
router.get('/projects', async (req, res) => {
|
router.get('/projects', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const projects = await projectManager.getAllProjects();
|
const projects = await projectManager.getAllProjects();
|
||||||
res.json(projects);
|
res.json(projects);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
serverError.sendError('Error getting all projects:', res, error);
|
serverError.sendError('Error getting all projects:', res, error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -49,23 +49,23 @@ router.get('/projects', async (req, res) => {
|
|||||||
* content:
|
* content:
|
||||||
* application/json:
|
* application/json:
|
||||||
* schema:
|
* schema:
|
||||||
* $ref: '#/components/schemas/Project'
|
* type: object
|
||||||
* 400:
|
* 400:
|
||||||
* description: ID de projet invalide.
|
* description: ID de projet invalide.
|
||||||
* 500:
|
* 500:
|
||||||
* description: Erreur serveur.
|
* description: Erreur serveur.
|
||||||
*/
|
*/
|
||||||
router.get('/projects/:id', async (req, res) => {
|
router.get('/projects/:id', async (req, res) => {
|
||||||
const projectId = req.params.id;
|
const projectId = req.params.id;
|
||||||
if (!projectId || isNaN(projectId)) {
|
if (!projectId || isNaN(projectId)) {
|
||||||
return res.status(400).json({ error: 'Invalid project ID' });
|
return res.status(400).json({ error: 'Invalid project ID' });
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const project = await projectManager.getProjectById(projectId);
|
const project = await projectManager.getProjectById(projectId);
|
||||||
res.json(project);
|
res.json(project);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
serverError.sendError('Error getting project by ID:', res, error);
|
serverError.sendError('Error getting project by ID:', res, error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -89,23 +89,23 @@ router.get('/projects/:id', async (req, res) => {
|
|||||||
* schema:
|
* schema:
|
||||||
* type: array
|
* type: array
|
||||||
* items:
|
* items:
|
||||||
* $ref: '#/components/schemas/Video'
|
* type: object
|
||||||
* 400:
|
* 400:
|
||||||
* description: ID de projet invalide.
|
* description: ID de projet invalide.
|
||||||
* 500:
|
* 500:
|
||||||
* description: Erreur serveur.
|
* description: Erreur serveur.
|
||||||
*/
|
*/
|
||||||
router.get('/projects/:id/videos', async (req, res) => {
|
router.get('/projects/:id/videos', async (req, res) => {
|
||||||
const projectId = req.params.id;
|
const projectId = req.params.id;
|
||||||
if (!projectId || isNaN(projectId)) {
|
if (!projectId || isNaN(projectId)) {
|
||||||
return res.status(400).json({ error: 'Invalid project ID' });
|
return res.status(400).json({ error: 'Invalid project ID' });
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const videos = await projectManager.getVideosByProjectId(projectId);
|
const videos = await projectManager.getVideosByProjectId(projectId);
|
||||||
res.json(videos);
|
res.json(videos);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
serverError.sendError('Error getting videos by project ID:', res, error);
|
serverError.sendError('Error getting videos by project ID:', res, error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -129,23 +129,23 @@ router.get('/projects/:id/videos', async (req, res) => {
|
|||||||
* schema:
|
* schema:
|
||||||
* type: array
|
* type: array
|
||||||
* items:
|
* items:
|
||||||
* $ref: '#/components/schemas/Measurement'
|
* type: object
|
||||||
* 400:
|
* 400:
|
||||||
* description: ID de projet invalide.
|
* description: ID de projet invalide.
|
||||||
* 500:
|
* 500:
|
||||||
* description: Erreur serveur.
|
* description: Erreur serveur.
|
||||||
*/
|
*/
|
||||||
router.get('/projects/:id/measurements', async (req, res) => {
|
router.get('/projects/:id/measurements', async (req, res) => {
|
||||||
const projectId = req.params.id;
|
const projectId = req.params.id;
|
||||||
if (!projectId || isNaN(projectId)) {
|
if (!projectId || isNaN(projectId)) {
|
||||||
return res.status(400).json({ error: 'Invalid project ID' });
|
return res.status(400).json({ error: 'Invalid project ID' });
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const measurements = await projectManager.getMeasurementsByProjectId(projectId);
|
const measurements = await projectManager.getMeasurementsByProjectId(projectId);
|
||||||
res.json(measurements);
|
res.json(measurements);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
serverError.sendError('Error getting measurements by project ID:', res, error);
|
serverError.sendError('Error getting measurements by project ID:', res, error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -174,17 +174,17 @@ router.get('/projects/:id/measurements', async (req, res) => {
|
|||||||
* description: Erreur serveur.
|
* description: Erreur serveur.
|
||||||
*/
|
*/
|
||||||
router.post('/projects', async (req, res) => {
|
router.post('/projects', async (req, res) => {
|
||||||
const { name, description } = req.body;
|
const { name, description } = req.body;
|
||||||
if (!name || !description) {
|
if (!name || !description) {
|
||||||
return res.status(400).json({ error: 'Name and description are required' });
|
return res.status(400).json({ error: 'Name and description are required' });
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const project = await projectManager.createProject(name, description, new Date(), 0);
|
const project = await projectManager.createProject(name, description, new Date(), 0);
|
||||||
projectManager.createProjectDirectory(project.id);
|
projectManager.createProjectDirectory(project.id);
|
||||||
res.status(201).json({ message: 'Project added successfully', id: project.id });
|
res.status(201).json({ message: 'Project added successfully', id: project.id });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
serverError.sendError('Error creating project:', res, error);
|
serverError.sendError('Error creating project:', res, error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -209,17 +209,17 @@ router.post('/projects', async (req, res) => {
|
|||||||
* description: Erreur serveur.
|
* description: Erreur serveur.
|
||||||
*/
|
*/
|
||||||
router.delete('/projects/:id', async (req, res) => {
|
router.delete('/projects/:id', async (req, res) => {
|
||||||
const projectId = req.params.id;
|
const projectId = req.params.id;
|
||||||
if (!projectId || isNaN(projectId)) {
|
if (!projectId || isNaN(projectId)) {
|
||||||
return res.status(400).json({ error: 'Invalid project ID' });
|
return res.status(400).json({ error: 'Invalid project ID' });
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
projectManager.deleteProjectDirectory(projectId);
|
projectManager.deleteProjectDirectory(projectId);
|
||||||
projectManager.deleteProjectById(projectId);
|
projectManager.deleteProjectById(projectId);
|
||||||
res.status(200).json({ message: 'Project deleted successfully', id: projectId });
|
res.status(200).json({ message: 'Project deleted successfully', id: projectId });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
serverError.sendError('Error deleting project:', res, error);
|
serverError.sendError('Error deleting project:', res, error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@@ -12,21 +12,22 @@ const upload = multer({ storage: multer.memoryStorage() });
|
|||||||
* post:
|
* post:
|
||||||
* summary: Télécharger une image
|
* summary: Télécharger une image
|
||||||
* description: Télécharge une image pour un projet et un ordre spécifiques.
|
* description: Télécharge une image pour un projet et un ordre spécifiques.
|
||||||
* consumes:
|
* requestBody:
|
||||||
* - multipart/form-data
|
* content:
|
||||||
* parameters:
|
* multipart/form-data:
|
||||||
* - in: formData
|
* schema:
|
||||||
* name: image
|
* type: object
|
||||||
* type: file
|
* properties:
|
||||||
* description: Fichier image à télécharger
|
* image:
|
||||||
* - in: formData
|
* type: string
|
||||||
* name: projectId
|
* format: binary
|
||||||
* type: integer
|
* description: Fichier image à télécharger
|
||||||
* description: ID du projet
|
* projectId:
|
||||||
* - in: formData
|
* type: integer
|
||||||
* name: orderId
|
* description: ID du projet
|
||||||
* type: integer
|
* orderId:
|
||||||
* description: ID de la commande
|
* type: integer
|
||||||
|
* description: ID de la commande
|
||||||
* responses:
|
* responses:
|
||||||
* 200:
|
* 200:
|
||||||
* description: Image téléchargée avec succès.
|
* description: Image téléchargée avec succès.
|
||||||
@@ -66,30 +67,29 @@ router.post('/upload', upload.single('image'), async (req, res) => {
|
|||||||
* post:
|
* post:
|
||||||
* summary: Télécharger une mesure avec une image
|
* summary: Télécharger une mesure avec une image
|
||||||
* description: Télécharge une mesure avec une image pour un projet spécifique.
|
* description: Télécharge une mesure avec une image pour un projet spécifique.
|
||||||
* consumes:
|
* requestBody:
|
||||||
* - multipart/form-data
|
* content:
|
||||||
* parameters:
|
* multipart/form-data:
|
||||||
* - in: formData
|
* schema:
|
||||||
* name: image
|
* type: object
|
||||||
* type: file
|
* properties:
|
||||||
* description: Fichier image à télécharger
|
* image:
|
||||||
* - in: formData
|
* type: string
|
||||||
* name: projectId
|
* format: binary
|
||||||
* type: integer
|
* description: Fichier image à télécharger
|
||||||
* description: ID du projet
|
* projectId:
|
||||||
* - in: formData
|
* type: integer
|
||||||
* name: timestamp
|
* description: ID du projet
|
||||||
* type: string
|
* timestamp:
|
||||||
* format: date-time
|
* type: string
|
||||||
* description: Horodatage de la mesure
|
* format: date-time
|
||||||
* - in: formData
|
* description: Horodatage de la mesure
|
||||||
* name: temperature
|
* temperature:
|
||||||
* type: number
|
* type: number
|
||||||
* description: Température mesurée
|
* description: Température mesurée
|
||||||
* - in: formData
|
* humidity:
|
||||||
* name: humidity
|
* type: number
|
||||||
* type: number
|
* description: Humidité mesurée
|
||||||
* description: Humidité mesurée
|
|
||||||
* responses:
|
* responses:
|
||||||
* 200:
|
* 200:
|
||||||
* description: Mesure téléchargée avec succès.
|
* description: Mesure téléchargée avec succès.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ const express = require('express');
|
|||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const db = require('../db');
|
const db = require('../db');
|
||||||
const serverError = require('../utils/serverError');
|
const serverError = require('../utils/serverError');
|
||||||
|
const videoManager = require('../src/video/videoManager');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @swagger
|
* @swagger
|
||||||
@@ -17,18 +18,43 @@ const serverError = require('../utils/serverError');
|
|||||||
* schema:
|
* schema:
|
||||||
* type: array
|
* type: array
|
||||||
* items:
|
* items:
|
||||||
* $ref: '#/components/schemas/Video'
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* id:
|
||||||
|
* type: integer
|
||||||
|
* project_id:
|
||||||
|
* type: integer
|
||||||
|
* measurement_ids:
|
||||||
|
* type: string
|
||||||
|
* video_path:
|
||||||
|
* type: string
|
||||||
|
* start_timestamp:
|
||||||
|
* type: string
|
||||||
|
* end_timestamp:
|
||||||
|
* type: string
|
||||||
|
* image_count:
|
||||||
|
* type: integer
|
||||||
|
* resolution:
|
||||||
|
* type: string
|
||||||
|
* duration:
|
||||||
|
* type: number
|
||||||
|
* fps:
|
||||||
|
* type: number
|
||||||
|
* status:
|
||||||
|
* type: integer
|
||||||
|
* name:
|
||||||
|
* type: string
|
||||||
* 500:
|
* 500:
|
||||||
* description: Erreur serveur.
|
* description: Erreur serveur.
|
||||||
*/
|
*/
|
||||||
router.get('/videos', (req, res) => {
|
router.get('/videos', (req, res) => {
|
||||||
const query = 'SELECT * FROM public.videos';
|
const query = 'SELECT * FROM public.videos';
|
||||||
db.query(query, (err, results) => {
|
db.query(query, (err, results) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
serverError.sendError('Erreur lors de la récupération des vidéos:', res, err);
|
serverError.sendError('Erreur lors de la récupération des vidéos:', res, err);
|
||||||
}
|
}
|
||||||
res.json(results.rows);
|
res.json(results.rows);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,24 +76,49 @@ router.get('/videos', (req, res) => {
|
|||||||
* content:
|
* content:
|
||||||
* application/json:
|
* application/json:
|
||||||
* schema:
|
* schema:
|
||||||
* $ref: '#/components/schemas/Video'
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* id:
|
||||||
|
* type: integer
|
||||||
|
* project_id:
|
||||||
|
* type: integer
|
||||||
|
* measurement_ids:
|
||||||
|
* type: string
|
||||||
|
* video_path:
|
||||||
|
* type: string
|
||||||
|
* start_timestamp:
|
||||||
|
* type: string
|
||||||
|
* end_timestamp:
|
||||||
|
* type: string
|
||||||
|
* image_count:
|
||||||
|
* type: integer
|
||||||
|
* resolution:
|
||||||
|
* type: string
|
||||||
|
* duration:
|
||||||
|
* type: number
|
||||||
|
* fps:
|
||||||
|
* type: number
|
||||||
|
* status:
|
||||||
|
* type: integer
|
||||||
|
* name:
|
||||||
|
* type: string
|
||||||
* 400:
|
* 400:
|
||||||
* description: ID de vidéo invalide.
|
* description: ID de vidéo invalide.
|
||||||
* 500:
|
* 500:
|
||||||
* description: Erreur serveur.
|
* description: Erreur serveur.
|
||||||
*/
|
*/
|
||||||
router.get('/videos/:id', (req, res) => {
|
router.get('/videos/:id', (req, res) => {
|
||||||
const videoId = req.params.id;
|
const videoId = req.params.id;
|
||||||
if (!videoId || isNaN(videoId)) {
|
if (!videoId || isNaN(videoId)) {
|
||||||
return res.status(400).json({ error: 'Invalid video ID' });
|
return res.status(400).json({ error: 'Invalid video ID' });
|
||||||
}
|
}
|
||||||
const query = 'SELECT * FROM public.videos WHERE id = $1';
|
const query = 'SELECT * FROM public.videos WHERE id = $1';
|
||||||
db.query(query, [videoId], (err, results) => {
|
db.query(query, [videoId], (err, results) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
serverError.sendError('Erreur lors de la récupération de la vidéo:', res, err);
|
serverError.sendError('Erreur lors de la récupération de la vidéo:', res, err);
|
||||||
}
|
}
|
||||||
res.json(results.rows);
|
res.json(results.rows);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -104,40 +155,40 @@ router.get('/videos/:id', (req, res) => {
|
|||||||
* description: Erreur serveur.
|
* description: Erreur serveur.
|
||||||
*/
|
*/
|
||||||
router.post('/videos', (req, res) => {
|
router.post('/videos', (req, res) => {
|
||||||
const { project_id, measurement_ids, video_path, duration, resolution, name } = req.body;
|
const { project_id, measurement_ids, video_path, duration, resolution, name } = req.body;
|
||||||
if (!project_id || !measurement_ids || !video_path || !duration || !resolution || !name) {
|
if (!project_id || !measurement_ids || !video_path || !duration || !resolution || !name) {
|
||||||
return res.status(400).json({ error: 'All fields are required' });
|
return res.status(400).json({ error: 'All fields are required' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const list_ids = measurement_ids.split(',');
|
const list_ids = measurement_ids.split(',');
|
||||||
const image_count = list_ids.length;
|
const image_count = list_ids.length;
|
||||||
const videoPath = '/videos/' + name + '.mp4';
|
const videoPath = '/videos/' + name + '.mp4';
|
||||||
|
|
||||||
const query_first = 'SELECT timestamp FROM public.measurements WHERE id = $1';
|
const query_first = 'SELECT timestamp FROM public.measurements WHERE id = $1';
|
||||||
const query_last = 'SELECT timestamp FROM public.measurements WHERE id = $1';
|
const query_last = 'SELECT timestamp FROM public.measurements WHERE id = $1';
|
||||||
|
|
||||||
db.query(query_first, [list_ids[0]], (err, results) => {
|
db.query(query_first, [list_ids[0]], (err, results) => {
|
||||||
if (err) {
|
|
||||||
serverError.sendError('Erreur lors de la récupération du timestamp de la première image:', res, err);
|
|
||||||
}
|
|
||||||
const start_timestamp = results.rows[0].timestamp;
|
|
||||||
|
|
||||||
db.query(query_last, [list_ids[image_count - 1]], (err, results) => {
|
|
||||||
if (err) {
|
if (err) {
|
||||||
serverError.sendError('Erreur lors de la récupération du timestamp de la dernière image:', res, err);
|
serverError.sendError('Erreur lors de la récupération du timestamp de la première image:', res, err);
|
||||||
}
|
}
|
||||||
const end_timestamp = results.rows[0].timestamp;
|
const start_timestamp = results.rows[0].timestamp;
|
||||||
const fps = image_count / duration;
|
|
||||||
|
|
||||||
const query = 'INSERT INTO public.videos (project_id, measurement_ids, video_path, start_timestamp, end_timestamp, image_count, resolution, duration, fps, status, name) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING id';
|
db.query(query_last, [list_ids[image_count - 1]], (err, results) => {
|
||||||
db.query(query, [project_id, measurement_ids, videoPath, start_timestamp, end_timestamp, image_count, resolution, duration, fps, 0, name], (err, results) => {
|
if (err) {
|
||||||
if (err) {
|
serverError.sendError('Erreur lors de la récupération du timestamp de la dernière image:', res, err);
|
||||||
serverError.sendError('Erreur lors de l\'ajout de la vidéo:', res, err);
|
}
|
||||||
}
|
const end_timestamp = results.rows[0].timestamp;
|
||||||
res.status(201).json({ message: 'Vidéo ajoutée avec succès', id: results.rows[0].id });
|
const fps = image_count / duration;
|
||||||
|
|
||||||
|
const query = 'INSERT INTO public.videos (project_id, measurement_ids, video_path, start_timestamp, end_timestamp, image_count, resolution, duration, fps, status, name) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING id';
|
||||||
|
db.query(query, [project_id, measurement_ids, videoPath, start_timestamp, end_timestamp, image_count, resolution, duration, fps, 0, name], (err, results) => {
|
||||||
|
if (err) {
|
||||||
|
serverError.sendError('Erreur lors de l\'ajout de la vidéo:', res, err);
|
||||||
|
}
|
||||||
|
res.status(201).json({ message: 'Vidéo ajoutée avec succès', id: results.rows[0].id });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -164,20 +215,20 @@ router.post('/videos', (req, res) => {
|
|||||||
* description: Erreur serveur.
|
* description: Erreur serveur.
|
||||||
*/
|
*/
|
||||||
router.delete('/videos/:id', (req, res) => {
|
router.delete('/videos/:id', (req, res) => {
|
||||||
const videoId = req.params.id;
|
const videoId = req.params.id;
|
||||||
if (!videoId || isNaN(videoId)) {
|
if (!videoId || isNaN(videoId)) {
|
||||||
return res.status(400).json({ error: 'Invalid video ID' });
|
return res.status(400).json({ error: 'Invalid video ID' });
|
||||||
}
|
}
|
||||||
const query = 'DELETE FROM public.videos WHERE id = $1 RETURNING id';
|
const query = 'DELETE FROM public.videos WHERE id = $1 RETURNING id';
|
||||||
db.query(query, [videoId], (err, results) => {
|
db.query(query, [videoId], (err, results) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
serverError.sendError('Erreur lors de la suppression de la vidéo:', res, err);
|
serverError.sendError('Erreur lors de la suppression de la vidéo:', res, err);
|
||||||
}
|
}
|
||||||
if (results.rowCount === 0) {
|
if (results.rowCount === 0) {
|
||||||
return res.status(404).json({ error: 'Aucune vidéo trouvée avec cet ID.' });
|
return res.status(404).json({ error: 'Aucune vidéo trouvée avec cet ID.' });
|
||||||
}
|
}
|
||||||
res.status(200).json({ message: 'Vidéo supprimée avec succès', id: videoId });
|
res.status(200).json({ message: 'Vidéo supprimée avec succès', id: videoId });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@@ -60,6 +60,6 @@ app.get('/', (req, res) => {
|
|||||||
|
|
||||||
// Démarrer le serveur
|
// Démarrer le serveur
|
||||||
app.listen(port, () => {
|
app.listen(port, () => {
|
||||||
console.log(`Serveur démarré sur http://localhost:${port}`);
|
console.log(`[SERVER] Serveur démarré sur http://localhost:${port}`);
|
||||||
console.log(`Swagger documentation disponible sur http://localhost:${port}/api-docs`);
|
console.log(`[SERVER] Swagger documentation disponible sur http://localhost:${port}/api-docs`);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,17 +3,20 @@ import path from 'path';
|
|||||||
import storageManager from '../data/storageManager.js';
|
import storageManager from '../data/storageManager.js';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
|
||||||
|
let localCounter = 0;
|
||||||
|
|
||||||
async function checkAndRemoveInvalidEntries() {
|
async function checkAndRemoveInvalidEntries() {
|
||||||
console.log('Checking for invalid entries...');
|
localCounter = 0;
|
||||||
|
console.log('[INFO] Vérification et suppression des entrées invalides...');
|
||||||
try {
|
try {
|
||||||
const measurementsRes = await db.query('SELECT id, path FROM measurements');
|
const measurementsRes = await db.query('SELECT id, path FROM measurements');
|
||||||
//console.log('Fetched measurements:', measurementsRes.rows);
|
//console.log('Fetched measurements:', measurementsRes.rows);
|
||||||
for (const row of measurementsRes.rows) {
|
for (const row of measurementsRes.rows) {
|
||||||
//console.log('Checking file path:', row.path);
|
//console.log('Checking file path:', row.path);
|
||||||
if (!fs.existsSync(row.path)) {
|
if (!fs.existsSync(row.path)) {
|
||||||
// Remove invalid entry
|
|
||||||
await db.query('DELETE FROM measurements WHERE id = $1', [row.id]);
|
await db.query('DELETE FROM measurements WHERE id = $1', [row.id]);
|
||||||
console.log(`Deleted invalid measurement entry with id: ${row.id}`);
|
console.log(`Deleted invalid measurement entry with id: ${row.id}`);
|
||||||
|
localCounter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,8 +29,14 @@ async function checkAndRemoveInvalidEntries() {
|
|||||||
// Remove the file if the entry does not exist
|
// Remove the file if the entry does not exist
|
||||||
fs.unlinkSync(imagePath);
|
fs.unlinkSync(imagePath);
|
||||||
console.log(`Deleted file at path: ${imagePath} as its database entry does not exist`);
|
console.log(`Deleted file at path: ${imagePath} as its database entry does not exist`);
|
||||||
|
localCounter++; // Increment counter if entry is deleted
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (localCounter > 0) {
|
||||||
|
console.log(`[INFO] ${localCounter} entrées ont été modifiées`);
|
||||||
|
} else {
|
||||||
|
console.log('[INFO] Aucune entrée n\'a été modifiée.');
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error checking and removing invalid entries:', err);
|
console.error('Error checking and removing invalid entries:', err);
|
||||||
}
|
}
|
||||||
@@ -36,7 +45,8 @@ async function checkAndRemoveInvalidEntries() {
|
|||||||
|
|
||||||
|
|
||||||
// Run the check periodically
|
// Run the check periodically
|
||||||
setInterval(checkAndRemoveInvalidEntries, 10000); // Every second
|
console.log('[INFO] Activation du FileWatcher pour surveiller les fichiers invalides...')
|
||||||
|
setInterval(checkAndRemoveInvalidEntries, 10000); // Every 10 seconds
|
||||||
|
|
||||||
// Initial run
|
// Initial run
|
||||||
checkAndRemoveInvalidEntries();
|
checkAndRemoveInvalidEntries();
|
||||||
@@ -1,64 +1,80 @@
|
|||||||
const fs = require('fs');
|
const fs = require('fs').promises;
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const PROJECTS_DIR = path.join('.');
|
const PROJECTS_DIR = path.join('.');
|
||||||
|
|
||||||
function createFolder(name){
|
async function createFolder(name) {
|
||||||
const projectDir = path.join(PROJECTS_DIR, `${name}`);
|
const projectDir = path.join(PROJECTS_DIR, `${name}`);
|
||||||
if (!fs.existsSync(projectDir)) {
|
try {
|
||||||
fs.mkdirSync(projectDir, { recursive: true });
|
await fs.access(projectDir);
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code === 'ENOENT') {
|
||||||
|
await fs.mkdir(projectDir, { recursive: true });
|
||||||
|
} else {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return projectDir;
|
return projectDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteFolder(name){
|
async function deleteFolder(name) {
|
||||||
const projectDir = path.join(PROJECTS_DIR, `${name
|
const projectDir = path.join(PROJECTS_DIR, `${name}`);
|
||||||
}`);
|
try {
|
||||||
if (fs.existsSync
|
await fs.access(projectDir);
|
||||||
(projectDir)) {
|
await fs.rm(projectDir, { recursive: true, force: true });
|
||||||
fs.rmSync(projectDir, { recursive: true, force: true });
|
} catch (error) {
|
||||||
|
if (error.code !== 'ENOENT') {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function scanAllImages(dir = 'storage') {
|
async function scanAllImages(dir = 'storage') {
|
||||||
const projectDir = path.join(PROJECTS_DIR, dir);
|
const projectDir = path.join(PROJECTS_DIR, dir);
|
||||||
let results = [];
|
let results = [];
|
||||||
|
|
||||||
function scanDirectory(directory) {
|
async function scanDirectory(directory) {
|
||||||
const files = fs.readdirSync(directory);
|
const files = await fs.readdir(directory);
|
||||||
files.forEach(file => {
|
for (const file of files) {
|
||||||
const filePath = path.join(directory, file);
|
const filePath = path.join(directory, file);
|
||||||
const stat = fs.statSync(filePath);
|
const stat = await fs.stat(filePath);
|
||||||
if (stat.isDirectory()) {
|
if (stat.isDirectory()) {
|
||||||
scanDirectory(filePath);
|
await scanDirectory(filePath);
|
||||||
} else if (file.endsWith('.jpg')) {
|
} else if (file.endsWith('.jpg')) {
|
||||||
results.push(filePath);
|
results.push(filePath);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scanDirectory(projectDir);
|
await scanDirectory(projectDir);
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveFile(filePath, content) {
|
async function saveFile(filePath, content) {
|
||||||
// Ensure content is a buffer
|
|
||||||
if (Buffer.isBuffer(content)) {
|
if (Buffer.isBuffer(content)) {
|
||||||
fs.writeFileSync(filePath, content);
|
await fs.writeFile(filePath, content);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Content must be a buffer');
|
throw new Error('Content must be a buffer');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFile(name){
|
async function getFile(name) {
|
||||||
const filePath = path.join(PROJECTS_DIR, `${name}`);
|
const filePath = path.join(PROJECTS_DIR, `${name}`);
|
||||||
return fs
|
return await fs.readFile(filePath);
|
||||||
.readFileSync(filePath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteFile(name){
|
async function deleteFile(name) {
|
||||||
const filePath = path.join(PROJECTS_DIR, `${name}`);
|
const filePath = path.join(PROJECTS_DIR, `${name}`);
|
||||||
if (fs.existsSync(filePath))
|
try {
|
||||||
fs.rmSync(filePath);
|
await fs.access(filePath); // Vérifie si le fichier existe
|
||||||
|
await fs.rm(filePath); // Supprime le fichier
|
||||||
|
return `File ${filePath} deleted successfully.`;
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code === 'ENOENT') {
|
||||||
|
return `File ${filePath} does not exist.`;
|
||||||
|
} else {
|
||||||
|
throw error; // Relance l'erreur si ce n'est pas une erreur de fichier introuvable
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@@ -7,13 +7,14 @@ async function uploadMeasureImage(image, projectId, orderId) {
|
|||||||
const imagesDir = storageManager.createFolder(path.join(projectDir, 'images'));
|
const imagesDir = storageManager.createFolder(path.join(projectDir, 'images'));
|
||||||
var imagePath = path.join(imagesDir, `${orderId}.jpg`);
|
var imagePath = path.join(imagesDir, `${orderId}.jpg`);
|
||||||
storageManager.saveFile(imagePath, image.buffer);
|
storageManager.saveFile(imagePath, image.buffer);
|
||||||
|
console.log("[FILE] uploadMeasureImage - Image saved to: " + imagePath);
|
||||||
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`;
|
||||||
|
console.log("[FILE] getMeasureImage - Image path: " + imagePath);
|
||||||
return storageManager.getFile(imagePath);
|
return storageManager.getFile(imagePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,6 +22,7 @@ async function getNextOrderId(projectId) {
|
|||||||
const query = 'SELECT MAX(order_id) FROM public.measurements WHERE project_id = $1';
|
const query = 'SELECT MAX(order_id) FROM public.measurements WHERE project_id = $1';
|
||||||
const values = [projectId];
|
const values = [projectId];
|
||||||
const res = await db.query(query, values);
|
const res = await db.query(query, values);
|
||||||
|
console.log("[DB] getNextOrderId - Max order_id: " + res.rows[0].max);
|
||||||
return res.rows[0].max + 1;
|
return res.rows[0].max + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,6 +75,13 @@ async function deleteMeasurement(id) {
|
|||||||
return res.rows[0];
|
return res.rows[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getPathFromIds(projectId, orderId) {
|
||||||
|
const query = 'SELECT path 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].path;
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
uploadMeasureImage,
|
uploadMeasureImage,
|
||||||
addMeasureToProject,
|
addMeasureToProject,
|
||||||
@@ -83,5 +92,6 @@ export {
|
|||||||
deleteMeasurement,
|
deleteMeasurement,
|
||||||
getMeasureImage,
|
getMeasureImage,
|
||||||
getMeasurementById,
|
getMeasurementById,
|
||||||
updateMeasurementById
|
updateMeasurementById,
|
||||||
|
getPathFromIds
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,17 +6,19 @@ function createProjectDirectory(projectId) {
|
|||||||
storageManager.createFolder(projectPath);
|
storageManager.createFolder(projectPath);
|
||||||
storageManager.createFolder(`${projectPath}/images`);
|
storageManager.createFolder(`${projectPath}/images`);
|
||||||
storageManager.createFolder(`${projectPath}/videos`);
|
storageManager.createFolder(`${projectPath}/videos`);
|
||||||
|
console.log("[FILE] createProjectDirectory : " + projectPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteProjectDirectory(projectId) {
|
function deleteProjectDirectory(projectId) {
|
||||||
const projectPath = `${projectId}`;
|
const projectPath = `${projectId}`;
|
||||||
storageManager.deleteFolder(projectPath);
|
storageManager.deleteFolder(projectPath);
|
||||||
|
console.log("[FILE] deleteProjectDirectory : " + projectPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getAllProjects() {
|
async function getAllProjects() {
|
||||||
const query = 'SELECT * FROM public.projects';
|
const query = 'SELECT * FROM public.projects';
|
||||||
const res = await db.query(query);
|
const res = await db.query(query);
|
||||||
console.log('getAllProjects:', res.rows);
|
console.log("[DB] getAllProjects : ", res.rows);
|
||||||
return res.rows;
|
return res.rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,6 +26,7 @@ async function getProjectById(projectId) {
|
|||||||
const query = 'SELECT * FROM public.projects WHERE id = $1';
|
const query = 'SELECT * FROM public.projects WHERE id = $1';
|
||||||
const values = [projectId];
|
const values = [projectId];
|
||||||
const res = await db.query(query, values);
|
const res = await db.query(query, values);
|
||||||
|
console.log("[DB] getProjectById : ", res.rows[0]);
|
||||||
return res.rows[0];
|
return res.rows[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,6 +34,7 @@ async function createProject(name, description, start_date, status) {
|
|||||||
const query = 'INSERT INTO public.projects (name, description, start_date, status) VALUES ($1, $2, $3, $4) RETURNING *';
|
const query = 'INSERT INTO public.projects (name, description, start_date, status) VALUES ($1, $2, $3, $4) RETURNING *';
|
||||||
const values = [name, description, start_date, status];
|
const values = [name, description, start_date, status];
|
||||||
const res = await db.query(query, values);
|
const res = await db.query(query, values);
|
||||||
|
console.log("[DB] createProject : ", res.rows[0]);
|
||||||
return res.rows[0];
|
return res.rows[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,12 +42,14 @@ async function editProjectById(projectID, name, description, startDate, status)
|
|||||||
const query = 'UPDATE public.projects SET name = $1, description = $2, start_date = $3, status = $4 WHERE id = $5 RETURNING *';
|
const query = 'UPDATE public.projects SET name = $1, description = $2, start_date = $3, status = $4 WHERE id = $5 RETURNING *';
|
||||||
const values = [name, description, startDate, status, projectID];
|
const values = [name, description, startDate, status, projectID];
|
||||||
const res = await db.query(query, values);
|
const res = await db.query(query, values);
|
||||||
|
console.log("[DB] editProjectById : ", res.rows[0]);
|
||||||
return res.rows[0];
|
return res.rows[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteProjectById(projectId) {
|
async function deleteProjectById(projectId) {
|
||||||
const query = 'DELETE FROM public.projects WHERE id = $1';
|
const query = 'DELETE FROM public.projects WHERE id = $1';
|
||||||
const values = [projectId];
|
const values = [projectId];
|
||||||
|
console.log("[DB] deleteProjectById : ", values);
|
||||||
await db.query(query, values);
|
await db.query(query, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,6 +57,7 @@ async function getVideosByProjectId(projectId) {
|
|||||||
const query = 'SELECT * FROM public.videos WHERE project_id = $1';
|
const query = 'SELECT * FROM public.videos WHERE project_id = $1';
|
||||||
const values = [projectId];
|
const values = [projectId];
|
||||||
const res = await db.query(query, values);
|
const res = await db.query(query, values);
|
||||||
|
console.log("[DB] getVideosByProjectId : ", res.rows);
|
||||||
return res.rows;
|
return res.rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,6 +65,7 @@ async function getMeasurementsByProjectId(projectId) {
|
|||||||
const query = 'SELECT * FROM public.measurements WHERE project_id = $1';
|
const query = 'SELECT * FROM public.measurements WHERE project_id = $1';
|
||||||
const values = [projectId];
|
const values = [projectId];
|
||||||
const res = await db.query(query, values);
|
const res = await db.query(query, values);
|
||||||
|
console.log("[DB] getMeasurementsByProjectId : ", res.rows);
|
||||||
return res.rows;
|
return res.rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
111
src/video/videoManager.js
Normal file
111
src/video/videoManager.js
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const { execSync } = require('child_process');
|
||||||
|
|
||||||
|
const serverError = require('../../utils/serverError');
|
||||||
|
const db = require('../../db');
|
||||||
|
const storageManager = require('../data/storageManager');
|
||||||
|
const measureManager = require('../measure/measureManager');
|
||||||
|
|
||||||
|
const PROJECTS_DIR = path.join('.');
|
||||||
|
|
||||||
|
async function createVideoWithList(projectId, pathList) {
|
||||||
|
//pathList étant la liste des chemins déjà triés
|
||||||
|
const tempFile = path.join('temp.txt');
|
||||||
|
try {
|
||||||
|
// Trouver tous les fichiers image pour le projet donné
|
||||||
|
const workdir = path.join(PROJECTS_DIR, 'storage', `${projectId}`);
|
||||||
|
const dir = path.join(PROJECTS_DIR, 'storage', `${projectId}`, 'images');
|
||||||
|
console.log('dir:', dir);
|
||||||
|
const images = pathList;
|
||||||
|
console.log('images:', images);
|
||||||
|
|
||||||
|
// Trier les images numériquement
|
||||||
|
const sortedImages = images.sort((a, b) => {
|
||||||
|
const numA = parseInt(path.basename(a).match(/\d+/)[0], 10);
|
||||||
|
const numB = parseInt(path.basename(b).match(/\d+/)[0], 10);
|
||||||
|
return numA - numB;
|
||||||
|
});
|
||||||
|
|
||||||
|
// En déduire l'id de la première et dernière image utilisée
|
||||||
|
const firstImageId = parseInt(path.basename(sortedImages[0]).match(/\d+/)[0], 10);
|
||||||
|
const lastImageId = parseInt(path.basename(sortedImages[sortedImages.length - 1]).match(/\d+/)[0], 10);
|
||||||
|
|
||||||
|
console.log('firstImageId:', firstImageId);
|
||||||
|
console.log('lastImageId:', lastImageId);
|
||||||
|
|
||||||
|
// Créer un fichier temporaire pour la liste des images
|
||||||
|
fs.writeFileSync(tempFile, sortedImages.map(image => `file '${image}'`).join('\n'));
|
||||||
|
|
||||||
|
const frameRate = 10;
|
||||||
|
|
||||||
|
// le fichier final prend cette forme : {projectId}_{firstImageId}_{lastImageId}-{timestamp}.mp4
|
||||||
|
const timestamp = new Date().getTime();
|
||||||
|
const outputVideo = path.join(workdir, `${projectId}_${firstImageId}_${lastImageId}-${timestamp}.mp4`);
|
||||||
|
|
||||||
|
// Commande ffmpeg pour créer la vidéo
|
||||||
|
const ffmpegCommand = `ffmpeg -r ${frameRate} -f concat -safe 0 -i ${tempFile} -vsync vfr -pix_fmt yuv420p ${outputVideo}`;
|
||||||
|
console.log('Running ffmpeg command:', ffmpegCommand);
|
||||||
|
execSync(ffmpegCommand);
|
||||||
|
console.log('Video created successfully:', outputVideo);
|
||||||
|
return outputVideo;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error creating video:', error);
|
||||||
|
serverError(error);
|
||||||
|
} finally {
|
||||||
|
// Supprimer le fichier temporaire
|
||||||
|
if (fs.existsSync(tempFile)) {
|
||||||
|
fs.unlinkSync(tempFile);
|
||||||
|
console.log('Temporary file deleted:', tempFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createVideo(projectId) {
|
||||||
|
const tempFile = path.join('temp.txt');
|
||||||
|
try {
|
||||||
|
// Trouver tous les fichiers image pour le projet donné
|
||||||
|
const workdir = path.join(PROJECTS_DIR, 'storage', `${projectId}`);
|
||||||
|
const dir = path.join(PROJECTS_DIR, 'storage', `${projectId}`, 'images');
|
||||||
|
console.log('dir:', dir);
|
||||||
|
const images = storageManager.scanAllImages(dir);
|
||||||
|
console.log('images:', images);
|
||||||
|
|
||||||
|
// Trier les images numériquement
|
||||||
|
const sortedImages = images.sort((a, b) => {
|
||||||
|
const numA = parseInt(path.basename(a).match(/\d+/)[0], 10);
|
||||||
|
const numB = parseInt(path.basename(b).match(/\d+/)[0], 10);
|
||||||
|
return numA - numB;
|
||||||
|
});
|
||||||
|
|
||||||
|
// En déduire l'id de la première et dernière image utilisée
|
||||||
|
const firstImageId = parseInt(path.basename(sortedImages[0]).match(/\d+/)[0], 10);
|
||||||
|
const lastImageId = parseInt(path.basename(sortedImages[sortedImages.length - 1]).match(/\d+/)[0], 10);
|
||||||
|
|
||||||
|
console.log('firstImageId:', firstImageId);
|
||||||
|
console.log('lastImageId:', lastImageId);
|
||||||
|
|
||||||
|
// Créer un fichier temporaire pour la liste des images
|
||||||
|
fs.writeFileSync(tempFile, sortedImages.map(image => `file '${image}'`).join('\n'));
|
||||||
|
|
||||||
|
const frameRate = 10;
|
||||||
|
const outputVideo = path.join(workdir, 'video.mp4');
|
||||||
|
|
||||||
|
// Commande ffmpeg pour créer la vidéo
|
||||||
|
const ffmpegCommand = `ffmpeg -r ${frameRate} -f concat -safe 0 -i ${tempFile} -vsync vfr -pix_fmt yuv420p ${outputVideo}`;
|
||||||
|
console.log('Running ffmpeg command:', ffmpegCommand);
|
||||||
|
execSync(ffmpegCommand);
|
||||||
|
console.log('Video created successfully:', outputVideo);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error creating video:', error);
|
||||||
|
serverError(error);
|
||||||
|
} finally {
|
||||||
|
// Supprimer le fichier temporaire
|
||||||
|
if (fs.existsSync(tempFile)) {
|
||||||
|
fs.unlinkSync(tempFile);
|
||||||
|
console.log('Temporary file deleted:', tempFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { createVideo, createVideoWithList };
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
const storageManager = require('../src/data/storageManager');
|
const storageManager = require('../src/data/storageManager');
|
||||||
|
const videoManager = require('../src/video/videoManager');
|
||||||
|
const measureManager = require('../src/measure/measureManager');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
console.log('Testing database functions...');
|
// console.log('Testing database functions...');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
storageManager.createFolder('test_folder');
|
storageManager.createFolder('test_folder');
|
||||||
@@ -16,4 +18,34 @@ function getSmileImage() {
|
|||||||
return path.join(__dirname, '../sample/smile.png');
|
return path.join(__dirname, '../sample/smile.png');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//test de lancement d'une création de vidéo sur le projet 1
|
||||||
|
// videoManager.createVideo(1).then(res => {
|
||||||
|
// console.log('3 - Video created:', res);
|
||||||
|
// }).catch(err => {
|
||||||
|
// console.error('Error creating video:', err);
|
||||||
|
// });
|
||||||
|
// async function run() {
|
||||||
|
// var Path = await measureManager.getPathFromIds(1, 1);
|
||||||
|
// console.log(Path);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// run().catch(err => {
|
||||||
|
// console.error('Error:', err);
|
||||||
|
// });
|
||||||
|
|
||||||
|
var pathList = [
|
||||||
|
'storage/1/images/1.jpg',
|
||||||
|
'storage/1/images/10.jpg',
|
||||||
|
'storage/1/images/20.jpg',
|
||||||
|
'storage/1/images/30.jpg',
|
||||||
|
];
|
||||||
|
videoManager.createVideoWithList(1, pathList).then(res => {
|
||||||
|
console.log('3 - Video created:', res);
|
||||||
|
return storageManager.deleteFile(res);
|
||||||
|
}).then(res => {
|
||||||
|
console.log('4 - Video deleted:', res);
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Error:', err);
|
||||||
|
});
|
||||||
|
|
||||||
exports.getSmileImage = getSmileImage;
|
exports.getSmileImage = getSmileImage;
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
const { execSync } = require('child_process');
|
|
||||||
const serverError = require('../utils/serverError');
|
|
||||||
|
|
||||||
async function createVideo(projectId) {
|
|
||||||
const imageDir = `/storage/${projectId}`;
|
|
||||||
const outputVideo = `/storage/videos/output_${projectId}_video.mp4`;
|
|
||||||
const frameRate = 24;
|
|
||||||
const tempFile = `/storage/${projectId}/temp_file.txt`;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const images = fs.readdirSync(imageDir).filter(file => file.endsWith('.jpg'));
|
|
||||||
if (images.length === 0) {
|
|
||||||
throw new Error('No images found for this project');
|
|
||||||
}
|
|
||||||
|
|
||||||
const tempFileContent = images.map(img => `file '${path.join(imageDir, img)}'`).join('\n');
|
|
||||||
fs.writeFileSync(tempFile, tempFileContent);
|
|
||||||
|
|
||||||
const ffmpegCommand = `ffmpeg -r ${frameRate} -f concat -safe 0 -i ${tempFile} -vsync vfr -pix_fmt yuv420p ${outputVideo}`;
|
|
||||||
execSync(ffmpegCommand);
|
|
||||||
|
|
||||||
fs.unlinkSync(tempFile);
|
|
||||||
return { message: 'Video created successfully', videoPath: outputVideo };
|
|
||||||
} catch (error) {
|
|
||||||
throw new Error(`Error creating video: ${error.message}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = { createVideo };
|
|
||||||
Reference in New Issue
Block a user