Commit pour la declarations et lenregistrement de la donnéePremierCommit_GTF

This commit is contained in:
2025-09-15 15:38:05 +02:00
parent 74d6ed9dc1
commit b4061e8aff
53 changed files with 1387 additions and 260 deletions

Binary file not shown.

View File

@@ -1,12 +0,0 @@
{
"Version": 1,
"WorkspaceRootPath": "C:\\Users\\oimer\\OneDrive - ENSUP\\GTF_Git\\",
"Documents": [],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": []
}
]
}

View File

@@ -1,58 +0,0 @@
{
"Version": 1,
"WorkspaceRootPath": "C:\\Users\\oimer\\OneDrive - ENSUP\\GTF_Git\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\oimer\\OneDrive - ENSUP\\GTF_Git\\GTF\\project\\backend\\config\\test-db.js||{14D17961-FE51-464D-9111-C4AF11D7D99A}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:GTF\\project\\backend\\config\\test-db.js||{14D17961-FE51-464D-9111-C4AF11D7D99A}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\oimer\\OneDrive - ENSUP\\GTF_Git\\GTF\\project\\backend\\db.php||{3B902123-F8A7-4915-9F01-361F908088D0}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:GTF\\project\\backend\\db.php||{3B902123-F8A7-4915-9F01-361F908088D0}"
}
],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": 1,
"Children": [
{
"$type": "Bookmark",
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
},
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "test-db.js",
"DocumentMoniker": "C:\\Users\\oimer\\OneDrive - ENSUP\\GTF_Git\\GTF\\project\\backend\\config\\test-db.js",
"RelativeDocumentMoniker": "GTF\\project\\backend\\config\\test-db.js",
"ToolTip": "C:\\Users\\oimer\\OneDrive - ENSUP\\GTF_Git\\GTF\\project\\backend\\config\\test-db.js",
"RelativeToolTip": "GTF\\project\\backend\\config\\test-db.js",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABcAAABMAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001646|",
"WhenOpened": "2025-09-15T08:03:52.452Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "db.php",
"DocumentMoniker": "C:\\Users\\oimer\\OneDrive - ENSUP\\GTF_Git\\GTF\\project\\backend\\db.php",
"RelativeDocumentMoniker": "GTF\\project\\backend\\db.php",
"ToolTip": "C:\\Users\\oimer\\OneDrive - ENSUP\\GTF_Git\\GTF\\project\\backend\\db.php",
"RelativeToolTip": "GTF\\project\\backend\\db.php",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.002338|",
"WhenOpened": "2025-09-15T08:00:38.102Z",
"EditorCaption": ""
}
]
}
]
}
]
}

View File

@@ -1,3 +0,0 @@
{
"CurrentProjectSetting": null
}

View File

@@ -1,11 +0,0 @@
{
"ExpandedNodes": [
"",
"\\GTF",
"\\GTF\\project",
"\\GTF\\project\\backend",
"\\GTF\\project\\backend\\config"
],
"SelectedNode": "\\GTF\\project\\backend\\config\\test-db.js",
"PreviewInSolutionExplorer": false
}

Binary file not shown.

View File

@@ -1,5 +1,7 @@
DB_SERVER=Localhost
DB_SERVER=BONEMINE
DB_DATABASE=GTF
DB_USER=ENSUP\oimer
DB_PASSWORD=Wijdane123@
DB_USER=gtf_app
DB_PASSWORD=GTF2025!Secure
DB_ENCRYPT=true
DB_TRUST_SERVER_CERTIFICATE=true
PORT=3001

View File

@@ -0,0 +1,282 @@
const express = require('express');
const cors = require('cors');
const sql = require('mssql');
require('dotenv').config();
const app = express();
const PORT = 3001;
// Configuration base de données
const dbConfig = {
server: process.env.DB_SERVER,
database: process.env.DB_DATABASE,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
options: {
encrypt: true,
trustServerCertificate: true,
enableArithAbort: true
}
};
// Middleware
app.use(cors({
origin: ['http://localhost:5173', 'http://localhost:3000', 'http://127.0.0.1:5173'],
credentials: true
}));
app.use(express.json());
// Log de toutes les requêtes
app.use((req, res, next) => {
console.log(`${new Date().toISOString()} - ${req.method} ${req.path} depuis ${req.get('origin') || 'inconnu'}`);
next();
});
// Variable pour stocker la connexion
let pool = null;
// Fonction pour se connecter à la base
async function connectDatabase() {
try {
pool = await sql.connect(dbConfig);
console.log('Base de données connectée');
return true;
} catch (error) {
console.error('Erreur de connexion :', error.message);
return false;
}
}
// Route de test
app.get('/api/test', (req, res) => {
res.json({
message: 'Le serveur fonctionne !',
timestamp: new Date().toISOString()
});
});
// Route pour tester la base de données
app.get('/api/db-test', async (req, res) => {
try {
if (!pool) {
return res.status(500).json({ error: 'Base non connectée' });
}
const result = await pool.request().query('SELECT COUNT(*) as total FROM FormateurSqy');
res.json({
message: 'Base OK',
formateurs: result.recordset[0].total
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Route pour lister les formateurs
app.get('/api/formateurs', async (req, res) => {
try {
const result = await pool.request().query(`
SELECT TOP 10
NUMERO,
NOM_ENS as nom,
PRENOM_ENS as prenom,
EMAIL1 as email
FROM FormateurSqy
WHERE EMAIL1 IS NOT NULL
ORDER BY NOM_ENS
`);
res.json({
success: true,
data: result.recordset
});
} catch (error) {
res.status(500).json({
success: false,
error: error.message
});
}
});
// Route pour sauvegarder une déclaration
app.post('/api/save_declaration', async (req, res) => {
try {
const { date, activityType, hours, description, user } = req.body;
console.log('Données reçues:', { date, activityType, hours, description, user });
// Validation simple
if (!date || !activityType || !hours) {
return res.status(400).json({
success: false,
error: 'Données manquantes'
});
}
let formateurNumero;
if (user && user.email) {
// Chercher le formateur par email
const formateurResult = await pool.request()
.input('email', sql.VarChar, user.email)
.query('SELECT NUMERO FROM FormateurSqy WHERE EMAIL1 = @email');
if (formateurResult.recordset.length > 0) {
// Formateur trouvé
formateurNumero = formateurResult.recordset[0].NUMERO;
console.log('Formateur trouvé par email:', formateurNumero);
} else {
// Créer un nouveau formateur
const maxNumeroResult = await pool.request()
.query('SELECT ISNULL(MAX(NUMERO), 0) + 1 as nextNumero FROM FormateurSqy');
const nextNumero = maxNumeroResult.recordset[0].nextNumero;
await pool.request()
.input('numero', sql.Int, nextNumero)
.input('nom', sql.VarChar, user.nom || 'Inconnu')
.input('prenom', sql.VarChar, user.prenom || 'Inconnu')
.input('email', sql.VarChar, user.email)
.input('department', sql.VarChar, user.department || 'Non défini')
.input('role', sql.VarChar, user.role || 'Employé')
.query(`
INSERT INTO FormateurSqy (
NUMERO, NOM_ENS, PRENOM_ENS, EMAIL1, [Ecole - Pole], Contrat
) VALUES (
@numero, @nom, @prenom, @email, @department, @role
)
`);
formateurNumero = nextNumero;
console.log('Nouveau formateur créé:', formateurNumero);
}
} else {
// Fallback : utiliser un formateur par défaut
formateurNumero = 999;
console.log('Utilisation du formateur par défaut:', formateurNumero);
}
// Récupérer l'ID du type de demande
const typeResult = await pool.request()
.input('activityType', sql.VarChar, activityType)
.query('SELECT id FROM types_demandes WHERE libelle = @activityType');
if (typeResult.recordset.length === 0) {
return res.status(400).json({
success: false,
error: `Type d'activité invalide: ${activityType}`
});
}
const typeDemandeId = typeResult.recordset[0].id;
// Vérifier si une déclaration existe déjà pour cette date
const existingResult = await pool.request()
.input('formateurNumero', sql.Int, formateurNumero)
.input('date', sql.Date, date)
.query('SELECT id FROM declarations WHERE formateur_numero = @formateurNumero AND date = @date');
if (existingResult.recordset.length > 0) {
// Mise à jour
await pool.request()
.input('utilisateurId', sql.Int, formateurNumero)
.input('typeDemandeId', sql.Int, typeDemandeId)
.input('hours', sql.Float, hours)
.input('description', sql.NVarChar, description || null)
.input('formateurNumero', sql.Int, formateurNumero)
.input('date', sql.Date, date)
.query(`
UPDATE declarations
SET utilisateur_id = @utilisateurId, type_demande_id = @typeDemandeId, duree = @hours, description = @description
WHERE formateur_numero = @formateurNumero AND date = @date
`);
console.log('Déclaration mise à jour');
} else {
// Création
await pool.request()
.input('utilisateurId', sql.Int, formateurNumero)
.input('formateurNumero', sql.Int, formateurNumero)
.input('typeDemandeId', sql.Int, typeDemandeId)
.input('date', sql.Date, date)
.input('hours', sql.Float, hours)
.input('description', sql.NVarChar, description || null)
.query(`
INSERT INTO declarations (utilisateur_id, formateur_numero, type_demande_id, date, duree, description)
VALUES (@utilisateurId, @formateurNumero, @typeDemandeId, @date, @hours, @description)
`);
console.log('Nouvelle déclaration créée');
}
res.json({
success: true,
message: 'Déclaration sauvegardée avec succès'
});
} catch (error) {
console.error('Erreur lors de la sauvegarde:', error);
res.status(500).json({
success: false,
error: error.message
});
}
});
// Route pour récupérer les déclarations
app.get('/api/get_declarations', async (req, res) => {
try {
const result = await pool.request().query(`
SELECT
d.id,
d.formateur_numero as utilisateur_id,
td.id as type_demande_id,
d.date,
d.duree,
d.description,
d.formateur_numero,
td.libelle as activityType
FROM declarations d
INNER JOIN types_demandes td ON d.type_demande_id = td.id
ORDER BY d.date DESC
`);
res.json(result.recordset);
} catch (error) {
console.error('Erreur lors de la récupération:', error);
res.status(500).json({ error: error.message });
}
});
// Démarrage du serveur
async function startServer() {
const dbConnected = await connectDatabase();
if (!dbConnected) {
console.log('Impossible de démarrer sans base de données');
return;
}
app.listen(PORT, () => {
console.log(`Serveur démarré sur http://localhost:${PORT}`);
console.log('Routes disponibles :');
console.log('- GET /api/test');
console.log('- GET /api/db-test');
console.log('- GET /api/formateurs');
console.log('- POST /api/save_declaration');
console.log('- GET /api/get_declarations');
});
}
// Arrêt propre
process.on('SIGINT', async () => {
console.log('Arrêt du serveur...');
if (pool) {
await pool.close();
}
process.exit(0);
});
// Démarrer
startServer();

View File

@@ -1,36 +1,59 @@
// Test avec authentification Windows
// Test avec authentification SQL Server
const sql = require('mssql');
const config = {
server: '16.0.1000.6',
server: 'BONEMINE',
database: 'GTF',
user: 'gtf_app',
password: 'GTF2025!Secure',
options: {
encrypt: true,
trustServerCertificate: true,
trustedConnection: true, // Utilise votre compte Windows actuel
enableArithAbort: true
}
};
async function testConnection() {
try {
console.log('🔄 Test avec authentification Windows...');
console.log('Utilisateur Windows actuel:', process.env.USERNAME);
console.log('Test avec authentification SQL Server...');
console.log('Serveur:', config.server);
console.log('Base:', config.database);
console.log('Utilisateur:', config.user);
await sql.connect(config);
console.log('Connexion réussie avec Windows Auth !');
console.log('Connexion réussie avec SQL Server Auth !');
const result = await sql.query('SELECT COUNT(*) as total FROM FormateurSqy');
console.log('📊 Nombre de formateurs :', result.recordset[0].total);
// Test des tables
const result1 = await sql.query('SELECT COUNT(*) as total FROM FormateurSqy');
console.log('Nombre de formateurs :', result1.recordset[0].total);
const result2 = await sql.query('SELECT COUNT(*) as total FROM declarations');
console.log('📊 Nombre de déclarations :', result2.recordset[0].total);
console.log('Nombre de déclarations :', result2.recordset[0].total);
console.log('🎉 Parfait ! Votre authentification Windows fonctionne.');
const result3 = await sql.query('SELECT COUNT(*) as total FROM types_demandes');
console.log('Nombre de types de demandes :', result3.recordset[0].total);
// Test d'insertion/lecture (pour vérifier les permissions)
const testResult = await sql.query(`
SELECT
id,
libelle
FROM types_demandes
`);
console.log('Types de demandes disponibles :');
testResult.recordset.forEach(t => {
console.log(`- ${t.id}: ${t.libelle}`);
});
console.log('Configuration SQL Server validée !');
} catch (error) {
console.error('Erreur :', error.message);
console.log('💡 Suggestion : Vérifiez que votre utilisateur Windows a accès à la base GTF');
console.error('Erreur :', error.message);
console.log('Code d\'erreur:', error.code);
if (error.code === 'ELOGIN') {
console.log('Vérifiez que l\'utilisateur gtf_app a été créé dans SQL Server');
}
} finally {
await sql.close();
}

View File

@@ -1,16 +0,0 @@
<?php
// db.php
$serverName = "BONEMINE";
$connectionOptions = [
"Database" => "GTF",
"Uid" => "oimer",
"PWD" => "Wijdane123@",
"CharacterSet" => "UTF-8"
];
$conn = sqlsrv_connect($serverName, $connectionOptions);
if ($conn === false) {
die(print_r(sqlsrv_errors(), true));
}
?>

View File

@@ -1,20 +0,0 @@
<?php
header("Content-Type: application/json");
require_once "db.php";
$conn = sqlsrv_connect($serverName, $connectionOptions);
if (!$conn) {
die(json_encode(["error" => sqlsrv_errors()]));
}
$sql = "SELECT id, utilisateur_id, type_demande_id, CONVERT(varchar, date, 23) as date, duree, description, formateur_numero FROM declarations";
$stmt = sqlsrv_query($conn, $sql);
$data = [];
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
$data[] = $row;
}
echo json_encode($data);

View File

@@ -523,6 +523,19 @@
"node": ">=6.6.0"
}
},
"node_modules/cors": {
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
"license": "MIT",
"dependencies": {
"object-assign": "^4",
"vary": "^1"
},
"engines": {
"node": ">= 0.10"
}
},
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
@@ -1196,6 +1209,15 @@
"node": ">= 0.6"
}
},
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/object-inspect": {
"version": "1.13.4",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",

33
GTF/project/backend/node_modules/cors/CONTRIBUTING.md generated vendored Normal file
View File

@@ -0,0 +1,33 @@
# contributing to `cors`
CORS is a node.js package for providing a [connect](http://www.senchalabs.org/connect/)/[express](http://expressjs.com/) middleware that can be used to enable [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing) with various options. Learn more about the project in [the README](README.md).
## The CORS Spec
[http://www.w3.org/TR/cors/](http://www.w3.org/TR/cors/)
## Pull Requests Welcome
* Include `'use strict';` in every javascript file.
* 2 space indentation.
* Please run the testing steps below before submitting.
## Testing
```bash
$ npm install
$ npm test
```
## Interactive Testing Harness
[http://node-cors-client.herokuapp.com](http://node-cors-client.herokuapp.com)
Related git repositories:
* [https://github.com/TroyGoode/node-cors-server](https://github.com/TroyGoode/node-cors-server)
* [https://github.com/TroyGoode/node-cors-client](https://github.com/TroyGoode/node-cors-client)
## License
[MIT License](http://www.opensource.org/licenses/mit-license.php)

58
GTF/project/backend/node_modules/cors/HISTORY.md generated vendored Normal file
View File

@@ -0,0 +1,58 @@
2.8.5 / 2018-11-04
==================
* Fix setting `maxAge` option to `0`
2.8.4 / 2017-07-12
==================
* Work-around Safari bug in default pre-flight response
2.8.3 / 2017-03-29
==================
* Fix error when options delegate missing `methods` option
2.8.2 / 2017-03-28
==================
* Fix error when frozen options are passed
* Send "Vary: Origin" when using regular expressions
* Send "Vary: Access-Control-Request-Headers" when dynamic `allowedHeaders`
2.8.1 / 2016-09-08
==================
This release only changed documentation.
2.8.0 / 2016-08-23
==================
* Add `optionsSuccessStatus` option
2.7.2 / 2016-08-23
==================
* Fix error when Node.js running in strict mode
2.7.1 / 2015-05-28
==================
* Move module into expressjs organization
2.7.0 / 2015-05-28
==================
* Allow array of matching condition as `origin` option
* Allow regular expression as `origin` option
2.6.1 / 2015-05-28
==================
* Update `license` in package.json
2.6.0 / 2015-04-27
==================
* Add `preflightContinue` option
* Fix "Vary: Origin" header added for "*"

22
GTF/project/backend/node_modules/cors/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,22 @@
(The MIT License)
Copyright (c) 2013 Troy Goode <troygoode@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

243
GTF/project/backend/node_modules/cors/README.md generated vendored Normal file
View File

@@ -0,0 +1,243 @@
# cors
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
CORS is a node.js package for providing a [Connect](http://www.senchalabs.org/connect/)/[Express](http://expressjs.com/) middleware that can be used to enable [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing) with various options.
**[Follow me (@troygoode) on Twitter!](https://twitter.com/intent/user?screen_name=troygoode)**
* [Installation](#installation)
* [Usage](#usage)
* [Simple Usage](#simple-usage-enable-all-cors-requests)
* [Enable CORS for a Single Route](#enable-cors-for-a-single-route)
* [Configuring CORS](#configuring-cors)
* [Configuring CORS Asynchronously](#configuring-cors-asynchronously)
* [Enabling CORS Pre-Flight](#enabling-cors-pre-flight)
* [Configuration Options](#configuration-options)
* [Demo](#demo)
* [License](#license)
* [Author](#author)
## Installation
This is a [Node.js](https://nodejs.org/en/) module available through the
[npm registry](https://www.npmjs.com/). Installation is done using the
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
```sh
$ npm install cors
```
## Usage
### Simple Usage (Enable *All* CORS Requests)
```javascript
var express = require('express')
var cors = require('cors')
var app = express()
app.use(cors())
app.get('/products/:id', function (req, res, next) {
res.json({msg: 'This is CORS-enabled for all origins!'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
```
### Enable CORS for a Single Route
```javascript
var express = require('express')
var cors = require('cors')
var app = express()
app.get('/products/:id', cors(), function (req, res, next) {
res.json({msg: 'This is CORS-enabled for a Single Route'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
```
### Configuring CORS
```javascript
var express = require('express')
var cors = require('cors')
var app = express()
var corsOptions = {
origin: 'http://example.com',
optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
}
app.get('/products/:id', cors(corsOptions), function (req, res, next) {
res.json({msg: 'This is CORS-enabled for only example.com.'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
```
### Configuring CORS w/ Dynamic Origin
```javascript
var express = require('express')
var cors = require('cors')
var app = express()
var whitelist = ['http://example1.com', 'http://example2.com']
var corsOptions = {
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
}
app.get('/products/:id', cors(corsOptions), function (req, res, next) {
res.json({msg: 'This is CORS-enabled for a whitelisted domain.'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
```
If you do not want to block REST tools or server-to-server requests,
add a `!origin` check in the origin function like so:
```javascript
var corsOptions = {
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1 || !origin) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
}
```
### Enabling CORS Pre-Flight
Certain CORS requests are considered 'complex' and require an initial
`OPTIONS` request (called the "pre-flight request"). An example of a
'complex' CORS request is one that uses an HTTP verb other than
GET/HEAD/POST (such as DELETE) or that uses custom headers. To enable
pre-flighting, you must add a new OPTIONS handler for the route you want
to support:
```javascript
var express = require('express')
var cors = require('cors')
var app = express()
app.options('/products/:id', cors()) // enable pre-flight request for DELETE request
app.del('/products/:id', cors(), function (req, res, next) {
res.json({msg: 'This is CORS-enabled for all origins!'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
```
You can also enable pre-flight across-the-board like so:
```javascript
app.options('*', cors()) // include before other routes
```
### Configuring CORS Asynchronously
```javascript
var express = require('express')
var cors = require('cors')
var app = express()
var whitelist = ['http://example1.com', 'http://example2.com']
var corsOptionsDelegate = function (req, callback) {
var corsOptions;
if (whitelist.indexOf(req.header('Origin')) !== -1) {
corsOptions = { origin: true } // reflect (enable) the requested origin in the CORS response
} else {
corsOptions = { origin: false } // disable CORS for this request
}
callback(null, corsOptions) // callback expects two parameters: error and options
}
app.get('/products/:id', cors(corsOptionsDelegate), function (req, res, next) {
res.json({msg: 'This is CORS-enabled for a whitelisted domain.'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
```
## Configuration Options
* `origin`: Configures the **Access-Control-Allow-Origin** CORS header. Possible values:
- `Boolean` - set `origin` to `true` to reflect the [request origin](http://tools.ietf.org/html/draft-abarth-origin-09), as defined by `req.header('Origin')`, or set it to `false` to disable CORS.
- `String` - set `origin` to a specific origin. For example if you set it to `"http://example.com"` only requests from "http://example.com" will be allowed.
- `RegExp` - set `origin` to a regular expression pattern which will be used to test the request origin. If it's a match, the request origin will be reflected. For example the pattern `/example\.com$/` will reflect any request that is coming from an origin ending with "example.com".
- `Array` - set `origin` to an array of valid origins. Each origin can be a `String` or a `RegExp`. For example `["http://example1.com", /\.example2\.com$/]` will accept any request from "http://example1.com" or from a subdomain of "example2.com".
- `Function` - set `origin` to a function implementing some custom logic. The function takes the request origin as the first parameter and a callback (which expects the signature `err [object], allow [bool]`) as the second.
* `methods`: Configures the **Access-Control-Allow-Methods** CORS header. Expects a comma-delimited string (ex: 'GET,PUT,POST') or an array (ex: `['GET', 'PUT', 'POST']`).
* `allowedHeaders`: Configures the **Access-Control-Allow-Headers** CORS header. Expects a comma-delimited string (ex: 'Content-Type,Authorization') or an array (ex: `['Content-Type', 'Authorization']`). If not specified, defaults to reflecting the headers specified in the request's **Access-Control-Request-Headers** header.
* `exposedHeaders`: Configures the **Access-Control-Expose-Headers** CORS header. Expects a comma-delimited string (ex: 'Content-Range,X-Content-Range') or an array (ex: `['Content-Range', 'X-Content-Range']`). If not specified, no custom headers are exposed.
* `credentials`: Configures the **Access-Control-Allow-Credentials** CORS header. Set to `true` to pass the header, otherwise it is omitted.
* `maxAge`: Configures the **Access-Control-Max-Age** CORS header. Set to an integer to pass the header, otherwise it is omitted.
* `preflightContinue`: Pass the CORS preflight response to the next handler.
* `optionsSuccessStatus`: Provides a status code to use for successful `OPTIONS` requests, since some legacy browsers (IE11, various SmartTVs) choke on `204`.
The default configuration is the equivalent of:
```json
{
"origin": "*",
"methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
"preflightContinue": false,
"optionsSuccessStatus": 204
}
```
For details on the effect of each CORS header, read [this](http://www.html5rocks.com/en/tutorials/cors/) article on HTML5 Rocks.
## Demo
A demo that illustrates CORS working (and not working) using jQuery is available here: [http://node-cors-client.herokuapp.com/](http://node-cors-client.herokuapp.com/)
Code for that demo can be found here:
* Client: [https://github.com/TroyGoode/node-cors-client](https://github.com/TroyGoode/node-cors-client)
* Server: [https://github.com/TroyGoode/node-cors-server](https://github.com/TroyGoode/node-cors-server)
## License
[MIT License](http://www.opensource.org/licenses/mit-license.php)
## Author
[Troy Goode](https://github.com/TroyGoode) ([troygoode@gmail.com](mailto:troygoode@gmail.com))
[coveralls-image]: https://img.shields.io/coveralls/expressjs/cors/master.svg
[coveralls-url]: https://coveralls.io/r/expressjs/cors?branch=master
[downloads-image]: https://img.shields.io/npm/dm/cors.svg
[downloads-url]: https://npmjs.org/package/cors
[npm-image]: https://img.shields.io/npm/v/cors.svg
[npm-url]: https://npmjs.org/package/cors
[travis-image]: https://img.shields.io/travis/expressjs/cors/master.svg
[travis-url]: https://travis-ci.org/expressjs/cors

238
GTF/project/backend/node_modules/cors/lib/index.js generated vendored Normal file
View File

@@ -0,0 +1,238 @@
(function () {
'use strict';
var assign = require('object-assign');
var vary = require('vary');
var defaults = {
origin: '*',
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
preflightContinue: false,
optionsSuccessStatus: 204
};
function isString(s) {
return typeof s === 'string' || s instanceof String;
}
function isOriginAllowed(origin, allowedOrigin) {
if (Array.isArray(allowedOrigin)) {
for (var i = 0; i < allowedOrigin.length; ++i) {
if (isOriginAllowed(origin, allowedOrigin[i])) {
return true;
}
}
return false;
} else if (isString(allowedOrigin)) {
return origin === allowedOrigin;
} else if (allowedOrigin instanceof RegExp) {
return allowedOrigin.test(origin);
} else {
return !!allowedOrigin;
}
}
function configureOrigin(options, req) {
var requestOrigin = req.headers.origin,
headers = [],
isAllowed;
if (!options.origin || options.origin === '*') {
// allow any origin
headers.push([{
key: 'Access-Control-Allow-Origin',
value: '*'
}]);
} else if (isString(options.origin)) {
// fixed origin
headers.push([{
key: 'Access-Control-Allow-Origin',
value: options.origin
}]);
headers.push([{
key: 'Vary',
value: 'Origin'
}]);
} else {
isAllowed = isOriginAllowed(requestOrigin, options.origin);
// reflect origin
headers.push([{
key: 'Access-Control-Allow-Origin',
value: isAllowed ? requestOrigin : false
}]);
headers.push([{
key: 'Vary',
value: 'Origin'
}]);
}
return headers;
}
function configureMethods(options) {
var methods = options.methods;
if (methods.join) {
methods = options.methods.join(','); // .methods is an array, so turn it into a string
}
return {
key: 'Access-Control-Allow-Methods',
value: methods
};
}
function configureCredentials(options) {
if (options.credentials === true) {
return {
key: 'Access-Control-Allow-Credentials',
value: 'true'
};
}
return null;
}
function configureAllowedHeaders(options, req) {
var allowedHeaders = options.allowedHeaders || options.headers;
var headers = [];
if (!allowedHeaders) {
allowedHeaders = req.headers['access-control-request-headers']; // .headers wasn't specified, so reflect the request headers
headers.push([{
key: 'Vary',
value: 'Access-Control-Request-Headers'
}]);
} else if (allowedHeaders.join) {
allowedHeaders = allowedHeaders.join(','); // .headers is an array, so turn it into a string
}
if (allowedHeaders && allowedHeaders.length) {
headers.push([{
key: 'Access-Control-Allow-Headers',
value: allowedHeaders
}]);
}
return headers;
}
function configureExposedHeaders(options) {
var headers = options.exposedHeaders;
if (!headers) {
return null;
} else if (headers.join) {
headers = headers.join(','); // .headers is an array, so turn it into a string
}
if (headers && headers.length) {
return {
key: 'Access-Control-Expose-Headers',
value: headers
};
}
return null;
}
function configureMaxAge(options) {
var maxAge = (typeof options.maxAge === 'number' || options.maxAge) && options.maxAge.toString()
if (maxAge && maxAge.length) {
return {
key: 'Access-Control-Max-Age',
value: maxAge
};
}
return null;
}
function applyHeaders(headers, res) {
for (var i = 0, n = headers.length; i < n; i++) {
var header = headers[i];
if (header) {
if (Array.isArray(header)) {
applyHeaders(header, res);
} else if (header.key === 'Vary' && header.value) {
vary(res, header.value);
} else if (header.value) {
res.setHeader(header.key, header.value);
}
}
}
}
function cors(options, req, res, next) {
var headers = [],
method = req.method && req.method.toUpperCase && req.method.toUpperCase();
if (method === 'OPTIONS') {
// preflight
headers.push(configureOrigin(options, req));
headers.push(configureCredentials(options, req));
headers.push(configureMethods(options, req));
headers.push(configureAllowedHeaders(options, req));
headers.push(configureMaxAge(options, req));
headers.push(configureExposedHeaders(options, req));
applyHeaders(headers, res);
if (options.preflightContinue) {
next();
} else {
// Safari (and potentially other browsers) need content-length 0,
// for 204 or they just hang waiting for a body
res.statusCode = options.optionsSuccessStatus;
res.setHeader('Content-Length', '0');
res.end();
}
} else {
// actual response
headers.push(configureOrigin(options, req));
headers.push(configureCredentials(options, req));
headers.push(configureExposedHeaders(options, req));
applyHeaders(headers, res);
next();
}
}
function middlewareWrapper(o) {
// if options are static (either via defaults or custom options passed in), wrap in a function
var optionsCallback = null;
if (typeof o === 'function') {
optionsCallback = o;
} else {
optionsCallback = function (req, cb) {
cb(null, o);
};
}
return function corsMiddleware(req, res, next) {
optionsCallback(req, function (err, options) {
if (err) {
next(err);
} else {
var corsOptions = assign({}, defaults, options);
var originCallback = null;
if (corsOptions.origin && typeof corsOptions.origin === 'function') {
originCallback = corsOptions.origin;
} else if (corsOptions.origin) {
originCallback = function (origin, cb) {
cb(null, corsOptions.origin);
};
}
if (originCallback) {
originCallback(req.headers.origin, function (err2, origin) {
if (err2 || !origin) {
next(err2);
} else {
corsOptions.origin = origin;
cors(corsOptions, req, res, next);
}
});
} else {
next();
}
}
});
};
}
// can pass either an options hash, an options delegate, or nothing
module.exports = middlewareWrapper;
}());

41
GTF/project/backend/node_modules/cors/package.json generated vendored Normal file
View File

@@ -0,0 +1,41 @@
{
"name": "cors",
"description": "Node.js CORS middleware",
"version": "2.8.5",
"author": "Troy Goode <troygoode@gmail.com> (https://github.com/troygoode/)",
"license": "MIT",
"keywords": [
"cors",
"express",
"connect",
"middleware"
],
"repository": "expressjs/cors",
"main": "./lib/index.js",
"dependencies": {
"object-assign": "^4",
"vary": "^1"
},
"devDependencies": {
"after": "0.8.2",
"eslint": "2.13.1",
"express": "4.16.3",
"mocha": "5.2.0",
"nyc": "13.1.0",
"supertest": "3.3.0"
},
"files": [
"lib/index.js",
"CONTRIBUTING.md",
"HISTORY.md",
"LICENSE",
"README.md"
],
"engines": {
"node": ">= 0.10"
},
"scripts": {
"test": "npm run lint && nyc --reporter=html --reporter=text mocha --require test/support/env",
"lint": "eslint lib test"
}
}

View File

@@ -0,0 +1,90 @@
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
'use strict';
/* eslint-disable no-unused-vars */
var getOwnPropertySymbols = Object.getOwnPropertySymbols;
var hasOwnProperty = Object.prototype.hasOwnProperty;
var propIsEnumerable = Object.prototype.propertyIsEnumerable;
function toObject(val) {
if (val === null || val === undefined) {
throw new TypeError('Object.assign cannot be called with null or undefined');
}
return Object(val);
}
function shouldUseNative() {
try {
if (!Object.assign) {
return false;
}
// Detect buggy property enumeration order in older V8 versions.
// https://bugs.chromium.org/p/v8/issues/detail?id=4118
var test1 = new String('abc'); // eslint-disable-line no-new-wrappers
test1[5] = 'de';
if (Object.getOwnPropertyNames(test1)[0] === '5') {
return false;
}
// https://bugs.chromium.org/p/v8/issues/detail?id=3056
var test2 = {};
for (var i = 0; i < 10; i++) {
test2['_' + String.fromCharCode(i)] = i;
}
var order2 = Object.getOwnPropertyNames(test2).map(function (n) {
return test2[n];
});
if (order2.join('') !== '0123456789') {
return false;
}
// https://bugs.chromium.org/p/v8/issues/detail?id=3056
var test3 = {};
'abcdefghijklmnopqrst'.split('').forEach(function (letter) {
test3[letter] = letter;
});
if (Object.keys(Object.assign({}, test3)).join('') !==
'abcdefghijklmnopqrst') {
return false;
}
return true;
} catch (err) {
// We don't expect any of the above to throw, but better to be safe.
return false;
}
}
module.exports = shouldUseNative() ? Object.assign : function (target, source) {
var from;
var to = toObject(target);
var symbols;
for (var s = 1; s < arguments.length; s++) {
from = Object(arguments[s]);
for (var key in from) {
if (hasOwnProperty.call(from, key)) {
to[key] = from[key];
}
}
if (getOwnPropertySymbols) {
symbols = getOwnPropertySymbols(from);
for (var i = 0; i < symbols.length; i++) {
if (propIsEnumerable.call(from, symbols[i])) {
to[symbols[i]] = from[symbols[i]];
}
}
}
}
return to;
};

21
GTF/project/backend/node_modules/object-assign/license generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,42 @@
{
"name": "object-assign",
"version": "4.1.1",
"description": "ES2015 `Object.assign()` ponyfill",
"license": "MIT",
"repository": "sindresorhus/object-assign",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
},
"engines": {
"node": ">=0.10.0"
},
"scripts": {
"test": "xo && ava",
"bench": "matcha bench.js"
},
"files": [
"index.js"
],
"keywords": [
"object",
"assign",
"extend",
"properties",
"es2015",
"ecmascript",
"harmony",
"ponyfill",
"prollyfill",
"polyfill",
"shim",
"browser"
],
"devDependencies": {
"ava": "^0.16.0",
"lodash": "^4.16.4",
"matcha": "^0.7.0",
"xo": "^0.16.0"
}
}

View File

@@ -0,0 +1,61 @@
# object-assign [![Build Status](https://travis-ci.org/sindresorhus/object-assign.svg?branch=master)](https://travis-ci.org/sindresorhus/object-assign)
> ES2015 [`Object.assign()`](http://www.2ality.com/2014/01/object-assign.html) [ponyfill](https://ponyfill.com)
## Use the built-in
Node.js 4 and up, as well as every evergreen browser (Chrome, Edge, Firefox, Opera, Safari),
support `Object.assign()` :tada:. If you target only those environments, then by all
means, use `Object.assign()` instead of this package.
## Install
```
$ npm install --save object-assign
```
## Usage
```js
const objectAssign = require('object-assign');
objectAssign({foo: 0}, {bar: 1});
//=> {foo: 0, bar: 1}
// multiple sources
objectAssign({foo: 0}, {bar: 1}, {baz: 2});
//=> {foo: 0, bar: 1, baz: 2}
// overwrites equal keys
objectAssign({foo: 0}, {foo: 1}, {foo: 2});
//=> {foo: 2}
// ignores null and undefined sources
objectAssign({foo: 0}, null, {bar: 1}, undefined);
//=> {foo: 0, bar: 1}
```
## API
### objectAssign(target, [source, ...])
Assigns enumerable own properties of `source` objects to the `target` object and returns the `target` object. Additional `source` objects will overwrite previous ones.
## Resources
- [ES2015 spec - Object.assign](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign)
## Related
- [deep-assign](https://github.com/sindresorhus/deep-assign) - Recursive `Object.assign()`
## License
MIT © [Sindre Sorhus](https://sindresorhus.com)

View File

@@ -9,6 +9,7 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"cors": "^2.8.5",
"dotenv": "^17.2.2",
"express": "^5.1.0",
"mssql": "^11.0.1"
@@ -533,6 +534,19 @@
"node": ">=6.6.0"
}
},
"node_modules/cors": {
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
"license": "MIT",
"dependencies": {
"object-assign": "^4",
"vary": "^1"
},
"engines": {
"node": ">= 0.10"
}
},
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
@@ -1206,6 +1220,15 @@
"node": ">= 0.6"
}
},
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/object-inspect": {
"version": "1.13.4",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",

View File

@@ -10,6 +10,7 @@
"license": "ISC",
"description": "",
"dependencies": {
"cors": "^2.8.5",
"dotenv": "^17.2.2",
"express": "^5.1.0",
"mssql": "^11.0.1"

View File

@@ -1,26 +0,0 @@
<?php
header("Content-Type: application/json");
require_once "db.php";
$data = json_decode(file_get_contents("php://input"), true);
$utilisateur_id = $data["utilisateur_id"];
$type_demande_id = $data["type_demande_id"];
$date = $data["date"];
$duree = $data["duree"];
$description = $data["description"] ?? null;
$formateur_numero = $data["formateur_numero"];
$sql = "INSERT INTO declarations (utilisateur_id, type_demande_id, date, duree, description, formateur_numero)
VALUES (?, ?, ?, ?, ?, ?)";
$params = [$utilisateur_id, $type_demande_id, $date, $duree, $description, $formateur_numero];
$stmt = sqlsrv_query($conn, $sql, $params);
if ($stmt) {
echo json_encode(["success" => true, "message" => "Déclaration enregistrée"]);
} else {
echo json_encode(["success" => false, "error" => sqlsrv_errors()]);
}
?>

View File

@@ -1,6 +1,6 @@
import {
BrowserPerformanceMeasurement
} from "./chunk-BXCAR3JX.js";
} from "./chunk-5VK5IHOT.js";
import {
__export
} from "./chunk-G3PMV62Z.js";
@@ -16999,7 +16999,7 @@ function getPerfMeasurementModule() {
sessionStorage = window[BrowserCacheLocation.SessionStorage];
const perfEnabled = sessionStorage == null ? void 0 : sessionStorage.getItem(BROWSER_PERF_ENABLED_KEY);
if (Number(perfEnabled) === 1) {
return import("./BrowserPerformanceMeasurement-5UJNI4WV.js");
return import("./BrowserPerformanceMeasurement-5VDOVMRB.js");
}
} catch (e) {
}

File diff suppressed because one or more lines are too long

View File

@@ -1,8 +1,8 @@
import {
BrowserPerformanceMeasurement
} from "./chunk-BXCAR3JX.js";
} from "./chunk-5VK5IHOT.js";
import "./chunk-G3PMV62Z.js";
export {
BrowserPerformanceMeasurement
};
//# sourceMappingURL=BrowserPerformanceMeasurement-5UJNI4WV.js.map
//# sourceMappingURL=BrowserPerformanceMeasurement-5VDOVMRB.js.map

View File

@@ -1,58 +1,58 @@
{
"hash": "0db3536e",
"configHash": "dc00d83f",
"lockfileHash": "14011340",
"browserHash": "672592a0",
"hash": "1e9c2bee",
"configHash": "451161ff",
"lockfileHash": "b1ec30a4",
"browserHash": "57e609ed",
"optimized": {
"react": {
"src": "../../react/index.js",
"file": "react.js",
"fileHash": "8ad7db99",
"fileHash": "4348729b",
"needsInterop": true
},
"react/jsx-dev-runtime": {
"src": "../../react/jsx-dev-runtime.js",
"file": "react_jsx-dev-runtime.js",
"fileHash": "ec7323e1",
"fileHash": "9694e297",
"needsInterop": true
},
"react/jsx-runtime": {
"src": "../../react/jsx-runtime.js",
"file": "react_jsx-runtime.js",
"fileHash": "7307506d",
"fileHash": "4fa96245",
"needsInterop": true
},
"@azure/msal-browser": {
"src": "../../@azure/msal-browser/dist/index.mjs",
"file": "@azure_msal-browser.js",
"fileHash": "8be31f82",
"needsInterop": false
},
"react-dom/client": {
"src": "../../react-dom/client.js",
"file": "react-dom_client.js",
"fileHash": "e3d0ad6f",
"fileHash": "8aa9b52d",
"needsInterop": true
},
"react-router-dom": {
"src": "../../../../node_modules/react-router-dom/dist/index.mjs",
"file": "react-router-dom.js",
"fileHash": "ca3428cd",
"needsInterop": false
},
"@azure/msal-browser": {
"src": "../../@azure/msal-browser/dist/index.mjs",
"file": "@azure_msal-browser.js",
"fileHash": "72740ae2",
"fileHash": "f4ac1124",
"needsInterop": false
}
},
"chunks": {
"chunk-6BKLQ22S": {
"file": "chunk-6BKLQ22S.js"
"chunk-4W2RIJ36": {
"file": "chunk-4W2RIJ36.js"
},
"chunk-DRWLMN53": {
"file": "chunk-DRWLMN53.js"
"chunk-QRULMDK5": {
"file": "chunk-QRULMDK5.js"
},
"BrowserPerformanceMeasurement-5UJNI4WV": {
"file": "BrowserPerformanceMeasurement-5UJNI4WV.js"
"BrowserPerformanceMeasurement-5VDOVMRB": {
"file": "BrowserPerformanceMeasurement-5VDOVMRB.js"
},
"chunk-BXCAR3JX": {
"file": "chunk-BXCAR3JX.js"
"chunk-5VK5IHOT": {
"file": "chunk-5VK5IHOT.js"
},
"chunk-G3PMV62Z": {
"file": "chunk-G3PMV62Z.js"

View File

@@ -1,6 +1,6 @@
import {
require_react
} from "./chunk-DRWLMN53.js";
} from "./chunk-QRULMDK5.js";
import {
__commonJS
} from "./chunk-G3PMV62Z.js";
@@ -21626,4 +21626,4 @@ react-dom/cjs/react-dom.development.js:
* @license Modernizr 3.0.0pre (Custom Build) | MIT
*)
*/
//# sourceMappingURL=chunk-6BKLQ22S.js.map
//# sourceMappingURL=chunk-4W2RIJ36.js.map

File diff suppressed because one or more lines are too long

View File

@@ -82,4 +82,4 @@ export {
@azure/msal-browser/dist/telemetry/BrowserPerformanceMeasurement.mjs:
(*! @azure/msal-browser v4.22.1 2025-09-09 *)
*/
//# sourceMappingURL=chunk-BXCAR3JX.js.map
//# sourceMappingURL=chunk-5VK5IHOT.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1903,4 +1903,4 @@ react/cjs/react.development.js:
* LICENSE file in the root directory of this source tree.
*)
*/
//# sourceMappingURL=chunk-DRWLMN53.js.map
//# sourceMappingURL=chunk-QRULMDK5.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +1,7 @@
import {
require_react_dom
} from "./chunk-6BKLQ22S.js";
import "./chunk-DRWLMN53.js";
} from "./chunk-4W2RIJ36.js";
import "./chunk-QRULMDK5.js";
import {
__commonJS
} from "./chunk-G3PMV62Z.js";

View File

@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../react-dom/client.js"],
"sourcesContent": ["'use strict';\n\nvar m = require('react-dom');\nif (process.env.NODE_ENV === 'production') {\n exports.createRoot = m.createRoot;\n exports.hydrateRoot = m.hydrateRoot;\n} else {\n var i = m.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;\n exports.createRoot = function(c, o) {\n i.usingClientEntryPoint = true;\n try {\n return m.createRoot(c, o);\n } finally {\n i.usingClientEntryPoint = false;\n }\n };\n exports.hydrateRoot = function(c, h, o) {\n i.usingClientEntryPoint = true;\n try {\n return m.hydrateRoot(c, h, o);\n } finally {\n i.usingClientEntryPoint = false;\n }\n };\n}\n"],
"sourcesContent": ["'use strict';\r\n\r\nvar m = require('react-dom');\r\nif (process.env.NODE_ENV === 'production') {\r\n exports.createRoot = m.createRoot;\r\n exports.hydrateRoot = m.hydrateRoot;\r\n} else {\r\n var i = m.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;\r\n exports.createRoot = function(c, o) {\r\n i.usingClientEntryPoint = true;\r\n try {\r\n return m.createRoot(c, o);\r\n } finally {\r\n i.usingClientEntryPoint = false;\r\n }\r\n };\r\n exports.hydrateRoot = function(c, h, o) {\r\n i.usingClientEntryPoint = true;\r\n try {\r\n return m.hydrateRoot(c, h, o);\r\n } finally {\r\n i.usingClientEntryPoint = false;\r\n }\r\n };\r\n}\r\n"],
"mappings": ";;;;;;;;;AAAA;AAAA;AAEA,QAAI,IAAI;AACR,QAAI,OAAuC;AACzC,cAAQ,aAAa,EAAE;AACvB,cAAQ,cAAc,EAAE;AAAA,IAC1B,OAAO;AACD,UAAI,EAAE;AACV,cAAQ,aAAa,SAAS,GAAG,GAAG;AAClC,UAAE,wBAAwB;AAC1B,YAAI;AACF,iBAAO,EAAE,WAAW,GAAG,CAAC;AAAA,QAC1B,UAAE;AACA,YAAE,wBAAwB;AAAA,QAC5B;AAAA,MACF;AACA,cAAQ,cAAc,SAAS,GAAG,GAAG,GAAG;AACtC,UAAE,wBAAwB;AAC1B,YAAI;AACF,iBAAO,EAAE,YAAY,GAAG,GAAG,CAAC;AAAA,QAC9B,UAAE;AACA,YAAE,wBAAwB;AAAA,QAC5B;AAAA,MACF;AAAA,IACF;AAjBM;AAAA;AAAA;",
"names": []
}

View File

@@ -1,9 +1,9 @@
import {
require_react_dom
} from "./chunk-6BKLQ22S.js";
} from "./chunk-4W2RIJ36.js";
import {
require_react
} from "./chunk-DRWLMN53.js";
} from "./chunk-QRULMDK5.js";
import {
__commonJS,
__toESM

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
import {
require_react
} from "./chunk-DRWLMN53.js";
} from "./chunk-QRULMDK5.js";
import "./chunk-G3PMV62Z.js";
export default require_react();
//# sourceMappingURL=react.js.map

View File

@@ -1,6 +1,6 @@
import {
require_react
} from "./chunk-DRWLMN53.js";
} from "./chunk-QRULMDK5.js";
import {
__commonJS
} from "./chunk-G3PMV62Z.js";

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
import {
require_react
} from "./chunk-DRWLMN53.js";
} from "./chunk-QRULMDK5.js";
import {
__commonJS
} from "./chunk-G3PMV62Z.js";

File diff suppressed because one or more lines are too long

View File

@@ -1,30 +1,61 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import Calendar from './components/Calendar';
import TimeEntryModal from './components/TimeEntryModal';
import UserProfile from './components/UserProfile';
import { TimeEntry } from './types/TimeEntry';
import { Clock, User, Calendar as CalendarIcon, Menu, X, LogOut } from 'lucide-react';
import { useAuth } from './context/AuthContext';
import { useAuth } from './context/AuthContext';
function App() {
const { logout, user } = useAuth(); // récupère user depuis AuthContext
const { logout, user } = useAuth();
const [selectedDate, setSelectedDate] = useState<string | null>(null);
const [timeEntries, setTimeEntries] = useState<TimeEntry[]>([]);
const [showProfile, setShowProfile] = useState(false);
const [loading, setLoading] = useState(true);
// Fonction pour charger les déclarations depuis la base
const loadDeclarations = async () => {
try {
console.log('Chargement des déclarations...');
const response = await fetch('http://localhost:3001/api/get_declarations');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log('Déclarations reçues:', data);
// Convertir les données du serveur au format TimeEntry
const entries: TimeEntry[] = data.map((d: any) => ({
date: d.date.split('T')[0], // Convertir la date SQL en format YYYY-MM-DD
activityType: d.activityType,
hours: d.duree,
description: d.description || '',
createdAt: new Date(d.date)
}));
setTimeEntries(entries);
console.log('Déclarations converties:', entries);
} catch (error) {
console.error('Erreur lors du chargement des déclarations:', error);
} finally {
setLoading(false);
}
};
// Charger les déclarations au démarrage
useEffect(() => {
loadDeclarations();
}, []);
const handleDateClick = (date: string) => setSelectedDate(date);
const handleCloseModal = () => setSelectedDate(null);
const handleSaveEntry = (entry: TimeEntry) => {
setTimeEntries(prev => {
const existingIndex = prev.findIndex(e => e.date === entry.date);
if (existingIndex >= 0) {
const updated = [...prev];
updated[existingIndex] = entry;
return updated;
}
return [...prev, entry];
});
const handleSaveEntry = async (entry: TimeEntry) => {
console.log('Sauvegarde réussie, rechargement des données...');
// Recharger les données depuis la base après sauvegarde
await loadDeclarations();
setSelectedDate(null);
};
@@ -121,10 +152,17 @@ function App() {
<div className="grid grid-cols-1 xl:grid-cols-3 gap-6 sm:gap-8">
{/* Calendar - Main Section */}
<div className="xl:col-span-2">
<Calendar
onDateClick={handleDateClick}
getEntryForDate={getEntryForDate}
/>
{loading ? (
<div className="bg-white rounded-2xl shadow-xl border border-gray-100 p-8 text-center">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto mb-4"></div>
<div className="text-gray-600">Chargement des déclarations...</div>
</div>
) : (
<Calendar
onDateClick={handleDateClick}
getEntryForDate={getEntryForDate}
/>
)}
</div>
{/* Sidebar */}
@@ -148,15 +186,16 @@ function App() {
<Clock className="h-5 w-5 text-blue-600" />
Actions rapides
</h3>
<div className="space-y-3">
<button
onClick={() => handleDateClick(new Date().toISOString().split('T')[0])}
className="w-full p-3 bg-blue-50 hover:bg-blue-100 text-blue-700 font-medium rounded-lg transition-colors text-left"
disabled={loading}
>
Déclarer aujourd'hui
{loading ? 'Chargement...' : 'Déclarer aujourd\'hui'}
</button>
<div className="text-sm text-gray-600">
<p className="mb-2">Limites:</p>
<ul className="space-y-1 text-xs">
@@ -168,13 +207,13 @@ function App() {
</div>
{/* Recent Entries */}
{timeEntries.length > 0 && (
{!loading && timeEntries.length > 0 && (
<div className="bg-white rounded-2xl shadow-lg p-4 sm:p-6 border border-gray-100">
<h3 className="text-lg font-semibold text-gray-800 mb-4 flex items-center gap-2">
<Clock className="h-5 w-5 text-green-600" />
Récentes déclarations
</h3>
<div className="space-y-3">
{getRecentEntries().map((entry, index) => (
<div key={index} className="p-3 bg-gray-50 rounded-lg">
@@ -187,10 +226,10 @@ function App() {
</span>
<span className={`
text-xs px-2 py-1 rounded-full
${entry.activityType === 'preparation'
? 'bg-blue-100 text-blue-700'
: 'bg-green-100 text-green-700'
}
${entry.activityType === 'preparation'
? 'bg-blue-100 text-blue-700'
: 'bg-green-100 text-green-700'
}
`}>
{entry.hours}h
</span>
@@ -206,6 +245,20 @@ function App() {
</div>
)}
{/* No Data Message */}
{!loading && timeEntries.length === 0 && (
<div className="bg-white rounded-2xl shadow-lg p-4 sm:p-6 border border-gray-100 text-center">
<h3 className="text-lg font-semibold text-gray-800 mb-2">Aucune déclaration</h3>
<p className="text-sm text-gray-600 mb-4">Commencez par déclarer vos premières heures</p>
<button
onClick={() => handleDateClick(new Date().toISOString().split('T')[0])}
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
>
Déclarer maintenant
</button>
</div>
)}
{/* Help Section */}
<div className="bg-gradient-to-br from-blue-50 to-indigo-50 rounded-2xl p-4 sm:p-6 border border-blue-100">
<h3 className="text-lg font-semibold text-gray-800 mb-3">
@@ -222,7 +275,7 @@ function App() {
</div>
{/* Modal */}
{selectedDate && (
{selectedDate && !loading && (
<TimeEntryModal
date={selectedDate}
existingEntry={getEntryForDate(selectedDate)}
@@ -234,4 +287,4 @@ function App() {
);
}
export default App;
export default App;

View File

@@ -39,7 +39,7 @@ const Calendar: React.FC<CalendarProps> = ({ onDateClick, getEntryForDate }) =>
// Charger les déclarations depuis PHP
useEffect(() => {
fetch("http://localhost/GTF/project/backend/get_declarations.php")
fetch("http://localhost:3001/api/get_declarations")
.then((res) => res.json())
.then((data) => setDeclarations(data))
.catch((err) => console.error("Erreur fetch:", err));
@@ -47,7 +47,7 @@ const Calendar: React.FC<CalendarProps> = ({ onDateClick, getEntryForDate }) =>
// Fonction de sauvegarde d'une déclaration (à utiliser selon besoin)
const saveDeclaration = async (newDeclaration: Declaration) => {
const res = await fetch("http://localhost/GTF/project/backend/save_declaration.php", {
const res = await fetch("http://localhost:3001/api/get_declarations", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(newDeclaration),

View File

@@ -1,6 +1,7 @@
import React, { useState, useEffect } from 'react';
import { X, Clock, FileText, Save, AlertCircle } from 'lucide-react';
import { TimeEntry } from '../types/TimeEntry';
import { useAuth } from '../context/AuthContext';
interface TimeEntryModalProps {
date: string;
@@ -20,6 +21,10 @@ const TimeEntryModal: React.FC<TimeEntryModalProps> = ({
const [description, setDescription] = useState('');
const [errors, setErrors] = useState<string[]>([]);
const [loading, setLoading] = useState(false);
const { user, isAuthorized } = useAuth();
console.log('DEBUG AUTH:', { user, isAuthorized });
console.log('user est:', typeof user, user);
useEffect(() => {
if (existingEntry) {
@@ -65,11 +70,24 @@ const TimeEntryModal: React.FC<TimeEntryModalProps> = ({
};
try {
const response = await fetch("http://localhost/GTF/project/backend/save_declaration.php", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(entry),
});
console.log('Utilisateur connecté:', user);
console.log('Données à envoyer:', {
...entry,
user: user
});
const response = await fetch("http://localhost:3001/api/save_declaration", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
date: date,
activityType: activityType,
hours: hours,
description: description.trim(),
user: user
}),
});
if (!response.ok) {
const errorMsg = await response.text();
setErrors([`Erreur serveur: ${errorMsg}`]);