feat: Release version 3.1.4 - Mode terrain et génération PDF
✨ Nouvelles fonctionnalités: - Ajout du mode terrain pour utilisation mobile hors connexion - Génération automatique de reçus PDF avec template personnalisé - Révision complète du système de cartes avec amélioration des performances 🔧 Améliorations techniques: - Refactoring du module chat avec architecture simplifiée - Optimisation du système de sécurité NIST SP 800-63B - Amélioration de la gestion des secteurs géographiques - Support UTF-8 étendu pour les noms d'utilisateurs 📱 Application mobile: - Nouveau mode terrain dans user_field_mode_page - Interface utilisateur adaptative pour conditions difficiles - Synchronisation offline améliorée 🗺️ Cartographie: - Optimisation des performances MapBox - Meilleure gestion des tuiles hors ligne - Amélioration de l'affichage des secteurs 📄 Documentation: - Ajout guide Android (ANDROID-GUIDE.md) - Documentation sécurité API (API-SECURITY.md) - Guide module chat (CHAT_MODULE.md) 🐛 Corrections: - Résolution des erreurs 400 lors de la création d'utilisateurs - Correction de la validation des noms d'utilisateurs - Fix des problèmes de synchronisation chat 🤖 Generated with Claude Code (https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
150
api/tests/test_user_creation.php
Executable file
150
api/tests/test_user_creation.php
Executable file
@@ -0,0 +1,150 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/**
|
||||
* Script de test pour la création d'utilisateurs
|
||||
* Teste les différents cas qui peuvent causer une erreur 400
|
||||
*/
|
||||
|
||||
// Configuration
|
||||
$apiUrl = 'http://localhost/api';
|
||||
$sessionId = ''; // À remplir avec un session_id valide
|
||||
|
||||
// Couleurs pour la sortie
|
||||
$red = "\033[31m";
|
||||
$green = "\033[32m";
|
||||
$yellow = "\033[33m";
|
||||
$blue = "\033[34m";
|
||||
$reset = "\033[0m";
|
||||
|
||||
function testRequest($endpoint, $method, $data = null, $sessionId = '') {
|
||||
$ch = curl_init($endpoint);
|
||||
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
||||
|
||||
if ($sessionId) {
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
'Content-Type: application/json',
|
||||
'Authorization: Bearer ' . $sessionId
|
||||
]);
|
||||
} else {
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
|
||||
}
|
||||
|
||||
if ($data) {
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
|
||||
}
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
return [
|
||||
'code' => $httpCode,
|
||||
'body' => json_decode($response, true) ?: $response
|
||||
];
|
||||
}
|
||||
|
||||
echo $blue . "=== Test de création d'utilisateur et vérification username ===" . $reset . "\n\n";
|
||||
|
||||
// Test 1: Vérification username sans données
|
||||
echo $yellow . "Test 1: POST /api/users/check-username sans données" . $reset . "\n";
|
||||
$result = testRequest($apiUrl . '/users/check-username', 'POST', [], $sessionId);
|
||||
echo "Code HTTP: " . ($result['code'] == 400 ? $green : $red) . $result['code'] . $reset . "\n";
|
||||
if (is_array($result['body'])) {
|
||||
echo "Message: " . $result['body']['message'] . "\n";
|
||||
echo "Field: " . ($result['body']['field'] ?? 'non spécifié') . "\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// Test 2: Vérification username avec format invalide (trop court)
|
||||
echo $yellow . "Test 2: POST /api/users/check-username avec username trop court" . $reset . "\n";
|
||||
$result = testRequest($apiUrl . '/users/check-username', 'POST', ['username' => 'abc'], $sessionId);
|
||||
echo "Code HTTP: " . ($result['code'] == 400 ? $green : $red) . $result['code'] . $reset . "\n";
|
||||
if (is_array($result['body'])) {
|
||||
echo "Message: " . $result['body']['message'] . "\n";
|
||||
echo "Format attendu: " . ($result['body']['format'] ?? 'non spécifié') . "\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// Test 3: Vérification username avec format invalide (commence par un chiffre)
|
||||
echo $yellow . "Test 3: POST /api/users/check-username avec username commençant par un chiffre" . $reset . "\n";
|
||||
$result = testRequest($apiUrl . '/users/check-username', 'POST', ['username' => '123test.user'], $sessionId);
|
||||
echo "Code HTTP: " . ($result['code'] == 400 ? $green : $red) . $result['code'] . $reset . "\n";
|
||||
if (is_array($result['body'])) {
|
||||
echo "Message: " . $result['body']['message'] . "\n";
|
||||
echo "Valeur testée: " . ($result['body']['value'] ?? 'non spécifié') . "\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// Test 4: Vérification username valide
|
||||
echo $yellow . "Test 4: POST /api/users/check-username avec username valide" . $reset . "\n";
|
||||
$result = testRequest($apiUrl . '/users/check-username', 'POST', ['username' => 'test.user123'], $sessionId);
|
||||
echo "Code HTTP: " . ($result['code'] == 200 ? $green : $red) . $result['code'] . $reset . "\n";
|
||||
if (is_array($result['body'])) {
|
||||
echo "Disponible: " . ($result['body']['available'] ? 'Oui' : 'Non') . "\n";
|
||||
echo "Message: " . $result['body']['message'] . "\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// Test 5: Création utilisateur sans email
|
||||
echo $yellow . "Test 5: POST /api/users sans email" . $reset . "\n";
|
||||
$result = testRequest($apiUrl . '/users', 'POST', [
|
||||
'name' => 'Test User',
|
||||
'fk_entite' => 1
|
||||
], $sessionId);
|
||||
echo "Code HTTP: " . ($result['code'] == 400 ? $green : $red) . $result['code'] . $reset . "\n";
|
||||
if (is_array($result['body'])) {
|
||||
echo "Message: " . $result['body']['message'] . "\n";
|
||||
echo "Field: " . ($result['body']['field'] ?? 'non spécifié') . "\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// Test 6: Création utilisateur sans nom
|
||||
echo $yellow . "Test 6: POST /api/users sans nom" . $reset . "\n";
|
||||
$result = testRequest($apiUrl . '/users', 'POST', [
|
||||
'email' => 'test@example.com',
|
||||
'fk_entite' => 1
|
||||
], $sessionId);
|
||||
echo "Code HTTP: " . ($result['code'] == 400 ? $green : $red) . $result['code'] . $reset . "\n";
|
||||
if (is_array($result['body'])) {
|
||||
echo "Message: " . $result['body']['message'] . "\n";
|
||||
echo "Field: " . ($result['body']['field'] ?? 'non spécifié') . "\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// Test 7: Création utilisateur avec email invalide
|
||||
echo $yellow . "Test 7: POST /api/users avec email invalide" . $reset . "\n";
|
||||
$result = testRequest($apiUrl . '/users', 'POST', [
|
||||
'email' => 'invalid-email',
|
||||
'name' => 'Test User',
|
||||
'fk_entite' => 1
|
||||
], $sessionId);
|
||||
echo "Code HTTP: " . ($result['code'] == 400 ? $green : $red) . $result['code'] . $reset . "\n";
|
||||
if (is_array($result['body'])) {
|
||||
echo "Message: " . $result['body']['message'] . "\n";
|
||||
echo "Field: " . ($result['body']['field'] ?? 'non spécifié') . "\n";
|
||||
echo "Valeur testée: " . ($result['body']['value'] ?? 'non spécifié') . "\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
// Test 8: Création utilisateur pour entité avec username manuel mais sans username
|
||||
echo $yellow . "Test 8: POST /api/users pour entité avec chk_username_manuel=1 sans username" . $reset . "\n";
|
||||
$result = testRequest($apiUrl . '/users', 'POST', [
|
||||
'email' => 'test@example.com',
|
||||
'name' => 'Test User',
|
||||
'fk_entite' => 5 // Supposons que l'entité 5 a chk_username_manuel=1
|
||||
], $sessionId);
|
||||
echo "Code HTTP: " . $result['code'] . "\n";
|
||||
if (is_array($result['body'])) {
|
||||
echo "Message: " . $result['body']['message'] . "\n";
|
||||
echo "Field: " . ($result['body']['field'] ?? 'non spécifié') . "\n";
|
||||
echo "Reason: " . ($result['body']['reason'] ?? 'non spécifié') . "\n";
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
echo $blue . "=== Fin des tests ===" . $reset . "\n";
|
||||
echo "\nRappel: Pour que ces tests fonctionnent, vous devez:\n";
|
||||
echo "1. Avoir un serveur local en cours d'exécution\n";
|
||||
echo "2. Remplir la variable \$sessionId avec un token de session valide\n";
|
||||
echo "3. Vérifier les logs dans /logs/ pour voir les détails\n";
|
||||
132
api/tests/test_username_validation.php
Executable file
132
api/tests/test_username_validation.php
Executable file
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/**
|
||||
* Script de test pour la validation ultra-souple des usernames
|
||||
* Teste les nouvelles règles : 8-30 caractères UTF-8, tous caractères acceptés
|
||||
*/
|
||||
|
||||
// Configuration
|
||||
$apiUrl = 'http://localhost/api';
|
||||
$sessionId = ''; // À remplir avec un session_id valide
|
||||
|
||||
// Couleurs pour la sortie
|
||||
$red = "\033[31m";
|
||||
$green = "\033[32m";
|
||||
$yellow = "\033[33m";
|
||||
$blue = "\033[34m";
|
||||
$reset = "\033[0m";
|
||||
|
||||
function testRequest($endpoint, $method, $data = null, $sessionId = '') {
|
||||
$ch = curl_init($endpoint);
|
||||
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
||||
|
||||
if ($sessionId) {
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
'Content-Type: application/json; charset=UTF-8',
|
||||
'Authorization: Bearer ' . $sessionId
|
||||
]);
|
||||
} else {
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json; charset=UTF-8']);
|
||||
}
|
||||
|
||||
if ($data) {
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
return [
|
||||
'code' => $httpCode,
|
||||
'body' => json_decode($response, true) ?: $response
|
||||
];
|
||||
}
|
||||
|
||||
echo $blue . "=== Test de validation ultra-souple des usernames ===" . $reset . "\n";
|
||||
echo "Nouvelles règles : 8-30 caractères UTF-8, tous caractères acceptés\n\n";
|
||||
|
||||
// Cas qui doivent ÉCHOUER (trop court ou trop long)
|
||||
$testsFail = [
|
||||
['username' => 'abc', 'desc' => 'Trop court (3 car.)'],
|
||||
['username' => '1234567', 'desc' => 'Trop court (7 car.)'],
|
||||
['username' => str_repeat('a', 31), 'desc' => 'Trop long (31 car.)'],
|
||||
['username' => str_repeat('😀', 31), 'desc' => 'Trop long (31 émojis)'],
|
||||
['username' => ' ', 'desc' => 'Espaces seulement (devient vide après trim)'],
|
||||
];
|
||||
|
||||
// Cas qui doivent RÉUSSIR
|
||||
$testsSuccess = [
|
||||
['username' => 'Jean-Pierre', 'desc' => 'Nom avec tiret et majuscules'],
|
||||
['username' => '12345678', 'desc' => 'Chiffres seulement (8 car.)'],
|
||||
['username' => 'user@company', 'desc' => 'Avec arobase'],
|
||||
['username' => 'Marie 2024', 'desc' => 'Avec espace'],
|
||||
['username' => 'josé.garcía', 'desc' => 'Avec accents'],
|
||||
['username' => '用户2024', 'desc' => 'Caractères chinois'],
|
||||
['username' => 'مستخدم123', 'desc' => 'Caractères arabes'],
|
||||
['username' => 'Admin_#123!', 'desc' => 'Caractères spéciaux'],
|
||||
['username' => '😀🎉Party2024', 'desc' => 'Avec émojis'],
|
||||
['username' => 'Пользователь', 'desc' => 'Cyrillique'],
|
||||
['username' => ' espacé ', 'desc' => 'Espaces (seront trimés)'],
|
||||
['username' => 'a' . str_repeat('b', 28) . 'c', 'desc' => 'Exactement 30 car.'],
|
||||
];
|
||||
|
||||
echo $yellow . "Tests qui doivent ÉCHOUER :" . $reset . "\n\n";
|
||||
|
||||
foreach ($testsFail as $index => $test) {
|
||||
echo "Test " . ($index + 1) . ": " . $test['desc'] . "\n";
|
||||
echo "Username: \"" . $test['username'] . "\"\n";
|
||||
|
||||
$result = testRequest($apiUrl . '/users/check-username', 'POST', ['username' => $test['username']], $sessionId);
|
||||
|
||||
$isExpectedFailure = ($result['code'] == 400);
|
||||
echo "Code HTTP: " . ($isExpectedFailure ? $green : $red) . $result['code'] . $reset;
|
||||
echo " - " . ($isExpectedFailure ? $green . "✓ OK" : $red . "✗ ERREUR") . $reset . "\n";
|
||||
|
||||
if (is_array($result['body'])) {
|
||||
echo "Message: " . $result['body']['message'] . "\n";
|
||||
if (isset($result['body']['details'])) {
|
||||
echo "Détails: " . $result['body']['details'] . "\n";
|
||||
}
|
||||
}
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
echo $yellow . "Tests qui doivent RÉUSSIR :" . $reset . "\n\n";
|
||||
|
||||
foreach ($testsSuccess as $index => $test) {
|
||||
echo "Test " . ($index + 1) . ": " . $test['desc'] . "\n";
|
||||
echo "Username: \"" . $test['username'] . "\"\n";
|
||||
echo "Longueur: " . mb_strlen(trim($test['username']), 'UTF-8') . " caractères\n";
|
||||
|
||||
$result = testRequest($apiUrl . '/users/check-username', 'POST', ['username' => $test['username']], $sessionId);
|
||||
|
||||
$isExpectedSuccess = ($result['code'] == 200);
|
||||
echo "Code HTTP: " . ($isExpectedSuccess ? $green : $red) . $result['code'] . $reset;
|
||||
echo " - " . ($isExpectedSuccess ? $green . "✓ OK" : $red . "✗ ERREUR") . $reset . "\n";
|
||||
|
||||
if (is_array($result['body'])) {
|
||||
if ($result['code'] == 200) {
|
||||
echo "Disponible: " . ($result['body']['available'] ? $green . "Oui" : $yellow . "Non (déjà pris)") . $reset . "\n";
|
||||
} else {
|
||||
echo "Message: " . $result['body']['message'] . "\n";
|
||||
if (isset($result['body']['details'])) {
|
||||
echo "Détails: " . $result['body']['details'] . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
echo $blue . "=== Résumé des nouvelles règles ===" . $reset . "\n";
|
||||
echo "✓ Minimum : 8 caractères UTF-8\n";
|
||||
echo "✓ Maximum : 30 caractères UTF-8\n";
|
||||
echo "✓ Tous caractères acceptés (lettres, chiffres, espaces, émojis, accents, etc.)\n";
|
||||
echo "✓ Trim automatique des espaces début/fin\n";
|
||||
echo "✓ Sensible à la casse (Jean ≠ jean)\n";
|
||||
echo "✓ Unicité vérifiée dans toute la base\n\n";
|
||||
|
||||
echo $yellow . "Note: N'oubliez pas d'exécuter le script SQL de migration !" . $reset . "\n";
|
||||
echo "scripts/sql/migration_username_utf8_support.sql\n";
|
||||
Reference in New Issue
Block a user