feat: Version 3.3.4 - Nouvelle architecture pages, optimisations widgets Flutter et API

- Mise à jour VERSION vers 3.3.4
- Optimisations et révisions architecture API (deploy-api.sh, scripts de migration)
- Ajout documentation Stripe Tap to Pay complète
- Migration vers polices Inter Variable pour Flutter
- Optimisations build Android et nettoyage fichiers temporaires
- Amélioration système de déploiement avec gestion backups
- Ajout scripts CRON et migrations base de données

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
pierre
2025-10-05 20:11:15 +02:00
parent 242a90720e
commit b6584c83fa
1625 changed files with 145669 additions and 51249 deletions

View File

@@ -1 +1 @@
3.2.4 3.3.4

View File

@@ -14,10 +14,17 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Build Commands ## Build Commands
- Install dependencies: `composer install` - install PHP dependencies - Install dependencies: `composer install` - install PHP dependencies
- Update dependencies: `composer update` - update PHP dependencies to latest versions - Update dependencies: `composer update` - update PHP dependencies to latest versions
- Deploy to REC: `./livre-api.sh rec` - deploy from DVA to RECETTE environment - Deploy to DEV: `./deploy-api.sh` - deploy local code to dva-geo on IN3 (195.154.80.116)
- Deploy to PROD: `./livre-api.sh prod` - deploy from RECETTE to PRODUCTION environment - Deploy to REC: `./deploy-api.sh rca` - deploy from dva-geo to rca-geo on IN3
- Deploy to PROD: `./deploy-api.sh pra` - deploy from rca-geo (IN3) to pra-geo (IN4)
- Export operations: `php export_operation.php` - export operations data - Export operations: `php export_operation.php` - export operations data
## Development Environment
- **DEV Container**: dva-geo on IN3 server (195.154.80.116)
- **DEV API URL Public**: https://dapp.geosector.fr/api/
- **DEV API URL Internal**: http://13.23.33.43/api/
- **Access**: Via Incus container on IN3 server
## Code Architecture ## Code Architecture
This is a PHP 8.3 API without framework, using a custom MVC-like architecture: This is a PHP 8.3 API without framework, using a custom MVC-like architecture:

View File

@@ -0,0 +1 @@
{"ip":"169.155.255.55","timestamp":1758618220,"retrieved_at":"2025-09-23 09:03:41"}

30
api/data/README.md Normal file
View File

@@ -0,0 +1,30 @@
# Répertoire data
Ce répertoire contient les données de référence pour l'API.
## Fichiers
- `stripe_certified_devices.json` (optionnel) : Liste personnalisée des appareils certifiés Stripe Tap to Pay
## Format stripe_certified_devices.json
Si vous souhaitez ajouter des appareils supplémentaires à la liste intégrée, créez un fichier `stripe_certified_devices.json` avec le format suivant :
```json
[
{
"manufacturer": "Samsung",
"model": "Galaxy A55",
"model_identifier": "SM-A556B",
"min_android_version": 14
},
{
"manufacturer": "Fairphone",
"model": "Fairphone 5",
"model_identifier": "FP5",
"min_android_version": 13
}
]
```
Les appareils dans ce fichier seront ajoutés à la liste intégrée dans le script CRON.

View File

@@ -24,8 +24,8 @@ HOST_PORT="22"
HOST_USER="root" HOST_USER="root"
# Configuration des serveurs # Configuration des serveurs
RCA_HOST="195.154.80.116" # Serveur de recette RCA_HOST="195.154.80.116" # IN3 - Serveur de recette
PRA_HOST="51.159.7.190" # Serveur de production PRA_HOST="51.159.7.190" # IN4 - Serveur de production
# Configuration Incus # Configuration Incus
INCUS_PROJECT="default" INCUS_PROJECT="default"
@@ -33,9 +33,10 @@ API_PATH="/var/www/geosector/api"
FINAL_OWNER="nginx" FINAL_OWNER="nginx"
FINAL_GROUP="nginx" FINAL_GROUP="nginx"
FINAL_OWNER_LOGS="nobody" FINAL_OWNER_LOGS="nobody"
FINAL_GROUP_LOGS="nginx"
# Configuration de sauvegarde # Configuration de sauvegarde
BACKUP_DIR="/data/backup/geosector" BACKUP_DIR="/data/backup/geosector/api"
# Couleurs pour les messages # Couleurs pour les messages
GREEN='\033[0;32m' GREEN='\033[0;32m'
@@ -65,31 +66,20 @@ echo_error() {
exit 1 exit 1
} }
# Fonction pour créer une sauvegarde locale # Fonction pour nettoyer les anciens backups
create_local_backup() { cleanup_old_backups() {
local archive_file=$1 local prefix=""
local backup_type=$2 case $TARGET_ENV in
"dev") prefix="api-dev-" ;;
echo_info "Creating backup in ${BACKUP_DIR}..." "rca") prefix="api-rca-" ;;
"pra") prefix="api-pra-" ;;
if [ ! -d "${BACKUP_DIR}" ]; then esac
mkdir -p "${BACKUP_DIR}" || echo_warning "Could not create backup directory ${BACKUP_DIR}"
fi echo_info "Cleaning old backups (keeping last 10)..."
ls -t "${BACKUP_DIR}"/${prefix}*.tar.gz 2>/dev/null | tail -n +11 | xargs -r rm -f && {
if [ -d "${BACKUP_DIR}" ]; then REMAINING_BACKUPS=$(ls "${BACKUP_DIR}"/${prefix}*.tar.gz 2>/dev/null | wc -l)
BACKUP_FILE="${BACKUP_DIR}/api-${backup_type}-$(date +%Y%m%d-%H%M%S).tar.gz" echo_info "Kept ${REMAINING_BACKUPS} backup(s) for ${TARGET_ENV}"
cp "${archive_file}" "${BACKUP_FILE}" && { }
echo_info "Backup saved to: ${BACKUP_FILE}"
echo_info "Backup size: $(du -h "${BACKUP_FILE}" | cut -f1)"
# Nettoyer les anciens backups (garder les 10 derniers)
echo_info "Cleaning old backups (keeping last 10)..."
ls -t "${BACKUP_DIR}"/api-${backup_type}-*.tar.gz 2>/dev/null | tail -n +11 | xargs -r rm -f && {
REMAINING_BACKUPS=$(ls "${BACKUP_DIR}"/api-${backup_type}-*.tar.gz 2>/dev/null | wc -l)
echo_info "Kept ${REMAINING_BACKUPS} backup(s)"
}
} || echo_warning "Failed to create backup in ${BACKUP_DIR}"
fi
} }
# ===================================== # =====================================
@@ -98,16 +88,17 @@ create_local_backup() {
case $TARGET_ENV in case $TARGET_ENV in
"dev") "dev")
echo_step "Configuring for LOCAL DEV deployment" echo_step "Configuring for DEV deployment on IN3"
SOURCE_TYPE="local_code" SOURCE_TYPE="local_code"
DEST_CONTAINER="geo" DEST_CONTAINER="dva-geo"
DEST_HOST="local" DEST_HOST="${RCA_HOST}" # IN3 pour le DEV aussi
ENV_NAME="DEVELOPMENT" ENV_NAME="DEVELOPMENT"
;; ;;
"rca") "rca")
echo_step "Configuring for RECETTE delivery" echo_step "Configuring for RECETTE delivery"
SOURCE_TYPE="local_container" SOURCE_TYPE="remote_container"
SOURCE_CONTAINER="geo" SOURCE_CONTAINER="dva-geo"
SOURCE_HOST="${RCA_HOST}"
DEST_CONTAINER="rca-geo" DEST_CONTAINER="rca-geo"
DEST_HOST="${RCA_HOST}" DEST_HOST="${RCA_HOST}"
ENV_NAME="RECETTE" ENV_NAME="RECETTE"
@@ -132,9 +123,29 @@ echo_info "Deployment flow: ${ENV_NAME}"
# Création de l'archive selon la source # Création de l'archive selon la source
# ===================================== # =====================================
TIMESTAMP=$(date +%s) # Créer le dossier de backup s'il n'existe pas
ARCHIVE_NAME="api-deploy-${TIMESTAMP}.tar.gz" if [ ! -d "${BACKUP_DIR}" ]; then
TEMP_ARCHIVE="/tmp/${ARCHIVE_NAME}" echo_info "Creating backup directory ${BACKUP_DIR}..."
mkdir -p "${BACKUP_DIR}" || echo_error "Failed to create backup directory"
fi
# Horodatage format YYYYMMDDHH
TIMESTAMP=$(date +%Y%m%d%H)
# Nom de l'archive selon l'environnement
case $TARGET_ENV in
"dev")
ARCHIVE_NAME="api-dev-${TIMESTAMP}.tar.gz"
;;
"rca")
ARCHIVE_NAME="api-rca-${TIMESTAMP}.tar.gz"
;;
"pra")
ARCHIVE_NAME="api-pra-${TIMESTAMP}.tar.gz"
;;
esac
ARCHIVE_PATH="${BACKUP_DIR}/${ARCHIVE_NAME}"
if [ "$SOURCE_TYPE" = "local_code" ]; then if [ "$SOURCE_TYPE" = "local_code" ]; then
# DEV: Créer une archive depuis le code local # DEV: Créer une archive depuis le code local
@@ -165,34 +176,15 @@ if [ "$SOURCE_TYPE" = "local_code" ]; then
--exclude='*.swp' \ --exclude='*.swp' \
--exclude='*.swo' \ --exclude='*.swo' \
--exclude='*~' \ --exclude='*~' \
--warning=no-file-changed \ -czf "${ARCHIVE_PATH}" . 2>/dev/null || echo_error "Failed to create archive"
--no-xattrs \
-czf "${TEMP_ARCHIVE}" . || echo_error "Failed to create archive" echo_info "Archive created: ${ARCHIVE_PATH}"
echo_info "Archive size: $(du -h "${ARCHIVE_PATH}" | cut -f1)"
create_local_backup "${TEMP_ARCHIVE}" "dev" # Cette section n'est plus utilisée car RCA utilise maintenant remote_container
elif [ "$SOURCE_TYPE" = "local_container" ]; then
# RCA: Créer une archive depuis le container local
echo_step "Creating archive from local container ${SOURCE_CONTAINER}..."
echo_info "Switching to Incus project ${INCUS_PROJECT}..."
incus project switch ${INCUS_PROJECT} || echo_error "Failed to switch project"
# Créer l'archive directement depuis le container local
incus exec ${SOURCE_CONTAINER} -- tar \
--exclude='logs' \
--exclude='uploads' \
--warning=no-file-changed \
-czf /tmp/${ARCHIVE_NAME} -C ${API_PATH} . || echo_error "Failed to create archive from container"
# Récupérer l'archive depuis le container
incus file pull ${SOURCE_CONTAINER}/tmp/${ARCHIVE_NAME} ${TEMP_ARCHIVE} || echo_error "Failed to pull archive from container"
incus exec ${SOURCE_CONTAINER} -- rm -f /tmp/${ARCHIVE_NAME}
create_local_backup "${TEMP_ARCHIVE}" "to-rca"
elif [ "$SOURCE_TYPE" = "remote_container" ]; then elif [ "$SOURCE_TYPE" = "remote_container" ]; then
# PRA: Créer une archive depuis un container distant # RCA et PRA: Créer une archive depuis un container distant
echo_step "Creating archive from remote container ${SOURCE_CONTAINER} on ${SOURCE_HOST}..." echo_step "Creating archive from remote container ${SOURCE_CONTAINER} on ${SOURCE_HOST}..."
# Créer l'archive sur le serveur source # Créer l'archive sur le serveur source
@@ -201,7 +193,6 @@ elif [ "$SOURCE_TYPE" = "remote_container" ]; then
incus exec ${SOURCE_CONTAINER} -- tar \ incus exec ${SOURCE_CONTAINER} -- tar \
--exclude='logs' \ --exclude='logs' \
--exclude='uploads' \ --exclude='uploads' \
--warning=no-file-changed \
-czf /tmp/${ARCHIVE_NAME} -C ${API_PATH} . -czf /tmp/${ARCHIVE_NAME} -C ${API_PATH} .
" || echo_error "Failed to create archive on remote" " || echo_error "Failed to create archive on remote"
@@ -211,54 +202,23 @@ elif [ "$SOURCE_TYPE" = "remote_container" ]; then
incus exec ${SOURCE_CONTAINER} -- rm -f /tmp/${ARCHIVE_NAME} incus exec ${SOURCE_CONTAINER} -- rm -f /tmp/${ARCHIVE_NAME}
" || echo_error "Failed to extract archive from remote container" " || echo_error "Failed to extract archive from remote container"
# Copier l'archive vers la machine locale pour backup # Copier l'archive vers la machine locale
scp -i ${HOST_KEY} -P ${HOST_PORT} ${HOST_USER}@${SOURCE_HOST}:/tmp/${ARCHIVE_NAME} ${TEMP_ARCHIVE} || echo_error "Failed to copy archive locally" scp -i ${HOST_KEY} -P ${HOST_PORT} ${HOST_USER}@${SOURCE_HOST}:/tmp/${ARCHIVE_NAME} ${ARCHIVE_PATH} || echo_error "Failed to copy archive locally"
create_local_backup "${TEMP_ARCHIVE}" "to-pra" echo_info "Archive saved: ${ARCHIVE_PATH}"
echo_info "Archive size: $(du -h "${ARCHIVE_PATH}" | cut -f1)"
fi fi
ARCHIVE_SIZE=$(du -h "${TEMP_ARCHIVE}" | cut -f1) # Nettoyer les anciens backups
echo_info "Archive size: ${ARCHIVE_SIZE}" cleanup_old_backups
# ===================================== # =====================================
# Déploiement selon la destination # Déploiement selon la destination
# ===================================== # =====================================
if [ "$DEST_HOST" = "local" ]; then # Tous les déploiements se font maintenant sur des containers distants
# Déploiement sur container local (DEV) if [ "$DEST_HOST" != "local" ]; then
echo_step "Deploying to local container ${DEST_CONTAINER}..." # Déploiement sur container distant (DEV, RCA ou PRA)
echo_info "Switching to Incus project ${INCUS_PROJECT}..."
incus project switch ${INCUS_PROJECT} || echo_error "Failed to switch to project ${INCUS_PROJECT}"
echo_info "Pushing archive to container..."
incus file push "${TEMP_ARCHIVE}" ${DEST_CONTAINER}/tmp/${ARCHIVE_NAME} || echo_error "Failed to push archive to container"
echo_info "Preparing deployment directory..."
incus exec ${DEST_CONTAINER} -- mkdir -p ${API_PATH} || echo_error "Failed to create deployment directory"
incus exec ${DEST_CONTAINER} -- rm -rf ${API_PATH}/* || echo_warning "Could not clean deployment directory"
echo_info "Extracting archive..."
incus exec ${DEST_CONTAINER} -- tar -xzf /tmp/${ARCHIVE_NAME} -C ${API_PATH}/ || echo_error "Failed to extract archive"
echo_info "Setting permissions..."
incus exec ${DEST_CONTAINER} -- mkdir -p ${API_PATH}/logs ${API_PATH}/uploads
incus exec ${DEST_CONTAINER} -- chown -R ${FINAL_OWNER}:${FINAL_GROUP} ${API_PATH}
incus exec ${DEST_CONTAINER} -- find ${API_PATH} -type d -exec chmod 755 {} \;
incus exec ${DEST_CONTAINER} -- find ${API_PATH} -type f -exec chmod 644 {} \;
# Permissions spéciales pour logs et uploads
incus exec ${DEST_CONTAINER} -- chown -R ${FINAL_OWNER}:${FINAL_OWNER_LOGS} ${API_PATH}/logs ${API_PATH}/uploads
incus exec ${DEST_CONTAINER} -- chmod -R 775 ${API_PATH}/logs ${API_PATH}/uploads
echo_info "Updating Composer dependencies..."
incus exec ${DEST_CONTAINER} -- bash -c "cd ${API_PATH} && composer update --no-dev --optimize-autoloader" || echo_warning "Composer not available or failed"
echo_info "Cleaning up..."
incus exec ${DEST_CONTAINER} -- rm -f /tmp/${ARCHIVE_NAME}
else
# Déploiement sur container distant (RCA ou PRA)
echo_step "Deploying to remote container ${DEST_CONTAINER} on ${DEST_HOST}..." echo_step "Deploying to remote container ${DEST_CONTAINER} on ${DEST_HOST}..."
# Créer une sauvegarde sur le serveur de destination # Créer une sauvegarde sur le serveur de destination
@@ -276,17 +236,20 @@ else
# Transférer l'archive vers le serveur de destination # Transférer l'archive vers le serveur de destination
echo_info "Transferring archive to ${DEST_HOST}..." echo_info "Transferring archive to ${DEST_HOST}..."
if [ "$SOURCE_TYPE" = "local_container" ]; then if [ "$SOURCE_TYPE" = "local_code" ]; then
# Pour RCA: copier depuis local vers distant # Pour DEV: copier depuis local vers IN3
scp -i ${HOST_KEY} -P ${HOST_PORT} ${TEMP_ARCHIVE} ${HOST_USER}@${DEST_HOST}:/tmp/${ARCHIVE_NAME} || echo_error "Failed to copy archive to destination" scp -i ${HOST_KEY} -P ${HOST_PORT} ${ARCHIVE_PATH} ${HOST_USER}@${DEST_HOST}:/tmp/${ARCHIVE_NAME} || echo_error "Failed to copy archive to destination"
elif [ "$SOURCE_TYPE" = "remote_container" ] && [ "$SOURCE_HOST" = "$DEST_HOST" ]; then
# Pour RCA: même serveur (IN3), pas de transfert nécessaire, l'archive est déjà là
echo_info "Archive already on destination server (same host)"
else else
# Pour PRA: copier de serveur à serveur # Pour PRA: l'archive est déjà sur la machine locale (copiée depuis IN3)
ssh -i ${HOST_KEY} -p ${HOST_PORT} ${HOST_USER}@${SOURCE_HOST} " # On la transfère maintenant vers IN4
scp -i ${HOST_KEY} -P ${HOST_PORT} /tmp/${ARCHIVE_NAME} ${HOST_USER}@${DEST_HOST}:/tmp/${ARCHIVE_NAME} echo_info "Transferring archive from local to IN4..."
" || echo_error "Failed to transfer archive between servers" scp -i ${HOST_KEY} -P ${HOST_PORT} ${ARCHIVE_PATH} ${HOST_USER}@${DEST_HOST}:/tmp/${ARCHIVE_NAME} || echo_error "Failed to copy archive to IN4"
# Nettoyer sur le serveur source # Nettoyer sur le serveur source IN3
ssh -i ${HOST_KEY} -p ${HOST_PORT} ${HOST_USER}@${SOURCE_HOST} "rm -f /tmp/${ARCHIVE_NAME}" ssh -i ${HOST_KEY} -p ${HOST_PORT} ${HOST_USER}@${SOURCE_HOST} "rm -f /tmp/${ARCHIVE_NAME}" || echo_warning "Could not clean source server"
fi fi
# Déployer sur le container de destination # Déployer sur le container de destination
@@ -311,16 +274,16 @@ else
# Permissions spéciales pour logs # Permissions spéciales pour logs
incus exec ${DEST_CONTAINER} -- test -d ${API_PATH}/logs && incus exec ${DEST_CONTAINER} -- test -d ${API_PATH}/logs &&
incus exec ${DEST_CONTAINER} -- chown -R ${FINAL_OWNER}:${FINAL_OWNER_LOGS} ${API_PATH}/logs && incus exec ${DEST_CONTAINER} -- chown -R ${FINAL_OWNER_LOGS}:${FINAL_GROUP_LOGS} ${API_PATH}/logs &&
incus exec ${DEST_CONTAINER} -- chmod -R 775 ${API_PATH}/logs || true && incus exec ${DEST_CONTAINER} -- chmod -R 755 ${API_PATH}/logs || true &&
# Permissions spéciales pour uploads # Permissions spéciales pour uploads
incus exec ${DEST_CONTAINER} -- test -d ${API_PATH}/uploads && incus exec ${DEST_CONTAINER} -- test -d ${API_PATH}/uploads &&
incus exec ${DEST_CONTAINER} -- chown -R ${FINAL_OWNER}:${FINAL_OWNER_LOGS} ${API_PATH}/uploads && incus exec ${DEST_CONTAINER} -- chown -R ${FINAL_OWNER_LOGS}:${FINAL_GROUP_LOGS} ${API_PATH}/uploads &&
incus exec ${DEST_CONTAINER} -- chmod -R 775 ${API_PATH}/uploads || true && incus exec ${DEST_CONTAINER} -- chmod -R 755 ${API_PATH}/uploads || true &&
# Composer # Composer
incus exec ${DEST_CONTAINER} -- bash -c 'cd ${API_PATH} && composer update --no-dev --optimize-autoloader' || echo 'Composer update skipped' && incus exec ${DEST_CONTAINER} -- bash -c 'cd ${API_PATH} && composer install --no-dev --optimize-autoloader' || echo 'Composer install skipped' &&
# Nettoyage # Nettoyage
incus exec ${DEST_CONTAINER} -- rm -f /tmp/${ARCHIVE_NAME} && incus exec ${DEST_CONTAINER} -- rm -f /tmp/${ARCHIVE_NAME} &&
@@ -330,8 +293,8 @@ else
echo_info "Remote backup saved: ${REMOTE_BACKUP_DIR} on ${DEST_CONTAINER}" echo_info "Remote backup saved: ${REMOTE_BACKUP_DIR} on ${DEST_CONTAINER}"
fi fi
# Nettoyage local # L'archive reste dans le dossier de backup, pas de nettoyage nécessaire
rm -f "${TEMP_ARCHIVE}" echo_info "Archive preserved in backup directory: ${ARCHIVE_PATH}"
# ===================================== # =====================================
# Résumé final # Résumé final
@@ -341,9 +304,9 @@ echo_step "Deployment completed successfully!"
echo_info "Environment: ${ENV_NAME}" echo_info "Environment: ${ENV_NAME}"
if [ "$TARGET_ENV" = "dev" ]; then if [ "$TARGET_ENV" = "dev" ]; then
echo_info "Deployed from local code to container ${DEST_CONTAINER}" echo_info "Deployed from local code to container ${DEST_CONTAINER} on IN3 (${DEST_HOST})"
elif [ "$TARGET_ENV" = "rca" ]; then elif [ "$TARGET_ENV" = "rca" ]; then
echo_info "Delivered from ${SOURCE_CONTAINER} (local) to ${DEST_CONTAINER} on ${DEST_HOST}" echo_info "Delivered from ${SOURCE_CONTAINER} to ${DEST_CONTAINER} on ${DEST_HOST}"
elif [ "$TARGET_ENV" = "pra" ]; then elif [ "$TARGET_ENV" = "pra" ]; then
echo_info "Delivered from ${SOURCE_CONTAINER} on ${SOURCE_HOST} to ${DEST_CONTAINER} on ${DEST_HOST}" echo_info "Delivered from ${SOURCE_CONTAINER} on ${SOURCE_HOST} to ${DEST_CONTAINER} on ${DEST_HOST}"
fi fi
@@ -351,4 +314,4 @@ fi
echo_info "Deployment completed at: $(date)" echo_info "Deployment completed at: $(date)"
# Journaliser le déploiement # Journaliser le déploiement
echo "$(date '+%Y-%m-%d %H:%M:%S') - API deployed to ${ENV_NAME} (${DEST_CONTAINER})" >> ~/.geo_deploy_history echo "$(date '+%Y-%m-%d %H:%M:%S') - API deployed to ${ENV_NAME} (${DEST_CONTAINER}) - Archive: ${ARCHIVE_NAME}" >> ~/.geo_deploy_history

View File

@@ -1,6 +1,7 @@
# PLANNING STRIPE - DÉVELOPPEUR BACKEND PHP # PLANNING STRIPE - DÉVELOPPEUR BACKEND PHP
## API PHP 8.3 - Intégration Stripe Connect + Terminal ## API PHP 8.3 - Intégration Stripe Tap to Pay (Mobile uniquement)
### Période : 25/08/2024 - 05/09/2024 ### Période : 25/08/2024 - 05/09/2024
### Mise à jour : Janvier 2025 - Simplification architecture
--- ---
@@ -31,7 +32,13 @@ composer require stripe/stripe-php
#### ✅ Base de données #### ✅ Base de données
```sql ```sql
-- Tables à créer -- Modification de la table ope_pass existante (JANVIER 2025)
ALTER TABLE `ope_pass`
DROP COLUMN IF EXISTS `is_striped`,
ADD COLUMN `stripe_payment_id` VARCHAR(50) DEFAULT NULL COMMENT 'ID du PaymentIntent Stripe (pi_xxx)',
ADD INDEX `idx_stripe_payment` (`stripe_payment_id`);
-- Tables à créer (simplifiées)
CREATE TABLE stripe_accounts ( CREATE TABLE stripe_accounts (
id INT PRIMARY KEY AUTO_INCREMENT, id INT PRIMARY KEY AUTO_INCREMENT,
amicale_id INT NOT NULL, amicale_id INT NOT NULL,
@@ -44,32 +51,8 @@ CREATE TABLE stripe_accounts (
FOREIGN KEY (amicale_id) REFERENCES amicales(id) FOREIGN KEY (amicale_id) REFERENCES amicales(id)
); );
CREATE TABLE payment_intents ( -- NOTE: Table payment_intents SUPPRIMÉE - on utilise directement stripe_payment_id dans ope_pass
id INT PRIMARY KEY AUTO_INCREMENT, -- NOTE: Table terminal_readers SUPPRIMÉE - Tap to Pay uniquement, pas de terminaux externes
stripe_payment_intent_id VARCHAR(255) UNIQUE,
amicale_id INT NOT NULL,
pompier_id INT NOT NULL,
amount INT NOT NULL, -- en centimes
currency VARCHAR(3) DEFAULT 'eur',
status VARCHAR(50),
application_fee INT,
metadata JSON,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (amicale_id) REFERENCES amicales(id),
FOREIGN KEY (pompier_id) REFERENCES users(id)
);
CREATE TABLE terminal_readers (
id INT PRIMARY KEY AUTO_INCREMENT,
stripe_reader_id VARCHAR(255) UNIQUE,
amicale_id INT NOT NULL,
label VARCHAR(255),
location VARCHAR(255),
status VARCHAR(50),
device_type VARCHAR(50),
last_seen_at TIMESTAMP,
FOREIGN KEY (amicale_id) REFERENCES amicales(id)
);
CREATE TABLE android_certified_devices ( CREATE TABLE android_certified_devices (
id INT PRIMARY KEY AUTO_INCREMENT, id INT PRIMARY KEY AUTO_INCREMENT,
@@ -162,45 +145,47 @@ public function handleWebhook(Request $request) {
} }
``` ```
#### ✅ Terminal Connection Token #### ✅ Configuration Tap to Pay
```php ```php
// POST /api/terminal/connection-token // POST /api/stripe/tap-to-pay/init
public function createConnectionToken(Request $request) { public function initTapToPay(Request $request) {
$pompier = Auth::user(); $userId = Session::getUserId();
$amicale = $pompier->amicale; $entityId = Session::getEntityId();
$connectionToken = \Stripe\Terminal\ConnectionToken::create([ // Vérifier que l'entité a un compte Stripe
'location' => $amicale->stripe_location_id, $account = $this->getStripeAccount($entityId);
], [
'stripe_account' => $amicale->stripe_account_id return [
]); 'stripe_account_id' => $account->stripe_account_id,
'tap_to_pay_enabled' => true
return ['secret' => $connectionToken->secret]; ];
} }
``` ```
### 🌆 Après-midi (4h) ### 🌆 Après-midi (4h)
#### ✅ Gestion des Locations #### ✅ Vérification compatibilité Device
```php ```php
// POST /api/amicales/{id}/create-location // POST /api/stripe/devices/check-tap-to-pay
public function createLocation($amicaleId) { public function checkTapToPayCapability(Request $request) {
$amicale = Amicale::find($amicaleId); $platform = $request->input('platform');
$model = $request->input('device_model');
$location = \Stripe\Terminal\Location::create([ $osVersion = $request->input('os_version');
'display_name' => $amicale->name,
'address' => [ if ($platform === 'iOS') {
'line1' => $amicale->address, // iPhone XS et ultérieurs avec iOS 16.4+
'city' => $amicale->city, $supported = $this->checkiOSCompatibility($model, $osVersion);
'postal_code' => $amicale->postal_code, } else {
'country' => 'FR', // Android certifié pour la France
], $supported = $this->checkAndroidCertification($model);
], [ }
'stripe_account' => $amicale->stripe_account_id
]); return [
'tap_to_pay_supported' => $supported,
$amicale->update(['stripe_location_id' => $location->id]); 'message' => $supported ?
return $location; 'Tap to Pay disponible' :
'Appareil non compatible'
];
} }
``` ```
@@ -210,24 +195,22 @@ public function createLocation($amicaleId) {
### 🌅 Matin (4h) ### 🌅 Matin (4h)
#### ✅ Création PaymentIntent avec commission #### ✅ Création PaymentIntent avec association au passage
```php ```php
// POST /api/payments/create-intent // POST /api/payments/create-intent
public function createPaymentIntent(Request $request) { public function createPaymentIntent(Request $request) {
$validated = $request->validate([ $validated = $request->validate([
'amount' => 'required|integer|min:100', // en centimes 'amount' => 'required|integer|min:100', // en centimes
'amicale_id' => 'required|exists:amicales,id', 'passage_id' => 'required|integer', // ID du passage ope_pass
'entity_id' => 'required|integer',
]); ]);
$pompier = Auth::user(); $userId = Session::getUserId();
$amicale = Amicale::find($validated['amicale_id']); $entity = $this->getEntity($validated['entity_id']);
// Calculer la commission (2.5% ou 50 centimes minimum) // Commission à 0% (décision client)
$applicationFee = max( $applicationFee = 0;
50, // 0.50€ minimum
round($validated['amount'] * 0.025) // 2.5%
);
$paymentIntent = \Stripe\PaymentIntent::create([ $paymentIntent = \Stripe\PaymentIntent::create([
'amount' => $validated['amount'], 'amount' => $validated['amount'],
'currency' => 'eur', 'currency' => 'eur',
@@ -235,26 +218,27 @@ public function createPaymentIntent(Request $request) {
'capture_method' => 'automatic', 'capture_method' => 'automatic',
'application_fee_amount' => $applicationFee, 'application_fee_amount' => $applicationFee,
'transfer_data' => [ 'transfer_data' => [
'destination' => $amicale->stripe_account_id, 'destination' => $entity->stripe_account_id,
], ],
'metadata' => [ 'metadata' => [
'pompier_id' => $pompier->id, 'passage_id' => $validated['passage_id'],
'pompier_name' => $pompier->name, 'user_id' => $userId,
'amicale_id' => $amicale->id, 'entity_id' => $entity->id,
'calendrier_annee' => date('Y'), 'year' => date('Y'),
], ],
]); ]);
// Sauvegarder en DB // Mise à jour directe dans ope_pass
PaymentIntent::create([ $this->db->prepare("
'stripe_payment_intent_id' => $paymentIntent->id, UPDATE ope_pass
'amicale_id' => $amicale->id, SET stripe_payment_id = :stripe_id,
'pompier_id' => $pompier->id, date_modified = NOW()
'amount' => $validated['amount'], WHERE id = :passage_id
'application_fee' => $applicationFee, ")->execute([
'status' => $paymentIntent->status, ':stripe_id' => $paymentIntent->id,
':passage_id' => $validated['passage_id']
]); ]);
return [ return [
'client_secret' => $paymentIntent->client_secret, 'client_secret' => $paymentIntent->client_secret,
'payment_intent_id' => $paymentIntent->id, 'payment_intent_id' => $paymentIntent->id,
@@ -268,31 +252,59 @@ public function createPaymentIntent(Request $request) {
```php ```php
// POST /api/payments/{id}/capture // POST /api/payments/{id}/capture
public function capturePayment($paymentIntentId) { public function capturePayment($paymentIntentId) {
$localPayment = PaymentIntent::where('stripe_payment_intent_id', $paymentIntentId)->first(); // Récupérer le passage depuis ope_pass
$stmt = $this->db->prepare("
SELECT id, stripe_payment_id, montant
FROM ope_pass
WHERE stripe_payment_id = :stripe_id
");
$stmt->execute([':stripe_id' => $paymentIntentId]);
$passage = $stmt->fetch();
$paymentIntent = \Stripe\PaymentIntent::retrieve($paymentIntentId); $paymentIntent = \Stripe\PaymentIntent::retrieve($paymentIntentId);
if ($paymentIntent->status === 'requires_capture') { if ($paymentIntent->status === 'requires_capture') {
$paymentIntent->capture(); $paymentIntent->capture();
} }
$localPayment->update(['status' => $paymentIntent->status]); // Mettre à jour le statut dans ope_pass si nécessaire
if ($paymentIntent->status === 'succeeded' && $passage) {
// Si succès, envoyer email reçu $this->db->prepare("
if ($paymentIntent->status === 'succeeded') { UPDATE ope_pass
$this->sendReceipt($localPayment); SET date_stripe_validated = NOW()
WHERE id = :passage_id
")->execute([':passage_id' => $passage['id']]);
// Envoyer email reçu si configuré
$this->sendReceipt($passage['id']);
} }
return $paymentIntent; return $paymentIntent;
} }
// GET /api/payments/{id}/status // GET /api/passages/{id}/stripe-status
public function getPaymentStatus($paymentIntentId) { public function getPassageStripeStatus($passageId) {
$payment = PaymentIntent::where('stripe_payment_intent_id', $paymentIntentId)->first(); $stmt = $this->db->prepare("
SELECT stripe_payment_id, montant, date_creat
FROM ope_pass
WHERE id = :id
");
$stmt->execute([':id' => $passageId]);
$passage = $stmt->fetch();
if (!$passage['stripe_payment_id']) {
return ['status' => 'no_stripe_payment'];
}
// Récupérer le statut depuis Stripe
$paymentIntent = \Stripe\PaymentIntent::retrieve($passage['stripe_payment_id']);
return [ return [
'status' => $payment->status, 'stripe_payment_id' => $passage['stripe_payment_id'],
'amount' => $payment->amount, 'status' => $paymentIntent->status,
'created_at' => $payment->created_at, 'amount' => $paymentIntent->amount,
'currency' => $paymentIntent->currency,
'created_at' => $passage['date_creat']
]; ];
} }
``` ```
@@ -625,14 +637,14 @@ Log::channel('stripe')->info('Payment created', [
## 🎯 BILAN DÉVELOPPEMENT API (01/09/2024) ## 🎯 BILAN DÉVELOPPEMENT API (01/09/2024)
### ✅ ENDPOINTS IMPLÉMENTÉS ET TESTÉS ### ✅ ENDPOINTS IMPLÉMENTÉS (TAP TO PAY UNIQUEMENT)
#### **Stripe Connect - Comptes** #### **Stripe Connect - Comptes**
- **POST /api/stripe/accounts** ✅ - **POST /api/stripe/accounts** ✅
- Création compte Stripe Express pour amicales - Création compte Stripe Express pour amicales
- Gestion déchiffrement données (encrypted_email, encrypted_name) - Gestion déchiffrement données (encrypted_email, encrypted_name)
- Support des comptes existants - Support des comptes existants
- **GET /api/stripe/accounts/:entityId/status** ✅ - **GET /api/stripe/accounts/:entityId/status** ✅
- Récupération statut complet du compte - Récupération statut complet du compte
- Vérification charges_enabled et payouts_enabled - Vérification charges_enabled et payouts_enabled
@@ -643,17 +655,6 @@ Log::channel('stripe')->info('Payment created', [
- URLs de retour configurées - URLs de retour configurées
- Gestion des erreurs et timeouts - Gestion des erreurs et timeouts
#### **Terminal et Locations**
- **POST /api/stripe/locations** ✅
- Création de locations Terminal
- Association avec compte Stripe de l'amicale
- ID location retourné : tml_GLJ21w7KCYX4Wj
- **POST /api/stripe/terminal/connection-token** ✅
- Génération tokens de connexion Terminal
- Authentification par session
- Support multi-amicales
#### **Configuration et Utilitaires** #### **Configuration et Utilitaires**
- **GET /api/stripe/config** ✅ - **GET /api/stripe/config** ✅
- Configuration publique Stripe - Configuration publique Stripe
@@ -728,9 +729,10 @@ Log::channel('stripe')->info('Payment created', [
- Public endpoints: webhook uniquement - Public endpoints: webhook uniquement
- Pas de stockage clés secrètes en base - Pas de stockage clés secrètes en base
#### **Base de données** #### **Base de données (MISE À JOUR JANVIER 2025)**
- **Modification table `ope_pass`** : `stripe_payment_id` VARCHAR(50) remplace `is_striped`
- **Table `payment_intents` supprimée** : Intégration directe dans `ope_pass`
- Utilisation tables existantes (entites) - Utilisation tables existantes (entites)
- Pas de nouvelles tables créées (pas nécessaire pour V1)
- Champs encrypted_email et encrypted_name supportés - Champs encrypted_email et encrypted_name supportés
- Déchiffrement automatique avant envoi Stripe - Déchiffrement automatique avant envoi Stripe
@@ -743,4 +745,74 @@ Log::channel('stripe')->info('Payment created', [
--- ---
*Document créé le 24/08/2024 - Dernière mise à jour : 01/09/2024* ## 📱 FLOW TAP TO PAY SIMPLIFIÉ (Janvier 2025)
### Architecture
```
Flutter App (Tap to Pay) ↔ API PHP ↔ Stripe API
```
### Étape 1: Création PaymentIntent
**Flutter → API**
```json
POST /api/stripe/payments/create-intent
{
"amount": 1500,
"passage_id": 123,
"entity_id": 5
}
```
**API → Stripe → Base de données**
```php
// 1. Créer le PaymentIntent
$paymentIntent = Stripe\PaymentIntent::create([...]);
// 2. Sauvegarder dans ope_pass
UPDATE ope_pass SET stripe_payment_id = 'pi_xxx' WHERE id = 123;
```
**API → Flutter**
```json
{
"client_secret": "pi_xxx_secret_yyy",
"payment_intent_id": "pi_xxx"
}
```
### Étape 2: Collecte du paiement (Flutter)
- L'app Flutter utilise le SDK Stripe Terminal
- Le téléphone devient le terminal de paiement (Tap to Pay)
- Utilise le client_secret pour collecter le paiement
### Étape 3: Confirmation (Webhook)
**Stripe → API**
- Event: `payment_intent.succeeded`
- Met à jour le statut dans la base de données
### Tables nécessaires
- ✅ `ope_pass.stripe_payment_id` - Association passage/paiement
- ✅ `stripe_accounts` - Comptes Connect des amicales
- ✅ `android_certified_devices` - Vérification compatibilité
- ❌ ~~`stripe_payment_intents`~~ - Supprimée
- ❌ ~~`terminal_readers`~~ - Pas de terminaux externes
### Endpoints essentiels
1. `POST /api/stripe/payments/create-intent` - Créer PaymentIntent
2. `POST /api/stripe/devices/check-tap-to-pay` - Vérifier compatibilité
3. `POST /api/stripe/webhook` - Recevoir confirmations
4. `GET /api/passages/{id}/stripe-status` - Vérifier statut
---
## 📝 CHANGELOG
### Janvier 2025 - Refactoring base de données
- **Suppression** de la table `payment_intents` (non nécessaire)
- **Migration** : `is_striped` → `stripe_payment_id` VARCHAR(50) dans `ope_pass`
- **Simplification** : Association directe PaymentIntent ↔ Passage
- **Avantage** : Traçabilité directe sans table intermédiaire
---
*Document créé le 24/08/2024 - Dernière mise à jour : 09/01/2025*

View File

@@ -0,0 +1,343 @@
# Flow de paiement Stripe Tap to Pay
## Vue d'ensemble
Ce document décrit le flow complet pour les paiements Stripe Tap to Pay dans l'application GeoSector, depuis la création du compte Stripe Connect jusqu'au paiement final.
---
## 🏢 PRÉALABLE : Création d'un compte Amicale Stripe Connect
Avant de pouvoir utiliser les paiements Stripe, chaque amicale doit créer son compte Stripe Connect.
### 📋 Flow de création du compte
#### 1. Initiation depuis l'application web admin
**Endpoint :** `POST /api/stripe/accounts/create`
**Requête :**
```json
{
"amicale_id": 45,
"type": "express", // Type de compte Stripe Connect
"country": "FR",
"email": "contact@amicale-pompiers-paris.fr",
"business_profile": {
"name": "Amicale des Pompiers de Paris",
"product_description": "Vente de calendriers des pompiers",
"mcc": "8398", // Code activité : organisations civiques
"url": "https://www.amicale-pompiers-paris.fr"
}
}
```
#### 2. Création du compte Stripe
**Actions API :**
1. Appel Stripe API pour créer un compte Express
2. Génération d'un lien d'onboarding personnalisé
3. Sauvegarde en base de données
**Réponse :**
```json
{
"success": true,
"stripe_account_id": "acct_1O3ABC456DEF789",
"onboarding_url": "https://connect.stripe.com/express/oauth/authorize?...",
"status": "pending"
}
```
#### 3. Processus d'onboarding Stripe
**Actions utilisateur (dirigeant amicale) :**
1. Clic sur le lien d'onboarding
2. Connexion/création compte Stripe
3. Saisie des informations légales :
- **Entité** : Association loi 1901
- **SIRET** de l'amicale
- **RIB** pour les virements
- **Pièce d'identité** du représentant légal
4. Validation des conditions d'utilisation
#### 4. Vérification et activation
**Webhook Stripe → API :**
```json
POST /api/stripe/webhooks
{
"type": "account.updated",
"data": {
"object": {
"id": "acct_1O3ABC456DEF789",
"charges_enabled": true,
"payouts_enabled": true,
"details_submitted": true
}
}
}
```
**Actions API :**
1. Mise à jour du statut en base
2. Notification email à l'amicale
3. Activation des fonctionnalités de paiement
#### 5. Structure en base de données
**Table `stripe_accounts` :**
```sql
CREATE TABLE `stripe_accounts` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`fk_entite` int(10) unsigned NOT NULL,
`stripe_account_id` varchar(50) NOT NULL,
`account_type` enum('express','standard','custom') DEFAULT 'express',
`charges_enabled` tinyint(1) DEFAULT 0,
`payouts_enabled` tinyint(1) DEFAULT 0,
`details_submitted` tinyint(1) DEFAULT 0,
`country` varchar(2) DEFAULT 'FR',
`default_currency` varchar(3) DEFAULT 'eur',
`business_name` varchar(255) DEFAULT NULL,
`support_email` varchar(255) DEFAULT NULL,
`onboarding_completed_at` timestamp NULL DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp(),
PRIMARY KEY (`id`),
UNIQUE KEY `stripe_account_id` (`stripe_account_id`),
KEY `fk_entite` (`fk_entite`),
CONSTRAINT `stripe_accounts_ibfk_1` FOREIGN KEY (`fk_entite`) REFERENCES `entites` (`id`)
);
```
### 🔐 Sécurité et validation
#### Prérequis pour créer un compte :
- ✅ Utilisateur administrateur de l'amicale
- ✅ Amicale active avec statut validé
- ✅ Email de contact vérifié
- ✅ Informations légales complètes (SIRET, adresse)
#### Validation avant paiements :
-`charges_enabled = 1` (peut recevoir des paiements)
-`payouts_enabled = 1` (peut recevoir des virements)
-`details_submitted = 1` (onboarding terminé)
### 📊 États du compte Stripe
| État | Description | Actions possibles |
|------|-------------|-------------------|
| `pending` | Compte créé, onboarding en cours | Compléter l'onboarding |
| `restricted` | Informations manquantes | Fournir documents manquants |
| `restricted_soon` | Vérification en cours | Attendre validation Stripe |
| `active` | Compte opérationnel | Recevoir des paiements ✅ |
| `rejected` | Compte refusé par Stripe | Contacter support |
### 🚨 Gestion des erreurs
#### Erreurs courantes lors de la création :
- **400** : Données manquantes ou invalides
- **409** : Compte Stripe déjà existant pour cette amicale
- **403** : Utilisateur non autorisé
#### Erreurs durant l'onboarding :
- Documents manquants ou invalides
- Informations bancaires incorrectes
- Activité non autorisée par Stripe
### 📞 Support et résolution
#### Pour les amicales :
1. **Email support** : support@geosector.fr
2. **Documentation** : Guides d'onboarding disponibles
3. **Assistance téléphonique** : Disponible aux heures ouvrables
#### Pour les développeurs :
1. **Stripe Dashboard** : Accès aux comptes et statuts
2. **Logs API** : Traçabilité complète des opérations
3. **Webhook monitoring** : Suivi des événements Stripe
---
## 🚨 IMPORTANT : Nouveau Flow (v2)
**Le passage est TOUJOURS créé/modifié EN PREMIER** pour obtenir un ID réel, PUIS le PaymentIntent est créé avec cet ID.
## Flow détaillé
### 1. Sauvegarde du passage EN PREMIER
L'application crée ou modifie d'abord le passage pour obtenir un ID réel :
```
POST /api/passages/create // Nouveau passage
PUT /api/passages/456 // Mise à jour passage existant
```
**Réponse avec l'ID réel :**
```json
{
"status": "success",
"passage_id": 456 // ID RÉEL du passage créé/modifié
}
```
### 2. Création du PaymentIntent AVEC l'ID réel
Ensuite seulement, création du PaymentIntent avec le `passage_id` réel :
```
POST /api/stripe/payments/create-intent
```
```json
{
"amount": 2500, // En centimes (25€)
"passage_id": 456, // ID RÉEL du passage (JAMAIS 0)
"payment_method_types": ["card_present"], // Tap to Pay
"location_id": "tml_xxx", // Terminal reader location
"amicale_id": 45,
"member_id": 67,
"stripe_account": "acct_xxx"
}
```
#### Réponse
```json
{
"status": "success",
"data": {
"client_secret": "pi_3QaXYZ_secret_xyz",
"payment_intent_id": "pi_3QaXYZ123ABC456",
"amount": 2500,
"currency": "eur",
"passage_id": 789, // 0 pour nouveau passage
"type": "tap_to_pay"
}
}
```
### 2. Traitement du paiement côté client
L'application utilise le SDK Stripe pour traiter le paiement via NFC :
```dart
// Flutter - Utilisation du client_secret
final paymentResult = await stripe.collectPaymentMethod(
clientSecret: response['client_secret'],
// ... configuration Tap to Pay
);
```
### 3. Traitement du paiement Tap to Pay
L'application utilise le SDK Stripe Terminal avec le `client_secret` pour collecter le paiement via NFC.
### 4. Mise à jour du passage avec stripe_payment_id
Après succès du paiement, l'app met à jour le passage avec le `stripe_payment_id` :
```json
PUT /api/passages/456
{
"stripe_payment_id": "pi_3QaXYZ123ABC456", // ← LIEN AVEC STRIPE
// ... autres champs si nécessaire
}
```
## Points clés du nouveau flow
### ✅ Avantages
1. **Passage toujours existant** : Le passage existe toujours avec un ID réel avant le paiement
2. **Traçabilité garantie** : Le `passage_id` dans Stripe est toujours valide
3. **Gestion d'erreur robuste** : Si le paiement échoue, le passage existe déjà
4. **Cohérence des données** : Pas de passage "orphelin" ou de paiement sans passage
### ❌ Ce qui n'est plus supporté
1. **passage_id=0** : Plus jamais utilisé dans `/create-intent`
2. **operation_id** : Plus nécessaire car le passage existe déjà
3. **Création conditionnelle** : Le passage est toujours créé avant
## Schéma de séquence (Nouveau Flow v2)
```
┌─────────┐ ┌─────────┐ ┌────────┐ ┌────────────┐
│ App │ │ API │ │ Stripe │ │ ope_pass │
└────┬────┘ └────┬────┘ └────┬───┘ └─────┬──────┘
│ │ │ │
│ 1. CREATE/UPDATE passage │ │
├──────────────>│ │ │
│ ├────────────────┼───────────────>│
│ │ │ INSERT/UPDATE │
│ │ │ │
│ 2. passage_id: 456 (réel) │ │
│<──────────────│ │ │
│ │ │ │
│ 3. create-intent (id=456) │ │
├──────────────>│ │ │
│ │ │ │
│ │ 4. Create PI │ │
│ ├───────────────>│ │
│ │ │ │
│ │ 5. PI created │ │
│ │<───────────────│ │
│ │ │ │
│ │ 6. UPDATE │ │
│ ├────────────────┼───────────────>│
│ │ stripe_payment_id = pi_xxx │
│ │ │ │
│ 7. client_secret + pi_id │ │
│<──────────────│ │ │
│ │ │ │
│ 8. Tap to Pay │ │ │
├───────────────┼───────────────>│ │
│ avec SDK │ │ │
│ │ │ │
│ 9. Payment OK │ │ │
│<──────────────┼────────────────│ │
│ │ │ │
│ 10. UPDATE passage (optionnel) │ │
├──────────────>│ │ │
│ ├────────────────┼───────────────>│
│ │ Confirmer stripe_payment_id │
│ │ │ │
│ 11. Success │ │ │
│<──────────────│ │ │
│ │ │ │
```
## Points importants (Nouveau Flow v2)
1. **Passage créé en premier** : Le passage est TOUJOURS créé/modifié AVANT le PaymentIntent
2. **ID réel obligatoire** : Le `passage_id` ne peut jamais être 0 dans `/create-intent`
3. **Lien Stripe automatique** : Le `stripe_payment_id` est ajouté automatiquement lors de la création du PaymentIntent
4. **Idempotence** : Un passage ne peut avoir qu'un seul `stripe_payment_id`
5. **Validation stricte** : Vérification du montant, propriété et existence du passage
## Erreurs possibles
- **400** :
- `passage_id` manquant ou ≤ 0
- Montant invalide (< 1 ou > 999€)
- Passage déjà payé par Stripe
- Montant ne correspond pas au passage
- **401** : Non authentifié
- **403** : Passage non autorisé (pas le bon utilisateur)
- **404** : Passage non trouvé
## Migration base de données
La colonne `stripe_payment_id VARCHAR(50)` a été ajoutée via :
```sql
ALTER TABLE `ope_pass` ADD COLUMN `stripe_payment_id` VARCHAR(50) DEFAULT NULL;
ALTER TABLE `ope_pass` ADD INDEX `idx_stripe_payment` (`stripe_payment_id`);
```
## Environnements
- **DEV** : dva-geo sur IN3 - Base mise à jour ✅
- **REC** : rca-geo sur IN3 - Base mise à jour ✅
- **PROD** : pra-geo sur IN4 - À mettre à jour

View File

@@ -0,0 +1,197 @@
# Stripe Tap to Pay - Requirements officiels
> Document basé sur la documentation officielle Stripe - Dernière vérification : 29 septembre 2025
## 📱 iOS - Tap to Pay sur iPhone
### Configuration minimum requise
| Composant | Requirement | Notes |
|-----------|------------|--------|
| **Appareil** | iPhone XS ou plus récent | iPhone XS, XR, 11, 12, 13, 14, 15, 16 |
| **iOS** | iOS 16.4 ou plus récent | Pour support PIN complet |
| **SDK** | Terminal iOS SDK 2.23.0+ | Version 3.6.0+ pour Interac (Canada) |
| **Entitlement** | Apple Tap to Pay | À demander sur Apple Developer |
### Fonctionnalités par version iOS
- **iOS 16.0-16.3** : Tap to Pay basique (sans PIN)
- **iOS 16.4+** : Support PIN complet pour toutes les cartes
- **Versions beta** : NON SUPPORTÉES
### Méthodes de paiement supportées
- ✅ Cartes sans contact : Visa, Mastercard, American Express
- ✅ Wallets NFC : Apple Pay, Google Pay, Samsung Pay
- ✅ Discover (USA uniquement)
- ✅ Interac (Canada uniquement, SDK 3.6.0+)
- ✅ eftpos (Australie uniquement)
### Limitations importantes
- ❌ iPad non supporté (pas de NFC)
- ❌ Puerto Rico non disponible
- ❌ Versions iOS beta non supportées
## 🤖 Android - Tap to Pay
### Configuration minimum requise
| Composant | Requirement | Notes |
|-----------|------------|--------|
| **Android** | Android 11 ou plus récent | API level 30+ |
| **NFC** | Capteur NFC fonctionnel | Obligatoire |
| **Processeur** | ARM | x86 non supporté |
| **Sécurité** | Appareil non rooté | Bootloader verrouillé |
| **Services** | Google Mobile Services | GMS obligatoire |
| **Keystore** | Hardware keystore intégré | Pour sécurité |
| **OS** | OS constructeur non modifié | Pas de ROM custom |
### Appareils certifiés en France (liste non exhaustive)
#### Samsung
- Galaxy S21, S21+, S21 Ultra, S21 FE (Android 11+)
- Galaxy S22, S22+, S22 Ultra (Android 12+)
- Galaxy S23, S23+, S23 Ultra, S23 FE (Android 13+)
- Galaxy S24, S24+, S24 Ultra (Android 14+)
- Galaxy Z Fold 3, 4, 5, 6
- Galaxy Z Flip 3, 4, 5, 6
- Galaxy Note 20, Note 20 Ultra
- Galaxy A54, A73 (haut de gamme)
#### Google Pixel
- Pixel 6, 6 Pro, 6a (Android 12+)
- Pixel 7, 7 Pro, 7a (Android 13+)
- Pixel 8, 8 Pro, 8a (Android 14+)
- Pixel 9, 9 Pro, 9 Pro XL (Android 14+)
- Pixel Fold (Android 13+)
- Pixel Tablet (Android 13+)
#### OnePlus
- OnePlus 9, 9 Pro (Android 11+)
- OnePlus 10 Pro, 10T (Android 12+)
- OnePlus 11, 11R (Android 13+)
- OnePlus 12, 12R (Android 14+)
- OnePlus Open (Android 13+)
#### Xiaomi
- Mi 11, 11 Ultra (Android 11+)
- Xiaomi 12, 12 Pro, 12T Pro (Android 12+)
- Xiaomi 13, 13 Pro, 13T Pro (Android 13+)
- Xiaomi 14, 14 Pro, 14 Ultra (Android 14+)
#### Autres marques
- OPPO Find X3/X5/X6 Pro, Find N2/N3
- Realme GT 2 Pro, GT 3, GT 5 Pro
- Honor Magic5/6 Pro, 90
- ASUS Zenfone 9/10, ROG Phone 7
- Nothing Phone (1), (2), (2a)
## 🌍 Disponibilité par pays
### Europe
- ✅ France : Disponible
- ✅ Royaume-Uni : Disponible
- ✅ Allemagne : Disponible
- ✅ Pays-Bas : Disponible
- ✅ Irlande : Disponible
- ✅ Italie : Disponible (récent)
- ✅ Espagne : Disponible (récent)
### Amérique
- ✅ États-Unis : Disponible (+ Discover)
- ✅ Canada : Disponible (+ Interac)
- ❌ Puerto Rico : Non disponible
- ❌ Mexique : Non disponible
### Asie-Pacifique
- ✅ Australie : Disponible (+ eftpos)
- ✅ Nouvelle-Zélande : Disponible
- ✅ Singapour : Disponible
- ✅ Japon : Disponible (récent)
## 🔧 Intégration technique
### SDK Requirements
```javascript
// iOS
pod 'StripeTerminal', '~> 2.23.0' // Minimum pour Tap to Pay
pod 'StripeTerminal', '~> 3.6.0' // Pour support Interac
// Android
implementation 'com.stripe:stripeterminal-taptopay:3.7.1'
implementation 'com.stripe:stripeterminal-core:3.7.1'
// React Native
"@stripe/stripe-terminal-react-native": "^0.0.1-beta.17"
// Flutter
stripe_terminal: ^3.2.0
```
### Capacités requises
#### iOS Info.plist
```xml
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Bluetooth nécessaire pour Tap to Pay</string>
<key>NFCReaderUsageDescription</key>
<string>NFC nécessaire pour lire les cartes</string>
<key>com.apple.developer.proximity-reader</key>
<true/>
```
#### Android Manifest
```xml
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-feature android:name="android.hardware.nfc" android:required="true" />
```
## 📊 Limites techniques
| Limite | Valeur | Notes |
|--------|--------|-------|
| **Montant min** | 1€ / $1 | Selon devise |
| **Montant max** | Variable par pays | France : 50€ sans PIN, illimité avec PIN |
| **Timeout transaction** | 60 secondes | Après présentation carte |
| **Distance NFC** | 4cm max | Distance optimale |
| **Tentatives PIN** | 3 max | Puis carte bloquée |
## 🔐 Sécurité
### Certifications
- PCI-DSS Level 1
- EMV Contactless Level 1
- Apple ProximityReader Framework
- Google SafetyNet Attestation
### Données sensibles
- Les données de carte ne transitent JAMAIS par l'appareil
- Tokenisation end-to-end par Stripe
- Pas de stockage local des données carte
- PIN chiffré directement vers Stripe
## 📚 Ressources officielles
- [Documentation Stripe Terminal](https://docs.stripe.com/terminal)
- [Tap to Pay sur iPhone - Apple Developer](https://developer.apple.com/tap-to-pay/)
- [Guide d'intégration iOS](https://docs.stripe.com/terminal/payments/setup-reader/tap-to-pay?platform=ios)
- [Guide d'intégration Android](https://docs.stripe.com/terminal/payments/setup-reader/tap-to-pay?platform=android)
- [SDK Terminal iOS](https://github.com/stripe/stripe-terminal-ios)
- [SDK Terminal Android](https://github.com/stripe/stripe-terminal-android)
## 🔄 Historique des versions
| Date | Version iOS | Changement |
|------|-------------|------------|
| Sept 2022 | iOS 16.0 | Lancement initial Tap to Pay |
| Mars 2023 | iOS 16.4 | Ajout support PIN |
| Sept 2023 | iOS 17.0 | Améliorations performances |
| Sept 2024 | iOS 18.0 | Support étendu international |
---
*Document maintenu par l'équipe GeoSector - Dernière mise à jour : 29/09/2025*

View File

@@ -10,7 +10,8 @@
6. [Sécurité](#sécurité) 6. [Sécurité](#sécurité)
7. [Gestion des mots de passe (NIST SP 800-63B)](#gestion-des-mots-de-passe-nist-sp-800-63b) 7. [Gestion des mots de passe (NIST SP 800-63B)](#gestion-des-mots-de-passe-nist-sp-800-63b)
8. [Endpoints API](#endpoints-api) 8. [Endpoints API](#endpoints-api)
9. [Changements récents](#changements-récents) 9. [Paiements Stripe Connect](#paiements-stripe-connect)
10. [Changements récents](#changements-récents)
## Structure du projet ## Structure du projet
@@ -130,6 +131,27 @@ Exemple détaillé du parcours d'une requête POST /api/users :
## Base de données ## Base de données
### Architecture des containers MariaDB
Depuis janvier 2025, les bases de données sont hébergées dans des containers MariaDB dédiés :
| Environnement | Container API | Container DB | Serveur | IP DB | Nom BDD | Utilisateur | Source des données |
|---------------|--------------|--------------|---------|-------|---------|-------------|-------------------|
| **DEV** | dva-geo | maria3 | IN3 | 13.23.33.4 | dva_geo | dva_geo_user | Migré depuis dva-geo/geo_app |
| **RECETTE** | rca-geo | maria3 | IN3 | 13.23.33.4 | rca_geo | rca_geo_user | Migré depuis rca-geo/geo_app |
| **PRODUCTION** | pra-geo | maria4 | IN4 | 13.23.33.4 | pra_geo | pra_geo_user | **Dupliqué depuis maria3/rca_geo** |
**Note importante :** La base de production `pra_geo` est créée en dupliquant `rca_geo` depuis IN3/maria3 vers IN4/maria4.
**Avantages de cette architecture :**
- Isolation des données par environnement
- Performances optimisées (containers dédiés)
- Sauvegardes indépendantes
- Maintenance simplifiée
- Séparation physique Production/Recette (serveurs différents)
**Migration :** Utiliser le script `scripts/migrate_to_maria_containers.sh` pour migrer les données.
### Structure des tables principales ### Structure des tables principales
#### Table `users` #### Table `users`
@@ -735,6 +757,300 @@ Lors du login, les paramètres de l'entité sont retournés dans le groupe `amic
Ces paramètres permettent à l'application Flutter d'adapter dynamiquement le formulaire de création de membre. Ces paramètres permettent à l'application Flutter d'adapter dynamiquement le formulaire de création de membre.
## Paiements Stripe Connect
### Vue d'ensemble
L'API intègre un système complet de paiements via Stripe Connect, permettant aux amicales de recevoir des paiements pour leurs calendriers via deux méthodes :
- **Paiements Web** : Interface de paiement dans un navigateur
- **Tap to Pay** : Paiements NFC via l'application mobile Flutter
### Architecture Stripe Connect
#### Tables de base de données
**Table `stripe_accounts` :**
```sql
CREATE TABLE `stripe_accounts` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`fk_entite` int(10) unsigned NOT NULL,
`stripe_account_id` varchar(50) NOT NULL,
`account_type` enum('express','standard','custom') DEFAULT 'express',
`charges_enabled` tinyint(1) DEFAULT 0,
`payouts_enabled` tinyint(1) DEFAULT 0,
`details_submitted` tinyint(1) DEFAULT 0,
`country` varchar(2) DEFAULT 'FR',
`default_currency` varchar(3) DEFAULT 'eur',
`business_name` varchar(255) DEFAULT NULL,
`support_email` varchar(255) DEFAULT NULL,
`onboarding_completed_at` timestamp NULL DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp(),
PRIMARY KEY (`id`),
UNIQUE KEY `stripe_account_id` (`stripe_account_id`),
KEY `fk_entite` (`fk_entite`),
CONSTRAINT `stripe_accounts_ibfk_1` FOREIGN KEY (`fk_entite`) REFERENCES `entites` (`id`)
);
```
**Ajout du champ `stripe_payment_id` dans `ope_pass` :**
```sql
ALTER TABLE `ope_pass` ADD COLUMN `stripe_payment_id` VARCHAR(50) DEFAULT NULL COMMENT 'ID du PaymentIntent Stripe (pi_xxx)';
ALTER TABLE `ope_pass` ADD INDEX `idx_stripe_payment` (`stripe_payment_id`);
```
#### Services principaux
**StripeService** (`src/Services/StripeService.php`) :
- Gestion des PaymentIntents
- Communication avec l'API Stripe
- Gestion des comptes Stripe Connect
**StripeController** (`src/Controllers/StripeController.php`) :
- Endpoints pour la création de PaymentIntents
- Gestion des webhooks Stripe
- API pour les comptes Connect
### Flow de paiement
#### 1. Création du compte Stripe Connect (Onboarding)
```http
POST /api/stripe/accounts/create
Authorization: Bearer {session_id}
Content-Type: application/json
{
"amicale_id": 45,
"type": "express",
"country": "FR",
"email": "contact@amicale-pompiers.fr",
"business_profile": {
"name": "Amicale des Pompiers",
"product_description": "Vente de calendriers des pompiers",
"mcc": "8398"
}
}
```
**Réponse :**
```json
{
"success": true,
"stripe_account_id": "acct_1O3ABC456DEF789",
"onboarding_url": "https://connect.stripe.com/express/oauth/authorize?...",
"status": "pending"
}
```
#### 2. Création d'un PaymentIntent (Tap to Pay)
**Flow actuel (v2) :**
1. L'application crée/modifie d'abord le passage pour obtenir un ID réel
2. Puis crée le PaymentIntent avec cet ID
```http
POST /api/stripe/payments/create-intent
Authorization: Bearer {session_id}
Content-Type: application/json
{
"amount": 2500, // 25€ en centimes
"passage_id": 456, // ID RÉEL du passage (jamais 0)
"payment_method_types": ["card_present"], // Tap to Pay
"location_id": "tml_xxx",
"amicale_id": 45,
"member_id": 67,
"stripe_account": "acct_1234"
}
```
**Réponse :**
```json
{
"success": true,
"client_secret": "pi_3QaXYZ_secret_xyz",
"payment_intent_id": "pi_3QaXYZ123ABC456",
"amount": 2500,
"currency": "eur",
"passage_id": 456,
"type": "tap_to_pay"
}
```
#### 3. Traitement du paiement
**Côté application Flutter :**
- Utilisation du SDK Stripe Terminal
- Collecte NFC avec le `client_secret`
- Traitement automatique du paiement
**Mise à jour automatique :**
- Le `stripe_payment_id` est automatiquement ajouté au passage lors de la création du PaymentIntent
- Lien bidirectionnel entre le passage et le paiement Stripe
### Endpoints Stripe
#### Gestion des comptes
- `POST /api/stripe/accounts/create` : Création d'un compte Connect
- `GET /api/stripe/accounts/{id}` : Statut d'un compte
- `PUT /api/stripe/accounts/{id}` : Mise à jour d'un compte
#### Gestion des paiements
- `POST /api/stripe/payments/create-intent` : Création d'un PaymentIntent
- `GET /api/stripe/payments/{id}` : Statut d'un paiement
- `POST /api/stripe/payments/confirm` : Confirmation d'un paiement
#### Gestion des devices Tap to Pay
- `GET /api/stripe/devices/certified-android` : Liste des appareils Android certifiés
- `POST /api/stripe/devices/check-tap-to-pay` : Vérification de compatibilité d'un appareil
- `GET /api/stripe/config` : Configuration publique Stripe
- `GET /api/stripe/stats` : Statistiques de paiement
#### Webhooks
- `POST /api/stripe/webhooks` : Réception des événements Stripe
- `account.updated` : Mise à jour du statut d'un compte
- `payment_intent.succeeded` : Confirmation d'un paiement réussi
- `payment_intent.payment_failed` : Échec d'un paiement
### Sécurité et validation
#### Prérequis pour les paiements :
- ✅ Compte Stripe Connect activé (`charges_enabled = 1`)
- ✅ Virements activés (`payouts_enabled = 1`)
- ✅ Onboarding terminé (`details_submitted = 1`)
- ✅ Passage existant avec montant correspondant
- ✅ Utilisateur authentifié et autorisé
#### Validation des montants :
- Minimum : 1€ (100 centimes)
- Maximum : 999€ (99 900 centimes)
- Vérification de correspondance avec le passage
#### Sécurité des transactions :
- Headers CORS configurés
- Validation côté serveur obligatoire
- Logs de toutes les transactions
- Gestion des erreurs robuste
### États et statuts
#### États des comptes Stripe :
- `pending` : Onboarding en cours
- `restricted` : Informations manquantes
- `active` : Opérationnel pour les paiements
- `rejected` : Refusé par Stripe
#### États des paiements :
- `requires_payment_method` : En attente de paiement
- `processing` : Traitement en cours
- `succeeded` : Paiement réussi
- `canceled` : Paiement annulé
- `requires_action` : Action utilisateur requise
### Intégration avec l'application
#### Flutter (Tap to Pay) :
- SDK Stripe Terminal pour iOS/Android
- Interface NFC native
- Gestion des états du terminal
- Validation en temps réel
#### Web (Paiements navigateur) :
- Stripe.js pour l'interface
- Formulaire de carte sécurisé
- Confirmation 3D Secure automatique
### Monitoring et logs
#### Logs importants :
- Création/mise à jour des comptes Connect
- Succès/échecs des paiements
- Erreurs webhook Stripe
- Tentatives de paiement frauduleuses
#### Métriques de suivi :
- Taux de succès des paiements par amicale
- Montants moyens des transactions
- Temps de traitement des paiements
- Erreurs par type d'appareil
### Configuration environnement
#### Variables Stripe par environnement :
| Environnement | Clés | Webhooks |
|---------------|------|----------|
| **DEV** | Test keys (pk_test_, sk_test_) | URL dev webhook |
| **RECETTE** | Test keys (pk_test_, sk_test_) | URL recette webhook |
| **PRODUCTION** | Live keys (pk_live_, sk_live_) | URL prod webhook |
#### Comptes Connect :
- Type : Express (simplifié pour les associations)
- Pays : France (FR)
- Devise : Euro (EUR)
- Frais : Standard Stripe Connect
### Gestion des appareils certifiés Tap to Pay
#### Table `stripe_android_certified_devices`
Stocke la liste des appareils Android certifiés pour Tap to Pay en France :
- **95+ appareils** pré-chargés lors de l'installation
- **Mise à jour automatique** hebdomadaire via CRON
- **Vérification de compatibilité** via endpoints dédiés
#### Endpoint de vérification de compatibilité
```http
POST /api/stripe/devices/check-tap-to-pay
Content-Type: application/json
{
"platform": "ios" | "android",
"manufacturer": "Samsung", // Requis pour Android
"model": "SM-S921B" // Requis pour Android
}
```
**Réponse Android compatible :**
```json
{
"status": "success",
"tap_to_pay_supported": true,
"message": "Tap to Pay disponible sur cet appareil",
"min_android_version": 14
}
```
**Réponse iOS :**
```json
{
"status": "success",
"message": "Vérification iOS à faire côté client",
"requirements": "iPhone XS ou plus récent avec iOS 16.4+",
"details": "iOS 16.4 minimum requis pour le support PIN complet"
}
```
#### Requirements Tap to Pay
| Plateforme | Appareil minimum | OS minimum | Notes |
|------------|------------------|------------|-------|
| **iOS** | iPhone XS (2018+) | iOS 16.4+ | Support PIN complet |
| **Android** | Variable | Android 11+ | NFC obligatoire, non rooté |
### Documentation technique complète
Pour le flow détaillé complet, voir :
- **`docs/STRIPE-TAP-TO-PAY-FLOW.md`** : Documentation technique complète du flow de paiement
- **`docs/PLANNING-STRIPE-API.md`** : Planification et architecture Stripe
- **`docs/STRIPE-TAP-TO-PAY-REQUIREMENTS.md`** : Requirements officiels et liste complète des devices certifiés
## Intégration Frontend ## Intégration Frontend
### Configuration des Requêtes ### Configuration des Requêtes
@@ -754,6 +1070,71 @@ fetch('/api/endpoint', {
- Pas besoin de stocker ou gérer des tokens manuellement - Pas besoin de stocker ou gérer des tokens manuellement
- Redirection vers /login si session expirée (401) - Redirection vers /login si session expirée (401)
## Système de tâches CRON
### Vue d'ensemble
L'API utilise des scripts CRON pour automatiser les tâches de maintenance et de traitement. Les scripts sont situés dans `/scripts/cron/` et s'exécutent dans les containers Incus Alpine.
### Tâches CRON configurées
| Script | Fréquence | Fonction | Container |
|--------|-----------|----------|-----------|
| `process_email_queue.php` | */5 * * * * | Traite la queue d'emails (reçus, notifications) | DVA, RCA |
| `cleanup_security_data.php` | 0 2 * * * | Nettoie les données de sécurité obsolètes | DVA, RCA |
| `update_stripe_devices.php` | 0 3 * * 0 | Met à jour la liste des devices certifiés Tap to Pay | DVA, RCA |
### Configuration des CRONs
Sur les containers Alpine (dva-geo, rca-geo, pra-geo) :
```bash
# Vérifier les crons actifs
crontab -l
# Éditer les crons
crontab -e
# Format des lignes cron
*/5 * * * * /usr/bin/php /var/www/geosector/api/scripts/cron/process_email_queue.php >> /var/www/geosector/api/logs/email_queue.log 2>&1
0 2 * * * /usr/bin/php /var/www/geosector/api/scripts/cron/cleanup_security_data.php >> /var/www/geosector/api/logs/cleanup_security.log 2>&1
0 3 * * 0 /usr/bin/php /var/www/geosector/api/scripts/cron/update_stripe_devices.php >> /var/www/geosector/api/logs/stripe_devices.log 2>&1
```
### Script `process_email_queue.php`
- **Fonction** : Envoie les emails en attente dans la table `email_queue`
- **Batch** : 50 emails maximum par exécution
- **Lock file** : `/tmp/process_email_queue.lock` (évite l'exécution simultanée)
- **Gestion d'erreur** : 3 tentatives max par email
### Script `cleanup_security_data.php`
- **Fonction** : Purge les données de sécurité selon la politique de rétention
- **Rétention** :
- Métriques de performance : 30 jours
- Tentatives de login échouées : 7 jours
- Alertes résolues : 90 jours
- IPs expirées : Déblocage immédiat
### Script `update_stripe_devices.php`
- **Fonction** : Maintient à jour la liste des appareils certifiés Tap to Pay
- **Source** : Liste de 95+ devices intégrée + fichier JSON optionnel
- **Actions** :
- Ajoute les nouveaux appareils certifiés
- Met à jour les versions Android minimales
- Désactive les appareils obsolètes
- Envoie une notification email si changements importants
- **Personnalisation** : Possibilité d'ajouter des devices via `/data/stripe_certified_devices.json`
### Monitoring des CRONs
Les logs sont stockés dans `/var/www/geosector/api/logs/` :
- `email_queue.log` : Logs du traitement des emails
- `cleanup_security.log` : Logs du nettoyage sécurité
- `stripe_devices.log` : Logs de mise à jour des devices
## Maintenance et Déploiement ## Maintenance et Déploiement
### Logs ### Logs
@@ -764,11 +1145,36 @@ fetch('/api/endpoint', {
### Déploiement ### Déploiement
1. Pull du repository Le script `deploy-api.sh` gère le déploiement sur les 3 environnements :
2. Vérification des permissions
3. Configuration de l'environnement ```bash
4. Tests des endpoints # Déploiement DEV : code local → container dva-geo sur IN3
5. Redémarrage des services ./deploy-api.sh
# Déploiement RECETTE : container dva-geo → container rca-geo sur IN3
./deploy-api.sh rca
# Déploiement PRODUCTION : container rca-geo (IN3) → container pra-geo (IN4)
./deploy-api.sh pra
```
Flux de déploiement :
1. **DEV** : Archive du code local, déploiement sur container `dva-geo` sur IN3 (195.154.80.116)
- URL publique : https://dapp.geosector.fr/api/
- IP interne : http://13.23.33.43/api/
2. **RECETTE** : Archive depuis container `dva-geo`, déploiement sur `rca-geo` sur IN3
- URL publique : https://rapp.geosector.fr/api/
3. **PRODUCTION** : Archive depuis `rca-geo` (IN3), déploiement sur `pra-geo` (51.159.7.190)
- URL publique : https://app.geosector.fr/api/
Caractéristiques :
- Sauvegarde automatique avec rotation (garde les 10 dernières)
- Préservation des dossiers `logs/` et `uploads/`
- Gestion des permissions :
- Code API : `nginx:nginx` (755/644)
- Logs et uploads : `nobody:nginx` (755/644)
- Installation des dépendances Composer (pas de mise à jour)
- Journalisation dans `~/.geo_deploy_history`
### Surveillance ### Surveillance
@@ -779,6 +1185,89 @@ fetch('/api/endpoint', {
## Changements récents ## Changements récents
### Version 3.2.5 (29 Septembre 2025)
#### 1. Système de gestion automatique des devices Tap to Pay
**Nouveaux endpoints ajoutés :**
- `GET /api/stripe/devices/certified-android` : Récupération de la liste complète des appareils certifiés
- `POST /api/stripe/devices/check-tap-to-pay` : Vérification de compatibilité d'un appareil spécifique
- Endpoints publics (pas d'authentification requise) pour vérification côté app
**Script CRON de mise à jour automatique :**
- **Script** : `/scripts/cron/update_stripe_devices.php`
- **Fréquence** : Hebdomadaire (dimanche 3h)
- **Fonction** : Maintient à jour la liste de 95+ appareils Android certifiés
- **Base de données** : Table `stripe_android_certified_devices` avec 77 appareils actifs
**Corrections des requirements iOS :**
- Mise à jour : iOS 16.4+ minimum (au lieu de 15.4/16.0)
- Raison : Support PIN complet obligatoire pour les paiements > 50€
**Documentation ajoutée :**
- `docs/STRIPE-TAP-TO-PAY-REQUIREMENTS.md` : Requirements officiels complets
- Liste exhaustive des appareils certifiés par fabricant
- Configuration SDK pour toutes les plateformes
#### 2. Configuration des tâches CRON sur les containers
**Environnements configurés :**
- **DVA-GEO (DEV)** : 3 CRONs actifs
- **RCA-GEO (RECETTE)** : 3 CRONs actifs (ajoutés le 29/09)
- **PRA-GEO (PROD)** : À configurer
**Tâches automatisées :**
1. Queue d'emails : Toutes les 5 minutes
2. Nettoyage sécurité : Quotidien à 2h
3. Mise à jour devices Stripe : Hebdomadaire dimanche 3h
### Version 3.2.4 (Septembre 2025)
#### 1. Implémentation complète de Stripe Connect V1
**Paiements Stripe intégrés pour les amicales :**
- **Stripe Connect Express** : Onboarding simplifié pour les associations
- **Tap to Pay** : Paiements NFC via l'application mobile Flutter
- **Paiements Web** : Interface de paiement navigateur avec Stripe.js
- **Webhooks** : Gestion automatique des événements Stripe
**Nouvelles tables de base de données :**
- `stripe_accounts` : Gestion des comptes Connect par amicale
- `stripe_payment_history` : Historique des transactions Stripe
- `stripe_refunds` : Gestion des remboursements
- Ajout de `stripe_payment_id` dans `ope_pass` pour liaison bidirectionnelle
**Nouveaux services :**
- **StripeService** : Communication avec l'API Stripe, gestion des PaymentIntents
- **StripeController** : Endpoints API pour création de comptes, paiements et webhooks
**Flow de paiement optimisé (v2) :**
1. Passage créé/modifié EN PREMIER pour obtenir un ID réel
2. Création PaymentIntent avec `passage_id` réel (jamais 0)
3. Traitement Tap to Pay via SDK Stripe Terminal
4. Mise à jour automatique du passage avec `stripe_payment_id`
**Endpoints ajoutés :**
- `POST /api/stripe/accounts/create` : Création compte Connect
- `POST /api/stripe/payments/create-intent` : Création PaymentIntent
- `GET /api/stripe/payments/{id}` : Statut d'un paiement
- `POST /api/stripe/webhooks` : Réception événements Stripe
**Sécurité et validation :**
- Validation stricte des montants (1€ à 999€)
- Vérification correspondance passage/montant
- Gestion des permissions par amicale
- Logs complets des transactions
**Configuration multi-environnements :**
- DEV/RECETTE : Clés de test Stripe
- PRODUCTION : Clés live avec webhooks sécurisés
- Migration base de données via `migrate_stripe_payment_id.sql`
**Documentation technique :**
- `docs/STRIPE-TAP-TO-PAY-FLOW.md` : Flow complet de paiement
- `docs/PLANNING-STRIPE-API.md` : Architecture et planification
### Version 3.0.7 (Août 2025) ### Version 3.0.7 (Août 2025)
#### 1. Implémentation complète de la norme NIST SP 800-63B pour les mots de passe #### 1. Implémentation complète de la norme NIST SP 800-63B pour les mots de passe

View File

@@ -0,0 +1,53 @@
-- Table pour stocker les informations des devices des utilisateurs
CREATE TABLE IF NOT EXISTS `user_devices` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`fk_user` int(10) unsigned NOT NULL COMMENT 'Référence vers la table users',
-- Informations générales du device
`platform` varchar(20) NOT NULL COMMENT 'Plateforme: iOS, Android, etc.',
`device_model` varchar(100) DEFAULT NULL COMMENT 'Modèle du device (ex: iPhone13,2)',
`device_name` varchar(255) DEFAULT NULL COMMENT 'Nom personnalisé du device',
`device_manufacturer` varchar(100) DEFAULT NULL COMMENT 'Fabricant (Apple, Samsung, etc.)',
`device_identifier` varchar(100) DEFAULT NULL COMMENT 'Identifiant unique du device',
-- Informations réseau (IPv4 uniquement)
`device_ip_local` varchar(15) DEFAULT NULL COMMENT 'Adresse IP locale IPv4',
`device_ip_public` varchar(15) DEFAULT NULL COMMENT 'Adresse IP publique IPv4',
`device_wifi_name` varchar(255) DEFAULT NULL COMMENT 'Nom du réseau WiFi (SSID)',
`device_wifi_bssid` varchar(17) DEFAULT NULL COMMENT 'BSSID du point d\'accès (format
XX:XX:XX:XX:XX:XX)',
-- Capacités et version OS
`ios_version` varchar(20) DEFAULT NULL COMMENT 'Version iOS/Android OS',
`device_nfc_capable` tinyint(1) DEFAULT NULL COMMENT 'Support NFC (1=oui, 0=non)',
`device_supports_tap_to_pay` tinyint(1) DEFAULT NULL COMMENT 'Support Tap to Pay (1=oui, 0=non)',
-- État batterie
`battery_level` tinyint(3) unsigned DEFAULT NULL COMMENT 'Niveau batterie en pourcentage (0-100)',
`battery_charging` tinyint(1) DEFAULT NULL COMMENT 'En charge (1=oui, 0=non)',
`battery_state` varchar(20) DEFAULT NULL COMMENT 'État batterie (charging, discharging, full)',
-- Versions application
`app_version` varchar(20) DEFAULT NULL COMMENT 'Version de l\'application (ex: 3.2.8)',
`app_build` varchar(20) DEFAULT NULL COMMENT 'Numéro de build (ex: 328)',
-- Timestamps
`last_device_info_check` timestamp NULL DEFAULT NULL COMMENT 'Dernier check des infos device côté
app',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date de création de
l\'enregistrement',
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT
'Date de dernière modification',
PRIMARY KEY (`id`),
KEY `idx_fk_user` (`fk_user`) COMMENT 'Index pour recherche par utilisateur',
KEY `idx_updated_at` (`updated_at`) COMMENT 'Index pour tri par date de mise à jour',
KEY `idx_last_check` (`last_device_info_check`) COMMENT 'Index pour recherche par dernière
vérification',
UNIQUE KEY `unique_user_device` (`fk_user`, `device_identifier`) COMMENT 'Un seul enregistrement
par device/user',
CONSTRAINT `fk_user_devices_user` FOREIGN KEY (`fk_user`)
REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Informations des devices
utilisateurs';

View File

@@ -0,0 +1,166 @@
1. Route /session/refresh/all
Méthode : POSTAuthentification : Requise (via session_id dans headers ou cookies)
Headers requis :
Authorization: Bearer {session_id}
// ou
Cookie: session_id={session_id}
Réponse attendue :
{
"status": "success",
"message": "Session refreshed",
"user": {
// Mêmes données que le login
"id": 123,
"email": "user@example.com",
"name": "John Doe",
"fk_role": 2,
"fk_entite": 1,
// ...
},
"amicale": {
// Données de l'amicale
"id": 1,
"name": "Amicale Pompiers",
// ...
},
"operations": [...],
"sectors": [...],
"passages": [...],
"membres": [...],
"session_id": "current_session_id",
"session_expiry": "2024-01-20T10:00:00Z"
}
Code PHP suggéré :
// routes/session.php
Route::post('/session/refresh/all', function(Request $request) {
$user = Auth::user();
if (!$user) {
return response()->json(['status' => 'error', 'message' => 'Not authenticated'], 401);
}
// Retourner les mêmes données qu'un login normal
return response()->json([
'status' => 'success',
'user' => $user->toArray(),
'amicale' => $user->amicale,
'operations' => Operation::where('fk_entite', $user->fk_entite)->get(),
'sectors' => Sector::where('fk_entite', $user->fk_entite)->get(),
'passages' => Passage::where('fk_entite', $user->fk_entite)->get(),
'membres' => Membre::where('fk_entite', $user->fk_entite)->get(),
'session_id' => session()->getId(),
'session_expiry' => now()->addDays(7)->toIso8601String()
]);
});
2. Route /session/refresh/partial
Méthode : POSTAuthentification : Requise
Body requis :
{
"last_sync": "2024-01-19T10:00:00Z"
}
Réponse attendue :
{
"status": "success",
"message": "Partial refresh completed",
"sectors": [
// Uniquement les secteurs modifiés après last_sync
{
"id": 45,
"name": "Secteur A",
"updated_at": "2024-01-19T15:00:00Z",
// ...
}
],
"passages": [
// Uniquement les passages modifiés après last_sync
{
"id": 789,
"fk_sector": 45,
"updated_at": "2024-01-19T14:30:00Z",
// ...
}
],
"operations": [...], // Si modifiées
"membres": [...] // Si modifiés
}
Code PHP suggéré :
// routes/session.php
Route::post('/session/refresh/partial', function(Request $request) {
$user = Auth::user();
if (!$user) {
return response()->json(['status' => 'error', 'message' => 'Not authenticated'], 401);
}
$lastSync = Carbon::parse($request->input('last_sync'));
// Récupérer uniquement les données modifiées après last_sync
$response = [
'status' => 'success',
'message' => 'Partial refresh completed'
];
// Secteurs modifiés
$sectors = Sector::where('fk_entite', $user->fk_entite)
->where('updated_at', '>', $lastSync)
->get();
if ($sectors->count() > 0) {
$response['sectors'] = $sectors;
}
// Passages modifiés
$passages = Passage::where('fk_entite', $user->fk_entite)
->where('updated_at', '>', $lastSync)
->get();
if ($passages->count() > 0) {
$response['passages'] = $passages;
}
// Opérations modifiées
$operations = Operation::where('fk_entite', $user->fk_entite)
->where('updated_at', '>', $lastSync)
->get();
if ($operations->count() > 0) {
$response['operations'] = $operations;
}
// Membres modifiés
$membres = Membre::where('fk_entite', $user->fk_entite)
->where('updated_at', '>', $lastSync)
->get();
if ($membres->count() > 0) {
$response['membres'] = $membres;
}
return response()->json($response);
});
Points importants pour l'API :
1. Vérification de session : Les deux routes doivent vérifier que le session_id est valide et non expiré
2. Timestamps : Assurez-vous que toutes vos tables ont des colonnes updated_at qui sont mises à jour automatiquement
3. Gestion des suppressions : Pour le refresh partiel, vous pourriez ajouter un champ pour les éléments supprimés :
{
"deleted": {
"sectors": [12, 34], // IDs des secteurs supprimés
"passages": [567, 890]
}
}
4. Optimisation : Pour éviter de surcharger, limitez le refresh partiel aux dernières 24-48h maximum
5. Gestion d'erreurs :
{
"status": "error",
"message": "Session expired",
"code": "SESSION_EXPIRED"
}
L'app Flutter s'attend à ces formats de réponse et utilisera automatiquement le refresh partiel si la dernière sync
date de moins de 24h, sinon elle fera un refresh complet.

View File

@@ -1,167 +0,0 @@
#!/bin/bash
# Vérification des arguments
if [ $# -ne 1 ]; then
echo "Usage: $0 <environment>"
echo " rec : Livrer de DVA (dva-geo) vers RECETTE (rca-geo)"
echo " prod : Livrer de RECETTE (rca-geo) vers PRODUCTION (pra-geo)"
echo ""
echo "Examples:"
echo " $0 rec # DVA → RECETTE"
echo " $0 prod # RECETTE → PRODUCTION"
exit 1
fi
HOST_IP="195.154.80.116"
HOST_USER=root
HOST_KEY=/home/pierre/.ssh/id_rsa_mbpi
HOST_PORT=22
# Mapping des environnements
ENVIRONMENT=$1
case $ENVIRONMENT in
"rca")
SOURCE_CONTAINER="dva-geo"
DEST_CONTAINER="rca-geo"
ENV_NAME="RECETTE"
;;
"pra")
SOURCE_CONTAINER="rca-geo"
DEST_CONTAINER="pra-geo"
ENV_NAME="PRODUCTION"
;;
*)
echo "❌ Environnement '$ENVIRONMENT' non reconnu"
echo "Utilisez 'rec' pour RECETTE ou 'prod' pour PRODUCTION"
exit 1
;;
esac
API_PATH="/var/www/geosector/api"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
BACKUP_DIR="${API_PATH}_backup_${TIMESTAMP}"
PROJECT="default"
echo "🔄 Livraison vers $ENV_NAME : $SOURCE_CONTAINER$DEST_CONTAINER (projet: $PROJECT)"
# Vérifier si les containers existent
echo "🔍 Vérification des containers..."
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus info $SOURCE_CONTAINER --project $PROJECT" > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "❌ Erreur: Le container source $SOURCE_CONTAINER n'existe pas ou n'est pas accessible dans le projet $PROJECT"
exit 1
fi
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus info $DEST_CONTAINER --project $PROJECT" > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "❌ Erreur: Le container destination $DEST_CONTAINER n'existe pas ou n'est pas accessible dans le projet $PROJECT"
exit 1
fi
# Créer une sauvegarde du dossier de destination avant de le remplacer
echo "📦 Création d'une sauvegarde sur $DEST_CONTAINER..."
# Vérifier si le dossier API existe
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $DEST_CONTAINER --project $PROJECT -- test -d $API_PATH"
if [ $? -eq 0 ]; then
# Le dossier existe, créer une sauvegarde
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $DEST_CONTAINER --project $PROJECT -- cp -r $API_PATH $BACKUP_DIR"
echo "✅ Sauvegarde créée dans $BACKUP_DIR"
else
echo "⚠️ Le dossier API n'existe pas sur la destination"
fi
# Copier le dossier API entre les containers
echo "📋 Copie des fichiers en cours..."
# Nettoyage sélectif : supprimer seulement le code, pas les données (logs et uploads)
echo "🧹 Nettoyage sélectif (préservation de logs et uploads)..."
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $DEST_CONTAINER --project $PROJECT -- find $API_PATH -mindepth 1 -maxdepth 1 ! -name 'uploads' ! -name 'logs' -exec rm -rf {} \;"
# Copier directement du container source vers le container destination (en excluant logs et uploads)
echo "📤 Transfert du code (hors logs et uploads)..."
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $SOURCE_CONTAINER --project $PROJECT -- tar -cf - -C $API_PATH --exclude='uploads' --exclude='logs' . | incus exec $DEST_CONTAINER --project $PROJECT -- tar -xf - -C $API_PATH"
if [ $? -ne 0 ]; then
echo "❌ Erreur lors du transfert entre containers"
echo "⚠️ Tentative de restauration de la sauvegarde..."
# Vérifier si la sauvegarde existe
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $DEST_CONTAINER --project $PROJECT -- test -d $BACKUP_DIR"
if [ $? -eq 0 ]; then
# La sauvegarde existe, la restaurer
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $DEST_CONTAINER --project $PROJECT -- rm -rf $API_PATH"
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $DEST_CONTAINER --project $PROJECT -- cp -r $BACKUP_DIR $API_PATH"
echo "✅ Restauration réussie"
else
echo "❌ Échec de la restauration"
fi
exit 1
fi
echo "✅ Code transféré avec succès (logs et uploads préservés)"
# Changer le propriétaire et les permissions des fichiers
echo "👤 Application des droits et permissions pour tous les fichiers..."
# Définir le propriétaire pour tous les fichiers
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $DEST_CONTAINER --project $PROJECT -- chown -R nginx:nginx $API_PATH"
# Appliquer les permissions de base pour les dossiers (755)
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $DEST_CONTAINER --project $PROJECT -- find $API_PATH -type d -exec chmod 755 {} \;"
# Appliquer les permissions pour les fichiers (644)
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $DEST_CONTAINER --project $PROJECT -- find $API_PATH -type f -exec chmod 644 {} \;"
# Appliquer des permissions spécifiques pour le dossier logs (pour permettre à PHP-FPM de l'utilisateur nobody d'y écrire)
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $DEST_CONTAINER --project $PROJECT -- test -d $API_PATH/logs"
if [ $? -eq 0 ]; then
# Changer le groupe du dossier logs à nobody (utilisateur PHP-FPM)
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $DEST_CONTAINER --project $PROJECT -- chown -R nginx:nobody $API_PATH/logs"
# Appliquer les permissions 775 pour le dossier
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $DEST_CONTAINER --project $PROJECT -- chmod -R 775 $API_PATH/logs"
# Appliquer les permissions 664 pour les fichiers
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $DEST_CONTAINER --project $PROJECT -- find $API_PATH/logs -type f -exec chmod 664 {} \;"
echo "✅ Droits spécifiques appliqués au dossier logs (nginx:nobody avec permissions 775/664)"
else
echo "⚠️ Le dossier logs n'existe pas"
fi
# Vérifier et corriger les permissions du dossier uploads s'il existe
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $DEST_CONTAINER --project $PROJECT -- test -d $API_PATH/uploads"
if [ $? -eq 0 ]; then
# S'assurer que uploads a les bonnes permissions
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $DEST_CONTAINER --project $PROJECT -- chown -R nginx:nobody $API_PATH/uploads"
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $DEST_CONTAINER --project $PROJECT -- chmod -R 775 $API_PATH/uploads"
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $DEST_CONTAINER --project $PROJECT -- find $API_PATH/uploads -type f -exec chmod 664 {} \;"
echo "✅ Droits vérifiés pour le dossier uploads (nginx:nginx avec permissions 775)"
else
# Créer le dossier uploads s'il n'existe pas
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $DEST_CONTAINER --project $PROJECT -- mkdir -p $API_PATH/uploads"
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $DEST_CONTAINER --project $PROJECT -- chown -R nginx:nobody $API_PATH/uploads"
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $DEST_CONTAINER --project $PROJECT -- chmod -R 775 $API_PATH/uploads"
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $DEST_CONTAINER --project $PROJECT -- find $API_PATH/uploads -type f -exec chmod 664 {} \;"
echo "✅ Dossier uploads créé avec les bonnes permissions (nginx:nginx avec permissions 775/664)"
fi
echo "✅ Propriétaire et permissions appliqués avec succès"
# Mise à jour des dépendances Composer
echo "📦 Mise à jour des dépendances Composer sur $DEST_CONTAINER..."
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $DEST_CONTAINER --project $PROJECT -- bash -c 'cd $API_PATH && composer update --no-dev --optimize-autoloader'" > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo "✅ Dépendances Composer mises à jour avec succès"
else
echo "⚠️ Composer non disponible ou échec, poursuite sans mise à jour des dépendances"
fi
# Vérifier la copie
echo "✅ Vérification de la copie..."
ssh -i $HOST_KEY -p $HOST_PORT $HOST_USER@$HOST_IP "incus exec $DEST_CONTAINER --project $PROJECT -- test -d $API_PATH"
if [ $? -eq 0 ]; then
echo "✅ Copie réussie"
else
echo "❌ Erreur: Le dossier API n'a pas été copié correctement"
fi
echo "✅ Livraison vers $ENV_NAME terminée avec succès!"
echo "📤 Source: $SOURCE_CONTAINER → Destination: $DEST_CONTAINER"
echo "📁 Sauvegarde créée: $BACKUP_DIR sur $DEST_CONTAINER"
echo "🔒 Données préservées: logs/ et uploads/ intouchés"
echo "👤 Permissions: nginx:nginx (755/644) + logs (nginx:nobody 775/664)"

View File

@@ -0,0 +1,442 @@
#!/usr/bin/env php
<?php
/**
* Script CRON pour mettre à jour la liste des appareils certifiés Stripe Tap to Pay
*
* Ce script récupère et met à jour la liste des appareils Android certifiés
* pour Tap to Pay en France dans la table stripe_android_certified_devices
*
* À exécuter hebdomadairement via crontab :
* Exemple: 0 3 * * 0 /usr/bin/php /path/to/api/scripts/cron/update_stripe_devices.php
*/
declare(strict_types=1);
// Configuration
define('LOCK_FILE', '/tmp/update_stripe_devices.lock');
define('DEVICES_JSON_URL', 'https://raw.githubusercontent.com/stripe/stripe-terminal-android/master/tap-to-pay/certified-devices.json');
define('DEVICES_LOCAL_FILE', __DIR__ . '/../../data/stripe_certified_devices.json');
// Empêcher l'exécution multiple simultanée
if (file_exists(LOCK_FILE)) {
$lockTime = filemtime(LOCK_FILE);
if (time() - $lockTime > 3600) { // Lock de plus d'1 heure = processus bloqué
unlink(LOCK_FILE);
} else {
die("[" . date('Y-m-d H:i:s') . "] Le processus est déjà en cours d'exécution\n");
}
}
// Créer le fichier de lock
file_put_contents(LOCK_FILE, getmypid());
// Enregistrer un handler pour supprimer le lock en cas d'arrêt
register_shutdown_function(function() {
if (file_exists(LOCK_FILE)) {
unlink(LOCK_FILE);
}
});
// Simuler l'environnement web pour AppConfig en CLI
if (php_sapi_name() === 'cli') {
$hostname = gethostname();
if (strpos($hostname, 'prod') !== false || strpos($hostname, 'pra') !== false) {
$_SERVER['SERVER_NAME'] = 'app.geosector.fr';
} elseif (strpos($hostname, 'rec') !== false || strpos($hostname, 'rca') !== false) {
$_SERVER['SERVER_NAME'] = 'rapp.geosector.fr';
} else {
$_SERVER['SERVER_NAME'] = 'dapp.geosector.fr'; // DVA par défaut
}
$_SERVER['REQUEST_URI'] = '/cron/update_stripe_devices';
$_SERVER['REQUEST_METHOD'] = 'CLI';
$_SERVER['HTTP_HOST'] = $_SERVER['SERVER_NAME'];
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
// Définir getallheaders si elle n'existe pas (CLI)
if (!function_exists('getallheaders')) {
function getallheaders() {
return [];
}
}
}
// Charger l'environnement
require_once dirname(dirname(__DIR__)) . '/vendor/autoload.php';
require_once dirname(dirname(__DIR__)) . '/src/Config/AppConfig.php';
require_once dirname(dirname(__DIR__)) . '/src/Core/Database.php';
require_once dirname(dirname(__DIR__)) . '/src/Services/LogService.php';
try {
echo "[" . date('Y-m-d H:i:s') . "] Début de la mise à jour des devices Stripe certifiés\n";
// Initialiser la configuration et la base de données
$appConfig = AppConfig::getInstance();
$dbConfig = $appConfig->getDatabaseConfig();
Database::init($dbConfig);
$db = Database::getInstance();
// Logger le début
LogService::log("Début de la mise à jour des devices Stripe certifiés", [
'source' => 'cron',
'script' => 'update_stripe_devices.php'
]);
// Étape 1: Récupérer la liste des devices
$devicesData = fetchCertifiedDevices();
if (empty($devicesData)) {
echo "[" . date('Y-m-d H:i:s') . "] Aucune donnée de devices récupérée\n";
LogService::log("Aucune donnée de devices récupérée", ['level' => 'warning']);
exit(1);
}
// Étape 2: Traiter et mettre à jour la base de données
$stats = updateDatabase($db, $devicesData);
// Étape 3: Logger les résultats
$message = sprintf(
"Mise à jour terminée : %d ajoutés, %d modifiés, %d désactivés, %d inchangés",
$stats['added'],
$stats['updated'],
$stats['disabled'],
$stats['unchanged']
);
echo "[" . date('Y-m-d H:i:s') . "] $message\n";
LogService::log($message, [
'source' => 'cron',
'stats' => $stats
]);
// Étape 4: Envoyer une notification si changements significatifs
if ($stats['added'] > 0 || $stats['disabled'] > 0) {
sendNotification($stats);
}
echo "[" . date('Y-m-d H:i:s') . "] Mise à jour terminée avec succès\n";
} catch (Exception $e) {
$errorMsg = "Erreur lors de la mise à jour des devices: " . $e->getMessage();
echo "[" . date('Y-m-d H:i:s') . "] $errorMsg\n";
LogService::log($errorMsg, [
'level' => 'error',
'trace' => $e->getTraceAsString()
]);
exit(1);
}
/**
* Récupère la liste des devices certifiés
* Essaie d'abord depuis une URL externe, puis depuis un fichier local en fallback
*/
function fetchCertifiedDevices(): array {
// Liste maintenue manuellement des devices certifiés en France
// Source: Documentation Stripe Terminal et tests confirmés
$frenchCertifiedDevices = [
// Samsung Galaxy S Series
['manufacturer' => 'Samsung', 'model' => 'Galaxy S21', 'model_identifier' => 'SM-G991B', 'min_android_version' => 11],
['manufacturer' => 'Samsung', 'model' => 'Galaxy S21+', 'model_identifier' => 'SM-G996B', 'min_android_version' => 11],
['manufacturer' => 'Samsung', 'model' => 'Galaxy S21 Ultra', 'model_identifier' => 'SM-G998B', 'min_android_version' => 11],
['manufacturer' => 'Samsung', 'model' => 'Galaxy S21 FE', 'model_identifier' => 'SM-G990B', 'min_android_version' => 11],
['manufacturer' => 'Samsung', 'model' => 'Galaxy S22', 'model_identifier' => 'SM-S901B', 'min_android_version' => 12],
['manufacturer' => 'Samsung', 'model' => 'Galaxy S22+', 'model_identifier' => 'SM-S906B', 'min_android_version' => 12],
['manufacturer' => 'Samsung', 'model' => 'Galaxy S22 Ultra', 'model_identifier' => 'SM-S908B', 'min_android_version' => 12],
['manufacturer' => 'Samsung', 'model' => 'Galaxy S23', 'model_identifier' => 'SM-S911B', 'min_android_version' => 13],
['manufacturer' => 'Samsung', 'model' => 'Galaxy S23+', 'model_identifier' => 'SM-S916B', 'min_android_version' => 13],
['manufacturer' => 'Samsung', 'model' => 'Galaxy S23 Ultra', 'model_identifier' => 'SM-S918B', 'min_android_version' => 13],
['manufacturer' => 'Samsung', 'model' => 'Galaxy S23 FE', 'model_identifier' => 'SM-S711B', 'min_android_version' => 13],
['manufacturer' => 'Samsung', 'model' => 'Galaxy S24', 'model_identifier' => 'SM-S921B', 'min_android_version' => 14],
['manufacturer' => 'Samsung', 'model' => 'Galaxy S24+', 'model_identifier' => 'SM-S926B', 'min_android_version' => 14],
['manufacturer' => 'Samsung', 'model' => 'Galaxy S24 Ultra', 'model_identifier' => 'SM-S928B', 'min_android_version' => 14],
// Samsung Galaxy Note
['manufacturer' => 'Samsung', 'model' => 'Galaxy Note 20', 'model_identifier' => 'SM-N980F', 'min_android_version' => 10],
['manufacturer' => 'Samsung', 'model' => 'Galaxy Note 20 Ultra', 'model_identifier' => 'SM-N986B', 'min_android_version' => 10],
// Samsung Galaxy Z Fold
['manufacturer' => 'Samsung', 'model' => 'Galaxy Z Fold3', 'model_identifier' => 'SM-F926B', 'min_android_version' => 11],
['manufacturer' => 'Samsung', 'model' => 'Galaxy Z Fold4', 'model_identifier' => 'SM-F936B', 'min_android_version' => 12],
['manufacturer' => 'Samsung', 'model' => 'Galaxy Z Fold5', 'model_identifier' => 'SM-F946B', 'min_android_version' => 13],
['manufacturer' => 'Samsung', 'model' => 'Galaxy Z Fold6', 'model_identifier' => 'SM-F956B', 'min_android_version' => 14],
// Samsung Galaxy Z Flip
['manufacturer' => 'Samsung', 'model' => 'Galaxy Z Flip3', 'model_identifier' => 'SM-F711B', 'min_android_version' => 11],
['manufacturer' => 'Samsung', 'model' => 'Galaxy Z Flip4', 'model_identifier' => 'SM-F721B', 'min_android_version' => 12],
['manufacturer' => 'Samsung', 'model' => 'Galaxy Z Flip5', 'model_identifier' => 'SM-F731B', 'min_android_version' => 13],
['manufacturer' => 'Samsung', 'model' => 'Galaxy Z Flip6', 'model_identifier' => 'SM-F741B', 'min_android_version' => 14],
// Samsung Galaxy A Series (haut de gamme)
['manufacturer' => 'Samsung', 'model' => 'Galaxy A54', 'model_identifier' => 'SM-A546B', 'min_android_version' => 13],
['manufacturer' => 'Samsung', 'model' => 'Galaxy A73', 'model_identifier' => 'SM-A736B', 'min_android_version' => 12],
// Google Pixel
['manufacturer' => 'Google', 'model' => 'Pixel 6', 'model_identifier' => 'oriole', 'min_android_version' => 12],
['manufacturer' => 'Google', 'model' => 'Pixel 6 Pro', 'model_identifier' => 'raven', 'min_android_version' => 12],
['manufacturer' => 'Google', 'model' => 'Pixel 6a', 'model_identifier' => 'bluejay', 'min_android_version' => 12],
['manufacturer' => 'Google', 'model' => 'Pixel 7', 'model_identifier' => 'panther', 'min_android_version' => 13],
['manufacturer' => 'Google', 'model' => 'Pixel 7 Pro', 'model_identifier' => 'cheetah', 'min_android_version' => 13],
['manufacturer' => 'Google', 'model' => 'Pixel 7a', 'model_identifier' => 'lynx', 'min_android_version' => 13],
['manufacturer' => 'Google', 'model' => 'Pixel 8', 'model_identifier' => 'shiba', 'min_android_version' => 14],
['manufacturer' => 'Google', 'model' => 'Pixel 8 Pro', 'model_identifier' => 'husky', 'min_android_version' => 14],
['manufacturer' => 'Google', 'model' => 'Pixel 8a', 'model_identifier' => 'akita', 'min_android_version' => 14],
['manufacturer' => 'Google', 'model' => 'Pixel 9', 'model_identifier' => 'tokay', 'min_android_version' => 14],
['manufacturer' => 'Google', 'model' => 'Pixel 9 Pro', 'model_identifier' => 'caiman', 'min_android_version' => 14],
['manufacturer' => 'Google', 'model' => 'Pixel 9 Pro XL', 'model_identifier' => 'komodo', 'min_android_version' => 14],
['manufacturer' => 'Google', 'model' => 'Pixel Fold', 'model_identifier' => 'felix', 'min_android_version' => 13],
['manufacturer' => 'Google', 'model' => 'Pixel Tablet', 'model_identifier' => 'tangorpro', 'min_android_version' => 13],
// OnePlus
['manufacturer' => 'OnePlus', 'model' => '9', 'model_identifier' => 'LE2113', 'min_android_version' => 11],
['manufacturer' => 'OnePlus', 'model' => '9 Pro', 'model_identifier' => 'LE2123', 'min_android_version' => 11],
['manufacturer' => 'OnePlus', 'model' => '10 Pro', 'model_identifier' => 'NE2213', 'min_android_version' => 12],
['manufacturer' => 'OnePlus', 'model' => '10T', 'model_identifier' => 'CPH2413', 'min_android_version' => 12],
['manufacturer' => 'OnePlus', 'model' => '11', 'model_identifier' => 'CPH2449', 'min_android_version' => 13],
['manufacturer' => 'OnePlus', 'model' => '11R', 'model_identifier' => 'CPH2487', 'min_android_version' => 13],
['manufacturer' => 'OnePlus', 'model' => '12', 'model_identifier' => 'CPH2581', 'min_android_version' => 14],
['manufacturer' => 'OnePlus', 'model' => '12R', 'model_identifier' => 'CPH2585', 'min_android_version' => 14],
['manufacturer' => 'OnePlus', 'model' => 'Open', 'model_identifier' => 'CPH2551', 'min_android_version' => 13],
// Xiaomi
['manufacturer' => 'Xiaomi', 'model' => 'Mi 11', 'model_identifier' => 'M2011K2G', 'min_android_version' => 11],
['manufacturer' => 'Xiaomi', 'model' => 'Mi 11 Ultra', 'model_identifier' => 'M2102K1G', 'min_android_version' => 11],
['manufacturer' => 'Xiaomi', 'model' => '12', 'model_identifier' => '2201123G', 'min_android_version' => 12],
['manufacturer' => 'Xiaomi', 'model' => '12 Pro', 'model_identifier' => '2201122G', 'min_android_version' => 12],
['manufacturer' => 'Xiaomi', 'model' => '12T Pro', 'model_identifier' => '2207122MC', 'min_android_version' => 12],
['manufacturer' => 'Xiaomi', 'model' => '13', 'model_identifier' => '2211133G', 'min_android_version' => 13],
['manufacturer' => 'Xiaomi', 'model' => '13 Pro', 'model_identifier' => '2210132G', 'min_android_version' => 13],
['manufacturer' => 'Xiaomi', 'model' => '13T Pro', 'model_identifier' => '23078PND5G', 'min_android_version' => 13],
['manufacturer' => 'Xiaomi', 'model' => '14', 'model_identifier' => '23127PN0CG', 'min_android_version' => 14],
['manufacturer' => 'Xiaomi', 'model' => '14 Pro', 'model_identifier' => '23116PN5BG', 'min_android_version' => 14],
['manufacturer' => 'Xiaomi', 'model' => '14 Ultra', 'model_identifier' => '24030PN60G', 'min_android_version' => 14],
// OPPO
['manufacturer' => 'OPPO', 'model' => 'Find X3 Pro', 'model_identifier' => 'CPH2173', 'min_android_version' => 11],
['manufacturer' => 'OPPO', 'model' => 'Find X5 Pro', 'model_identifier' => 'CPH2305', 'min_android_version' => 12],
['manufacturer' => 'OPPO', 'model' => 'Find X6 Pro', 'model_identifier' => 'CPH2449', 'min_android_version' => 13],
['manufacturer' => 'OPPO', 'model' => 'Find N2', 'model_identifier' => 'CPH2399', 'min_android_version' => 13],
['manufacturer' => 'OPPO', 'model' => 'Find N3', 'model_identifier' => 'CPH2499', 'min_android_version' => 13],
// Realme
['manufacturer' => 'Realme', 'model' => 'GT 2 Pro', 'model_identifier' => 'RMX3301', 'min_android_version' => 12],
['manufacturer' => 'Realme', 'model' => 'GT 3', 'model_identifier' => 'RMX3709', 'min_android_version' => 13],
['manufacturer' => 'Realme', 'model' => 'GT 5 Pro', 'model_identifier' => 'RMX3888', 'min_android_version' => 14],
// Honor
['manufacturer' => 'Honor', 'model' => 'Magic5 Pro', 'model_identifier' => 'PGT-N19', 'min_android_version' => 13],
['manufacturer' => 'Honor', 'model' => 'Magic6 Pro', 'model_identifier' => 'BVL-N49', 'min_android_version' => 14],
['manufacturer' => 'Honor', 'model' => '90', 'model_identifier' => 'REA-NX9', 'min_android_version' => 13],
// ASUS
['manufacturer' => 'ASUS', 'model' => 'Zenfone 9', 'model_identifier' => 'AI2202', 'min_android_version' => 12],
['manufacturer' => 'ASUS', 'model' => 'Zenfone 10', 'model_identifier' => 'AI2302', 'min_android_version' => 13],
['manufacturer' => 'ASUS', 'model' => 'ROG Phone 7', 'model_identifier' => 'AI2205', 'min_android_version' => 13],
// Nothing
['manufacturer' => 'Nothing', 'model' => 'Phone (1)', 'model_identifier' => 'A063', 'min_android_version' => 12],
['manufacturer' => 'Nothing', 'model' => 'Phone (2)', 'model_identifier' => 'A065', 'min_android_version' => 13],
['manufacturer' => 'Nothing', 'model' => 'Phone (2a)', 'model_identifier' => 'A142', 'min_android_version' => 14],
];
// Essayer de charger depuis un fichier JSON local si présent
if (file_exists(DEVICES_LOCAL_FILE)) {
$localData = json_decode(file_get_contents(DEVICES_LOCAL_FILE), true);
if (!empty($localData)) {
echo "[" . date('Y-m-d H:i:s') . "] Données chargées depuis le fichier local\n";
return array_merge($frenchCertifiedDevices, $localData);
}
}
echo "[" . date('Y-m-d H:i:s') . "] Utilisation de la liste intégrée des devices certifiés\n";
return $frenchCertifiedDevices;
}
/**
* Met à jour la base de données avec les nouvelles données
*/
function updateDatabase($db, array $devices): array {
$stats = [
'added' => 0,
'updated' => 0,
'disabled' => 0,
'unchanged' => 0,
'total' => 0
];
// Récupérer tous les devices existants
$stmt = $db->prepare("SELECT * FROM stripe_android_certified_devices WHERE country = 'FR'");
$stmt->execute();
$existingDevices = [];
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$key = $row['manufacturer'] . '|' . $row['model'] . '|' . $row['model_identifier'];
$existingDevices[$key] = $row;
}
// Marquer tous les devices pour tracking
$processedKeys = [];
// Traiter chaque device de la nouvelle liste
foreach ($devices as $device) {
$key = $device['manufacturer'] . '|' . $device['model'] . '|' . $device['model_identifier'];
$processedKeys[$key] = true;
if (isset($existingDevices[$key])) {
// Le device existe, vérifier s'il faut le mettre à jour
$existing = $existingDevices[$key];
// Vérifier si des champs ont changé
$needsUpdate = false;
if ($existing['min_android_version'] != $device['min_android_version']) {
$needsUpdate = true;
}
if ($existing['tap_to_pay_certified'] != 1) {
$needsUpdate = true;
}
if ($needsUpdate) {
$stmt = $db->prepare("
UPDATE stripe_android_certified_devices
SET min_android_version = :min_version,
tap_to_pay_certified = 1,
last_verified = NOW(),
updated_at = NOW()
WHERE manufacturer = :manufacturer
AND model = :model
AND model_identifier = :model_identifier
AND country = 'FR'
");
$stmt->execute([
'min_version' => $device['min_android_version'],
'manufacturer' => $device['manufacturer'],
'model' => $device['model'],
'model_identifier' => $device['model_identifier']
]);
$stats['updated']++;
LogService::log("Device mis à jour", [
'device' => $device['manufacturer'] . ' ' . $device['model']
]);
} else {
// Juste mettre à jour last_verified
$stmt = $db->prepare("
UPDATE stripe_android_certified_devices
SET last_verified = NOW()
WHERE manufacturer = :manufacturer
AND model = :model
AND model_identifier = :model_identifier
AND country = 'FR'
");
$stmt->execute([
'manufacturer' => $device['manufacturer'],
'model' => $device['model'],
'model_identifier' => $device['model_identifier']
]);
$stats['unchanged']++;
}
} else {
// Nouveau device, l'ajouter
$stmt = $db->prepare("
INSERT INTO stripe_android_certified_devices
(manufacturer, model, model_identifier, tap_to_pay_certified,
certification_date, min_android_version, country, notes, last_verified)
VALUES
(:manufacturer, :model, :model_identifier, 1,
NOW(), :min_version, 'FR', 'Ajouté automatiquement via CRON', NOW())
");
$stmt->execute([
'manufacturer' => $device['manufacturer'],
'model' => $device['model'],
'model_identifier' => $device['model_identifier'],
'min_version' => $device['min_android_version']
]);
$stats['added']++;
LogService::log("Nouveau device ajouté", [
'device' => $device['manufacturer'] . ' ' . $device['model']
]);
}
}
// Désactiver les devices qui ne sont plus dans la liste
foreach ($existingDevices as $key => $existing) {
if (!isset($processedKeys[$key]) && $existing['tap_to_pay_certified'] == 1) {
$stmt = $db->prepare("
UPDATE stripe_android_certified_devices
SET tap_to_pay_certified = 0,
notes = CONCAT(IFNULL(notes, ''), ' | Désactivé le ', NOW(), ' (non présent dans la mise à jour)'),
updated_at = NOW()
WHERE id = :id
");
$stmt->execute(['id' => $existing['id']]);
$stats['disabled']++;
LogService::log("Device désactivé", [
'device' => $existing['manufacturer'] . ' ' . $existing['model'],
'reason' => 'Non présent dans la liste mise à jour'
]);
}
}
$stats['total'] = count($devices);
return $stats;
}
/**
* Envoie une notification email aux administrateurs si changements importants
*/
function sendNotification(array $stats): void {
try {
// Récupérer la configuration
$appConfig = AppConfig::getInstance();
$emailConfig = $appConfig->getEmailConfig();
if (empty($emailConfig['admin_email'])) {
return; // Pas d'email admin configuré
}
$db = Database::getInstance();
// Préparer le contenu de l'email
$subject = "Mise à jour des devices Stripe Tap to Pay";
$body = "Bonjour,\n\n";
$body .= "La mise à jour automatique de la liste des appareils certifiés Stripe Tap to Pay a été effectuée.\n\n";
$body .= "Résumé des changements :\n";
$body .= "- Nouveaux appareils ajoutés : " . $stats['added'] . "\n";
$body .= "- Appareils mis à jour : " . $stats['updated'] . "\n";
$body .= "- Appareils désactivés : " . $stats['disabled'] . "\n";
$body .= "- Appareils inchangés : " . $stats['unchanged'] . "\n";
$body .= "- Total d'appareils traités : " . $stats['total'] . "\n\n";
if ($stats['added'] > 0) {
$body .= "Les nouveaux appareils ont été automatiquement ajoutés à la base de données.\n";
}
if ($stats['disabled'] > 0) {
$body .= "Certains appareils ont été désactivés car ils ne sont plus certifiés.\n";
}
$body .= "\nConsultez les logs pour plus de détails.\n";
$body .= "\nCordialement,\nLe système GeoSector";
// Insérer dans la queue d'emails
$stmt = $db->prepare("
INSERT INTO email_queue
(to_email, subject, body, status, created_at, attempts)
VALUES
(:to_email, :subject, :body, 'pending', NOW(), 0)
");
$stmt->execute([
'to_email' => $emailConfig['admin_email'],
'subject' => $subject,
'body' => $body
]);
echo "[" . date('Y-m-d H:i:s') . "] Notification ajoutée à la queue d'emails\n";
} catch (Exception $e) {
// Ne pas faire échouer le script si l'email ne peut pas être envoyé
echo "[" . date('Y-m-d H:i:s') . "] Impossible d'envoyer la notification: " . $e->getMessage() . "\n";
}
}

View File

@@ -0,0 +1,248 @@
#!/bin/bash
# Script de migration des bases de données vers les containers MariaDB
# Date: Janvier 2025
# Auteur: Pierre (avec l'aide de Claude)
#
# Ce script migre les bases de données depuis les containers applicatifs
# vers les containers MariaDB dédiés (maria3 sur IN3, maria4 sur IN4)
set -euo pipefail
# Configuration SSH
HOST_KEY="/home/pierre/.ssh/id_rsa_mbpi"
HOST_PORT="22"
HOST_USER="root"
# Serveurs
RCA_HOST="195.154.80.116" # IN3
PRA_HOST="51.159.7.190" # IN4
# Configuration MariaDB
MARIA_ROOT_PASS="MyAlpLocal,90b" # Mot de passe root pour maria3 et maria4
# Couleurs
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
NC='\033[0m'
echo_step() {
echo -e "${GREEN}==>${NC} $1"
}
echo_info() {
echo -e "${BLUE}Info:${NC} $1"
}
echo_warning() {
echo -e "${YELLOW}Warning:${NC} $1"
}
echo_error() {
echo -e "${RED}Error:${NC} $1"
exit 1
}
# Fonction pour créer une base de données et un utilisateur
create_database_and_user() {
local HOST=$1
local CONTAINER=$2
local DB_NAME=$3
local DB_USER=$4
local DB_PASS=$5
local SOURCE_CONTAINER=$6
echo_step "Creating database ${DB_NAME} in ${CONTAINER} on ${HOST}..."
# Commandes SQL pour créer la base et l'utilisateur
SQL_COMMANDS="
CREATE DATABASE IF NOT EXISTS ${DB_NAME} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS '${DB_USER}'@'%' IDENTIFIED BY '${DB_PASS}';
GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'%';
FLUSH PRIVILEGES;
"
if [ "$HOST" = "local" ]; then
# Pour local (non utilisé actuellement)
incus exec ${CONTAINER} -- mysql -u root -p${MARIA_ROOT_PASS} -e "${SQL_COMMANDS}"
else
# Pour serveur distant
ssh -i ${HOST_KEY} -p ${HOST_PORT} ${HOST_USER}@${HOST} \
"incus exec ${CONTAINER} -- mysql -u root -p${MARIA_ROOT_PASS} -e \"${SQL_COMMANDS}\""
fi
echo_info "Database ${DB_NAME} and user ${DB_USER} created"
}
# Fonction pour migrer les données
migrate_data() {
local HOST=$1
local SOURCE_CONTAINER=$2
local TARGET_CONTAINER=$3
local SOURCE_DB=$4
local TARGET_DB=$5
local TARGET_USER=$6
local TARGET_PASS=$7
echo_step "Migrating data from ${SOURCE_CONTAINER}/${SOURCE_DB} to ${TARGET_CONTAINER}/${TARGET_DB}..."
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
DUMP_FILE="/tmp/${SOURCE_DB}_dump_${TIMESTAMP}.sql"
# Créer le dump depuis le container source
echo_info "Creating database dump..."
# Déterminer si le container source utilise root avec mot de passe
# Les containers d'app (dva-geo, rca-geo, pra-geo) n'ont probablement pas de mot de passe root
ssh -i ${HOST_KEY} -p ${HOST_PORT} ${HOST_USER}@${HOST} \
"incus exec ${SOURCE_CONTAINER} -- mysqldump --single-transaction --routines --triggers ${SOURCE_DB} > ${DUMP_FILE} 2>/dev/null || \
incus exec ${SOURCE_CONTAINER} -- mysqldump -u root -p${MARIA_ROOT_PASS} --single-transaction --routines --triggers ${SOURCE_DB} > ${DUMP_FILE}"
# Importer dans le container cible
echo_info "Importing data into ${TARGET_CONTAINER}..."
ssh -i ${HOST_KEY} -p ${HOST_PORT} ${HOST_USER}@${HOST} \
"cat ${DUMP_FILE} | incus exec ${TARGET_CONTAINER} -- mysql -u ${TARGET_USER} -p${TARGET_PASS} ${TARGET_DB}"
# Nettoyer
ssh -i ${HOST_KEY} -p ${HOST_PORT} ${HOST_USER}@${HOST} "rm -f ${DUMP_FILE}"
echo_info "Migration completed for ${TARGET_DB}"
}
# Fonction pour migrer les données entre serveurs différents (pour PRODUCTION)
migrate_data_cross_server() {
local SOURCE_HOST=$1
local SOURCE_CONTAINER=$2
local TARGET_HOST=$3
local TARGET_CONTAINER=$4
local SOURCE_DB=$5
local TARGET_DB=$6
local TARGET_USER=$7
local TARGET_PASS=$8
echo_step "Migrating data from ${SOURCE_HOST}/${SOURCE_CONTAINER}/${SOURCE_DB} to ${TARGET_HOST}/${TARGET_CONTAINER}/${TARGET_DB}..."
echo_info "Using WireGuard VPN tunnel (IN3 → IN4)..."
# Option 1: Streaming direct via VPN avec agent forwarding
echo_info "Streaming database directly through VPN tunnel..."
echo_warning "Note: This requires SSH agent forwarding (ssh -A) when connecting to IN3"
# Utiliser -A pour activer l'agent forwarding vers IN3
# Utilise l'alias 'in4' défini dans /root/.ssh/config sur IN3
ssh -A -i ${HOST_KEY} -p ${HOST_PORT} ${HOST_USER}@${SOURCE_HOST} "
# Dump depuis maria3 avec mot de passe root et pipe direct vers IN4 via VPN
incus exec ${SOURCE_CONTAINER} -- mysqldump -u root -p${MARIA_ROOT_PASS} --single-transaction --routines --triggers ${SOURCE_DB} | \
ssh in4 'incus exec ${TARGET_CONTAINER} -- mysql -u ${TARGET_USER} -p${TARGET_PASS} ${TARGET_DB}'
"
if [ $? -eq 0 ]; then
echo_info "Direct VPN streaming migration completed successfully!"
else
echo_warning "VPN streaming failed, falling back to file transfer method..."
# Option 2: Fallback avec fichiers temporaires si le streaming échoue
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
DUMP_FILE="/tmp/${SOURCE_DB}_dump_${TIMESTAMP}.sql"
# Créer le dump sur IN3
echo_info "Creating database dump..."
ssh -A -i ${HOST_KEY} -p ${HOST_PORT} ${HOST_USER}@${SOURCE_HOST} \
"incus exec ${SOURCE_CONTAINER} -- mysqldump -u root -p${MARIA_ROOT_PASS} --single-transaction --routines --triggers ${SOURCE_DB} > ${DUMP_FILE}"
# Transférer via VPN depuis IN3 vers IN4 (utilise l'alias 'in4')
echo_info "Transferring dump file through VPN..."
ssh -A -i ${HOST_KEY} -p ${HOST_PORT} ${HOST_USER}@${SOURCE_HOST} \
"scp ${DUMP_FILE} in4:${DUMP_FILE}"
# Importer sur IN4 (utilise l'alias 'in4')
echo_info "Importing data on IN4..."
ssh -A -i ${HOST_KEY} -p ${HOST_PORT} ${HOST_USER}@${SOURCE_HOST} \
"ssh in4 'cat ${DUMP_FILE} | incus exec ${TARGET_CONTAINER} -- mysql -u ${TARGET_USER} -p${TARGET_PASS} ${TARGET_DB}'"
# Nettoyer
ssh -A -i ${HOST_KEY} -p ${HOST_PORT} ${HOST_USER}@${SOURCE_HOST} "rm -f ${DUMP_FILE}"
ssh -A -i ${HOST_KEY} -p ${HOST_PORT} ${HOST_USER}@${SOURCE_HOST} \
"ssh in4 'rm -f ${DUMP_FILE}'"
fi
echo_info "Cross-server migration completed for ${TARGET_DB}"
}
# Menu de sélection
echo_step "Database Migration to MariaDB Containers"
echo ""
echo "Select environment to migrate:"
echo "1) DEV - dva-geo → maria3/dva_geo"
echo "2) RCA - rca-geo → maria3/rca_geo"
echo "3) PROD - rca_geo (IN3/maria3) → maria4/pra_geo (copy from RECETTE)"
echo "4) ALL - Migrate all environments"
echo ""
read -p "Your choice [1-4]: " choice
case $choice in
1)
echo_step "Migrating DEV environment..."
create_database_and_user "${RCA_HOST}" "maria3" "dva_geo" "dva_geo_user" "CBq9tKHj6PGPZuTmAHV7" "dva-geo"
migrate_data "${RCA_HOST}" "dva-geo" "maria3" "geo_app" "dva_geo" "dva_geo_user" "CBq9tKHj6PGPZuTmAHV7"
echo_step "DEV migration completed!"
;;
2)
echo_step "Migrating RECETTE environment..."
create_database_and_user "${RCA_HOST}" "maria3" "rca_geo" "rca_geo_user" "UPf3C0cQ805LypyM71iW" "rca-geo"
migrate_data "${RCA_HOST}" "rca-geo" "maria3" "geo_app" "rca_geo" "rca_geo_user" "UPf3C0cQ805LypyM71iW"
echo_step "RECETTE migration completed!"
;;
3)
echo_step "Migrating PRODUCTION environment (copying from RECETTE)..."
echo_warning "Note: PRODUCTION will be duplicated from rca_geo on IN3/maria3"
# Créer la base et l'utilisateur sur IN4/maria4
create_database_and_user "${PRA_HOST}" "maria4" "pra_geo" "pra_geo_user" "d2jAAGGWi8fxFrWgXjOA" "pra-geo"
# Copier les données depuis rca_geo (IN3/maria3) vers pra_geo (IN4/maria4)
migrate_data_cross_server "${RCA_HOST}" "maria3" "${PRA_HOST}" "maria4" "rca_geo" "pra_geo" "pra_geo_user" "d2jAAGGWi8fxFrWgXjOA"
echo_step "PRODUCTION migration completed (duplicated from RECETTE)!"
;;
4)
echo_step "Migrating ALL environments..."
echo_info "Starting DEV migration..."
create_database_and_user "${RCA_HOST}" "maria3" "dva_geo" "dva_geo_user" "CBq9tKHj6PGPZuTmAHV7" "dva-geo"
migrate_data "${RCA_HOST}" "dva-geo" "maria3" "geo_app" "dva_geo" "dva_geo_user" "CBq9tKHj6PGPZuTmAHV7"
echo_info "Starting RECETTE migration..."
create_database_and_user "${RCA_HOST}" "maria3" "rca_geo" "rca_geo_user" "UPf3C0cQ805LypyM71iW" "rca-geo"
migrate_data "${RCA_HOST}" "rca-geo" "maria3" "geo_app" "rca_geo" "rca_geo_user" "UPf3C0cQ805LypyM71iW"
echo_info "Starting PRODUCTION migration (copying from RECETTE)..."
echo_warning "Note: PRODUCTION will be duplicated from rca_geo on IN3/maria3"
create_database_and_user "${PRA_HOST}" "maria4" "pra_geo" "pra_geo_user" "d2jAAGGWi8fxFrWgXjOA" "pra-geo"
migrate_data_cross_server "${RCA_HOST}" "maria3" "${PRA_HOST}" "maria4" "rca_geo" "pra_geo" "pra_geo_user" "d2jAAGGWi8fxFrWgXjOA"
echo_step "All migrations completed!"
;;
*)
echo_error "Invalid choice"
;;
esac
echo ""
echo_step "Migration Summary:"
echo ""
echo "┌─────────────┬──────────────┬──────────────┬─────────────┬──────────────────────┐"
echo "│ Environment │ Source │ Target │ Database │ User │"
echo "├─────────────┼──────────────┼──────────────┼─────────────┼──────────────────────┤"
echo "│ DEV │ dva-geo │ maria3 (IN3) │ dva_geo │ dva_geo_user │"
echo "│ RECETTE │ rca-geo │ maria3 (IN3) │ rca_geo │ rca_geo_user │"
echo "│ PRODUCTION │ pra-geo │ maria4 (IN4) │ pra_geo │ pra_geo_user │"
echo "└─────────────┴──────────────┴──────────────┴─────────────┴──────────────────────┘"
echo ""
echo_warning "Remember to:"
echo " 1. Test database connectivity from application containers"
echo " 2. Deploy the updated AppConfig.php"
echo " 3. Monitor application logs after migration"
echo " 4. Keep old databases for rollback if needed"

View File

@@ -0,0 +1,94 @@
-- =====================================================
-- Migration Stripe : is_striped → stripe_payment_id
-- Date : Janvier 2025
-- Description : Refactoring pour simplifier la gestion des paiements Stripe
-- =====================================================
-- 1. Modifier la table ope_pass
-- ------------------------------
ALTER TABLE `ope_pass` DROP COLUMN IF EXISTS `chk_striped`;
ALTER TABLE `ope_pass` ADD COLUMN `stripe_payment_id` VARCHAR(50) DEFAULT NULL COMMENT 'ID du PaymentIntent Stripe (pi_xxx)';
ALTER TABLE `ope_pass` ADD INDEX `idx_stripe_payment` (`stripe_payment_id`);
-- 2. Modifier stripe_payment_history pour la rendre indépendante
-- ----------------------------------------------------------------
-- Supprimer la clé étrangère vers stripe_payment_intents
ALTER TABLE `stripe_payment_history`
DROP FOREIGN KEY IF EXISTS `stripe_payment_history_ibfk_1`;
-- Modifier la colonne pour stocker directement l'ID Stripe (totalement indépendante)
ALTER TABLE `stripe_payment_history`
DROP INDEX IF EXISTS `idx_fk_payment_intent`,
CHANGE COLUMN `fk_payment_intent` `stripe_payment_intent_id` VARCHAR(255) DEFAULT NULL COMMENT 'ID du PaymentIntent Stripe',
ADD INDEX `idx_stripe_payment_intent_id` (`stripe_payment_intent_id`);
-- 3. Modifier stripe_refunds pour la rendre indépendante
-- --------------------------------------------------------
ALTER TABLE `stripe_refunds`
DROP FOREIGN KEY IF EXISTS `stripe_refunds_ibfk_1`;
-- Modifier la colonne pour stocker directement l'ID Stripe (totalement indépendante)
ALTER TABLE `stripe_refunds`
DROP INDEX IF EXISTS `idx_fk_payment_intent`,
CHANGE COLUMN `fk_payment_intent` `stripe_payment_intent_id` VARCHAR(255) NOT NULL COMMENT 'ID du PaymentIntent Stripe',
ADD INDEX `idx_stripe_payment_intent_id` (`stripe_payment_intent_id`);
-- 4. Supprimer la vue qui dépend de stripe_payment_intents
-- ----------------------------------------------------------
DROP VIEW IF EXISTS `v_stripe_payment_stats`;
-- 5. Supprimer la table stripe_payment_intents
-- ---------------------------------------------
DROP TABLE IF EXISTS `stripe_payment_intents`;
-- 6. Créer une nouvelle vue basée sur ope_pass
-- ----------------------------------------------
CREATE OR REPLACE VIEW `v_stripe_payment_stats` AS
SELECT
o.fk_entite,
e.encrypted_name as entite_name,
p.fk_user,
CONCAT(u.first_name, ' ', u.sect_name) as user_name,
COUNT(DISTINCT p.id) as total_ventes,
COUNT(DISTINCT CASE WHEN p.stripe_payment_id IS NOT NULL THEN p.id END) as ventes_stripe,
SUM(CASE WHEN p.stripe_payment_id IS NOT NULL THEN p.montant ELSE 0 END) as montant_stripe,
SUM(CASE WHEN p.stripe_payment_id IS NULL THEN p.montant ELSE 0 END) as montant_autres,
DATE(p.created_at) as date_vente
FROM ope_pass p
LEFT JOIN operations o ON p.fk_operation = o.id
LEFT JOIN entites e ON o.fk_entite = e.id
LEFT JOIN users u ON p.fk_user = u.id
WHERE p.fk_type = 2 -- Type vente calendrier
GROUP BY o.fk_entite, p.fk_user, DATE(p.created_at);
-- 7. Vue pour les statistiques par entité uniquement
-- ----------------------------------------------------
CREATE OR REPLACE VIEW `v_stripe_entite_stats` AS
SELECT
e.id as entite_id,
e.encrypted_name as entite_name,
sa.stripe_account_id,
sa.charges_enabled,
sa.payouts_enabled,
COUNT(DISTINCT p.id) as total_passages,
COUNT(DISTINCT CASE WHEN p.stripe_payment_id IS NOT NULL THEN p.id END) as passages_stripe,
SUM(CASE WHEN p.stripe_payment_id IS NOT NULL THEN p.montant ELSE 0 END) as revenue_stripe,
SUM(p.montant) as revenue_total
FROM entites e
LEFT JOIN stripe_accounts sa ON e.id = sa.fk_entite
LEFT JOIN operations o ON e.id = o.fk_entite
LEFT JOIN ope_pass p ON o.id = p.fk_operation
GROUP BY e.id, e.encrypted_name, sa.stripe_account_id;
-- 8. Fonction helper pour vérifier si un passage a un paiement Stripe
-- ---------------------------------------------------------------------
-- NOTE: Si vous exécutez en copier/coller, cette fonction est optionnelle
-- Vous pouvez l'ignorer ou l'exécuter séparément avec DELIMITER
-- =====================================================
-- FIN DE LA MIGRATION
-- =====================================================
-- Tables supprimées : stripe_payment_intents
-- Tables modifiées : ope_pass, stripe_payment_history, stripe_refunds
-- Tables conservées : stripe_accounts, stripe_terminal_readers, etc.
-- =====================================================

95
api/scripts/test_whitelist.php Executable file
View File

@@ -0,0 +1,95 @@
#!/usr/bin/env php
<?php
/**
* Script de test pour la whitelist dynamique
* Usage: php scripts/test_whitelist.php [refresh]
*/
require_once __DIR__ . '/../src/Services/Security/IPBlocker.php';
use App\Services\Security\IPBlocker;
echo "=== Test de la whitelist dynamique depuis IN3 ===\n\n";
// Si l'argument "refresh" est passé, forcer le rafraîchissement
if (isset($argv[1]) && $argv[1] === 'refresh') {
echo "Forçage du rafraîchissement de la whitelist...\n";
$ips = IPBlocker::refreshDynamicWhitelist();
echo "✓ Whitelist rafraîchie\n\n";
}
// Test 1: Récupérer les IPs whitelistées
echo "1. IPs whitelistées statiques:\n";
$staticWhitelist = IPBlocker::WHITELIST;
foreach ($staticWhitelist as $ip) {
echo " - $ip\n";
}
echo "\n2. Récupération de la whitelist dynamique depuis IN3...\n";
try {
// Forcer le rafraîchissement pour le test
$dynamicIps = IPBlocker::refreshDynamicWhitelist();
if (empty($dynamicIps)) {
echo " ⚠ Aucune IP dynamique récupérée\n";
echo " Vérifiez:\n";
echo " - La connexion SSH vers IN3 (195.154.80.116)\n";
echo " - L'existence du fichier /var/bat/IP sur IN3\n";
echo " - Les clés SSH sont configurées pour root@IN3\n";
} else {
echo " ✓ IPs dynamiques récupérées:\n";
foreach ($dynamicIps as $ip) {
echo " - $ip\n";
}
}
} catch (Exception $e) {
echo " ✗ Erreur: " . $e->getMessage() . "\n";
}
// Test 2: Vérifier le fichier de cache
echo "\n3. Vérification du cache local:\n";
$cacheFile = __DIR__ . '/../config/whitelist_ip_cache.txt';
if (file_exists($cacheFile)) {
$cacheData = json_decode(file_get_contents($cacheFile), true);
if ($cacheData) {
echo " ✓ Cache trouvé:\n";
echo " - IP: " . ($cacheData['ip'] ?? 'N/A') . "\n";
echo " - Récupéré le: " . ($cacheData['retrieved_at'] ?? 'N/A') . "\n";
echo " - Timestamp: " . ($cacheData['timestamp'] ?? 'N/A') . "\n";
$age = time() - ($cacheData['timestamp'] ?? 0);
$ageMinutes = round($age / 60);
echo " - Âge du cache: $ageMinutes minutes\n";
if ($age > 3600) {
echo " ⚠ Le cache a plus d'1 heure et sera rafraîchi au prochain appel\n";
}
} else {
echo " ⚠ Cache invalide\n";
}
} else {
echo " - Pas de cache local trouvé\n";
}
// Test 3: Tester quelques IPs
echo "\n4. Test de blocage pour quelques IPs:\n";
$testIps = [
'127.0.0.1' => 'Localhost (whitelist statique)',
'8.8.8.8' => 'Google DNS (non whitelisté)',
];
// Ajouter l'IP dynamique si elle existe
if (!empty($dynamicIps) && isset($dynamicIps[0])) {
$testIps[$dynamicIps[0]] = 'IP depuis IN3 (whitelist dynamique)';
}
foreach ($testIps as $ip => $description) {
$isWhitelisted = IPBlocker::isWhitelisted($ip);
$isBlocked = IPBlocker::isBlocked($ip);
echo " - $ip ($description):\n";
echo " Whitelisté: " . ($isWhitelisted ? '✓ Oui' : '✗ Non') . "\n";
echo " Bloqué: " . ($isBlocked ? '✗ Oui' : '✓ Non') . "\n";
}
echo "\n=== Fin du test ===\n";

View File

@@ -92,13 +92,13 @@ class AppConfig {
$this->config['app.geosector.fr'] = array_merge($baseConfig, [ $this->config['app.geosector.fr'] = array_merge($baseConfig, [
'env' => 'production', 'env' => 'production',
'database' => [ 'database' => [
'host' => 'localhost', 'host' => '13.23.33.4', // Container maria4 sur IN4
'name' => 'geo_app', 'name' => 'pra_geo',
'username' => 'geo_app_user_prod', 'username' => 'pra_geo_user',
'password' => 'QO:96-SrHJ6k7-df*?k{4W6m', 'password' => 'd2jAAGGWi8fxFrWgXjOA',
], ],
'addresses_database' => [ 'addresses_database' => [
'host' => '13.23.33.26', 'host' => '13.23.33.4', // Container maria4 sur IN4
'name' => 'adresses', 'name' => 'adresses',
'username' => 'adr_geo_user', 'username' => 'adr_geo_user',
'password' => 'd66,AdrGeo.User', 'password' => 'd66,AdrGeo.User',
@@ -109,13 +109,20 @@ class AppConfig {
$this->config['rapp.geosector.fr'] = array_merge($baseConfig, [ $this->config['rapp.geosector.fr'] = array_merge($baseConfig, [
'env' => 'recette', 'env' => 'recette',
'database' => [ 'database' => [
// Configuration future avec maria3 (à activer après migration)
// 'host' => '13.23.33.4', // Container maria3 sur IN3
// 'name' => 'rca_geo',
// 'username' => 'rca_geo_user',
// 'password' => 'UPf3C0cQ805LypyM71iW',
// Configuration actuelle - base locale dans rca-geo
'host' => 'localhost', 'host' => 'localhost',
'name' => 'geo_app', 'name' => 'geo_app',
'username' => 'geo_app_user_rec', 'username' => 'geo_app_user_rec',
'password' => 'QO:96df*?k-dS3KiO-{4W6m', 'password' => 'UPf3C0cQ805LypyM71iW', // À ajuster si nécessaire
], ],
'addresses_database' => [ 'addresses_database' => [
'host' => '13.23.33.36', 'host' => '13.23.33.4', // Container maria3 sur IN3
'name' => 'adresses', 'name' => 'adresses',
'username' => 'adr_geo_user', 'username' => 'adr_geo_user',
'password' => 'd66,AdrGeoRec.User', 'password' => 'd66,AdrGeoRec.User',
@@ -124,16 +131,23 @@ class AppConfig {
]); ]);
// Configuration DÉVELOPPEMENT // Configuration DÉVELOPPEMENT
$this->config['app.geo.dev'] = array_merge($baseConfig, [ $this->config['dapp.geosector.fr'] = array_merge($baseConfig, [
'env' => 'development', 'env' => 'development',
'database' => [ 'database' => [
'host' => '13.23.33.46', // Configuration future avec maria3 (à activer après migration)
// 'host' => '13.23.33.4', // Container maria3 sur IN3
// 'name' => 'dva_geo',
// 'username' => 'dva_geo_user',
// 'password' => 'CBq9tKHj6PGPZuTmAHV7',
// Configuration actuelle - base locale dans dva-geo
'host' => 'localhost',
'name' => 'geo_app', 'name' => 'geo_app',
'username' => 'geo_app_user_dev', 'username' => 'geo_app_user_dev',
'password' => '34GOz-X5gJu-oH@Fa3$#Z', 'password' => 'CBq9tKHj6PGPZuTmAHV7', // À ajuster si nécessaire
], ],
'addresses_database' => [ 'addresses_database' => [
'host' => '13.23.33.46', 'host' => '13.23.33.4', // Container maria3 sur IN3
'name' => 'adresses', 'name' => 'adresses',
'username' => 'adr_geo_user', 'username' => 'adr_geo_user',
'password' => 'd66,AdrGeoDev.User', 'password' => 'd66,AdrGeoDev.User',
@@ -148,7 +162,7 @@ class AppConfig {
if (empty($this->currentHost)) { if (empty($this->currentHost)) {
// Journaliser cette situation anormale // Journaliser cette situation anormale
error_log("WARNING: No host detected, falling back to development environment"); error_log("WARNING: No host detected, falling back to development environment");
$this->currentHost = 'app.geo.dev'; $this->currentHost = 'dapp.geosector.fr';
} }
// Si l'hôte n'existe pas dans la configuration, tenter une correction // Si l'hôte n'existe pas dans la configuration, tenter une correction
@@ -166,7 +180,7 @@ class AppConfig {
// Si toujours pas de correspondance, utiliser l'environnement de développement par défaut // Si toujours pas de correspondance, utiliser l'environnement de développement par défaut
if (!isset($this->config[$this->currentHost])) { if (!isset($this->config[$this->currentHost])) {
error_log("WARNING: Unknown host '{$this->currentHost}', falling back to development environment"); error_log("WARNING: Unknown host '{$this->currentHost}', falling back to development environment");
$this->currentHost = 'app.geo.dev'; $this->currentHost = 'dapp.geosector.fr';
} }
} }
@@ -186,8 +200,8 @@ class AppConfig {
/** /**
* Retourne l'identifiant de l'application basé sur l'hôte * Retourne l'identifiant de l'application basé sur l'hôte
* *
* @return string L'identifiant de l'application (app.geosector.fr, rapp.geosector.fr, app.geo.dev) * @return string L'identifiant de l'application (app.geosector.fr, rapp.geosector.fr, dapp.geosector.fr)
*/ */
public function getAppIdentifier(): string { public function getAppIdentifier(): string {
return $this->currentHost; return $this->currentHost;

View File

@@ -593,6 +593,11 @@ class EntiteController {
$updateFields[] = 'chk_user_delete_pass = ?'; $updateFields[] = 'chk_user_delete_pass = ?';
$params[] = $data['chk_user_delete_pass'] ? 1 : 0; $params[] = $data['chk_user_delete_pass'] ? 1 : 0;
} }
if (isset($data['chk_lot_actif'])) {
$updateFields[] = 'chk_lot_actif = ?';
$params[] = $data['chk_lot_actif'] ? 1 : 0;
}
} }
// Si aucun champ à mettre à jour, retourner une erreur // Si aucun champ à mettre à jour, retourner une erreur

View File

@@ -50,10 +50,10 @@ class LoginController {
$username = trim($data['username']); $username = trim($data['username']);
$encryptedUsername = ApiService::encryptSearchableData($username); $encryptedUsername = ApiService::encryptSearchableData($username);
// Récupérer le type d'utilisateur // Récupérer le type d'utilisateur
// admin accessible uniquement aux fk_role>1 // user accessible aux fk_role=1 ET fk_role=2 (membres + admins amicale)
// user accessible uniquement aux fk_role=1 // admin accessible uniquement aux fk_role>1 (admins amicale + super-admins)
$roleCondition = ($interface === 'user') ? 'AND fk_role=1' : 'AND fk_role>1'; $roleCondition = ($interface === 'user') ? 'AND fk_role IN (1, 2)' : 'AND fk_role>1';
// Log pour le debug // Log pour le debug
LogService::log('Tentative de connexion GeoSector', [ LogService::log('Tentative de connexion GeoSector', [
@@ -343,18 +343,26 @@ class LoginController {
// 3. Récupérer les passages selon l'interface et le rôle // 3. Récupérer les passages selon l'interface et le rôle
if ($interface === 'user' && !empty($sectors)) { if ($interface === 'user' && !empty($sectors)) {
// Interface utilisateur : passages liés aux secteurs de l'utilisateur // Interface utilisateur : passages de l'utilisateur + passages à finaliser sur ses secteurs
$userId = $user['id'];
$sectorIds = array_column($sectors, 'id'); $sectorIds = array_column($sectors, 'id');
$sectorIdsString = implode(',', $sectorIds); $sectorIdsString = implode(',', $sectorIds);
if (!empty($sectorIdsString)) { if (!empty($sectorIdsString)) {
$passagesStmt = $this->db->prepare( $passagesStmt = $this->db->prepare(
"SELECT id, fk_operation, fk_sector, fk_user, fk_type, fk_adresse, passed_at, numero, rue, rue_bis, ville, residence, fk_habitat, appt, niveau, "SELECT id, fk_operation, fk_sector, fk_user, fk_type, fk_adresse, passed_at, numero, rue, rue_bis, ville, residence, fk_habitat, appt, niveau,
gps_lat, gps_lng, nom_recu, encrypted_name, remarque, encrypted_email, encrypted_phone, montant, fk_type_reglement, email_erreur, nb_passages gps_lat, gps_lng, nom_recu, encrypted_name, remarque, encrypted_email, encrypted_phone, montant, fk_type_reglement, email_erreur, nb_passages
FROM ope_pass FROM ope_pass
WHERE fk_operation = ? AND fk_sector IN ($sectorIdsString) AND chk_active = 1" WHERE fk_operation = ?
AND chk_active = 1
AND (
(fk_user = ?) -- TOUS les passages de l'utilisateur
OR
(fk_sector IN ($sectorIdsString) AND fk_type = 2 AND fk_user != ?) -- Passages type 2 des autres sur ses secteurs
)
ORDER BY passed_at DESC"
); );
$passagesStmt->execute([$activeOperationId]); $passagesStmt->execute([$activeOperationId, $userId, $userId]);
} }
} elseif ($interface === 'admin' && $user['fk_role'] == 2) { } elseif ($interface === 'admin' && $user['fk_role'] == 2) {
// Interface admin avec rôle 2 : tous les passages de l'opération // Interface admin avec rôle 2 : tous les passages de l'opération
@@ -888,6 +896,700 @@ class LoginController {
} }
} }
public function refreshSession(): void {
try {
// 1. Récupérer l'ID utilisateur depuis la session active
$userId = Session::getUserId();
if (!$userId) {
Response::json(['error' => 'Session invalide'], 401);
return;
}
// 2. Récupérer le mode depuis l'URL
$mode = $_GET['mode'] ?? 'user';
// 3. Validation du mode
if (!in_array($mode, ['user', 'admin'])) {
Response::json(['error' => 'Mode invalide. Valeurs acceptées: user, admin'], 400);
return;
}
// Déterminer le roleCondition selon le mode (même logique que login)
$roleCondition = ($mode === 'user') ? 'AND fk_role IN (1, 2)' : 'AND fk_role>1';
// Log pour le debug
LogService::log('Rafraîchissement session GeoSector', [
'level' => 'info',
'userId' => $userId,
'mode' => $mode,
'role_condition' => $roleCondition
]);
// 4. Requête pour récupérer l'utilisateur et son entité (même requête que login)
$stmt = $this->db->prepare(
'SELECT
u.id, u.encrypted_email, u.encrypted_user_name, u.encrypted_name, u.user_pass_hash,
u.first_name, u.fk_role, u.fk_entite, u.fk_titre, u.chk_active, u.sect_name,
u.date_naissance, u.date_embauche, u.encrypted_phone, u.encrypted_mobile,
e.id AS entite_id, e.encrypted_name AS entite_encrypted_name,
e.adresse1, e.code_postal, e.ville, e.gps_lat, e.gps_lng, e.chk_active AS entite_chk_active
FROM users u
LEFT JOIN entites e ON u.fk_entite = e.id
WHERE u.id = ? AND u.chk_active != 0 ' . $roleCondition
);
$stmt->execute([$userId]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$user) {
LogService::log('Rafraîchissement session échoué : utilisateur non trouvé ou accès interdit', [
'level' => 'warning',
'userId' => $userId,
'mode' => $mode
]);
Response::json(['error' => 'Utilisateur non trouvé ou accès interdit à cette interface'], 403);
return;
}
// Vérifier si l'utilisateur a une entité et si elle est active
if (!empty($user['fk_entite']) && (!isset($user['entite_chk_active']) || $user['entite_chk_active'] != 1)) {
LogService::log('Rafraîchissement session échoué : entité non active', [
'level' => 'warning',
'userId' => $userId,
'entite_id' => $user['fk_entite']
]);
Response::json([
'status' => 'error',
'message' => 'Votre amicale n\'est pas activée. Veuillez contacter votre administrateur.'
], 403);
return;
}
// Déchiffrement du nom
$decryptedName = ApiService::decryptData($user['encrypted_name']);
$username = ApiService::decryptSearchableData($user['encrypted_user_name']);
// Déchiffrement de l'email si disponible
$email = '';
if (!empty($user['encrypted_email'])) {
$email = ApiService::decryptSearchableData($user['encrypted_email']);
if (empty($email)) {
LogService::log('Déchiffrement email échoué', [
'level' => 'error',
'message' => 'Déchiffrement de l\'email échoué',
'encrypted_email' => $user['encrypted_email'],
'user_id' => $user['id']
]);
Response::json([
'status' => 'error',
'message' => 'Erreur de déchiffrement de l\'email. Exécutez le script de migration pour résoudre ce problème.',
'debug_info' => [
'encrypted_email' => $user['encrypted_email'],
'user_id' => $user['id']
]
], 500);
return;
}
}
// Préparation des données utilisateur pour la réponse
$userData = [
'id' => $user['id'],
'fk_entite' => $user['fk_entite'] ?? null,
'fk_role' => $user['fk_role'] ?? '0',
'fk_titre' => $user['fk_titre'] ?? null,
'first_name' => $user['first_name'] ?? '',
'sect_name' => $user['sect_name'] ?? '',
'date_naissance' => $user['date_naissance'] ?? null,
'date_embauche' => $user['date_embauche'] ?? null,
'username' => $username,
'name' => $decryptedName
];
// Déchiffrement du téléphone
if (!empty($user['encrypted_phone'])) {
$userData['phone'] = ApiService::decryptData($user['encrypted_phone']);
} else {
$userData['phone'] = '';
}
// Déchiffrement du mobile
if (!empty($user['encrypted_mobile'])) {
$userData['mobile'] = ApiService::decryptData($user['encrypted_mobile']);
} else {
$userData['mobile'] = '';
}
$userData['email'] = $email;
// 5. Charger toutes les données selon le mode (MÊME LOGIQUE QUE LOGIN)
$operationsData = [];
$sectorsData = [];
$passagesData = [];
$usersSectorsData = [];
// Récupération des opérations selon les critères
$operationLimit = 0;
$activeOperationOnly = false;
if ($mode === 'user') {
$operationLimit = 1;
$activeOperationOnly = true;
} elseif ($mode === 'admin' && $user['fk_role'] == 2) {
$operationLimit = 3;
} elseif ($mode === 'admin' && $user['fk_role'] > 2) {
$operationLimit = 10;
} else {
$operationLimit = 0;
}
if ($operationLimit > 0 && !empty($user['fk_entite'])) {
$operationQuery = "SELECT id, fk_entite, libelle, date_deb, date_fin, chk_active
FROM operations
WHERE fk_entite = ?";
if ($activeOperationOnly) {
$operationQuery .= " AND chk_active = 1";
}
$operationQuery .= " ORDER BY id DESC LIMIT " . $operationLimit;
$operationStmt = $this->db->prepare($operationQuery);
$operationStmt->execute([$user['fk_entite']]);
$operations = $operationStmt->fetchAll(PDO::FETCH_ASSOC);
if (!empty($operations)) {
foreach ($operations as $operation) {
$operationsData[] = [
'id' => $operation['id'],
'fk_entite' => $operation['fk_entite'],
'libelle' => $operation['libelle'],
'date_deb' => $operation['date_deb'],
'date_fin' => $operation['date_fin'],
'chk_active' => $operation['chk_active']
];
}
$activeOperationId = $operations[0]['id'];
// Récupérer les secteurs selon le mode et le rôle
if ($mode === 'user') {
$sectorsStmt = $this->db->prepare(
'SELECT s.id, s.libelle, s.color, s.sector
FROM ope_sectors s
JOIN ope_users_sectors us ON s.id = us.fk_sector
WHERE us.fk_operation = ? AND us.fk_user = ? AND us.chk_active = 1 AND s.chk_active = 1'
);
$sectorsStmt->execute([$activeOperationId, $user['id']]);
} elseif ($mode === 'admin' && $user['fk_role'] == 2) {
$sectorsStmt = $this->db->prepare(
'SELECT DISTINCT s.id, s.libelle, s.color, s.sector
FROM ope_sectors s
WHERE s.fk_operation = ? AND s.chk_active = 1'
);
$sectorsStmt->execute([$activeOperationId]);
} else {
$sectors = [];
$sectorsData = [];
}
if (isset($sectorsStmt)) {
$sectors = $sectorsStmt->fetchAll(PDO::FETCH_ASSOC);
} else {
$sectors = [];
}
if (!empty($sectors)) {
$sectorsData = $sectors;
// Récupérer les passages selon le mode et le rôle
if ($mode === 'user' && !empty($sectors)) {
$sectorIds = array_column($sectors, 'id');
$sectorIdsString = implode(',', $sectorIds);
if (!empty($sectorIdsString)) {
$passagesStmt = $this->db->prepare(
"SELECT id, fk_operation, fk_sector, fk_user, fk_type, fk_adresse, passed_at, numero, rue, rue_bis, ville, residence, fk_habitat, appt, niveau,
gps_lat, gps_lng, nom_recu, encrypted_name, remarque, encrypted_email, encrypted_phone, montant, fk_type_reglement, email_erreur, nb_passages
FROM ope_pass
WHERE fk_operation = ?
AND chk_active = 1
AND (
(fk_user = ?)
OR
(fk_sector IN ($sectorIdsString) AND fk_type = 2 AND fk_user != ?)
)
ORDER BY passed_at DESC"
);
$passagesStmt->execute([$activeOperationId, $user['id'], $user['id']]);
}
} elseif ($mode === 'admin' && $user['fk_role'] == 2) {
$passagesStmt = $this->db->prepare(
"SELECT id, fk_operation, fk_sector, fk_user, fk_type, fk_adresse, passed_at, numero, rue, rue_bis, ville, residence, fk_habitat, appt, niveau,
gps_lat, gps_lng, nom_recu, encrypted_name, remarque, encrypted_email, encrypted_phone, montant, fk_type_reglement, email_erreur, nb_passages
FROM ope_pass
WHERE fk_operation = ? AND chk_active = 1"
);
$passagesStmt->execute([$activeOperationId]);
} else {
$passages = [];
$passagesData = [];
}
if (isset($passagesStmt)) {
$passages = $passagesStmt->fetchAll(PDO::FETCH_ASSOC);
} else {
$passages = [];
}
if (!empty($passages)) {
foreach ($passages as &$passage) {
$passage['name'] = '';
if (!empty($passage['encrypted_name'])) {
$passage['name'] = ApiService::decryptData($passage['encrypted_name']);
}
unset($passage['encrypted_name']);
$passage['email'] = '';
if (!empty($passage['encrypted_email'])) {
$decryptedEmail = ApiService::decryptSearchableData($passage['encrypted_email']);
if ($decryptedEmail) {
$passage['email'] = $decryptedEmail;
}
}
unset($passage['encrypted_email']);
$passage['phone'] = '';
if (!empty($passage['encrypted_phone'])) {
$passage['phone'] = ApiService::decryptData($passage['encrypted_phone']);
}
unset($passage['encrypted_phone']);
}
$passagesData = $passages;
}
// Récupérer les utilisateurs des secteurs partagés
if (($mode === 'user' || ($mode === 'admin' && $user['fk_role'] == 2)) && !empty($sectors)) {
$sectorIds = array_column($sectors, 'id');
$sectorIdsString = implode(',', $sectorIds);
if (!empty($sectorIdsString)) {
$usersSectorsStmt = $this->db->prepare(
"SELECT DISTINCT u.id, u.first_name, u.encrypted_name, u.sect_name, us.fk_sector
FROM users u
JOIN ope_users_sectors us ON u.id = us.fk_user
WHERE us.fk_sector IN ($sectorIdsString)
AND us.fk_operation = ?
AND us.chk_active = 1
AND u.chk_active = 1
AND u.id != ?"
);
$usersSectorsStmt->execute([$activeOperationId, $user['id']]);
$usersSectors = $usersSectorsStmt->fetchAll(PDO::FETCH_ASSOC);
if (!empty($usersSectors)) {
foreach ($usersSectors as &$userSector) {
if (!empty($userSector['encrypted_name'])) {
$userSector['name'] = ApiService::decryptData($userSector['encrypted_name']);
unset($userSector['encrypted_name']);
}
}
$usersSectorsData = $usersSectors;
}
}
} else {
$usersSectorsData = [];
}
}
}
}
// Récupérer les membres si nécessaire
$membresData = [];
if ($mode === 'admin' && $user['fk_role'] == 2 && !empty($user['fk_entite'])) {
$membresStmt = $this->db->prepare(
'SELECT id, fk_role, fk_entite, fk_titre, encrypted_name, first_name, sect_name,
encrypted_user_name, encrypted_phone, encrypted_mobile, encrypted_email,
date_naissance, date_embauche, chk_active
FROM users
WHERE fk_entite = ?'
);
$membresStmt->execute([$user['fk_entite']]);
$membres = $membresStmt->fetchAll(PDO::FETCH_ASSOC);
if (!empty($membres)) {
foreach ($membres as $membre) {
$membreItem = [
'id' => $membre['id'],
'fk_role' => $membre['fk_role'],
'fk_entite' => $membre['fk_entite'],
'fk_titre' => $membre['fk_titre'],
'first_name' => $membre['first_name'] ?? '',
'sect_name' => $membre['sect_name'] ?? '',
'date_naissance' => $membre['date_naissance'] ?? null,
'date_embauche' => $membre['date_embauche'] ?? null,
'chk_active' => $membre['chk_active']
];
if (!empty($membre['encrypted_name'])) {
$membreItem['name'] = ApiService::decryptData($membre['encrypted_name']);
} else {
$membreItem['name'] = '';
}
if (!empty($membre['encrypted_user_name'])) {
$membreItem['username'] = ApiService::decryptSearchableData($membre['encrypted_user_name']);
} else {
$membreItem['username'] = '';
}
if (!empty($membre['encrypted_phone'])) {
$membreItem['phone'] = ApiService::decryptData($membre['encrypted_phone']);
} else {
$membreItem['phone'] = '';
}
if (!empty($membre['encrypted_mobile'])) {
$membreItem['mobile'] = ApiService::decryptData($membre['encrypted_mobile']);
} else {
$membreItem['mobile'] = '';
}
if (!empty($membre['encrypted_email'])) {
$decryptedEmail = ApiService::decryptSearchableData($membre['encrypted_email']);
if ($decryptedEmail) {
$membreItem['email'] = $decryptedEmail;
}
} else {
$membreItem['email'] = '';
}
$membresData[] = $membreItem;
}
}
}
// Récupérer les amicales selon le rôle
$amicalesData = [];
if (!empty($user['fk_entite'])) {
if ($user['fk_role'] <= 2) {
$amicaleStmt = $this->db->prepare(
'SELECT e.id, e.encrypted_name as name, e.adresse1, e.adresse2, e.code_postal, e.ville,
e.fk_region, r.libelle AS lib_region, e.fk_type, e.encrypted_phone as phone, e.encrypted_mobile as mobile,
e.encrypted_email as email, e.gps_lat, e.gps_lng,
e.encrypted_stripe_id as stripe_id, e.chk_demo, e.chk_mdp_manuel, e.chk_username_manuel,
e.chk_copie_mail_recu, e.chk_accept_sms, e.chk_active, e.chk_stripe, e.chk_user_delete_pass
FROM entites e
LEFT JOIN x_regions r ON e.fk_region = r.id
WHERE e.id = ? AND e.chk_active = 1'
);
$amicaleStmt->execute([$user['fk_entite']]);
$amicales = $amicaleStmt->fetchAll(PDO::FETCH_ASSOC);
} else {
$amicaleStmt = $this->db->prepare(
'SELECT e.id, e.encrypted_name as name, e.adresse1, e.adresse2, e.code_postal, e.ville,
e.fk_region, r.libelle AS lib_region, e.fk_type, e.encrypted_phone as phone, e.encrypted_mobile as mobile,
e.encrypted_email as email, e.gps_lat, e.gps_lng,
e.encrypted_stripe_id as stripe_id, e.chk_demo, e.chk_mdp_manuel, e.chk_username_manuel,
e.chk_copie_mail_recu, e.chk_accept_sms, e.chk_active, e.chk_stripe, e.chk_user_delete_pass
FROM entites e
LEFT JOIN x_regions r ON e.fk_region = r.id
WHERE e.id != 1 AND e.chk_active = 1'
);
$amicaleStmt->execute();
$amicales = $amicaleStmt->fetchAll(PDO::FETCH_ASSOC);
}
if (!empty($amicales)) {
foreach ($amicales as &$amicale) {
if (!empty($amicale['name'])) {
$amicale['name'] = ApiService::decryptData($amicale['name']);
}
if (!empty($amicale['email'])) {
$decryptedEmail = ApiService::decryptSearchableData($amicale['email']);
if ($decryptedEmail) {
$amicale['email'] = $decryptedEmail;
}
}
if (!empty($amicale['phone'])) {
$amicale['phone'] = ApiService::decryptData($amicale['phone']);
}
if (!empty($amicale['mobile'])) {
$amicale['mobile'] = ApiService::decryptData($amicale['mobile']);
}
if (!empty($amicale['stripe_id'])) {
$amicale['stripe_id'] = ApiService::decryptData($amicale['stripe_id']);
}
}
$amicalesData = $amicales;
}
}
// Récupérer les entités de type 1 pour les utilisateurs avec fk_role > 2
$entitesData = [];
if ($user['fk_role'] > 2) {
$entitesStmt = $this->db->prepare(
'SELECT e.id, e.encrypted_name as name, e.adresse1, e.adresse2, e.code_postal, e.ville,
e.fk_region, r.libelle AS lib_region, e.fk_type, e.encrypted_phone as phone, e.encrypted_mobile as mobile,
e.encrypted_email as email, e.gps_lat, e.gps_lng,
e.encrypted_stripe_id as stripe_id, e.chk_demo, e.chk_mdp_manuel, e.chk_username_manuel,
e.chk_copie_mail_recu, e.chk_accept_sms, e.chk_active, e.chk_stripe, e.chk_user_delete_pass
FROM entites e
LEFT JOIN x_regions r ON e.fk_region = r.id
WHERE e.fk_type = 1 AND e.chk_active = 1'
);
$entitesStmt->execute();
$entites = $entitesStmt->fetchAll(PDO::FETCH_ASSOC);
if (!empty($entites)) {
foreach ($entites as &$entite) {
if (!empty($entite['name'])) {
$entite['name'] = ApiService::decryptData($entite['name']);
}
if (!empty($entite['email'])) {
$decryptedEmail = ApiService::decryptSearchableData($entite['email']);
if ($decryptedEmail) {
$entite['email'] = $decryptedEmail;
}
}
if (!empty($entite['phone'])) {
$entite['phone'] = ApiService::decryptData($entite['phone']);
}
if (!empty($entite['mobile'])) {
$entite['mobile'] = ApiService::decryptData($entite['mobile']);
}
if (!empty($entite['stripe_id'])) {
$entite['stripe_id'] = ApiService::decryptData($entite['stripe_id']);
}
}
$entitesData = $entites;
}
}
// Préparation de la réponse (MÊME STRUCTURE QUE LOGIN)
$response = [
'status' => 'success',
'message' => 'Session rafraîchie',
'session_id' => session_id(),
'session_expiry' => date('c', strtotime('+24 hours')),
'user' => $userData
];
// Ajout des amicales avec logo
if (!empty($amicalesData)) {
$logoData = null;
if (!empty($user['fk_entite'])) {
$logoStmt = $this->db->prepare('
SELECT id, fichier, file_path, file_type, mime_type, processed_width, processed_height
FROM medias
WHERE support = ? AND support_id = ? AND file_category = ?
ORDER BY created_at DESC
LIMIT 1
');
$logoStmt->execute(['entite', $user['fk_entite'], 'logo']);
$logo = $logoStmt->fetch(PDO::FETCH_ASSOC);
if ($logo && file_exists($logo['file_path'])) {
$imageData = file_get_contents($logo['file_path']);
if ($imageData !== false) {
$base64 = base64_encode($imageData);
$dataUrl = 'data:' . $logo['mime_type'] . ';base64,' . $base64;
$logoData = [
'id' => $logo['id'],
'data_url' => $dataUrl,
'file_name' => $logo['fichier'],
'mime_type' => $logo['mime_type'],
'width' => $logo['processed_width'],
'height' => $logo['processed_height']
];
}
}
}
if (count($amicalesData) === 1) {
$response['amicale'] = $amicalesData[0];
if ($logoData !== null) {
$response['amicale']['logo'] = $logoData;
}
} else {
$response['amicale'] = $amicalesData;
if ($logoData !== null && !empty($user['fk_entite'])) {
foreach ($response['amicale'] as &$amicale) {
if ($amicale['id'] == $user['fk_entite']) {
$amicale['logo'] = $logoData;
break;
}
}
}
}
}
$response['clients'] = $entitesData;
if (!empty($membresData)) {
$response['membres'] = $membresData;
}
if (!empty($operationsData)) {
$response['operations'] = $operationsData;
}
if (!empty($sectorsData)) {
$response['sectors'] = $sectorsData;
}
if (!empty($passagesData)) {
$response['passages'] = $passagesData;
}
if (!empty($usersSectorsData)) {
$response['users_sectors'] = $usersSectorsData;
}
// Récupérer les régions selon le rôle
$regionsData = [];
if ($user['fk_role'] <= 2 && !empty($user['fk_entite'])) {
$amicaleStmt = $this->db->prepare('SELECT code_postal FROM entites WHERE id = ?');
$amicaleStmt->execute([$user['fk_entite']]);
$amicale = $amicaleStmt->fetch(PDO::FETCH_ASSOC);
if (!empty($amicale) && !empty($amicale['code_postal'])) {
$departement = substr($amicale['code_postal'], 0, 2);
$regionStmt = $this->db->prepare(
'SELECT id, fk_pays, libelle, libelle_long, table_osm, departements, chk_active
FROM x_regions
WHERE FIND_IN_SET(?, departements) > 0 AND chk_active = 1'
);
$regionStmt->execute([$departement]);
$regions = $regionStmt->fetchAll(PDO::FETCH_ASSOC);
if (!empty($regions)) {
$regionsData = $regions;
}
}
} else {
$regionStmt = $this->db->prepare(
'SELECT id, fk_pays, libelle, libelle_long, table_osm, departements, chk_active
FROM x_regions
WHERE chk_active = 1'
);
$regionStmt->execute();
$regions = $regionStmt->fetchAll(PDO::FETCH_ASSOC);
if (!empty($regions)) {
$regionsData = $regions;
}
}
if (!empty($regionsData)) {
$response['regions'] = $regionsData;
}
// Ajout des informations du module chat
$chatData = [];
$roomCountStmt = $this->db->prepare('
SELECT COUNT(DISTINCT r.id) as total_rooms
FROM chat_rooms r
INNER JOIN chat_participants p ON r.id = p.room_id
WHERE p.user_id = :user_id
AND p.left_at IS NULL
AND r.is_active = 1
');
$roomCountStmt->execute(['user_id' => $user['id']]);
$roomCount = $roomCountStmt->fetch(PDO::FETCH_ASSOC);
$chatData['total_rooms'] = (int)($roomCount['total_rooms'] ?? 0);
$unreadStmt = $this->db->prepare('
SELECT COUNT(*) as unread_count
FROM chat_messages m
INNER JOIN chat_participants p ON m.room_id = p.room_id
WHERE p.user_id = :user_id
AND p.left_at IS NULL
AND m.sender_id != :sender_id
AND m.sent_at > COALESCE(p.last_read_at, p.joined_at)
AND m.is_deleted = 0
');
$unreadStmt->execute([
'user_id' => $user['id'],
'sender_id' => $user['id']
]);
$unreadResult = $unreadStmt->fetch(PDO::FETCH_ASSOC);
$chatData['unread_messages'] = (int)($unreadResult['unread_count'] ?? 0);
$lastRoomStmt = $this->db->prepare('
SELECT
r.id,
r.title,
r.type,
(SELECT m.content
FROM chat_messages m
WHERE m.room_id = r.id
AND m.is_deleted = 0
ORDER BY m.sent_at DESC
LIMIT 1) as last_message,
(SELECT m.sent_at
FROM chat_messages m
WHERE m.room_id = r.id
AND m.is_deleted = 0
ORDER BY m.sent_at DESC
LIMIT 1) as last_message_at
FROM chat_rooms r
INNER JOIN chat_participants p ON r.id = p.room_id
WHERE p.user_id = :user_id
AND p.left_at IS NULL
AND r.is_active = 1
ORDER BY COALESCE(
(SELECT MAX(m.sent_at) FROM chat_messages m WHERE m.room_id = r.id),
r.created_at
) DESC
LIMIT 1
');
$lastRoomStmt->execute(['user_id' => $user['id']]);
$lastRoom = $lastRoomStmt->fetch(PDO::FETCH_ASSOC);
if ($lastRoom) {
$chatData['last_active_room'] = [
'id' => $lastRoom['id'],
'title' => $lastRoom['title'],
'type' => $lastRoom['type'],
'last_message' => $lastRoom['last_message'],
'last_message_at' => $lastRoom['last_message_at']
];
}
$chatData['chat_enabled'] = true;
$response['chat'] = $chatData;
// 6. Envoi de la réponse
Response::json($response);
} catch (PDOException $e) {
LogService::log('Erreur base de données lors du rafraîchissement de session', [
'level' => 'error',
'error' => $e->getMessage(),
'code' => $e->getCode()
]);
Response::json([
'status' => 'error',
'message' => 'Erreur serveur'
], 500);
} catch (Exception $e) {
LogService::log('Erreur inattendue lors du rafraîchissement de session', [
'level' => 'error',
'error' => $e->getMessage()
]);
Response::json([
'status' => 'error',
'message' => 'Une erreur inattendue est survenue'
], 500);
}
}
public function lostPassword(): void { public function lostPassword(): void {
try { try {
$data = Request::getJson(); $data = Request::getJson();

File diff suppressed because it is too large Load Diff

View File

@@ -119,9 +119,17 @@ class PassageController {
$errors[] = 'La ville est obligatoire'; $errors[] = 'La ville est obligatoire';
} }
// Validation du nom (chiffré) // Validation du nom (chiffré) - obligatoire seulement si (type=1 Effectué ou 5 Lot) ET email présent
if (!isset($data['encrypted_name']) && !isset($data['name'])) { $fk_type = isset($data['fk_type']) ? (int)$data['fk_type'] : 0;
$errors[] = 'Le nom est obligatoire'; $hasEmail = (isset($data['email']) && !empty(trim($data['email']))) ||
(isset($data['encrypted_email']) && !empty($data['encrypted_email']));
if (($fk_type === 1 || $fk_type === 5) && $hasEmail) {
if (!isset($data['encrypted_name']) && !isset($data['name'])) {
$errors[] = 'Le nom est obligatoire pour ce type de passage avec email';
} elseif (isset($data['name']) && empty(trim($data['name']))) {
$errors[] = 'Le nom ne peut pas être vide pour ce type de passage avec email';
}
} }
// Validation du montant // Validation du montant
@@ -157,6 +165,15 @@ class PassageController {
} }
} }
// Validation de l'ID Stripe si fourni
if (isset($data['stripe_payment_id']) && !empty($data['stripe_payment_id'])) {
$stripeId = trim($data['stripe_payment_id']);
// L'ID PaymentIntent Stripe doit commencer par 'pi_'
if (!preg_match('/^pi_[a-zA-Z0-9]{24,}$/', $stripeId)) {
$errors[] = 'Format d\'ID de paiement Stripe invalide';
}
}
return empty($errors) ? null : $errors; return empty($errors) ? null : $errors;
} }
@@ -210,13 +227,13 @@ class PassageController {
// Requête principale avec jointures // Requête principale avec jointures
$stmt = $this->db->prepare(" $stmt = $this->db->prepare("
SELECT SELECT
p.id, p.fk_operation, p.fk_sector, p.fk_user, p.fk_adresse, p.id, p.fk_operation, p.fk_sector, p.fk_user, p.fk_adresse,
p.passed_at, p.fk_type, p.numero, p.rue, p.rue_bis, p.ville, p.passed_at, p.fk_type, p.numero, p.rue, p.rue_bis, p.ville,
p.fk_habitat, p.appt, p.niveau, p.residence, p.gps_lat, p.gps_lng, p.fk_habitat, p.appt, p.niveau, p.residence, p.gps_lat, p.gps_lng,
p.encrypted_name, p.montant, p.fk_type_reglement, p.remarque, p.encrypted_name, p.montant, p.fk_type_reglement, p.remarque,
p.encrypted_email, p.encrypted_phone, p.nom_recu, p.date_recu, p.encrypted_email, p.encrypted_phone, p.nom_recu, p.date_recu,
p.chk_email_sent, p.docremis, p.date_repasser, p.nb_passages, p.chk_email_sent, p.stripe_payment_id, p.docremis, p.date_repasser, p.nb_passages,
p.chk_mobile, p.anomalie, p.created_at, p.updated_at, p.chk_active, p.chk_mobile, p.anomalie, p.created_at, p.updated_at, p.chk_active,
o.libelle as operation_libelle, o.libelle as operation_libelle,
u.encrypted_name as user_name, u.first_name as user_first_name u.encrypted_name as user_name, u.first_name as user_first_name
@@ -389,11 +406,11 @@ class PassageController {
$offset = ($page - 1) * $limit; $offset = ($page - 1) * $limit;
$stmt = $this->db->prepare(' $stmt = $this->db->prepare('
SELECT SELECT
p.id, p.fk_operation, p.fk_sector, p.fk_user, p.passed_at, p.id, p.fk_operation, p.fk_sector, p.fk_user, p.passed_at,
p.numero, p.rue, p.rue_bis, p.ville, p.gps_lat, p.gps_lng, p.numero, p.rue, p.rue_bis, p.ville, p.gps_lat, p.gps_lng,
p.encrypted_name, p.montant, p.fk_type_reglement, p.remarque, p.encrypted_name, p.montant, p.fk_type_reglement, p.remarque,
p.encrypted_email, p.encrypted_phone, p.chk_email_sent, p.encrypted_email, p.encrypted_phone, p.stripe_payment_id, p.chk_email_sent,
p.docremis, p.date_repasser, p.nb_passages, p.chk_mobile, p.docremis, p.date_repasser, p.nb_passages, p.chk_mobile,
p.anomalie, p.created_at, p.updated_at, p.anomalie, p.created_at, p.updated_at,
u.encrypted_name as user_name, u.first_name as user_first_name u.encrypted_name as user_name, u.first_name as user_first_name
@@ -494,7 +511,13 @@ class PassageController {
} }
// Chiffrement des données sensibles // Chiffrement des données sensibles
$encryptedName = isset($data['name']) ? ApiService::encryptData($data['name']) : (isset($data['encrypted_name']) ? $data['encrypted_name'] : ''); $encryptedName = '';
if (isset($data['name']) && !empty(trim($data['name']))) {
$encryptedName = ApiService::encryptData($data['name']);
} elseif (isset($data['encrypted_name']) && !empty($data['encrypted_name'])) {
$encryptedName = $data['encrypted_name'];
}
// Le nom peut rester vide si les conditions ne l'exigent pas
$encryptedEmail = isset($data['email']) && !empty($data['email']) ? $encryptedEmail = isset($data['email']) && !empty($data['email']) ?
ApiService::encryptSearchableData($data['email']) : ''; ApiService::encryptSearchableData($data['email']) : '';
$encryptedPhone = isset($data['phone']) && !empty($data['phone']) ? $encryptedPhone = isset($data['phone']) && !empty($data['phone']) ?
@@ -524,6 +547,7 @@ class PassageController {
'remarque' => $data['remarque'] ?? '', 'remarque' => $data['remarque'] ?? '',
'encrypted_email' => $encryptedEmail, 'encrypted_email' => $encryptedEmail,
'encrypted_phone' => $encryptedPhone, 'encrypted_phone' => $encryptedPhone,
'stripe_payment_id' => isset($data['stripe_payment_id']) ? trim($data['stripe_payment_id']) : null,
'nom_recu' => $data['nom_recu'] ?? null, 'nom_recu' => $data['nom_recu'] ?? null,
'date_recu' => isset($data['date_recu']) ? $data['date_recu'] : null, 'date_recu' => isset($data['date_recu']) ? $data['date_recu'] : null,
'docremis' => isset($data['docremis']) ? (int)$data['docremis'] : 0, 'docremis' => isset($data['docremis']) ? (int)$data['docremis'] : 0,
@@ -646,7 +670,7 @@ class PassageController {
} }
$stmt = $this->db->prepare(' $stmt = $this->db->prepare('
SELECT p.id, p.fk_operation SELECT p.id, p.fk_operation, p.fk_type, p.fk_user
FROM ope_pass p FROM ope_pass p
INNER JOIN operations o ON p.fk_operation = o.id INNER JOIN operations o ON p.fk_operation = o.id
WHERE p.id = ? AND o.fk_entite = ? AND p.chk_active = 1 WHERE p.id = ? AND o.fk_entite = ? AND p.chk_active = 1
@@ -673,6 +697,19 @@ class PassageController {
return; return;
} }
// Si le passage était de type 2 et que l'utilisateur actuel est différent du créateur
// On force l'attribution du passage à l'utilisateur actuel
if ((int)$passage['fk_type'] === 2 && (int)$passage['fk_user'] !== $userId) {
$data['fk_user'] = $userId;
LogService::log('Attribution automatique d\'un passage type 2 à l\'utilisateur', [
'level' => 'info',
'passageId' => $passageId,
'ancien_user' => $passage['fk_user'],
'nouveau_user' => $userId
]);
}
// Construction de la requête de mise à jour dynamique // Construction de la requête de mise à jour dynamique
$updateFields = []; $updateFields = [];
$params = []; $params = [];
@@ -697,6 +734,7 @@ class PassageController {
'montant', 'montant',
'fk_type_reglement', 'fk_type_reglement',
'remarque', 'remarque',
'stripe_payment_id',
'nom_recu', 'nom_recu',
'date_recu', 'date_recu',
'docremis', 'docremis',
@@ -714,9 +752,10 @@ class PassageController {
} }
// Gestion des champs chiffrés // Gestion des champs chiffrés
if (isset($data['name'])) { if (array_key_exists('name', $data)) {
$updateFields[] = "encrypted_name = ?"; $updateFields[] = "encrypted_name = ?";
$params[] = ApiService::encryptData($data['name']); // Permettre de vider le nom si les conditions le permettent
$params[] = !empty(trim($data['name'])) ? ApiService::encryptData($data['name']) : '';
} }
if (isset($data['email'])) { if (isset($data['email'])) {

View File

@@ -544,24 +544,85 @@ class SectorController
$stmt->execute($params); $stmt->execute($params);
} }
// Gestion des membres // Gestion des membres (reçus comme 'users' depuis Flutter)
if (isset($data['membres'])) { if (isset($data['users'])) {
$this->logService->info('[UPDATE USERS] Début modification des membres', [
'sector_id' => $id,
'users_demandes' => $data['users'],
'nb_users' => count($data['users'])
]);
// Récupérer l'opération du secteur pour l'INSERT
$opQuery = "SELECT fk_operation FROM ope_sectors WHERE id = :sector_id";
$this->logService->info('[UPDATE USERS] SQL - Récupération fk_operation', [
'query' => $opQuery,
'params' => ['sector_id' => $id]
]);
$opStmt = $this->db->prepare($opQuery);
$opStmt->execute(['sector_id' => $id]);
$operationId = $opStmt->fetch()['fk_operation'];
$this->logService->info('[UPDATE USERS] fk_operation récupéré', [
'operation_id' => $operationId
]);
// Supprimer les affectations existantes // Supprimer les affectations existantes
$deleteQuery = "DELETE FROM ope_users_sectors WHERE fk_sector = :sector_id"; $deleteQuery = "DELETE FROM ope_users_sectors WHERE fk_sector = :sector_id";
$this->logService->info('[UPDATE USERS] SQL - Suppression des anciens membres', [
'query' => $deleteQuery,
'params' => ['sector_id' => $id]
]);
$deleteStmt = $this->db->prepare($deleteQuery); $deleteStmt = $this->db->prepare($deleteQuery);
$deleteStmt->execute(['sector_id' => $id]); $deleteStmt->execute(['sector_id' => $id]);
$deletedCount = $deleteStmt->rowCount();
$this->logService->info('[UPDATE USERS] Membres supprimés', [
'nb_deleted' => $deletedCount
]);
// Ajouter les nouvelles affectations // Ajouter les nouvelles affectations
if (!empty($data['membres'])) { if (!empty($data['users'])) {
$insertQuery = "INSERT INTO ope_users_sectors (fk_user, fk_sector) VALUES (:user_id, :sector_id)"; $insertQuery = "INSERT INTO ope_users_sectors (fk_operation, fk_user, fk_sector, created_at, fk_user_creat, chk_active)
VALUES (:operation_id, :user_id, :sector_id, NOW(), :user_creat, 1)";
$this->logService->info('[UPDATE USERS] SQL - Requête INSERT préparée', [
'query' => $insertQuery
]);
$insertStmt = $this->db->prepare($insertQuery); $insertStmt = $this->db->prepare($insertQuery);
foreach ($data['membres'] as $memberId) { $insertedUsers = [];
$insertStmt->execute([ $failedUsers = [];
'user_id' => $memberId, foreach ($data['users'] as $memberId) {
'sector_id' => $id try {
]); $params = [
'operation_id' => $operationId,
'user_id' => $memberId,
'sector_id' => $id,
'user_creat' => $_SESSION['user_id'] ?? null
];
$this->logService->info('[UPDATE USERS] SQL - INSERT user', [
'params' => $params
]);
$insertStmt->execute($params);
$insertedUsers[] = $memberId;
$this->logService->info('[UPDATE USERS] User inséré avec succès', [
'user_id' => $memberId
]);
} catch (\PDOException $e) {
$failedUsers[] = $memberId;
$this->logService->warning('[UPDATE USERS] ERREUR insertion user', [
'sector_id' => $id,
'user_id' => $memberId,
'error' => $e->getMessage(),
'error_code' => $e->getCode()
]);
}
} }
$this->logService->info('[UPDATE USERS] Résultat des insertions', [
'users_demandes' => $data['users'],
'users_inseres' => $insertedUsers,
'users_echoues' => $failedUsers,
'nb_succes' => count($insertedUsers),
'nb_echecs' => count($failedUsers)
]);
} }
} }
@@ -651,7 +712,8 @@ class SectorController
$this->logService->info('[UPDATE] Début mise à jour des passages', ['sector_id' => $id]); $this->logService->info('[UPDATE] Début mise à jour des passages', ['sector_id' => $id]);
$passageCounters = $this->updatePassagesForSector($id, $data['sector']); $passageCounters = $this->updatePassagesForSector($id, $data['sector']);
} }
// Commit des modifications (users et/ou secteur)
$this->db->commit(); $this->db->commit();
// Récupérer le secteur mis à jour // Récupérer le secteur mis à jour
@@ -711,14 +773,29 @@ class SectorController
$passagesDecrypted[] = $passage; $passagesDecrypted[] = $passage;
} }
// Récupérer les users affectés // Récupérer les users affectés (avec READ UNCOMMITTED pour forcer la lecture des données fraîches)
$usersQuery = "SELECT u.id, u.first_name, u.sect_name, u.encrypted_name, ous.fk_sector $usersQuery = "SELECT u.id, u.first_name, u.sect_name, u.encrypted_name, ous.fk_sector
FROM ope_users_sectors ous FROM ope_users_sectors ous
JOIN users u ON ous.fk_user = u.id JOIN users u ON ous.fk_user = u.id
WHERE ous.fk_sector = :sector_id"; WHERE ous.fk_sector = :sector_id
ORDER BY u.id";
$this->logService->info('[UPDATE USERS] SQL - Récupération finale des users', [
'query' => $usersQuery,
'params' => ['sector_id' => $id]
]);
$usersStmt = $this->db->prepare($usersQuery); $usersStmt = $this->db->prepare($usersQuery);
$usersStmt->execute(['sector_id' => $id]); $usersStmt->execute(['sector_id' => $id]);
$usersSectors = $usersStmt->fetchAll(\PDO::FETCH_ASSOC); $usersSectors = $usersStmt->fetchAll(\PDO::FETCH_ASSOC);
$userIds = array_column($usersSectors, 'id');
$this->logService->info('[UPDATE USERS] Users récupérés après commit', [
'sector_id' => $id,
'users_ids' => $userIds,
'nb_users' => count($userIds),
'users_demandes_initialement' => $data['users'] ?? []
]);
// Déchiffrer les noms des utilisateurs // Déchiffrer les noms des utilisateurs
$usersDecrypted = []; $usersDecrypted = [];
@@ -1066,6 +1143,7 @@ class SectorController
/** /**
* Mettre à jour les passages affectés à un secteur lors de la modification du périmètre * Mettre à jour les passages affectés à un secteur lors de la modification du périmètre
* VERSION OPTIMISÉE avec requêtes groupées
* Retourne un tableau avec les compteurs détaillés * Retourne un tableau avec les compteurs détaillés
*/ */
private function updatePassagesForSector($sectorId, $newSectorCoords): array private function updatePassagesForSector($sectorId, $newSectorCoords): array
@@ -1080,18 +1158,18 @@ class SectorController
try { try {
// Récupérer l'opération et l'entité du secteur // Récupérer l'opération et l'entité du secteur
$sectorQuery = "SELECT o.id as operation_id, o.fk_entite, s.fk_operation $sectorQuery = "SELECT o.id as operation_id, o.fk_entite, s.fk_operation
FROM ope_sectors s FROM ope_sectors s
JOIN operations o ON s.fk_operation = o.id JOIN operations o ON s.fk_operation = o.id
WHERE s.id = :sector_id"; WHERE s.id = :sector_id";
$sectorStmt = $this->db->prepare($sectorQuery); $sectorStmt = $this->db->prepare($sectorQuery);
$sectorStmt->execute(['sector_id' => $sectorId]); $sectorStmt->execute(['sector_id' => $sectorId]);
$sectorInfo = $sectorStmt->fetch(); $sectorInfo = $sectorStmt->fetch();
if (!$sectorInfo) { if (!$sectorInfo) {
return 0; return $counters;
} }
$operationId = $sectorInfo['operation_id']; $operationId = $sectorInfo['operation_id'];
$entityId = $sectorInfo['fk_entite']; $entityId = $sectorInfo['fk_entite'];
@@ -1099,7 +1177,7 @@ class SectorController
$points = explode('#', rtrim($newSectorCoords, '#')); $points = explode('#', rtrim($newSectorCoords, '#'));
$coordinates = []; $coordinates = [];
$polygonPoints = []; $polygonPoints = [];
foreach ($points as $point) { foreach ($points as $point) {
if (!empty($point)) { if (!empty($point)) {
list($lat, $lng) = explode('/', $point); list($lat, $lng) = explode('/', $point);
@@ -1110,170 +1188,249 @@ class SectorController
$polygonPoints[] = $polygonPoints[0]; // Fermer le polygone $polygonPoints[] = $polygonPoints[0]; // Fermer le polygone
$polygonString = 'POLYGON((' . implode(',', $polygonPoints) . '))'; $polygonString = 'POLYGON((' . implode(',', $polygonPoints) . '))';
// 1. VÉRIFICATION GÉOGRAPHIQUE DES PASSAGES EXISTANTS // 1. VÉRIFICATION GÉOGRAPHIQUE DES PASSAGES EXISTANTS (OPTIMISÉE)
$checkPassagesQuery = "SELECT id, gps_lat, gps_lng, fk_type, encrypted_name // Utiliser une seule requête pour vérifier tous les passages
FROM ope_pass $checkPassagesQuery = "
WHERE fk_sector = :sector_id SELECT
AND gps_lat IS NOT NULL p.id,
AND gps_lng IS NOT NULL"; p.gps_lat,
p.gps_lng,
p.fk_type,
p.encrypted_name,
ST_Contains(ST_GeomFromText(:polygon, 4326),
POINT(CAST(p.gps_lng AS DECIMAL(10,8)),
CAST(p.gps_lat AS DECIMAL(10,8)))) as is_inside
FROM ope_pass p
WHERE p.fk_sector = :sector_id
AND p.gps_lat IS NOT NULL
AND p.gps_lng IS NOT NULL";
$checkStmt = $this->db->prepare($checkPassagesQuery); $checkStmt = $this->db->prepare($checkPassagesQuery);
$checkStmt->execute(['sector_id' => $sectorId]); $checkStmt->execute([
'sector_id' => $sectorId,
'polygon' => $polygonString
]);
$existingPassages = $checkStmt->fetchAll(); $existingPassages = $checkStmt->fetchAll();
$passagesToDelete = []; $passagesToDelete = [];
$passagesToOrphan = [];
foreach ($existingPassages as $passage) { foreach ($existingPassages as $passage) {
// Vérifier si le passage est dans le nouveau polygone if ($passage['is_inside'] == 0) {
$pointInPolygonQuery = "SELECT ST_Contains(ST_GeomFromText(:polygon, 4326),
POINT(CAST(:lng AS DECIMAL(10,8)),
CAST(:lat AS DECIMAL(10,8)))) as is_inside";
$pointStmt = $this->db->prepare($pointInPolygonQuery);
$pointStmt->execute([
'polygon' => $polygonString,
'lng' => $passage['gps_lng'],
'lat' => $passage['gps_lat']
]);
$result = $pointStmt->fetch();
if ($result['is_inside'] == 0) {
// Le passage est hors du nouveau périmètre // Le passage est hors du nouveau périmètre
// Vérifier si c'est un passage non visité (fk_type=2 ET encrypted_name vide)
if ($passage['fk_type'] == 2 && ($passage['encrypted_name'] === '' || $passage['encrypted_name'] === null)) { if ($passage['fk_type'] == 2 && ($passage['encrypted_name'] === '' || $passage['encrypted_name'] === null)) {
// Passage non visité : à supprimer // Passage non visité : à supprimer
$passagesToDelete[] = $passage['id']; $passagesToDelete[] = $passage['id'];
$counters['passages_deleted'] = ($counters['passages_deleted'] ?? 0) + 1; $counters['passages_deleted']++;
} else { } else {
// Passage visité : mettre en orphelin // Passage visité : à mettre en orphelin
$orphanQuery = "UPDATE ope_pass SET fk_sector = NULL WHERE id = :passage_id"; $passagesToOrphan[] = $passage['id'];
$orphanStmt = $this->db->prepare($orphanQuery);
$orphanStmt->execute(['passage_id' => $passage['id']]);
$counters['passages_orphaned']++; $counters['passages_orphaned']++;
} }
} else { } else {
$counters['passages_kept']++; $counters['passages_kept']++;
} }
} }
// Supprimer les passages non visités qui sont hors zone // Supprimer les passages non visités en une seule requête
if (!empty($passagesToDelete)) { if (!empty($passagesToDelete)) {
$deleteQuery = "DELETE FROM ope_pass WHERE id IN (" . implode(',', $passagesToDelete) . ")"; $placeholders = str_repeat('?,', count($passagesToDelete) - 1) . '?';
$this->db->exec($deleteQuery); $deleteQuery = "DELETE FROM ope_pass WHERE id IN ($placeholders)";
$deleteStmt = $this->db->prepare($deleteQuery);
$deleteStmt->execute($passagesToDelete);
}
// Mettre en orphelin les passages visités en une seule requête
if (!empty($passagesToOrphan)) {
$placeholders = str_repeat('?,', count($passagesToOrphan) - 1) . '?';
$orphanQuery = "UPDATE ope_pass SET fk_sector = NULL WHERE id IN ($placeholders)";
$orphanStmt = $this->db->prepare($orphanQuery);
$orphanStmt->execute($passagesToOrphan);
} }
// 2. CRÉATION/MISE À JOUR DES PASSAGES POUR LES NOUVELLES ADRESSES // 2. CRÉATION/MISE À JOUR DES PASSAGES POUR LES NOUVELLES ADRESSES (OPTIMISÉE)
// Récupérer toutes les adresses du secteur depuis sectors_adresses // Récupérer toutes les adresses du secteur depuis sectors_adresses
$addressesQuery = "SELECT * FROM sectors_adresses WHERE fk_sector = :sector_id"; $addressesQuery = "SELECT * FROM sectors_adresses WHERE fk_sector = :sector_id";
$addressesStmt = $this->db->prepare($addressesQuery); $addressesStmt = $this->db->prepare($addressesQuery);
$addressesStmt->execute(['sector_id' => $sectorId]); $addressesStmt->execute(['sector_id' => $sectorId]);
$addresses = $addressesStmt->fetchAll(); $addresses = $addressesStmt->fetchAll();
$this->logService->info('[updatePassagesForSector] Adresses dans sectors_adresses', [ $this->logService->info('[updatePassagesForSector] Adresses dans sectors_adresses', [
'sector_id' => $sectorId, 'sector_id' => $sectorId,
'nb_addresses' => count($addresses) 'nb_addresses' => count($addresses)
]); ]);
// Récupérer le premier utilisateur affecté au secteur // Récupérer le premier utilisateur affecté au secteur
$userQuery = "SELECT fk_user FROM ope_users_sectors WHERE fk_sector = :sector_id LIMIT 1"; $userQuery = "SELECT fk_user FROM ope_users_sectors WHERE fk_sector = :sector_id LIMIT 1";
$userStmt = $this->db->prepare($userQuery); $userStmt = $this->db->prepare($userQuery);
$userStmt->execute(['sector_id' => $sectorId]); $userStmt->execute(['sector_id' => $sectorId]);
$firstUser = $userStmt->fetch(); $firstUser = $userStmt->fetch();
$firstUserId = $firstUser ? $firstUser['fk_user'] : null; $firstUserId = $firstUser ? $firstUser['fk_user'] : null;
if ($firstUserId && !empty($addresses)) { if ($firstUserId && !empty($addresses)) {
$this->logService->info('[updatePassagesForSector] Création passages pour user', [ $this->logService->info('[updatePassagesForSector] Optimisation passages', [
'user_id' => $firstUserId, 'user_id' => $firstUserId,
'nb_addresses_to_process' => count($addresses) 'nb_addresses' => count($addresses)
]); ]);
// Préparer la requête de création de passage (même format que dans create)
$createPassageQuery = "INSERT INTO ope_pass ( // OPTIMISATION : Récupérer TOUS les passages existants en UNE requête
fk_operation, fk_sector, fk_user, fk_adresse, $addressIds = array_filter(array_column($addresses, 'fk_adresse'));
numero, rue, rue_bis, ville,
gps_lat, gps_lng, fk_type, encrypted_name, // Construire la requête pour récupérer tous les passages existants
created_at, fk_user_creat, chk_active $existingQuery = "
) VALUES ( SELECT id, fk_adresse, numero, rue, rue_bis, ville
:operation_id, :sector_id, :user_id, :fk_adresse, FROM ope_pass
:numero, :rue, :rue_bis, :ville, WHERE fk_operation = :operation_id
:gps_lat, :gps_lng, 2, '', AND (";
NOW(), :user_creat, 1
)"; $params = ['operation_id' => $operationId];
$createStmt = $this->db->prepare($createPassageQuery); $conditions = [];
// Condition pour les fk_adresse
if (!empty($addressIds)) {
$placeholders = [];
foreach ($addressIds as $idx => $addrId) {
$key = 'addr_' . $idx;
$placeholders[] = ':' . $key;
$params[$key] = $addrId;
}
$conditions[] = "fk_adresse IN (" . implode(',', $placeholders) . ")";
}
// Condition pour les données d'adresse (numero, rue, ville)
$addressConditions = [];
foreach ($addresses as $idx => $addr) {
$numKey = 'num_' . $idx;
$rueKey = 'rue_' . $idx;
$bisKey = 'bis_' . $idx;
$villeKey = 'ville_' . $idx;
$addressConditions[] = "(numero = :$numKey AND rue = :$rueKey AND rue_bis = :$bisKey AND ville = :$villeKey)";
$params[$numKey] = $addr['numero'];
$params[$rueKey] = $addr['rue'];
$params[$bisKey] = $addr['rue_bis'];
$params[$villeKey] = $addr['ville'];
}
if (!empty($addressConditions)) {
$conditions[] = "(" . implode(' OR ', $addressConditions) . ")";
}
$existingQuery .= implode(' OR ', $conditions) . ")";
$existingStmt = $this->db->prepare($existingQuery);
$existingStmt->execute($params);
$existingPassages = $existingStmt->fetchAll();
// Indexer les passages existants pour recherche rapide
$passagesByAddress = [];
$passagesByData = [];
foreach ($existingPassages as $p) {
if (!empty($p['fk_adresse'])) {
$passagesByAddress[$p['fk_adresse']] = $p;
}
$dataKey = $p['numero'] . '|' . $p['rue'] . '|' . $p['rue_bis'] . '|' . $p['ville'];
$passagesByData[$dataKey] = $p;
}
// Préparer les listes pour batch insert/update
$toInsert = [];
$toUpdate = [];
foreach ($addresses as $address) { foreach ($addresses as $address) {
// 2.1 Vérification primaire par fk_adresse // Vérification en mémoire PHP (0 requête)
if (!empty($address['fk_adresse'])) { if (!empty($address['fk_adresse']) && isset($passagesByAddress[$address['fk_adresse']])) {
$checkByAddressQuery = "SELECT id FROM ope_pass continue; // Déjà existant avec bon fk_adresse
WHERE fk_operation = :operation_id
AND fk_adresse = :fk_adresse";
$checkByAddressStmt = $this->db->prepare($checkByAddressQuery);
$checkByAddressStmt->execute([
'operation_id' => $operationId,
'fk_adresse' => $address['fk_adresse']
]);
if ($checkByAddressStmt->fetch()) {
continue; // Passage déjà existant, passer au suivant
}
} }
// 2.2 Vérification secondaire par données d'adresse $dataKey = $address['numero'] . '|' . $address['rue'] . '|' . $address['rue_bis'] . '|' . $address['ville'];
$checkByDataQuery = "SELECT id FROM ope_pass if (isset($passagesByData[$dataKey])) {
WHERE fk_operation = :operation_id // Passage existant mais sans fk_adresse ou avec fk_adresse différent
AND numero = :numero if (!empty($address['fk_adresse']) && $passagesByData[$dataKey]['fk_adresse'] != $address['fk_adresse']) {
AND rue_bis = :rue_bis $toUpdate[] = [
AND rue = :rue 'id' => $passagesByData[$dataKey]['id'],
AND ville = :ville"; 'fk_adresse' => $address['fk_adresse']
$checkByDataStmt = $this->db->prepare($checkByDataQuery); ];
$checkByDataStmt->execute([
'operation_id' => $operationId,
'numero' => $address['numero'],
'rue_bis' => $address['rue_bis'],
'rue' => $address['rue'],
'ville' => $address['ville']
]);
$matchingPassages = $checkByDataStmt->fetchAll();
if (!empty($matchingPassages)) {
// Mettre à jour les passages trouvés avec le fk_adresse
if (!empty($address['fk_adresse'])) {
$updateQuery = "UPDATE ope_pass SET fk_adresse = :fk_adresse WHERE id = :passage_id";
$updateStmt = $this->db->prepare($updateQuery);
foreach ($matchingPassages as $matchingPassage) {
$updateStmt->execute([
'fk_adresse' => $address['fk_adresse'],
'passage_id' => $matchingPassage['id']
]);
$counters['passages_updated']++;
}
} }
continue; } else {
// Nouveau passage à créer
$toInsert[] = $address;
} }
}
// 2.3 Création du passage (aucun passage existant trouvé)
// INSERT MULTIPLE en une seule requête
if (!empty($toInsert)) {
$values = [];
$insertParams = [];
$paramIndex = 0;
foreach ($toInsert as $addr) {
$values[] = "(:op$paramIndex, :sect$paramIndex, :usr$paramIndex, :addr$paramIndex,
:num$paramIndex, :rue$paramIndex, :bis$paramIndex, :ville$paramIndex,
:lat$paramIndex, :lng$paramIndex, 2, '', NOW(), :creat$paramIndex, 1)";
$insertParams["op$paramIndex"] = $operationId;
$insertParams["sect$paramIndex"] = $sectorId;
$insertParams["usr$paramIndex"] = $firstUserId;
$insertParams["addr$paramIndex"] = $addr['fk_adresse'];
$insertParams["num$paramIndex"] = $addr['numero'];
$insertParams["rue$paramIndex"] = $addr['rue'];
$insertParams["bis$paramIndex"] = $addr['rue_bis'];
$insertParams["ville$paramIndex"] = $addr['ville'];
$insertParams["lat$paramIndex"] = $addr['gps_lat'];
$insertParams["lng$paramIndex"] = $addr['gps_lng'];
$insertParams["creat$paramIndex"] = $_SESSION['user_id'] ?? null;
$paramIndex++;
}
$insertQuery = "INSERT INTO ope_pass
(fk_operation, fk_sector, fk_user, fk_adresse, numero, rue, rue_bis,
ville, gps_lat, gps_lng, fk_type, encrypted_name, created_at, fk_user_creat, chk_active)
VALUES " . implode(',', $values);
try { try {
$createStmt->execute([ $insertStmt = $this->db->prepare($insertQuery);
'operation_id' => $operationId, $insertStmt->execute($insertParams);
'sector_id' => $sectorId, $counters['passages_created'] = count($toInsert);
'user_id' => $firstUserId,
'fk_adresse' => $address['fk_adresse'],
'numero' => $address['numero'],
'rue' => $address['rue'],
'rue_bis' => $address['rue_bis'],
'ville' => $address['ville'],
'gps_lat' => $address['gps_lat'],
'gps_lng' => $address['gps_lng'],
'user_creat' => $_SESSION['user_id'] ?? null
]);
$counters['passages_created']++;
} catch (\Exception $e) { } catch (\Exception $e) {
$this->logService->warning('Erreur lors de la création d\'un passage pendant update', [ $this->logService->error('Erreur lors de l\'insertion multiple des passages', [
'sector_id' => $sectorId, 'sector_id' => $sectorId,
'address' => $address,
'error' => $e->getMessage() 'error' => $e->getMessage()
]); ]);
} }
} }
// UPDATE MULTIPLE avec CASE WHEN
if (!empty($toUpdate)) {
$updateIds = array_column($toUpdate, 'id');
$placeholders = str_repeat('?,', count($updateIds) - 1) . '?';
$caseWhen = [];
$updateParams = [];
foreach ($toUpdate as $upd) {
$caseWhen[] = "WHEN id = ? THEN ?";
$updateParams[] = $upd['id'];
$updateParams[] = $upd['fk_adresse'];
}
$updateQuery = "UPDATE ope_pass
SET fk_adresse = CASE " . implode(' ', $caseWhen) . " END
WHERE id IN ($placeholders)";
try {
$updateStmt = $this->db->prepare($updateQuery);
$updateStmt->execute(array_merge($updateParams, $updateIds));
$counters['passages_updated'] = count($toUpdate);
} catch (\Exception $e) {
$this->logService->error('Erreur lors de la mise à jour multiple des passages', [
'sector_id' => $sectorId,
'error' => $e->getMessage()
]);
}
}
} else { } else {
$this->logService->warning('[updatePassagesForSector] Pas de création de passages', [ $this->logService->warning('[updatePassagesForSector] Pas de création de passages', [
'reason' => !$firstUserId ? 'Pas d\'utilisateur affecté' : 'Pas d\'adresses', 'reason' => !$firstUserId ? 'Pas d\'utilisateur affecté' : 'Pas d\'adresses',

View File

@@ -137,111 +137,143 @@ class StripeController extends Controller {
} }
} }
/**
* POST /api/stripe/locations
* Créer une Location pour Terminal/Tap to Pay
*/
public function createLocation(): void {
try {
$this->requireAuth();
// Vérifier le rôle de l'utilisateur
$userId = Session::getUserId();
$stmt = $this->db->prepare('SELECT fk_role FROM users WHERE id = ?');
$stmt->execute([$userId]);
$result = $stmt->fetch();
$userRole = $result ? (int)$result['fk_role'] : 0;
if ($userRole < 2) {
$this->sendError('Droits insuffisants', 403);
return;
}
$data = $this->getJsonInput();
$entiteId = $data['fk_entite'] ?? Session::getEntityId();
$result = $this->stripeService->createLocation($entiteId);
if ($result['success']) {
$this->sendSuccess($result);
} else {
$this->sendError($result['message'], 400);
}
} catch (Exception $e) {
$this->sendError('Erreur: ' . $e->getMessage());
}
}
/**
* POST /api/stripe/terminal/connection-token
* Créer un token de connexion pour Terminal/Tap to Pay
*/
public function createConnectionToken(): void {
try {
$this->requireAuth();
$entiteId = Session::getEntityId();
if (!$entiteId) {
$this->sendError('Entité non définie', 400);
return;
}
$result = $this->stripeService->createConnectionToken($entiteId);
if ($result['success']) {
$this->sendSuccess(['secret' => $result['secret']]);
} else {
$this->sendError($result['message'], 400);
}
} catch (Exception $e) {
$this->sendError('Erreur: ' . $e->getMessage());
}
}
/** /**
* POST /api/stripe/payments/create-intent * POST /api/stripe/payments/create-intent
* Créer une intention de paiement * Créer une intention de paiement pour Tap to Pay ou paiement Web
*
* Payload Tap to Pay:
* {
* "amount": 2500,
* "currency": "eur",
* "description": "Calendrier pompiers - Passage #789",
* "payment_method_types": ["card_present"],
* "capture_method": "automatic",
* "passage_id": 789,
* "amicale_id": 42,
* "member_id": 156,
* "stripe_account": "acct_1O3ABC456DEF789",
* "location_id": "tml_FGH123456789",
* "metadata": {...}
* }
*/ */
public function createPaymentIntent(): void { public function createPaymentIntent(): void {
try { try {
$this->requireAuth(); $this->requireAuth();
$data = $this->getJsonInput(); $data = $this->getJsonInput();
// Validation // Validation des champs requis
$amount = $data['amount'] ?? 0; if (!isset($data['amount']) || !isset($data['passage_id'])) {
$this->sendError('Montant et passage_id requis', 400);
return;
}
$amount = (int)$data['amount'];
$passageId = (int)$data['passage_id'];
// Validation du passage_id (doit être > 0 car le passage est créé avant)
if ($passageId <= 0) {
$this->sendError('passage_id invalide. Le passage doit être créé avant le paiement', 400);
return;
}
// Validation du montant
if ($amount < 100) { if ($amount < 100) {
$this->sendError('Le montant minimum est de 1€ (100 centimes)', 400); $this->sendError('Le montant minimum est de 1€ (100 centimes)', 400);
return; return;
} }
if ($amount > 50000) { if ($amount > 99900) { // 999€ max selon la doc
$this->sendError('Le montant maximum est de 500€', 400); $this->sendError('Le montant maximum est de 999€', 400);
return; return;
} }
// Vérifier que le passage existe et appartient à l'utilisateur
$stmt = $this->db->prepare('
SELECT p.*, o.fk_entite
FROM ope_pass p
JOIN operations o ON p.fk_operation = o.id
WHERE p.id = ? AND p.fk_user = ?
');
$stmt->execute([$passageId, Session::getUserId()]);
$passage = $stmt->fetch();
if (!$passage) {
$this->sendError('Passage non trouvé ou non autorisé', 404);
return;
}
// Vérifier qu'il n'y a pas déjà un paiement Stripe pour ce passage
if (!empty($passage['stripe_payment_id'])) {
$this->sendError('Un paiement Stripe existe déjà pour ce passage', 400);
return;
}
// Vérifier que le montant correspond (passage.montant est en euros, amount en centimes)
$expectedAmount = (int)($passage['montant'] * 100);
if ($amount !== $expectedAmount) {
$this->sendError("Le montant ne correspond pas au passage (attendu: {$expectedAmount} centimes, reçu: {$amount} centimes)", 400);
return;
}
$entiteId = $passage['fk_entite'];
// Déterminer le type de paiement (Tap to Pay ou Web)
$paymentMethodTypes = $data['payment_method_types'] ?? ['card_present'];
$isTapToPay = in_array('card_present', $paymentMethodTypes);
// Préparer les paramètres pour StripeService
$params = [ $params = [
'amount' => $amount, 'amount' => $amount,
'fk_entite' => $data['fk_entite'] ?? Session::getEntityId(), 'currency' => $data['currency'] ?? 'eur',
'fk_user' => Session::getUserId(), 'description' => $data['description'] ?? "Calendrier pompiers - Passage #$passageId",
'metadata' => $data['metadata'] ?? [] 'payment_method_types' => $paymentMethodTypes,
'capture_method' => $data['capture_method'] ?? 'automatic',
'passage_id' => $passageId,
'amicale_id' => $data['amicale_id'] ?? $entiteId,
'member_id' => $data['member_id'] ?? Session::getUserId(),
'stripe_account' => $data['stripe_account'] ?? null,
'metadata' => array_merge(
[
'passage_id' => (string)$passageId,
'amicale_id' => (string)($data['amicale_id'] ?? $entiteId),
'member_id' => (string)($data['member_id'] ?? Session::getUserId()),
'type' => $isTapToPay ? 'tap_to_pay' : 'web'
],
$data['metadata'] ?? []
)
]; ];
// Ajouter location_id si fourni (pour Tap to Pay)
if (isset($data['location_id'])) {
$params['location_id'] = $data['location_id'];
}
// Créer le PaymentIntent via StripeService
$result = $this->stripeService->createPaymentIntent($params); $result = $this->stripeService->createPaymentIntent($params);
if ($result['success']) { if ($result['success']) {
// Mettre à jour le passage avec le stripe_payment_id
$stmt = $this->db->prepare('
UPDATE ope_pass
SET stripe_payment_id = ?, updated_at = NOW()
WHERE id = ?
');
$stmt->execute([$result['payment_intent_id'], $passageId]);
// Retourner la réponse
$this->sendSuccess([ $this->sendSuccess([
'client_secret' => $result['client_secret'], 'client_secret' => $result['client_secret'],
'payment_intent_id' => $result['payment_intent_id'], 'payment_intent_id' => $result['payment_intent_id'],
'amount' => $result['amount'], 'amount' => $result['amount'],
'application_fee' => $result['application_fee'] 'currency' => $params['currency'],
'passage_id' => $passageId,
'type' => $isTapToPay ? 'tap_to_pay' : 'web'
]); ]);
} else { } else {
$this->sendError($result['message'], 400); $this->sendError($result['message'], 400);
} }
} catch (Exception $e) { } catch (Exception $e) {
$this->sendError('Erreur: ' . $e->getMessage()); $this->sendError('Erreur: ' . $e->getMessage());
} }
@@ -249,60 +281,78 @@ class StripeController extends Controller {
/** /**
* GET /api/stripe/payments/{paymentIntentId} * GET /api/stripe/payments/{paymentIntentId}
* Récupérer le statut d'un paiement * Récupérer le statut d'un paiement depuis ope_pass et Stripe
*/ */
public function getPaymentStatus(string $paymentIntentId): void { public function getPaymentStatus(string $paymentIntentId): void {
try { try {
$this->requireAuth(); $this->requireAuth();
$stmt = $this->db->prepare( // Récupérer les informations depuis ope_pass
"SELECT spi.*, e.nom as entite_nom, u.nom as user_nom, u.prenom as user_prenom $stmt = $this->db->prepare("
FROM stripe_payment_intents spi SELECT p.*, o.fk_entite,
LEFT JOIN entites e ON spi.fk_entite = e.id e.encrypted_name as entite_nom,
LEFT JOIN users u ON spi.fk_user = u.id u.first_name as user_prenom, u.sect_name as user_nom
WHERE spi.stripe_payment_intent_id = :pi_id" FROM ope_pass p
); JOIN operations o ON p.fk_operation = o.id
LEFT JOIN entites e ON o.fk_entite = e.id
LEFT JOIN users u ON p.fk_user = u.id
WHERE p.stripe_payment_id = :pi_id
");
$stmt->execute(['pi_id' => $paymentIntentId]); $stmt->execute(['pi_id' => $paymentIntentId]);
$payment = $stmt->fetch(); $passage = $stmt->fetch();
if (!$payment) { if (!$passage) {
$this->sendError('Paiement non trouvé', 404); $this->sendError('Paiement non trouvé', 404);
return; return;
} }
// Vérifier les droits // Vérifier les droits
$userEntityId = Session::getEntityId(); $userEntityId = Session::getEntityId();
$userId = Session::getUserId(); $userId = Session::getUserId();
// Récupérer le rôle depuis la base de données // Récupérer le rôle depuis la base de données
$stmt = $this->db->prepare('SELECT fk_role FROM users WHERE id = ?'); $stmt = $this->db->prepare('SELECT fk_role FROM users WHERE id = ?');
$stmt->execute([$userId]); $stmt->execute([$userId]);
$result = $stmt->fetch(); $result = $stmt->fetch();
$userRole = $result ? (int)$result['fk_role'] : 0; $userRole = $result ? (int)$result['fk_role'] : 0;
if ($payment['fk_entite'] != $userEntityId && if ($passage['fk_entite'] != $userEntityId &&
$payment['fk_user'] != $userId && $passage['fk_user'] != $userId &&
$userRole < 3) { $userRole < 3) {
$this->sendError('Non autorisé', 403); $this->sendError('Non autorisé', 403);
return; return;
} }
// Récupérer le statut en temps réel depuis Stripe
$stripeStatus = $this->stripeService->getPaymentIntentStatus($paymentIntentId);
// Déchiffrer le nom de l'entité si nécessaire
$entiteNom = '';
if (!empty($passage['entite_nom'])) {
try {
$entiteNom = \ApiService::decryptData($passage['entite_nom']);
} catch (Exception $e) {
$entiteNom = 'Entité inconnue';
}
}
$this->sendSuccess([ $this->sendSuccess([
'payment_intent_id' => $payment['stripe_payment_intent_id'], 'payment_intent_id' => $paymentIntentId,
'status' => $payment['status'], 'passage_id' => $passage['id'],
'amount' => $payment['amount'], 'status' => $stripeStatus['status'] ?? 'unknown',
'currency' => $payment['currency'], 'amount' => (int)($passage['montant'] * 100), // montant en BDD est en euros, on convertit en centimes
'application_fee' => $payment['application_fee'], 'currency' => 'eur',
'entite' => [ 'entite' => [
'id' => $payment['fk_entite'], 'id' => $passage['fk_entite'],
'nom' => $payment['entite_nom'] 'nom' => $entiteNom
], ],
'user' => [ 'user' => [
'id' => $payment['fk_user'], 'id' => $passage['fk_user'],
'nom' => $payment['user_nom'], 'nom' => $passage['user_nom'],
'prenom' => $payment['user_prenom'] 'prenom' => $passage['user_prenom']
], ],
'created_at' => $payment['created_at'] 'created_at' => $passage['date_creat'],
'stripe_details' => $stripeStatus
]); ]);
} catch (Exception $e) { } catch (Exception $e) {
@@ -419,10 +469,11 @@ class StripeController extends Controller {
$platform = $data['platform'] ?? ''; $platform = $data['platform'] ?? '';
if ($platform === 'ios') { if ($platform === 'ios') {
// Pour iOS, on vérifie côté client (iPhone XS+ avec iOS 15.4+) // Pour iOS, on vérifie côté client (iPhone XS+ avec iOS 16.4+)
$this->sendSuccess([ $this->sendSuccess([
'message' => 'Vérification iOS à faire côté client', 'message' => 'Vérification iOS à faire côté client',
'requirements' => 'iPhone XS ou plus récent avec iOS 15.4+' 'requirements' => 'iPhone XS ou plus récent avec iOS 16.4+',
'details' => 'iOS 16.4 minimum requis pour le support PIN complet'
]); ]);
return; return;
} }

View File

@@ -225,36 +225,32 @@ class UserController {
'has_password' => isset($data['password']) 'has_password' => isset($data['password'])
]); ]);
// Validation des données requises // Validation : au moins name OU sect_name requis
if (!isset($data['email']) || empty(trim($data['email']))) { if ((!isset($data['name']) || empty(trim($data['name']))) &&
LogService::log('Erreur création utilisateur : Email manquant', [ (!isset($data['sect_name']) || empty(trim($data['sect_name'])))) {
'level' => 'warning', LogService::log('Erreur création utilisateur : Aucun nom fourni', [
'createdBy' => $currentUserId
]);
Response::json([
'status' => 'error',
'message' => 'Email requis',
'field' => 'email'
], 400);
return;
}
if (!isset($data['name']) || empty(trim($data['name']))) {
LogService::log('Erreur création utilisateur : Nom manquant', [
'level' => 'warning', 'level' => 'warning',
'createdBy' => $currentUserId, 'createdBy' => $currentUserId,
'email' => $data['email'] ?? 'non fourni' 'email' => $data['email'] ?? 'non fourni',
'has_name' => isset($data['name']),
'has_sect_name' => isset($data['sect_name'])
]); ]);
Response::json([ Response::json([
'status' => 'error', 'status' => 'error',
'message' => 'Nom requis', 'message' => 'Au moins un nom (name ou sect_name) est requis',
'field' => 'name' 'field' => 'name_or_sect_name'
], 400); ], 400);
return; return;
} }
$email = trim(strtolower($data['email'])); // L'email est maintenant optionnel
$name = trim($data['name']); $email = isset($data['email']) && !empty(trim($data['email']))
? trim(strtolower($data['email']))
: '';
// Le name peut être vide si sect_name est fourni
$name = isset($data['name']) && !empty(trim($data['name']))
? trim($data['name'])
: '';
$firstName = isset($data['first_name']) ? trim($data['first_name']) : ''; $firstName = isset($data['first_name']) ? trim($data['first_name']) : '';
$role = isset($data['role']) ? (int)$data['role'] : 1; $role = isset($data['role']) ? (int)$data['role'] : 1;
$entiteId = isset($data['fk_entite']) ? (int)$data['fk_entite'] : 1; $entiteId = isset($data['fk_entite']) ? (int)$data['fk_entite'] : 1;
@@ -288,8 +284,8 @@ class UserController {
return; return;
} }
// Validation de l'email // Validation de l'email seulement s'il est fourni
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { if (!empty($email) && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
LogService::log('Erreur création utilisateur : Format email invalide', [ LogService::log('Erreur création utilisateur : Format email invalide', [
'level' => 'warning', 'level' => 'warning',
'createdBy' => $currentUserId, 'createdBy' => $currentUserId,
@@ -305,8 +301,10 @@ class UserController {
} }
// Chiffrement des données sensibles // Chiffrement des données sensibles
$encryptedEmail = ApiService::encryptSearchableData($email); // Chiffrer l'email seulement s'il n'est pas vide
$encryptedName = ApiService::encryptData($name); $encryptedEmail = !empty($email) ? ApiService::encryptSearchableData($email) : null;
// Chiffrer le name seulement s'il n'est pas vide
$encryptedName = !empty($name) ? ApiService::encryptData($name) : null;
// Vérification de l'existence de l'email // Vérification de l'existence de l'email
// DÉSACTIVÉ : Le client souhaite permettre plusieurs comptes avec le même email // DÉSACTIVÉ : Le client souhaite permettre plusieurs comptes avec le même email
@@ -503,36 +501,43 @@ class UserController {
]); ]);
$userId = $this->db->lastInsertId(); $userId = $this->db->lastInsertId();
// Envoi des emails séparés pour plus de sécurité // Envoi des emails séparés pour plus de sécurité (seulement si un email est fourni)
if (!empty($email)) {
// 1er email : TOUJOURS envoyer l'identifiant (username) // 1er email : Envoyer l'identifiant (username)
$usernameEmailData = [ $usernameEmailData = [
'email' => $email, 'email' => $email,
'username' => $username, 'username' => $username,
'name' => $name 'name' => $name
]; ];
ApiService::sendEmail($email, $name, 'welcome_username', $usernameEmailData); ApiService::sendEmail($email, $name, 'welcome_username', $usernameEmailData);
// 2ème email : Envoyer le mot de passe (toujours, qu'il soit manuel ou généré) // 2ème email : Envoyer le mot de passe (toujours, qu'il soit manuel ou généré)
// Attendre un peu entre les deux emails pour éviter qu'ils arrivent dans le mauvais ordre // Attendre un peu entre les deux emails pour éviter qu'ils arrivent dans le mauvais ordre
sleep(1); sleep(1);
$passwordEmailData = [ $passwordEmailData = [
'email' => $email, 'email' => $email,
'password' => $password, 'password' => $password,
'name' => $name 'name' => $name
]; ];
ApiService::sendEmail($email, $name, 'welcome_password', $passwordEmailData); ApiService::sendEmail($email, $name, 'welcome_password', $passwordEmailData);
} else {
LogService::log('Utilisateur créé sans email - pas d\'envoi de credentials', [
'level' => 'info',
'userId' => $userId,
'username' => $username
]);
}
LogService::log('Utilisateur GeoSector créé', [ LogService::log('Utilisateur GeoSector créé', [
'level' => 'info', 'level' => 'info',
'createdBy' => $currentUserId, 'createdBy' => $currentUserId,
'newUserId' => $userId, 'newUserId' => $userId,
'email' => $email, 'email' => !empty($email) ? $email : 'non fourni',
'username' => $username, 'username' => $username,
'usernameManual' => $chkUsernameManuel === 1 ? 'oui' : 'non', 'usernameManual' => $chkUsernameManuel === 1 ? 'oui' : 'non',
'passwordManual' => $chkMdpManuel === 1 ? 'oui' : 'non', 'passwordManual' => $chkMdpManuel === 1 ? 'oui' : 'non',
'emailsSent' => '2 emails (username + password)' 'emailsSent' => !empty($email) ? '2 emails (username + password)' : 'aucun (pas d\'email)'
]); ]);
// Préparer la réponse avec les informations de connexion si générées automatiquement // Préparer la réponse avec les informations de connexion si générées automatiquement
@@ -639,6 +644,58 @@ class UserController {
$params['encrypted_mobile'] = ApiService::encryptData(trim($data['mobile'])); $params['encrypted_mobile'] = ApiService::encryptData(trim($data['mobile']));
} }
// Gestion de la modification du username
if (isset($data['username'])) {
$username = trim($data['username']);
// Validation de la longueur en caractères UTF-8
$usernameLength = mb_strlen($username, 'UTF-8');
if ($usernameLength < 8) {
Response::json([
'status' => 'error',
'message' => 'Identifiant trop court',
'field' => 'username',
'details' => 'Minimum 8 caractères'
], 400);
return;
}
if ($usernameLength > 30) {
Response::json([
'status' => 'error',
'message' => 'Identifiant trop long',
'field' => 'username',
'details' => 'Maximum 30 caractères'
], 400);
return;
}
$encryptedUsername = ApiService::encryptSearchableData($username);
// Vérifier l'unicité du username (sauf pour l'utilisateur courant)
$checkStmt = $this->db->prepare('SELECT id FROM users WHERE encrypted_user_name = ? AND id != ?');
$checkStmt->execute([$encryptedUsername, $id]);
if ($checkStmt->fetch()) {
Response::json([
'status' => 'error',
'message' => 'Cet identifiant est déjà utilisé par un autre utilisateur',
'field' => 'username'
], 409);
return;
}
$updateFields[] = "encrypted_user_name = :encrypted_user_name";
$params['encrypted_user_name'] = $encryptedUsername;
LogService::log('Modification du username', [
'level' => 'info',
'userId' => $id,
'newUsername' => $username,
'modifiedBy' => $currentUserId
]);
}
// Traitement des champs non chiffrés // Traitement des champs non chiffrés
$nonEncryptedFields = [ $nonEncryptedFields = [
'first_name', 'first_name',
@@ -1142,6 +1199,209 @@ class UserController {
} }
} }
/**
* Enregistre les informations du device de l'utilisateur
* POST /api/users/device-info
*/
public function saveDeviceInfo(): void {
Session::requireAuth();
$userId = Session::getUserId();
if (!$userId) {
LogService::log('Device info error: Invalid session', [
'level' => 'error',
'session_id' => session_id()
]);
Response::json([
'status' => 'error',
'message' => 'Session invalide'
], 401);
return;
}
// Récupération des données du payload
$data = Request::getJson();
// Validation des données requises
if (empty($data['platform'])) {
LogService::log('Device info error: Missing platform', [
'level' => 'error',
'user_id' => $userId,
'data' => $data
]);
Response::json([
'status' => 'error',
'message' => 'Platform requis',
'field' => 'platform'
], 400);
return;
}
// Validation des IPs (IPv4 uniquement)
// Pour la plateforme Web, device_ip_local contient "Web Platform" → on le traite comme NULL
$deviceIpLocal = $data['device_ip_local'] ?? null;
$deviceIpPublic = $data['device_ip_public'] ?? null;
if ($deviceIpLocal && !filter_var($deviceIpLocal, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
LogService::log('Device IP local invalide, ignorée', [
'level' => 'debug',
'user_id' => $userId,
'device_ip_local' => $deviceIpLocal
]);
$deviceIpLocal = null; // Ignorer si ce n'est pas une IPv4 valide
}
if ($deviceIpPublic && !filter_var($deviceIpPublic, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
LogService::log('Device IP public invalide, ignorée', [
'level' => 'debug',
'user_id' => $userId,
'device_ip_public' => $deviceIpPublic
]);
$deviceIpPublic = null; // Ignorer si ce n'est pas une IPv4 valide
}
// Validation du niveau de batterie (0-100)
$batteryLevel = isset($data['battery_level']) ? intval($data['battery_level']) : null;
if ($batteryLevel !== null && ($batteryLevel < 0 || $batteryLevel > 100)) {
$batteryLevel = null;
}
// Conversion des booléens
$nfcCapable = isset($data['device_nfc_capable']) ? ($data['device_nfc_capable'] ? 1 : 0) : null;
$tapToPay = isset($data['device_supports_tap_to_pay']) ? ($data['device_supports_tap_to_pay'] ? 1 : 0) : null;
$batteryCharging = isset($data['battery_charging']) ? ($data['battery_charging'] ? 1 : 0) : null;
// Conversion de la date de check
$lastDeviceInfoCheck = null;
if (!empty($data['last_device_info_check'])) {
try {
$date = new \DateTime($data['last_device_info_check']);
$lastDeviceInfoCheck = $date->format('Y-m-d H:i:s');
} catch (\Exception $e) {
// Ignorer si le format de date est invalide
}
}
try {
$this->db->beginTransaction();
// Pour les plateformes Web sans device_identifier, générer un identifiant unique basé sur user_id + platform
$deviceIdentifier = $data['device_identifier'] ?? null;
// Si device_identifier est vide ou NULL pour la plateforme Web, générer un identifiant
if (empty($deviceIdentifier)) {
$platform = $data['platform'] ?? 'unknown';
if ($platform === 'Web') {
// Un seul device Web par utilisateur
$deviceIdentifier = 'web_' . $userId . '_' . md5($userId . '_web');
} else {
// Pour les autres plateformes sans identifier, générer un identifiant aléatoire
$deviceIdentifier = strtolower($platform) . '_' . $userId . '_' . uniqid();
}
LogService::log('Device identifier généré automatiquement', [
'level' => 'debug',
'user_id' => $userId,
'platform' => $platform,
'device_identifier' => $deviceIdentifier
]);
}
// Requête INSERT ... ON DUPLICATE KEY UPDATE
$sql = "INSERT INTO user_devices (
fk_user, platform, device_model, device_name, device_manufacturer,
device_identifier, device_ip_local, device_ip_public, device_wifi_name,
device_wifi_bssid, ios_version, device_nfc_capable, device_supports_tap_to_pay,
battery_level, battery_charging, battery_state, app_version, app_build,
last_device_info_check
) VALUES (
:fk_user, :platform, :device_model, :device_name, :device_manufacturer,
:device_identifier, :device_ip_local, :device_ip_public, :device_wifi_name,
:device_wifi_bssid, :ios_version, :device_nfc_capable, :device_supports_tap_to_pay,
:battery_level, :battery_charging, :battery_state, :app_version, :app_build,
:last_device_info_check
) ON DUPLICATE KEY UPDATE
platform = VALUES(platform),
device_model = VALUES(device_model),
device_name = VALUES(device_name),
device_manufacturer = VALUES(device_manufacturer),
device_ip_local = VALUES(device_ip_local),
device_ip_public = VALUES(device_ip_public),
device_wifi_name = VALUES(device_wifi_name),
device_wifi_bssid = VALUES(device_wifi_bssid),
ios_version = VALUES(ios_version),
device_nfc_capable = VALUES(device_nfc_capable),
device_supports_tap_to_pay = VALUES(device_supports_tap_to_pay),
battery_level = VALUES(battery_level),
battery_charging = VALUES(battery_charging),
battery_state = VALUES(battery_state),
app_version = VALUES(app_version),
app_build = VALUES(app_build),
last_device_info_check = VALUES(last_device_info_check),
updated_at = CURRENT_TIMESTAMP";
$stmt = $this->db->prepare($sql);
$params = [
':fk_user' => $userId,
':platform' => $data['platform'] ?? null,
':device_model' => $data['device_model'] ?? null,
':device_name' => $data['device_name'] ?? null,
':device_manufacturer' => $data['device_manufacturer'] ?? null,
':device_identifier' => $deviceIdentifier,
':device_ip_local' => $deviceIpLocal,
':device_ip_public' => $deviceIpPublic,
':device_wifi_name' => $data['device_wifi_name'] ?? null,
':device_wifi_bssid' => $data['device_wifi_bssid'] ?? null,
':ios_version' => $data['ios_version'] ?? null,
':device_nfc_capable' => $nfcCapable,
':device_supports_tap_to_pay' => $tapToPay,
':battery_level' => $batteryLevel,
':battery_charging' => $batteryCharging,
':battery_state' => $data['battery_state'] ?? null,
':app_version' => $data['app_version'] ?? null,
':app_build' => $data['app_build'] ?? null,
':last_device_info_check' => $lastDeviceInfoCheck
];
$stmt->execute($params);
$this->db->commit();
LogService::log('Device info enregistrées avec succès', [
'level' => 'info',
'user_id' => $userId,
'platform' => $data['platform'],
'device_identifier' => $deviceIdentifier
]);
Response::json([
'status' => 'success',
'message' => 'Informations du device enregistrées'
], 200);
} catch (\PDOException $e) {
if ($this->db->inTransaction()) {
$this->db->rollBack();
}
LogService::log('Error saving device info', [
'level' => 'error',
'user_id' => $userId,
'error' => $e->getMessage(),
'code' => $e->getCode(),
'platform' => $data['platform'] ?? 'unknown'
]);
Response::json([
'status' => 'error',
'message' => 'Erreur lors de l\'enregistrement des informations du device',
'details' => $e->getMessage()
], 500);
}
}
// Méthodes auxiliaires // Méthodes auxiliaires
private function validateUpdateData(array $data): ?string { private function validateUpdateData(array $data): ?string {
// Validation de l'email // Validation de l'email

View File

@@ -37,6 +37,7 @@ class Router {
// Routes privées utilisateurs // Routes privées utilisateurs
// IMPORTANT: Les routes spécifiques doivent être déclarées AVANT les routes avec paramètres // IMPORTANT: Les routes spécifiques doivent être déclarées AVANT les routes avec paramètres
$this->post('users/check-username', ['UserController', 'checkUsername']); // Déplacé avant les routes avec :id $this->post('users/check-username', ['UserController', 'checkUsername']); // Déplacé avant les routes avec :id
$this->post('users/device-info', ['UserController', 'saveDeviceInfo']); // Endpoint pour sauvegarder les infos du device
$this->get('users', ['UserController', 'getUsers']); $this->get('users', ['UserController', 'getUsers']);
$this->get('users/:id', ['UserController', 'getUserById']); $this->get('users/:id', ['UserController', 'getUserById']);
$this->post('users', ['UserController', 'createUser']); $this->post('users', ['UserController', 'createUser']);
@@ -44,6 +45,7 @@ class Router {
$this->delete('users/:id', ['UserController', 'deleteUser']); $this->delete('users/:id', ['UserController', 'deleteUser']);
$this->post('users/:id/reset-password', ['UserController', 'resetPassword']); $this->post('users/:id/reset-password', ['UserController', 'resetPassword']);
$this->post('logout', ['LoginController', 'logout']); $this->post('logout', ['LoginController', 'logout']);
$this->get('user/session', ['LoginController', 'refreshSession']);
// Routes entités // Routes entités
$this->get('entites', ['EntiteController', 'getEntites']); $this->get('entites', ['EntiteController', 'getEntites']);
@@ -128,21 +130,19 @@ class Router {
$this->post('stripe/accounts', ['StripeController', 'createAccount']); $this->post('stripe/accounts', ['StripeController', 'createAccount']);
$this->get('stripe/accounts/:entityId/status', ['StripeController', 'getAccountStatus']); $this->get('stripe/accounts/:entityId/status', ['StripeController', 'getAccountStatus']);
$this->post('stripe/accounts/:accountId/onboarding-link', ['StripeController', 'createOnboardingLink']); $this->post('stripe/accounts/:accountId/onboarding-link', ['StripeController', 'createOnboardingLink']);
$this->post('stripe/locations', ['StripeController', 'createLocation']);
// Tap to Pay - Vérification compatibilité
// Terminal et Tap to Pay
$this->post('stripe/terminal/connection-token', ['StripeController', 'createConnectionToken']);
$this->post('stripe/devices/check-tap-to-pay', ['StripeController', 'checkTapToPayCapability']); $this->post('stripe/devices/check-tap-to-pay', ['StripeController', 'checkTapToPayCapability']);
$this->get('stripe/devices/certified-android', ['StripeController', 'getCertifiedAndroidDevices']); $this->get('stripe/devices/certified-android', ['StripeController', 'getCertifiedAndroidDevices']);
// Paiements // Paiements
$this->post('stripe/payments/create-intent', ['StripeController', 'createPaymentIntent']); $this->post('stripe/payments/create-intent', ['StripeController', 'createPaymentIntent']);
$this->get('stripe/payments/:paymentIntentId', ['StripeController', 'getPaymentStatus']); $this->get('stripe/payments/:paymentIntentId', ['StripeController', 'getPaymentStatus']);
// Statistiques et configuration // Statistiques et configuration
$this->get('stripe/stats', ['StripeController', 'getPaymentStats']); $this->get('stripe/stats', ['StripeController', 'getPaymentStats']);
$this->get('stripe/config', ['StripeController', 'getPublicConfig']); $this->get('stripe/config', ['StripeController', 'getPublicConfig']);
// Webhook (IMPORTANT: pas d'authentification requise pour les webhooks Stripe) // Webhook (IMPORTANT: pas d'authentification requise pour les webhooks Stripe)
$this->post('stripe/webhook', ['StripeWebhookController', 'handleWebhook']); $this->post('stripe/webhook', ['StripeWebhookController', 'handleWebhook']);
} }

View File

@@ -14,26 +14,125 @@ use Database;
* Bloque temporairement ou définitivement des adresses IP suspectes * Bloque temporairement ou définitivement des adresses IP suspectes
*/ */
class IPBlocker { class IPBlocker {
private static ?PDO $db = null; private static ?PDO $db = null;
private static array $cache = []; private static array $cache = [];
private static ?int $lastCacheClean = null; private static ?int $lastCacheClean = null;
private static ?array $dynamicWhitelist = null;
// IPs en whitelist (jamais bloquées) private static ?int $whitelistLastCheck = null;
// IPs en whitelist statique (jamais bloquées)
const WHITELIST = [ const WHITELIST = [
'127.0.0.1', '127.0.0.1',
'::1', '::1',
'localhost' 'localhost'
]; ];
// Configuration pour récupérer l'IP depuis IN3
const IN3_CONFIG = [
'host' => '195.154.80.116',
'user' => 'root',
'ip_file' => '/var/bat/IP',
'cache_duration' => 3600, // 1 heure de cache
'local_cache_file' => __DIR__ . '/../../../config/whitelist_ip_cache.txt'
];
/**
* Récupérer la whitelist dynamique depuis IN3
*/
private static function getDynamicWhitelist(): array {
$now = time();
// Vérifier le cache en mémoire (valide 1 heure)
if (self::$dynamicWhitelist !== null &&
self::$whitelistLastCheck !== null &&
($now - self::$whitelistLastCheck) < self::IN3_CONFIG['cache_duration']) {
return self::$dynamicWhitelist;
}
$dynamicIps = [];
// D'abord, essayer de lire le cache local
$cacheFile = self::IN3_CONFIG['local_cache_file'];
if (file_exists($cacheFile)) {
$cacheData = json_decode(file_get_contents($cacheFile), true);
if ($cacheData && isset($cacheData['ip']) && isset($cacheData['timestamp'])) {
// Si le cache a moins d'1 heure, l'utiliser
if (($now - $cacheData['timestamp']) < self::IN3_CONFIG['cache_duration']) {
$dynamicIps[] = $cacheData['ip'];
self::$dynamicWhitelist = $dynamicIps;
self::$whitelistLastCheck = $now;
return $dynamicIps;
}
}
}
// Sinon, récupérer depuis IN3 via SSH
try {
$command = sprintf(
'ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no %s@%s "cat %s 2>/dev/null"',
escapeshellarg(self::IN3_CONFIG['user']),
escapeshellarg(self::IN3_CONFIG['host']),
escapeshellarg(self::IN3_CONFIG['ip_file'])
);
$output = shell_exec($command);
if ($output) {
$ip = trim($output);
// Valider que c'est une IP valide
if (filter_var($ip, FILTER_VALIDATE_IP)) {
$dynamicIps[] = $ip;
// Sauvegarder dans le cache local
$cacheDir = dirname($cacheFile);
if (!is_dir($cacheDir)) {
mkdir($cacheDir, 0755, true);
}
file_put_contents($cacheFile, json_encode([
'ip' => $ip,
'timestamp' => $now,
'retrieved_at' => date('Y-m-d H:i:s')
]));
error_log("Whitelist IP mise à jour depuis IN3: $ip");
}
}
} catch (\Exception $e) {
error_log("Erreur lors de la récupération de l'IP depuis IN3: " . $e->getMessage());
// En cas d'erreur, utiliser le cache local même s'il est expiré
if (file_exists($cacheFile)) {
$cacheData = json_decode(file_get_contents($cacheFile), true);
if ($cacheData && isset($cacheData['ip'])) {
$dynamicIps[] = $cacheData['ip'];
error_log("Utilisation du cache local expiré: " . $cacheData['ip']);
}
}
}
self::$dynamicWhitelist = $dynamicIps;
self::$whitelistLastCheck = $now;
return $dynamicIps;
}
/** /**
* Vérifier si une IP est bloquée * Vérifier si une IP est bloquée
*/ */
public static function isBlocked(string $ip): bool { public static function isBlocked(string $ip): bool {
// Vérifier la whitelist // Vérifier la whitelist statique
if (in_array($ip, self::WHITELIST)) { if (in_array($ip, self::WHITELIST)) {
return false; return false;
} }
// Vérifier la whitelist dynamique depuis IN3
$dynamicWhitelist = self::getDynamicWhitelist();
if (in_array($ip, $dynamicWhitelist)) {
return false;
}
// Vérifier le cache en mémoire // Vérifier le cache en mémoire
if (isset(self::$cache[$ip])) { if (isset(self::$cache[$ip])) {
@@ -322,7 +421,33 @@ class IPBlocker {
return false; return false;
} }
} }
/**
* Vérifier si une IP est dans la whitelist (méthode publique)
*/
public static function isWhitelisted(string $ip): bool {
// Vérifier la whitelist statique
if (in_array($ip, self::WHITELIST)) {
return true;
}
// Vérifier la whitelist dynamique
$dynamicWhitelist = self::getDynamicWhitelist();
return in_array($ip, $dynamicWhitelist);
}
/**
* Forcer la mise à jour de la whitelist dynamique
*/
public static function refreshDynamicWhitelist(): array {
// Forcer l'expiration du cache
self::$whitelistLastCheck = 0;
self::$dynamicWhitelist = null;
// Récupérer la nouvelle whitelist
return self::getDynamicWhitelist();
}
/** /**
* Obtenir la liste des IPs bloquées * Obtenir la liste des IPs bloquées
*/ */

View File

@@ -463,7 +463,7 @@ class StripeService {
'success' => true, 'success' => true,
'tap_to_pay_supported' => false, 'tap_to_pay_supported' => false,
'message' => 'Appareil non certifié pour Tap to Pay en France', 'message' => 'Appareil non certifié pour Tap to Pay en France',
'alternative' => 'Utilisez un iPhone XS ou plus récent avec iOS 15.4+' 'alternative' => 'Utilisez un iPhone XS ou plus récent avec iOS 16.4+'
]; ];
} catch (Exception $e) { } catch (Exception $e) {

33
api/test_device_info.sh Executable file
View File

@@ -0,0 +1,33 @@
#!/bin/bash
# Test de l'endpoint device-info
# Remplacez SESSION_ID par un ID de session valide
SESSION_ID="YOUR_SESSION_ID_HERE"
API_URL="http://localhost/api/users/device-info"
curl -X POST "$API_URL" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SESSION_ID" \
-d '{
"platform": "iOS",
"device_model": "iPhone13,2",
"device_name": "iPhone de Pierre",
"device_manufacturer": "Apple",
"device_identifier": "iPhone13,2",
"device_ip_local": "192.168.1.42",
"device_ip_public": "86.245.168.123",
"device_wifi_name": "Bbox-A1B2C3",
"device_wifi_bssid": "00:1A:2B:3C:4D:5E",
"ios_version": "17.2.1",
"device_nfc_capable": true,
"device_supports_tap_to_pay": true,
"battery_level": 85,
"battery_charging": false,
"battery_state": "discharging",
"last_device_info_check": "2024-12-28T10:30:45.123Z",
"app_version": "3.2.8",
"app_build": "328"
}'
echo ""

View File

@@ -6,23 +6,29 @@
// @dart = 2.13 // @dart = 2.13
// ignore_for_file: type=lint // ignore_for_file: type=lint
import 'package:battery_plus/src/battery_plus_web.dart';
import 'package:connectivity_plus/src/connectivity_plus_web.dart'; import 'package:connectivity_plus/src/connectivity_plus_web.dart';
import 'package:device_info_plus/src/device_info_plus_web.dart';
import 'package:geolocator_web/geolocator_web.dart'; import 'package:geolocator_web/geolocator_web.dart';
import 'package:image_picker_for_web/image_picker_for_web.dart'; import 'package:image_picker_for_web/image_picker_for_web.dart';
import 'package:network_info_plus/src/network_info_plus_web.dart';
import 'package:package_info_plus/src/package_info_plus_web.dart'; import 'package:package_info_plus/src/package_info_plus_web.dart';
import 'package:permission_handler_html/permission_handler_html.dart';
import 'package:sensors_plus/src/sensors_plus_web.dart'; import 'package:sensors_plus/src/sensors_plus_web.dart';
import 'package:shared_preferences_web/shared_preferences_web.dart';
import 'package:url_launcher_web/url_launcher_web.dart'; import 'package:url_launcher_web/url_launcher_web.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart'; import 'package:flutter_web_plugins/flutter_web_plugins.dart';
void registerPlugins([final Registrar? pluginRegistrar]) { void registerPlugins([final Registrar? pluginRegistrar]) {
final Registrar registrar = pluginRegistrar ?? webPluginRegistrar; final Registrar registrar = pluginRegistrar ?? webPluginRegistrar;
BatteryPlusWebPlugin.registerWith(registrar);
ConnectivityPlusWebPlugin.registerWith(registrar); ConnectivityPlusWebPlugin.registerWith(registrar);
DeviceInfoPlusWebPlugin.registerWith(registrar);
GeolocatorPlugin.registerWith(registrar); GeolocatorPlugin.registerWith(registrar);
ImagePickerPlugin.registerWith(registrar); ImagePickerPlugin.registerWith(registrar);
NetworkInfoPlusWebPlugin.registerWith(registrar);
PackageInfoPlusWebPlugin.registerWith(registrar); PackageInfoPlusWebPlugin.registerWith(registrar);
WebPermissionHandler.registerWith(registrar);
WebSensorsPlugin.registerWith(registrar); WebSensorsPlugin.registerWith(registrar);
SharedPreferencesPlugin.registerWith(registrar);
UrlLauncherPlugin.registerWith(registrar); UrlLauncherPlugin.registerWith(registrar);
registrar.registerMessageHandler(); registrar.registerMessageHandler();
} }

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
{"inputs":[],"outputs":[]}

View File

@@ -1 +0,0 @@
{"inputs":["/home/pierre/dev/geosector/app/.dart_tool/flutter_build/6ced80b14fe32342d5c3c0e19b465026/armeabi-v7a/app.so"],"outputs":["/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/armeabi-v7a/app.so"]}

View File

@@ -1 +0,0 @@
{"inputs":["/home/pierre/dev/geosector/app/.dart_tool/flutter_build/6ced80b14fe32342d5c3c0e19b465026/arm64-v8a/app.so"],"outputs":["/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/arm64-v8a/app.so"]}

View File

@@ -1 +0,0 @@
{"inputs":["/home/pierre/dev/geosector/app/.dart_tool/flutter_build/6ced80b14fe32342d5c3c0e19b465026/x86_64/app.so"],"outputs":["/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/x86_64/app.so"]}

View File

@@ -1 +0,0 @@
{"inputs":["/home/pierre/dev/flutter/packages/flutter_tools/lib/src/build_system/targets/android.dart","/home/pierre/dev/geosector/app/.dart_tool/flutter_build/6ced80b14fe32342d5c3c0e19b465026/app.dill","/home/pierre/dev/flutter/bin/cache/engine.stamp","/home/pierre/dev/flutter/bin/cache/engine.stamp","/home/pierre/dev/flutter/bin/cache/engine.stamp"],"outputs":["/home/pierre/dev/geosector/app/.dart_tool/flutter_build/6ced80b14fe32342d5c3c0e19b465026/armeabi-v7a/app.so"]}

View File

@@ -1 +0,0 @@
{"inputs":["/home/pierre/dev/flutter/packages/flutter_tools/lib/src/build_system/targets/android.dart","/home/pierre/dev/geosector/app/.dart_tool/flutter_build/6ced80b14fe32342d5c3c0e19b465026/app.dill","/home/pierre/dev/flutter/bin/cache/engine.stamp","/home/pierre/dev/flutter/bin/cache/engine.stamp","/home/pierre/dev/flutter/bin/cache/engine.stamp"],"outputs":["/home/pierre/dev/geosector/app/.dart_tool/flutter_build/6ced80b14fe32342d5c3c0e19b465026/arm64-v8a/app.so"]}

View File

@@ -1 +0,0 @@
{"inputs":["/home/pierre/dev/flutter/packages/flutter_tools/lib/src/build_system/targets/android.dart","/home/pierre/dev/geosector/app/.dart_tool/flutter_build/6ced80b14fe32342d5c3c0e19b465026/app.dill","/home/pierre/dev/flutter/bin/cache/engine.stamp","/home/pierre/dev/flutter/bin/cache/engine.stamp","/home/pierre/dev/flutter/bin/cache/engine.stamp"],"outputs":["/home/pierre/dev/geosector/app/.dart_tool/flutter_build/6ced80b14fe32342d5c3c0e19b465026/x86_64/app.so"]}

View File

@@ -1 +0,0 @@
/home/pierre/dev/geosector/app/.dart_tool/flutter_build/6ced80b14fe32342d5c3c0e19b465026/dart_build_result.json:

View File

@@ -1 +0,0 @@
{"inputs":["/home/pierre/dev/flutter/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart","/home/pierre/dev/geosector/app/.dart_tool/package_config.json"],"outputs":["/home/pierre/dev/geosector/app/.dart_tool/flutter_build/6ced80b14fe32342d5c3c0e19b465026/dart_build_result.json","/home/pierre/dev/geosector/app/.dart_tool/flutter_build/6ced80b14fe32342d5c3c0e19b465026/dart_build_result.json"]}

View File

@@ -1 +0,0 @@
{"dependencies":[],"code_assets":[]}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
{"inputs":["/home/pierre/dev/geosector/app/.dart_tool/package_config.json"],"outputs":["/home/pierre/dev/geosector/app/.dart_tool/flutter_build/dart_plugin_registrant.dart"]}

View File

@@ -1 +0,0 @@
/home/pierre/dev/geosector/app/.dart_tool/flutter_build/6ced80b14fe32342d5c3c0e19b465026/native_assets.json:

View File

@@ -1 +0,0 @@
{"inputs":["/home/pierre/dev/flutter/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart","/home/pierre/dev/geosector/app/.dart_tool/package_config.json"],"outputs":["/home/pierre/dev/geosector/app/.dart_tool/flutter_build/6ced80b14fe32342d5c3c0e19b465026/native_assets.json","/home/pierre/dev/geosector/app/.dart_tool/flutter_build/6ced80b14fe32342d5c3c0e19b465026/native_assets.json"]}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
{"format-version":[1,0,0],"native-assets":{}}

View File

@@ -1 +0,0 @@
["/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/flutter_assets/assets/images/logo-geosector-512.png-autosave.kra","/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/flutter_assets/assets/images/icon-geosector.svg","/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/flutter_assets/assets/images/geosector_map_admin.png","/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/flutter_assets/assets/images/logo_recu.png","/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/flutter_assets/assets/images/logo-geosector-512.png","/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/flutter_assets/assets/images/geosector-logo.png","/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/flutter_assets/assets/images/logo-geosector-1024.png","/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/flutter_assets/assets/animations/geo_main.json","/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/flutter_assets/lib/chat/chat_config.yaml","/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/flutter_assets/assets/fonts/Figtree-VariableFont_wght.ttf","/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/flutter_assets/packages/flutter_map/lib/assets/flutter_map_logo.png","/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf","/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/flutter_assets/fonts/MaterialIcons-Regular.otf","/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/flutter_assets/shaders/ink_sparkle.frag","/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/flutter_assets/AssetManifest.json","/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/flutter_assets/AssetManifest.bin","/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/flutter_assets/FontManifest.json","/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/flutter_assets/NOTICES.Z","/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/flutter_assets/NativeAssetsManifest.json","/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/x86_64/app.so","/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/arm64-v8a/app.so","/home/pierre/dev/geosector/app/build/app/intermediates/flutter/release/armeabi-v7a/app.so"]

View File

@@ -10,36 +10,35 @@ import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:geolocator_android/geolocator_android.dart'; import 'package:geolocator_android/geolocator_android.dart';
import 'package:image_picker_android/image_picker_android.dart'; import 'package:image_picker_android/image_picker_android.dart';
import 'package:path_provider_android/path_provider_android.dart'; import 'package:path_provider_android/path_provider_android.dart';
import 'package:shared_preferences_android/shared_preferences_android.dart';
import 'package:url_launcher_android/url_launcher_android.dart'; import 'package:url_launcher_android/url_launcher_android.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:geolocator_apple/geolocator_apple.dart'; import 'package:geolocator_apple/geolocator_apple.dart';
import 'package:image_picker_ios/image_picker_ios.dart'; import 'package:image_picker_ios/image_picker_ios.dart';
import 'package:path_provider_foundation/path_provider_foundation.dart'; import 'package:path_provider_foundation/path_provider_foundation.dart';
import 'package:shared_preferences_foundation/shared_preferences_foundation.dart';
import 'package:url_launcher_ios/url_launcher_ios.dart'; import 'package:url_launcher_ios/url_launcher_ios.dart';
import 'package:battery_plus/battery_plus.dart';
import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:file_selector_linux/file_selector_linux.dart'; import 'package:file_selector_linux/file_selector_linux.dart';
import 'package:flutter_local_notifications_linux/flutter_local_notifications_linux.dart'; import 'package:flutter_local_notifications_linux/flutter_local_notifications_linux.dart';
import 'package:geolocator_linux/geolocator_linux.dart';
import 'package:image_picker_linux/image_picker_linux.dart'; import 'package:image_picker_linux/image_picker_linux.dart';
import 'package:network_info_plus/network_info_plus.dart';
import 'package:package_info_plus/package_info_plus.dart'; import 'package:package_info_plus/package_info_plus.dart';
import 'package:path_provider_linux/path_provider_linux.dart'; import 'package:path_provider_linux/path_provider_linux.dart';
import 'package:shared_preferences_linux/shared_preferences_linux.dart';
import 'package:url_launcher_linux/url_launcher_linux.dart'; import 'package:url_launcher_linux/url_launcher_linux.dart';
import 'package:file_selector_macos/file_selector_macos.dart'; import 'package:file_selector_macos/file_selector_macos.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:geolocator_apple/geolocator_apple.dart'; import 'package:geolocator_apple/geolocator_apple.dart';
import 'package:image_picker_macos/image_picker_macos.dart'; import 'package:image_picker_macos/image_picker_macos.dart';
import 'package:path_provider_foundation/path_provider_foundation.dart'; import 'package:path_provider_foundation/path_provider_foundation.dart';
import 'package:shared_preferences_foundation/shared_preferences_foundation.dart';
import 'package:url_launcher_macos/url_launcher_macos.dart'; import 'package:url_launcher_macos/url_launcher_macos.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:file_selector_windows/file_selector_windows.dart'; import 'package:file_selector_windows/file_selector_windows.dart';
import 'package:flutter_local_notifications_windows/flutter_local_notifications_windows.dart'; import 'package:flutter_local_notifications_windows/flutter_local_notifications_windows.dart';
import 'package:image_picker_windows/image_picker_windows.dart'; import 'package:image_picker_windows/image_picker_windows.dart';
import 'package:network_info_plus/network_info_plus.dart';
import 'package:package_info_plus/package_info_plus.dart'; import 'package:package_info_plus/package_info_plus.dart';
import 'package:path_provider_windows/path_provider_windows.dart'; import 'package:path_provider_windows/path_provider_windows.dart';
import 'package:shared_preferences_windows/shared_preferences_windows.dart';
import 'package:url_launcher_windows/url_launcher_windows.dart'; import 'package:url_launcher_windows/url_launcher_windows.dart';
@pragma('vm:entry-point') @pragma('vm:entry-point')
@@ -84,15 +83,6 @@ class _PluginRegistrant {
); );
} }
try {
SharedPreferencesAndroid.registerWith();
} catch (err) {
print(
'`shared_preferences_android` threw an error: $err. '
'The app may not function as expected until you remove this plugin from pubspec.yaml'
);
}
try { try {
UrlLauncherAndroid.registerWith(); UrlLauncherAndroid.registerWith();
} catch (err) { } catch (err) {
@@ -139,15 +129,6 @@ class _PluginRegistrant {
); );
} }
try {
SharedPreferencesFoundation.registerWith();
} catch (err) {
print(
'`shared_preferences_foundation` threw an error: $err. '
'The app may not function as expected until you remove this plugin from pubspec.yaml'
);
}
try { try {
UrlLauncherIOS.registerWith(); UrlLauncherIOS.registerWith();
} catch (err) { } catch (err) {
@@ -158,6 +139,15 @@ class _PluginRegistrant {
} }
} else if (Platform.isLinux) { } else if (Platform.isLinux) {
try {
BatteryPlusLinuxPlugin.registerWith();
} catch (err) {
print(
'`battery_plus` threw an error: $err. '
'The app may not function as expected until you remove this plugin from pubspec.yaml'
);
}
try { try {
ConnectivityPlusLinuxPlugin.registerWith(); ConnectivityPlusLinuxPlugin.registerWith();
} catch (err) { } catch (err) {
@@ -167,6 +157,15 @@ class _PluginRegistrant {
); );
} }
try {
DeviceInfoPlusLinuxPlugin.registerWith();
} catch (err) {
print(
'`device_info_plus` threw an error: $err. '
'The app may not function as expected until you remove this plugin from pubspec.yaml'
);
}
try { try {
FileSelectorLinux.registerWith(); FileSelectorLinux.registerWith();
} catch (err) { } catch (err) {
@@ -186,19 +185,19 @@ class _PluginRegistrant {
} }
try { try {
GeolocatorLinux.registerWith(); ImagePickerLinux.registerWith();
} catch (err) { } catch (err) {
print( print(
'`geolocator_linux` threw an error: $err. ' '`image_picker_linux` threw an error: $err. '
'The app may not function as expected until you remove this plugin from pubspec.yaml' 'The app may not function as expected until you remove this plugin from pubspec.yaml'
); );
} }
try { try {
ImagePickerLinux.registerWith(); NetworkInfoPlusLinuxPlugin.registerWith();
} catch (err) { } catch (err) {
print( print(
'`image_picker_linux` threw an error: $err. ' '`network_info_plus` threw an error: $err. '
'The app may not function as expected until you remove this plugin from pubspec.yaml' 'The app may not function as expected until you remove this plugin from pubspec.yaml'
); );
} }
@@ -221,15 +220,6 @@ class _PluginRegistrant {
); );
} }
try {
SharedPreferencesLinux.registerWith();
} catch (err) {
print(
'`shared_preferences_linux` threw an error: $err. '
'The app may not function as expected until you remove this plugin from pubspec.yaml'
);
}
try { try {
UrlLauncherLinux.registerWith(); UrlLauncherLinux.registerWith();
} catch (err) { } catch (err) {
@@ -285,15 +275,6 @@ class _PluginRegistrant {
); );
} }
try {
SharedPreferencesFoundation.registerWith();
} catch (err) {
print(
'`shared_preferences_foundation` threw an error: $err. '
'The app may not function as expected until you remove this plugin from pubspec.yaml'
);
}
try { try {
UrlLauncherMacOS.registerWith(); UrlLauncherMacOS.registerWith();
} catch (err) { } catch (err) {
@@ -304,6 +285,15 @@ class _PluginRegistrant {
} }
} else if (Platform.isWindows) { } else if (Platform.isWindows) {
try {
DeviceInfoPlusWindowsPlugin.registerWith();
} catch (err) {
print(
'`device_info_plus` threw an error: $err. '
'The app may not function as expected until you remove this plugin from pubspec.yaml'
);
}
try { try {
FileSelectorWindows.registerWith(); FileSelectorWindows.registerWith();
} catch (err) { } catch (err) {
@@ -331,6 +321,15 @@ class _PluginRegistrant {
); );
} }
try {
NetworkInfoPlusWindowsPlugin.registerWith();
} catch (err) {
print(
'`network_info_plus` threw an error: $err. '
'The app may not function as expected until you remove this plugin from pubspec.yaml'
);
}
try { try {
PackageInfoPlusWindowsPlugin.registerWith(); PackageInfoPlusWindowsPlugin.registerWith();
} catch (err) { } catch (err) {
@@ -349,15 +348,6 @@ class _PluginRegistrant {
); );
} }
try {
SharedPreferencesWindows.registerWith();
} catch (err) {
print(
'`shared_preferences_windows` threw an error: $err. '
'The app may not function as expected until you remove this plugin from pubspec.yaml'
);
}
try { try {
UrlLauncherWindows.registerWith(); UrlLauncherWindows.registerWith();
} catch (err) { } catch (err) {

View File

@@ -31,6 +31,18 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.4" "languageVersion": "3.4"
}, },
{
"name": "battery_plus",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/battery_plus-4.1.0",
"packageUri": "lib/",
"languageVersion": "2.18"
},
{
"name": "battery_plus_platform_interface",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/battery_plus_platform_interface-1.2.2",
"packageUri": "lib/",
"languageVersion": "2.12"
},
{ {
"name": "boolean_selector", "name": "boolean_selector",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/boolean_selector-2.1.2", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/boolean_selector-2.1.2",
@@ -81,7 +93,7 @@
}, },
{ {
"name": "built_value", "name": "built_value",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/built_value-8.11.2", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/built_value-8.12.0",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.0" "languageVersion": "3.0"
}, },
@@ -103,6 +115,12 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.8" "languageVersion": "3.8"
}, },
{
"name": "class_to_string",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/class_to_string-1.0.0",
"packageUri": "lib/",
"languageVersion": "3.0"
},
{ {
"name": "cli_util", "name": "cli_util",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/cli_util-0.4.2", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/cli_util-0.4.2",
@@ -117,9 +135,9 @@
}, },
{ {
"name": "code_builder", "name": "code_builder",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/code_builder-4.10.1", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/code_builder-4.11.0",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.5" "languageVersion": "3.7"
}, },
{ {
"name": "collection", "name": "collection",
@@ -129,15 +147,15 @@
}, },
{ {
"name": "connectivity_plus", "name": "connectivity_plus",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/connectivity_plus-5.0.2",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.2" "languageVersion": "2.18"
}, },
{ {
"name": "connectivity_plus_platform_interface", "name": "connectivity_plus_platform_interface",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/connectivity_plus_platform_interface-2.0.1", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/connectivity_plus_platform_interface-1.2.4",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "2.18" "languageVersion": "2.12"
}, },
{ {
"name": "convert", "name": "convert",
@@ -169,18 +187,6 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.1" "languageVersion": "3.1"
}, },
{
"name": "dart_earcut",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/dart_earcut-1.2.0",
"packageUri": "lib/",
"languageVersion": "3.0"
},
{
"name": "dart_polylabel2",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/dart_polylabel2-1.0.0",
"packageUri": "lib/",
"languageVersion": "3.6"
},
{ {
"name": "dart_style", "name": "dart_style",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/dart_style-2.3.6", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/dart_style-2.3.6",
@@ -193,6 +199,18 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "2.17" "languageVersion": "2.17"
}, },
{
"name": "device_info_plus",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/device_info_plus-9.1.2",
"packageUri": "lib/",
"languageVersion": "2.18"
},
{
"name": "device_info_plus_platform_interface",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/device_info_plus_platform_interface-7.0.3",
"packageUri": "lib/",
"languageVersion": "3.7"
},
{ {
"name": "dio", "name": "dio",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/dio-5.9.0",
@@ -201,9 +219,15 @@
}, },
{ {
"name": "dio_cache_interceptor", "name": "dio_cache_interceptor",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/dio_cache_interceptor-4.0.3", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/dio_cache_interceptor-3.5.1",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.0" "languageVersion": "2.14"
},
{
"name": "dio_cache_interceptor_hive_store",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/dio_cache_interceptor_hive_store-3.2.2",
"packageUri": "lib/",
"languageVersion": "2.14"
}, },
{ {
"name": "dio_web_adapter", "name": "dio_web_adapter",
@@ -267,13 +291,13 @@
}, },
{ {
"name": "fl_chart", "name": "fl_chart",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/fl_chart-1.1.0", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/fl_chart-1.1.1",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.6" "languageVersion": "3.6"
}, },
{ {
"name": "flutter", "name": "flutter",
"rootUri": "file:///home/pierre/dev/flutter/packages/flutter", "rootUri": "file:///opt/flutter/packages/flutter",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.8" "languageVersion": "3.8"
}, },
@@ -291,7 +315,7 @@
}, },
{ {
"name": "flutter_local_notifications", "name": "flutter_local_notifications",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/flutter_local_notifications-19.4.1", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/flutter_local_notifications-19.4.2",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.4" "languageVersion": "3.4"
}, },
@@ -309,25 +333,25 @@
}, },
{ {
"name": "flutter_local_notifications_windows", "name": "flutter_local_notifications_windows",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/flutter_local_notifications_windows-1.0.2", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/flutter_local_notifications_windows-1.0.3",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.4" "languageVersion": "3.4"
}, },
{ {
"name": "flutter_localizations", "name": "flutter_localizations",
"rootUri": "file:///home/pierre/dev/flutter/packages/flutter_localizations", "rootUri": "file:///opt/flutter/packages/flutter_localizations",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.8" "languageVersion": "3.8"
}, },
{ {
"name": "flutter_map", "name": "flutter_map",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/flutter_map-8.2.1", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/flutter_map-6.2.1",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.6" "languageVersion": "3.0"
}, },
{ {
"name": "flutter_map_cache", "name": "flutter_map_cache",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/flutter_map_cache-2.0.0+1", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/flutter_map_cache-1.5.2",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.6" "languageVersion": "3.6"
}, },
@@ -337,6 +361,12 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.7" "languageVersion": "3.7"
}, },
{
"name": "flutter_stripe",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/flutter_stripe-12.0.2",
"packageUri": "lib/",
"languageVersion": "3.8"
},
{ {
"name": "flutter_svg", "name": "flutter_svg",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1",
@@ -345,37 +375,37 @@
}, },
{ {
"name": "flutter_test", "name": "flutter_test",
"rootUri": "file:///home/pierre/dev/flutter/packages/flutter_test", "rootUri": "file:///opt/flutter/packages/flutter_test",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.8" "languageVersion": "3.8"
}, },
{ {
"name": "flutter_web_plugins", "name": "flutter_web_plugins",
"rootUri": "file:///home/pierre/dev/flutter/packages/flutter_web_plugins", "rootUri": "file:///opt/flutter/packages/flutter_web_plugins",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.8" "languageVersion": "3.8"
}, },
{
"name": "freezed_annotation",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/freezed_annotation-3.1.0",
"packageUri": "lib/",
"languageVersion": "3.0"
},
{ {
"name": "frontend_server_client", "name": "frontend_server_client",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/frontend_server_client-4.0.0", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/frontend_server_client-4.0.0",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.0" "languageVersion": "3.0"
}, },
{
"name": "geoclue",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/geoclue-0.1.1",
"packageUri": "lib/",
"languageVersion": "2.16"
},
{ {
"name": "geolocator", "name": "geolocator",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/geolocator-14.0.2", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/geolocator-12.0.0",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.5" "languageVersion": "2.15"
}, },
{ {
"name": "geolocator_android", "name": "geolocator_android",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/geolocator_android-5.0.2", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/geolocator_android-4.6.2",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.5" "languageVersion": "3.5"
}, },
@@ -385,12 +415,6 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.5" "languageVersion": "3.5"
}, },
{
"name": "geolocator_linux",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/geolocator_linux-0.2.3",
"packageUri": "lib/",
"languageVersion": "3.5"
},
{ {
"name": "geolocator_platform_interface", "name": "geolocator_platform_interface",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/geolocator_platform_interface-4.2.6", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/geolocator_platform_interface-4.2.6",
@@ -417,13 +441,13 @@
}, },
{ {
"name": "go_router", "name": "go_router",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/go_router-16.2.1", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/go_router-16.2.4",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.7" "languageVersion": "3.7"
}, },
{ {
"name": "google_fonts", "name": "google_fonts",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/google_fonts-6.3.1", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/google_fonts-6.3.2",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.7" "languageVersion": "3.7"
}, },
@@ -433,12 +457,6 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.4" "languageVersion": "3.4"
}, },
{
"name": "gsettings",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/gsettings-0.2.8",
"packageUri": "lib/",
"languageVersion": "2.12"
},
{ {
"name": "hive", "name": "hive",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/hive-2.2.3", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/hive-2.2.3",
@@ -469,18 +487,6 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.4" "languageVersion": "3.4"
}, },
{
"name": "http_cache_core",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/http_cache_core-1.1.1",
"packageUri": "lib/",
"languageVersion": "3.0"
},
{
"name": "http_cache_file_store",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/http_cache_file_store-2.0.1",
"packageUri": "lib/",
"languageVersion": "3.0"
},
{ {
"name": "http_multi_server", "name": "http_multi_server",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/http_multi_server-3.2.2", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/http_multi_server-3.2.2",
@@ -507,9 +513,9 @@
}, },
{ {
"name": "image_picker_android", "name": "image_picker_android",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_android-0.8.13+1", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/image_picker_android-0.8.13+3",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.7" "languageVersion": "3.9"
}, },
{ {
"name": "image_picker_for_web", "name": "image_picker_for_web",
@@ -561,9 +567,9 @@
}, },
{ {
"name": "js", "name": "js",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/js-0.7.2", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/js-0.6.7",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.7" "languageVersion": "2.19"
}, },
{ {
"name": "json_annotation", "name": "json_annotation",
@@ -579,7 +585,7 @@
}, },
{ {
"name": "leak_tracker", "name": "leak_tracker",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/leak_tracker-11.0.1", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/leak_tracker-11.0.2",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.2" "languageVersion": "3.2"
}, },
@@ -631,6 +637,18 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "2.17" "languageVersion": "2.17"
}, },
{
"name": "mek_data_class",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/mek_data_class-1.4.0",
"packageUri": "lib/",
"languageVersion": "3.0"
},
{
"name": "mek_stripe_terminal",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/mek_stripe_terminal-4.6.0",
"packageUri": "lib/",
"languageVersion": "3.5"
},
{ {
"name": "meta", "name": "meta",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/meta-1.16.0", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/meta-1.16.0",
@@ -649,12 +667,42 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.2" "languageVersion": "3.2"
}, },
{
"name": "ndef_record",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/ndef_record-1.3.3",
"packageUri": "lib/",
"languageVersion": "3.9"
},
{
"name": "network_info_plus",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/network_info_plus-7.0.0",
"packageUri": "lib/",
"languageVersion": "2.18"
},
{
"name": "network_info_plus_platform_interface",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/network_info_plus_platform_interface-2.0.2",
"packageUri": "lib/",
"languageVersion": "2.18"
},
{
"name": "nfc_manager",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/nfc_manager-4.1.1",
"packageUri": "lib/",
"languageVersion": "3.9"
},
{ {
"name": "nm", "name": "nm",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/nm-0.5.0", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/nm-0.5.0",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "2.12" "languageVersion": "2.12"
}, },
{
"name": "one_for_all",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/one_for_all-1.1.1",
"packageUri": "lib/",
"languageVersion": "3.0"
},
{ {
"name": "package_config", "name": "package_config",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/package_config-2.2.0", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/package_config-2.2.0",
@@ -663,15 +711,15 @@
}, },
{ {
"name": "package_info_plus", "name": "package_info_plus",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/package_info_plus-8.3.1", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/package_info_plus-4.2.0",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.3" "languageVersion": "2.18"
}, },
{ {
"name": "package_info_plus_platform_interface", "name": "package_info_plus_platform_interface",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/package_info_plus_platform_interface-3.2.1", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/package_info_plus_platform_interface-2.0.1",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "2.18" "languageVersion": "2.12"
}, },
{ {
"name": "path", "name": "path",
@@ -721,6 +769,42 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.2" "languageVersion": "3.2"
}, },
{
"name": "permission_handler",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/permission_handler-11.4.0",
"packageUri": "lib/",
"languageVersion": "3.5"
},
{
"name": "permission_handler_android",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/permission_handler_android-12.1.0",
"packageUri": "lib/",
"languageVersion": "3.5"
},
{
"name": "permission_handler_apple",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/permission_handler_apple-9.4.7",
"packageUri": "lib/",
"languageVersion": "2.18"
},
{
"name": "permission_handler_html",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/permission_handler_html-0.1.3+5",
"packageUri": "lib/",
"languageVersion": "3.3"
},
{
"name": "permission_handler_platform_interface",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/permission_handler_platform_interface-4.3.0",
"packageUri": "lib/",
"languageVersion": "3.5"
},
{
"name": "permission_handler_windows",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/permission_handler_windows-0.2.1",
"packageUri": "lib/",
"languageVersion": "2.12"
},
{ {
"name": "petitparser", "name": "petitparser",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/petitparser-7.0.1", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/petitparser-7.0.1",
@@ -740,10 +824,16 @@
"languageVersion": "3.0" "languageVersion": "3.0"
}, },
{ {
"name": "pool", "name": "polylabel",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/pool-1.5.1", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/polylabel-1.0.1",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "2.12" "languageVersion": "2.13"
},
{
"name": "pool",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/pool-1.5.2",
"packageUri": "lib/",
"languageVersion": "3.4"
}, },
{ {
"name": "posix", "name": "posix",
@@ -769,6 +859,12 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.6" "languageVersion": "3.6"
}, },
{
"name": "recase",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/recase-4.1.0",
"packageUri": "lib/",
"languageVersion": "2.12"
},
{ {
"name": "retry", "name": "retry",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/retry-3.1.2", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/retry-3.1.2",
@@ -777,57 +873,15 @@
}, },
{ {
"name": "sensors_plus", "name": "sensors_plus",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/sensors_plus-6.1.2", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/sensors_plus-3.1.0",
"packageUri": "lib/",
"languageVersion": "3.3"
},
{
"name": "sensors_plus_platform_interface",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/sensors_plus_platform_interface-2.0.1",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "2.18" "languageVersion": "2.18"
}, },
{ {
"name": "shared_preferences", "name": "sensors_plus_platform_interface",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/shared_preferences-2.5.3", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/sensors_plus_platform_interface-1.2.0",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.5" "languageVersion": "2.18"
},
{
"name": "shared_preferences_android",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.12",
"packageUri": "lib/",
"languageVersion": "3.7"
},
{
"name": "shared_preferences_foundation",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4",
"packageUri": "lib/",
"languageVersion": "3.4"
},
{
"name": "shared_preferences_linux",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1",
"packageUri": "lib/",
"languageVersion": "3.3"
},
{
"name": "shared_preferences_platform_interface",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/shared_preferences_platform_interface-2.4.1",
"packageUri": "lib/",
"languageVersion": "3.2"
},
{
"name": "shared_preferences_web",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.3",
"packageUri": "lib/",
"languageVersion": "3.4"
},
{
"name": "shared_preferences_windows",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1",
"packageUri": "lib/",
"languageVersion": "3.3"
}, },
{ {
"name": "shelf", "name": "shelf",
@@ -843,7 +897,7 @@
}, },
{ {
"name": "sky_engine", "name": "sky_engine",
"rootUri": "file:///home/pierre/dev/flutter/bin/cache/pkg/sky_engine", "rootUri": "file:///opt/flutter/bin/cache/pkg/sky_engine",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.8" "languageVersion": "3.8"
}, },
@@ -895,6 +949,24 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.1" "languageVersion": "3.1"
}, },
{
"name": "stripe_android",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/stripe_android-12.0.1",
"packageUri": "lib/",
"languageVersion": "3.8"
},
{
"name": "stripe_ios",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/stripe_ios-12.0.1",
"packageUri": "lib/",
"languageVersion": "3.8"
},
{
"name": "stripe_platform_interface",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/stripe_platform_interface-12.0.0",
"packageUri": "lib/",
"languageVersion": "3.8"
},
{ {
"name": "syncfusion_flutter_charts", "name": "syncfusion_flutter_charts",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.7", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/syncfusion_flutter_charts-30.2.7",
@@ -907,12 +979,6 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.7" "languageVersion": "3.7"
}, },
{
"name": "synchronized",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/synchronized-3.4.0",
"packageUri": "lib/",
"languageVersion": "3.8"
},
{ {
"name": "term_glyph", "name": "term_glyph",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/term_glyph-1.2.2", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/term_glyph-1.2.2",
@@ -961,6 +1027,12 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "2.17" "languageVersion": "2.17"
}, },
{
"name": "upower",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/upower-0.7.0",
"packageUri": "lib/",
"languageVersion": "2.14"
},
{ {
"name": "url_launcher", "name": "url_launcher",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/url_launcher-6.3.2", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/url_launcher-6.3.2",
@@ -969,9 +1041,9 @@
}, },
{ {
"name": "url_launcher_android", "name": "url_launcher_android",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.18", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.23",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.7" "languageVersion": "3.9"
}, },
{ {
"name": "url_launcher_ios", "name": "url_launcher_ios",
@@ -1047,7 +1119,7 @@
}, },
{ {
"name": "watcher", "name": "watcher",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/watcher-1.1.3", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/watcher-1.1.4",
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.1" "languageVersion": "3.1"
}, },
@@ -1075,6 +1147,12 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.8" "languageVersion": "3.8"
}, },
{
"name": "win32_registry",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/win32_registry-1.1.5",
"packageUri": "lib/",
"languageVersion": "3.4"
},
{ {
"name": "wkt_parser", "name": "wkt_parser",
"rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/wkt_parser-2.0.0", "rootUri": "file:///home/pierre/.pub-cache/hosted/pub.dev/wkt_parser-2.0.0",
@@ -1107,8 +1185,8 @@
} }
], ],
"generator": "pub", "generator": "pub",
"generatorVersion": "3.9.0", "generatorVersion": "3.9.2",
"flutterRoot": "file:///home/pierre/dev/flutter", "flutterRoot": "file:///opt/flutter",
"flutterVersion": "3.35.1", "flutterVersion": "3.35.5",
"pubCache": "file:///home/pierre/.pub-cache" "pubCache": "file:///home/pierre/.pub-cache"
} }

View File

@@ -5,32 +5,38 @@
"packages": [ "packages": [
{ {
"name": "geosector_app", "name": "geosector_app",
"version": "3.2.4+324", "version": "3.3.4+334",
"dependencies": [ "dependencies": [
"battery_plus",
"connectivity_plus", "connectivity_plus",
"cupertino_icons", "cupertino_icons",
"device_info_plus",
"dio", "dio",
"dio_cache_interceptor_hive_store",
"fl_chart", "fl_chart",
"flutter", "flutter",
"flutter_local_notifications", "flutter_local_notifications",
"flutter_localizations", "flutter_localizations",
"flutter_map", "flutter_map",
"flutter_map_cache", "flutter_map_cache",
"flutter_stripe",
"flutter_svg", "flutter_svg",
"geolocator", "geolocator",
"go_router", "go_router",
"google_fonts", "google_fonts",
"hive", "hive",
"hive_flutter", "hive_flutter",
"http_cache_file_store",
"image_picker", "image_picker",
"intl", "intl",
"latlong2", "latlong2",
"mek_stripe_terminal",
"network_info_plus",
"nfc_manager",
"package_info_plus", "package_info_plus",
"path_provider", "path_provider",
"permission_handler",
"retry", "retry",
"sensors_plus", "sensors_plus",
"shared_preferences",
"syncfusion_flutter_charts", "syncfusion_flutter_charts",
"universal_html", "universal_html",
"url_launcher", "url_launcher",
@@ -134,6 +140,89 @@
"vector_math" "vector_math"
] ]
}, },
{
"name": "permission_handler",
"version": "11.4.0",
"dependencies": [
"flutter",
"meta",
"permission_handler_android",
"permission_handler_apple",
"permission_handler_html",
"permission_handler_platform_interface",
"permission_handler_windows"
]
},
{
"name": "flutter_stripe",
"version": "12.0.2",
"dependencies": [
"flutter",
"meta",
"stripe_android",
"stripe_ios",
"stripe_platform_interface"
]
},
{
"name": "mek_stripe_terminal",
"version": "4.6.0",
"dependencies": [
"collection",
"flutter",
"mek_data_class",
"meta",
"one_for_all",
"recase"
]
},
{
"name": "nfc_manager",
"version": "4.1.1",
"dependencies": [
"flutter",
"ndef_record"
]
},
{
"name": "network_info_plus",
"version": "7.0.0",
"dependencies": [
"collection",
"ffi",
"flutter",
"flutter_web_plugins",
"meta",
"network_info_plus_platform_interface",
"nm",
"win32"
]
},
{
"name": "battery_plus",
"version": "4.1.0",
"dependencies": [
"battery_plus_platform_interface",
"flutter",
"flutter_web_plugins",
"meta",
"upower"
]
},
{
"name": "device_info_plus",
"version": "9.1.2",
"dependencies": [
"device_info_plus_platform_interface",
"ffi",
"file",
"flutter",
"flutter_web_plugins",
"meta",
"win32",
"win32_registry"
]
},
{ {
"name": "yaml", "name": "yaml",
"version": "3.1.3", "version": "3.1.3",
@@ -159,7 +248,7 @@
}, },
{ {
"name": "flutter_local_notifications", "name": "flutter_local_notifications",
"version": "19.4.1", "version": "19.4.2",
"dependencies": [ "dependencies": [
"clock", "clock",
"flutter", "flutter",
@@ -171,7 +260,7 @@
}, },
{ {
"name": "sensors_plus", "name": "sensors_plus",
"version": "6.1.2", "version": "3.1.0",
"dependencies": [ "dependencies": [
"flutter", "flutter",
"flutter_web_plugins", "flutter_web_plugins",
@@ -195,12 +284,11 @@
}, },
{ {
"name": "geolocator", "name": "geolocator",
"version": "14.0.2", "version": "12.0.0",
"dependencies": [ "dependencies": [
"flutter", "flutter",
"geolocator_android", "geolocator_android",
"geolocator_apple", "geolocator_apple",
"geolocator_linux",
"geolocator_platform_interface", "geolocator_platform_interface",
"geolocator_web", "geolocator_web",
"geolocator_windows" "geolocator_windows"
@@ -226,17 +314,16 @@
] ]
}, },
{ {
"name": "http_cache_file_store", "name": "dio_cache_interceptor_hive_store",
"version": "2.0.1", "version": "3.2.2",
"dependencies": [ "dependencies": [
"http_cache_core", "dio_cache_interceptor",
"path", "hive"
"synchronized"
] ]
}, },
{ {
"name": "flutter_map_cache", "name": "flutter_map_cache",
"version": "2.0.0+1", "version": "1.5.2",
"dependencies": [ "dependencies": [
"dio", "dio",
"dio_cache_interceptor", "dio_cache_interceptor",
@@ -246,21 +333,18 @@
}, },
{ {
"name": "flutter_map", "name": "flutter_map",
"version": "8.2.1", "version": "6.2.1",
"dependencies": [ "dependencies": [
"async", "async",
"collection", "collection",
"dart_earcut",
"dart_polylabel2",
"flutter", "flutter",
"http", "http",
"latlong2", "latlong2",
"logger", "logger",
"meta", "meta",
"path", "polylabel",
"path_provider",
"proj4dart", "proj4dart",
"uuid" "vector_math"
] ]
}, },
{ {
@@ -277,19 +361,6 @@
"url_launcher_windows" "url_launcher_windows"
] ]
}, },
{
"name": "shared_preferences",
"version": "2.5.3",
"dependencies": [
"flutter",
"shared_preferences_android",
"shared_preferences_foundation",
"shared_preferences_linux",
"shared_preferences_platform_interface",
"shared_preferences_web",
"shared_preferences_windows"
]
},
{ {
"name": "syncfusion_flutter_charts", "name": "syncfusion_flutter_charts",
"version": "30.2.7", "version": "30.2.7",
@@ -302,7 +373,7 @@
}, },
{ {
"name": "fl_chart", "name": "fl_chart",
"version": "1.1.0", "version": "1.1.1",
"dependencies": [ "dependencies": [
"equatable", "equatable",
"flutter", "flutter",
@@ -330,9 +401,8 @@
}, },
{ {
"name": "package_info_plus", "name": "package_info_plus",
"version": "8.3.1", "version": "4.2.0",
"dependencies": [ "dependencies": [
"clock",
"ffi", "ffi",
"flutter", "flutter",
"flutter_web_plugins", "flutter_web_plugins",
@@ -340,7 +410,6 @@
"meta", "meta",
"package_info_plus_platform_interface", "package_info_plus_platform_interface",
"path", "path",
"web",
"win32" "win32"
] ]
}, },
@@ -357,7 +426,7 @@
}, },
{ {
"name": "google_fonts", "name": "google_fonts",
"version": "6.3.1", "version": "6.3.2",
"dependencies": [ "dependencies": [
"crypto", "crypto",
"flutter", "flutter",
@@ -372,15 +441,14 @@
}, },
{ {
"name": "connectivity_plus", "name": "connectivity_plus",
"version": "6.1.5", "version": "5.0.2",
"dependencies": [ "dependencies": [
"collection",
"connectivity_plus_platform_interface", "connectivity_plus_platform_interface",
"flutter", "flutter",
"flutter_web_plugins", "flutter_web_plugins",
"js",
"meta", "meta",
"nm", "nm"
"web"
] ]
}, },
{ {
@@ -416,7 +484,7 @@
}, },
{ {
"name": "go_router", "name": "go_router",
"version": "16.2.1", "version": "16.2.4",
"dependencies": [ "dependencies": [
"collection", "collection",
"flutter", "flutter",
@@ -507,7 +575,7 @@
}, },
{ {
"name": "watcher", "name": "watcher",
"version": "1.1.3", "version": "1.1.4",
"dependencies": [ "dependencies": [
"async", "async",
"path" "path"
@@ -573,7 +641,7 @@
}, },
{ {
"name": "pool", "name": "pool",
"version": "1.5.1", "version": "1.5.2",
"dependencies": [ "dependencies": [
"async", "async",
"stack_trace" "stack_trace"
@@ -603,8 +671,10 @@
}, },
{ {
"name": "js", "name": "js",
"version": "0.7.2", "version": "0.6.7",
"dependencies": [] "dependencies": [
"meta"
]
}, },
{ {
"name": "io", "name": "io",
@@ -674,7 +744,7 @@
}, },
{ {
"name": "code_builder", "name": "code_builder",
"version": "4.10.1", "version": "4.11.0",
"dependencies": [ "dependencies": [
"built_collection", "built_collection",
"built_value", "built_value",
@@ -887,6 +957,178 @@
"term_glyph" "term_glyph"
] ]
}, },
{
"name": "permission_handler_platform_interface",
"version": "4.3.0",
"dependencies": [
"flutter",
"meta",
"plugin_platform_interface"
]
},
{
"name": "permission_handler_windows",
"version": "0.2.1",
"dependencies": [
"flutter",
"permission_handler_platform_interface"
]
},
{
"name": "permission_handler_html",
"version": "0.1.3+5",
"dependencies": [
"flutter",
"flutter_web_plugins",
"permission_handler_platform_interface",
"web"
]
},
{
"name": "permission_handler_apple",
"version": "9.4.7",
"dependencies": [
"flutter",
"permission_handler_platform_interface"
]
},
{
"name": "permission_handler_android",
"version": "12.1.0",
"dependencies": [
"flutter",
"permission_handler_platform_interface"
]
},
{
"name": "stripe_platform_interface",
"version": "12.0.0",
"dependencies": [
"flutter",
"freezed_annotation",
"json_annotation",
"meta",
"plugin_platform_interface"
]
},
{
"name": "stripe_ios",
"version": "12.0.1",
"dependencies": [
"flutter"
]
},
{
"name": "stripe_android",
"version": "12.0.1",
"dependencies": [
"flutter"
]
},
{
"name": "one_for_all",
"version": "1.1.1",
"dependencies": [
"meta"
]
},
{
"name": "mek_data_class",
"version": "1.4.0",
"dependencies": [
"class_to_string",
"collection",
"meta"
]
},
{
"name": "recase",
"version": "4.1.0",
"dependencies": []
},
{
"name": "ndef_record",
"version": "1.3.3",
"dependencies": [
"collection"
]
},
{
"name": "ffi",
"version": "2.1.4",
"dependencies": []
},
{
"name": "win32",
"version": "5.14.0",
"dependencies": [
"ffi"
]
},
{
"name": "network_info_plus_platform_interface",
"version": "2.0.2",
"dependencies": [
"flutter",
"meta",
"plugin_platform_interface"
]
},
{
"name": "flutter_web_plugins",
"version": "0.0.0",
"dependencies": [
"flutter"
]
},
{
"name": "nm",
"version": "0.5.0",
"dependencies": [
"dbus"
]
},
{
"name": "upower",
"version": "0.7.0",
"dependencies": [
"dbus"
]
},
{
"name": "battery_plus_platform_interface",
"version": "1.2.2",
"dependencies": [
"flutter",
"meta",
"plugin_platform_interface"
]
},
{
"name": "win32_registry",
"version": "1.1.5",
"dependencies": [
"ffi",
"win32"
]
},
{
"name": "file",
"version": "7.0.1",
"dependencies": [
"meta",
"path"
]
},
{
"name": "device_info_plus_platform_interface",
"version": "7.0.3",
"dependencies": [
"flutter",
"meta",
"plugin_platform_interface"
]
},
{ {
"name": "string_scanner", "name": "string_scanner",
"version": "1.4.1", "version": "1.4.1",
@@ -964,7 +1206,7 @@
}, },
{ {
"name": "image_picker_android", "name": "image_picker_android",
"version": "0.8.13+1", "version": "0.8.13+3",
"dependencies": [ "dependencies": [
"flutter", "flutter",
"flutter_plugin_android_lifecycle", "flutter_plugin_android_lifecycle",
@@ -988,7 +1230,7 @@
}, },
{ {
"name": "flutter_local_notifications_windows", "name": "flutter_local_notifications_windows",
"version": "1.0.2", "version": "1.0.3",
"dependencies": [ "dependencies": [
"ffi", "ffi",
"flutter", "flutter",
@@ -1012,7 +1254,7 @@
}, },
{ {
"name": "sensors_plus_platform_interface", "name": "sensors_plus_platform_interface",
"version": "2.0.1", "version": "1.2.0",
"dependencies": [ "dependencies": [
"flutter", "flutter",
"logging", "logging",
@@ -1020,13 +1262,6 @@
"plugin_platform_interface" "plugin_platform_interface"
] ]
}, },
{
"name": "flutter_web_plugins",
"version": "0.0.0",
"dependencies": [
"flutter"
]
},
{ {
"name": "universal_io", "name": "universal_io",
"version": "2.2.2", "version": "2.2.2",
@@ -1063,18 +1298,6 @@
"source_span" "source_span"
] ]
}, },
{
"name": "geolocator_linux",
"version": "0.2.3",
"dependencies": [
"dbus",
"flutter",
"geoclue",
"geolocator_platform_interface",
"gsettings",
"package_info_plus"
]
},
{ {
"name": "geolocator_windows", "name": "geolocator_windows",
"version": "0.2.5", "version": "0.2.5",
@@ -1103,7 +1326,7 @@
}, },
{ {
"name": "geolocator_android", "name": "geolocator_android",
"version": "5.0.2", "version": "4.6.2",
"dependencies": [ "dependencies": [
"flutter", "flutter",
"geolocator_platform_interface", "geolocator_platform_interface",
@@ -1167,26 +1390,13 @@
"path_provider_platform_interface" "path_provider_platform_interface"
] ]
}, },
{
"name": "synchronized",
"version": "3.4.0",
"dependencies": []
},
{
"name": "http_cache_core",
"version": "1.1.1",
"dependencies": [
"collection",
"string_scanner",
"uuid"
]
},
{ {
"name": "dio_cache_interceptor", "name": "dio_cache_interceptor",
"version": "4.0.3", "version": "3.5.1",
"dependencies": [ "dependencies": [
"dio", "dio",
"http_cache_core" "string_scanner",
"uuid"
] ]
}, },
{ {
@@ -1198,6 +1408,13 @@
"wkt_parser" "wkt_parser"
] ]
}, },
{
"name": "polylabel",
"version": "1.0.1",
"dependencies": [
"collection"
]
},
{ {
"name": "logger", "name": "logger",
"version": "2.6.1", "version": "2.6.1",
@@ -1215,19 +1432,6 @@
"web" "web"
] ]
}, },
{
"name": "dart_polylabel2",
"version": "1.0.0",
"dependencies": [
"collection",
"meta"
]
},
{
"name": "dart_earcut",
"version": "1.2.0",
"dependencies": []
},
{ {
"name": "url_launcher_windows", "name": "url_launcher_windows",
"version": "3.1.4", "version": "3.1.4",
@@ -1280,70 +1484,12 @@
}, },
{ {
"name": "url_launcher_android", "name": "url_launcher_android",
"version": "6.3.18", "version": "6.3.23",
"dependencies": [ "dependencies": [
"flutter", "flutter",
"url_launcher_platform_interface" "url_launcher_platform_interface"
] ]
}, },
{
"name": "shared_preferences_windows",
"version": "2.4.1",
"dependencies": [
"file",
"flutter",
"path",
"path_provider_platform_interface",
"path_provider_windows",
"shared_preferences_platform_interface"
]
},
{
"name": "shared_preferences_web",
"version": "2.4.3",
"dependencies": [
"flutter",
"flutter_web_plugins",
"shared_preferences_platform_interface",
"web"
]
},
{
"name": "shared_preferences_platform_interface",
"version": "2.4.1",
"dependencies": [
"flutter",
"plugin_platform_interface"
]
},
{
"name": "shared_preferences_linux",
"version": "2.4.1",
"dependencies": [
"file",
"flutter",
"path",
"path_provider_linux",
"path_provider_platform_interface",
"shared_preferences_platform_interface"
]
},
{
"name": "shared_preferences_foundation",
"version": "2.5.4",
"dependencies": [
"flutter",
"shared_preferences_platform_interface"
]
},
{
"name": "shared_preferences_android",
"version": "2.4.12",
"dependencies": [
"flutter",
"shared_preferences_platform_interface"
]
},
{ {
"name": "syncfusion_flutter_core", "name": "syncfusion_flutter_core",
"version": "30.2.7", "version": "30.2.7",
@@ -1370,32 +1516,15 @@
"version": "7.0.0", "version": "7.0.0",
"dependencies": [] "dependencies": []
}, },
{
"name": "win32",
"version": "5.14.0",
"dependencies": [
"ffi"
]
},
{
"name": "web",
"version": "1.1.1",
"dependencies": []
},
{ {
"name": "package_info_plus_platform_interface", "name": "package_info_plus_platform_interface",
"version": "3.2.1", "version": "2.0.1",
"dependencies": [ "dependencies": [
"flutter", "flutter",
"meta", "meta",
"plugin_platform_interface" "plugin_platform_interface"
] ]
}, },
{
"name": "ffi",
"version": "2.1.4",
"dependencies": []
},
{ {
"name": "vector_graphics_compiler", "name": "vector_graphics_compiler",
"version": "1.1.19", "version": "1.1.19",
@@ -1422,16 +1551,9 @@
"vector_graphics_codec" "vector_graphics_codec"
] ]
}, },
{
"name": "nm",
"version": "0.5.0",
"dependencies": [
"dbus"
]
},
{ {
"name": "connectivity_plus_platform_interface", "name": "connectivity_plus_platform_interface",
"version": "2.0.1", "version": "1.2.4",
"dependencies": [ "dependencies": [
"flutter", "flutter",
"meta", "meta",
@@ -1501,16 +1623,13 @@
] ]
}, },
{ {
"name": "file", "name": "web",
"version": "7.0.1", "version": "1.1.1",
"dependencies": [ "dependencies": []
"meta",
"path"
]
}, },
{ {
"name": "built_value", "name": "built_value",
"version": "8.11.2", "version": "8.12.0",
"dependencies": [ "dependencies": [
"built_collection", "built_collection",
"collection", "collection",
@@ -1548,7 +1667,7 @@
}, },
{ {
"name": "leak_tracker", "name": "leak_tracker",
"version": "11.0.1", "version": "11.0.2",
"dependencies": [ "dependencies": [
"clock", "clock",
"collection", "collection",
@@ -1570,6 +1689,37 @@
"string_scanner" "string_scanner"
] ]
}, },
{
"name": "plugin_platform_interface",
"version": "2.1.8",
"dependencies": [
"meta"
]
},
{
"name": "freezed_annotation",
"version": "3.1.0",
"dependencies": [
"collection",
"json_annotation",
"meta"
]
},
{
"name": "class_to_string",
"version": "1.0.0",
"dependencies": []
},
{
"name": "dbus",
"version": "0.7.11",
"dependencies": [
"args",
"ffi",
"meta",
"xml"
]
},
{ {
"name": "file_selector_windows", "name": "file_selector_windows",
"version": "0.9.3+4", "version": "0.9.3+4",
@@ -1589,13 +1739,6 @@
"plugin_platform_interface" "plugin_platform_interface"
] ]
}, },
{
"name": "plugin_platform_interface",
"version": "2.1.8",
"dependencies": [
"meta"
]
},
{ {
"name": "cross_file", "name": "cross_file",
"version": "0.3.4+2", "version": "0.3.4+2",
@@ -1637,32 +1780,6 @@
"path" "path"
] ]
}, },
{
"name": "dbus",
"version": "0.7.11",
"dependencies": [
"args",
"ffi",
"meta",
"xml"
]
},
{
"name": "gsettings",
"version": "0.2.8",
"dependencies": [
"dbus",
"xdg_directories"
]
},
{
"name": "geoclue",
"version": "0.1.1",
"dependencies": [
"dbus",
"meta"
]
},
{ {
"name": "platform", "name": "platform",
"version": "3.1.6", "version": "3.1.6",

View File

@@ -1 +1 @@
3.35.1 3.35.5

View File

@@ -1,21 +1,14 @@
# Paramètres de connexion au host Debian 12 # Configuration de déploiement pour l'environnement DEV
HOST_SSH_USER=pierre # Utilisé par deploy-app.sh
HOST_SSH_HOST=195.154.80.116
HOST_SSH_PORT=22
if [[ "$OSTYPE" == "darwin"* ]]; then
# macOS
HOST_SSH_KEY=/Users/pierre/.ssh/id_rsa_mbpi
else
# Linux/Ubuntu
HOST_SSH_KEY=/home/pierre/.ssh/id_rsa_mbpi
fi
# Paramètres du container Incus # Répertoire de build Flutter
INCUS_PROJECT=default FLUTTER_BUILD_DIR="build/web"
INCUS_CONTAINER=dva-geo
CONTAINER_USER=root
USE_SUDO=true
# Paramètres de déploiement # URL de l'application web (pour la détection d'environnement)
DEPLOY_TARGET_DIR=/var/www/geosector/app APP_URL="https://dapp.geosector.fr"
FLUTTER_BUILD_DIR=build/web
# URL de l'API backend
API_URL="https://dapp.geosector.fr/api"
# Environnement
ENVIRONMENT="DEV"

File diff suppressed because one or more lines are too long

115
app/.gitignore vendored Normal file
View File

@@ -0,0 +1,115 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
/build/
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
# iOS/XCode related
**/ios/**/*.mode1v3
**/ios/**/*.mode2v3
**/ios/**/*.moved-aside
**/ios/**/*.pbxuser
**/ios/**/*.perspectivev3
**/ios/**/*sync/
**/ios/**/.sconsign.dblite
**/ios/**/.tags*
**/ios/**/.vagrant/
**/ios/**/DerivedData/
**/ios/**/Icon?
**/ios/**/Pods/
**/ios/**/.symlinks/
**/ios/**/profile
**/ios/**/xcuserdata
**/ios/.generated/
**/ios/Flutter/App.framework
**/ios/Flutter/Flutter.framework
**/ios/Flutter/Flutter.podspec
**/ios/Flutter/Generated.xcconfig
**/ios/Flutter/ephemeral/
**/ios/Flutter/app.flx
**/ios/Flutter/app.zip
**/ios/Flutter/flutter_assets/
**/ios/Flutter/flutter_export_environment.sh
**/ios/ServiceDefinitions.json
**/ios/Runner/GeneratedPluginRegistrant.*
# Windows
windows/flutter/generated_plugin_registrant.cc
windows/flutter/generated_plugin_registrant.h
windows/flutter/generated_plugins.cmake
# Linux
linux/flutter/generated_plugin_registrant.cc
linux/flutter/generated_plugin_registrant.h
linux/flutter/generated_plugins.cmake
# Web
web/flutter_service_worker.js
web/main.dart.js
web/flutter.js
# Environment variables
.env
.env.local
.env.*.local
.env-deploy-*
# Exceptions to above rules.
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
# Custom
*.g.dart
*.freezed.dart
.cxx/
.gradle/
gradlew
gradlew.bat
local.properties
# Scripts et documentation
# *.sh
# /docs/
# Build outputs (APK/AAB)
*.apk
*.aab
*.ipa

View File

@@ -1,16 +0,0 @@
# geosector_app
A new Flutter project.
## Getting Started
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference.

View File

@@ -35,7 +35,8 @@ android {
applicationId = "fr.geosector.app2025" applicationId = "fr.geosector.app2025"
// You can update the following values to match your application needs. // You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config. // For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion // Minimum SDK 28 requis pour Stripe Tap to Pay
minSdk = 28
targetSdk = flutter.targetSdkVersion targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode versionCode = flutter.versionCode
versionName = flutter.versionName versionName = flutter.versionName

View File

@@ -4,9 +4,13 @@
<!-- Permissions pour la géolocalisation --> <!-- Permissions pour la géolocalisation -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- Permission NFC pour Tap to Pay -->
<uses-permission android:name="android.permission.NFC" />
<!-- Feature GPS requise pour l'application --> <!-- Feature GPS requise pour l'application -->
<uses-feature android:name="android.hardware.location.gps" android:required="true" /> <uses-feature android:name="android.hardware.location.gps" android:required="true" />
<!-- Feature NFC optionnelle (pour ne pas exclure les appareils sans NFC) -->
<uses-feature android:name="android.hardware.nfc" android:required="false" />
<application <application
android:label="GeoSector" android:label="GeoSector"

View File

@@ -19,7 +19,7 @@ pluginManagement {
plugins { plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0" id("dev.flutter.flutter-plugin-loader") version "1.0.0"
id("com.android.application") version "8.7.0" apply false id("com.android.application") version "8.7.0" apply false
id("org.jetbrains.kotlin.android") version "1.8.22" apply false id("org.jetbrains.kotlin.android") version "2.1.0" apply false
} }
include(":app") include(":app")

Binary file not shown.

Binary file not shown.

View File

@@ -1,803 +0,0 @@
{
"inputs" :
[
{
"path" : "CMakeLists.txt"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeDetermineSystem.cmake"
},
{
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/ndk/27.0.12077973/build/cmake/android.toolchain.cmake"
},
{
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/ndk/27.0.12077973/build/cmake/android-legacy.toolchain.cmake"
},
{
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/ndk/27.0.12077973/build/cmake/abis.cmake"
},
{
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/ndk/27.0.12077973/build/cmake/platforms.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Android-Determine.cmake"
},
{
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/ndk/27.0.12077973/build/cmake/hooks/pre/Android-Determine.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeSystem.cmake.in"
},
{
"isGenerated" : true,
"path" : "/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a/CMakeFiles/3.22.1-g37088a8/CMakeSystem.cmake"
},
{
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/ndk/27.0.12077973/build/cmake/android.toolchain.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeSystemSpecificInitialize.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Android-Initialize.cmake"
},
{
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/ndk/27.0.12077973/build/cmake/hooks/pre/Android-Initialize.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeDetermineCCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeDetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Android-Determine-C.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Android/Determine-Compiler.cmake"
},
{
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/ndk/27.0.12077973/build/cmake/hooks/pre/Determine-Compiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeDetermineCompilerId.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCompilerIdDetection.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/ADSP-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/ARMCC-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/ARMClang-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/AppleClang-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang-DetermineCompilerInternal.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Borland-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Bruce-C-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang-DetermineCompilerInternal.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Compaq-C-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Cray-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Embarcadero-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Fujitsu-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/FujitsuClang-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/GHS-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/GNU-C-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/HP-C-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/IAR-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Intel-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/IntelLLVM-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/MSVC-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/NVHPC-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/NVIDIA-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/OpenWatcom-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/PGI-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/PathScale-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/SCO-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/SDCC-C-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/SunPro-C-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/TI-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/TinyCC-C-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/VisualAge-C-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Watcom-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/XL-C-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/XLClang-C-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/zOS-C-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeFindBinUtils.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang-FindBinUtils.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCCompiler.cmake.in"
},
{
"isGenerated" : true,
"path" : "/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a/CMakeFiles/3.22.1-g37088a8/CMakeCCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeDetermineCXXCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeDetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Android-Determine-CXX.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Android/Determine-Compiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeDetermineCompilerId.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCompilerIdDetection.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/ADSP-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/ARMCC-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/ARMClang-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/AppleClang-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang-DetermineCompilerInternal.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Borland-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang-DetermineCompilerInternal.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Comeau-CXX-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Compaq-CXX-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Cray-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Embarcadero-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Fujitsu-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/FujitsuClang-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/GHS-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/GNU-CXX-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/HP-CXX-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/IAR-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Intel-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/IntelLLVM-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/MSVC-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/NVHPC-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/NVIDIA-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/OpenWatcom-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/PGI-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/PathScale-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/SCO-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/SunPro-CXX-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/TI-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/VisualAge-CXX-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Watcom-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/XL-CXX-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/XLClang-CXX-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/zOS-CXX-DetermineCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeFindBinUtils.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang-FindBinUtils.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCXXCompiler.cmake.in"
},
{
"isGenerated" : true,
"path" : "/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a/CMakeFiles/3.22.1-g37088a8/CMakeCXXCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeSystemSpecificInformation.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeGenericSystem.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeInitializeConfigs.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Android.cmake"
},
{
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/ndk/27.0.12077973/build/cmake/hooks/pre/Android.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Linux.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/UnixPaths.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCInformation.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeLanguageInformation.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang-C.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/CMakeCommonCompilerMacros.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/GNU.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/CMakeCommonCompilerMacros.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Android-Clang-C.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Android-Clang.cmake"
},
{
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/ndk/27.0.12077973/build/cmake/hooks/pre/Android-Clang.cmake"
},
{
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/ndk/27.0.12077973/build/cmake/flags.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCommonLanguageInclude.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeTestCCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeTestCompilerCommon.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeDetermineCompilerABI.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeParseImplicitIncludeInfo.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeParseImplicitLinkInfo.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeParseLibraryArchitecture.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeTestCompilerCommon.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCCompilerABI.c"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeDetermineCompileFeatures.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Internal/FeatureTesting.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCCompiler.cmake.in"
},
{
"isGenerated" : true,
"path" : "/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a/CMakeFiles/3.22.1-g37088a8/CMakeCCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCXXInformation.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeLanguageInformation.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang-CXX.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Compiler/Clang.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Android-Clang-CXX.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Platform/Android-Clang.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCommonLanguageInclude.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeTestCXXCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeTestCompilerCommon.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeDetermineCompilerABI.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeParseImplicitIncludeInfo.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeParseImplicitLinkInfo.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeParseLibraryArchitecture.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeTestCompilerCommon.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCXXCompilerABI.cpp"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeDetermineCompileFeatures.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/Internal/FeatureTesting.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22/Modules/CMakeCXXCompiler.cmake.in"
},
{
"isGenerated" : true,
"path" : "/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a/CMakeFiles/3.22.1-g37088a8/CMakeCXXCompiler.cmake"
}
],
"kind" : "cmakeFiles",
"paths" :
{
"build" : "/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a",
"source" : "/home/pierre/dev/flutter/packages/flutter_tools/gradle/src/main/scripts"
},
"version" :
{
"major" : 1,
"minor" : 0
}
}

View File

@@ -1,43 +0,0 @@
{
"configurations" :
[
{
"directories" :
[
{
"build" : ".",
"jsonFile" : "directory-.-release-f5ebdc15457944623624.json",
"minimumCMakeVersion" :
{
"string" : "3.6.0"
},
"projectIndex" : 0,
"source" : "."
}
],
"name" : "release",
"projects" :
[
{
"directoryIndexes" :
[
0
],
"name" : "Project"
}
],
"targets" : []
}
],
"kind" : "codemodel",
"paths" :
{
"build" : "/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a",
"source" : "/home/pierre/dev/flutter/packages/flutter_tools/gradle/src/main/scripts"
},
"version" :
{
"major" : 2,
"minor" : 3
}
}

View File

@@ -1,14 +0,0 @@
{
"backtraceGraph" :
{
"commands" : [],
"files" : [],
"nodes" : []
},
"installers" : [],
"paths" :
{
"build" : ".",
"source" : "."
}
}

View File

@@ -1,92 +0,0 @@
{
"cmake" :
{
"generator" :
{
"multiConfig" : false,
"name" : "Ninja"
},
"paths" :
{
"cmake" : "/home/pierre/Android/Sdk/cmake/3.22.1/bin/cmake",
"cpack" : "/home/pierre/Android/Sdk/cmake/3.22.1/bin/cpack",
"ctest" : "/home/pierre/Android/Sdk/cmake/3.22.1/bin/ctest",
"root" : "/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22"
},
"version" :
{
"isDirty" : false,
"major" : 3,
"minor" : 22,
"patch" : 1,
"string" : "3.22.1-g37088a8",
"suffix" : "g37088a8"
}
},
"objects" :
[
{
"jsonFile" : "codemodel-v2-3e8fcb0f18d08e82c202.json",
"kind" : "codemodel",
"version" :
{
"major" : 2,
"minor" : 3
}
},
{
"jsonFile" : "cache-v2-b9fd1038ca8f5360552b.json",
"kind" : "cache",
"version" :
{
"major" : 2,
"minor" : 0
}
},
{
"jsonFile" : "cmakeFiles-v1-6ada4372188de4832272.json",
"kind" : "cmakeFiles",
"version" :
{
"major" : 1,
"minor" : 0
}
}
],
"reply" :
{
"client-agp" :
{
"cache-v2" :
{
"jsonFile" : "cache-v2-b9fd1038ca8f5360552b.json",
"kind" : "cache",
"version" :
{
"major" : 2,
"minor" : 0
}
},
"cmakeFiles-v1" :
{
"jsonFile" : "cmakeFiles-v1-6ada4372188de4832272.json",
"kind" : "cmakeFiles",
"version" :
{
"major" : 1,
"minor" : 0
}
},
"codemodel-v2" :
{
"jsonFile" : "codemodel-v2-3e8fcb0f18d08e82c202.json",
"kind" : "codemodel",
"version" :
{
"major" : 2,
"minor" : 3
}
}
}
}
}

View File

@@ -1,403 +0,0 @@
# This is the CMakeCache file.
# For build in directory: /home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a
# It was generated by CMake: /home/pierre/Android/Sdk/cmake/3.22.1/bin/cmake
# You can edit this file to change values found and used by cmake.
# If you do not want to change any of the values, simply exit the editor.
# If you do want to change a value, simply edit, save, and exit the editor.
# The syntax for the file is as follows:
# KEY:TYPE=VALUE
# KEY is the name of a variable in the cache.
# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!.
# VALUE is the current value for the KEY.
########################
# EXTERNAL cache entries
########################
//No help, variable specified on the command line.
ANDROID_ABI:UNINITIALIZED=arm64-v8a
//No help, variable specified on the command line.
ANDROID_NDK:UNINITIALIZED=/home/pierre/Android/Sdk/ndk/27.0.12077973
//No help, variable specified on the command line.
ANDROID_PLATFORM:UNINITIALIZED=android-24
//Path to a program.
CMAKE_ADDR2LINE:FILEPATH=/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-addr2line
//No help, variable specified on the command line.
CMAKE_ANDROID_ARCH_ABI:UNINITIALIZED=arm64-v8a
//No help, variable specified on the command line.
CMAKE_ANDROID_NDK:UNINITIALIZED=/home/pierre/Android/Sdk/ndk/27.0.12077973
//Archiver
CMAKE_AR:FILEPATH=/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar
//Flags used by the compiler during all build types.
CMAKE_ASM_FLAGS:STRING=
//Flags used by the compiler during debug builds.
CMAKE_ASM_FLAGS_DEBUG:STRING=
//Flags used by the compiler during release builds.
CMAKE_ASM_FLAGS_RELEASE:STRING=
//Choose the type of build, options are: None Debug Release RelWithDebInfo
// MinSizeRel ...
CMAKE_BUILD_TYPE:STRING=release
//LLVM archiver
CMAKE_CXX_COMPILER_AR:FILEPATH=/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar
//Generate index for LLVM archive
CMAKE_CXX_COMPILER_RANLIB:FILEPATH=/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ranlib
//Flags used by the compiler during all build types.
CMAKE_CXX_FLAGS:STRING=
//Flags used by the compiler during debug builds.
CMAKE_CXX_FLAGS_DEBUG:STRING=
//Flags used by the CXX compiler during MINSIZEREL builds.
CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG
//Flags used by the compiler during release builds.
CMAKE_CXX_FLAGS_RELEASE:STRING=
//Flags used by the CXX compiler during RELWITHDEBINFO builds.
CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG
//Libraries linked by default with all C++ applications.
CMAKE_CXX_STANDARD_LIBRARIES:STRING=-latomic -lm
//LLVM archiver
CMAKE_C_COMPILER_AR:FILEPATH=/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar
//Generate index for LLVM archive
CMAKE_C_COMPILER_RANLIB:FILEPATH=/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ranlib
//Flags used by the compiler during all build types.
CMAKE_C_FLAGS:STRING=
//Flags used by the compiler during debug builds.
CMAKE_C_FLAGS_DEBUG:STRING=
//Flags used by the C compiler during MINSIZEREL builds.
CMAKE_C_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG
//Flags used by the compiler during release builds.
CMAKE_C_FLAGS_RELEASE:STRING=
//Flags used by the C compiler during RELWITHDEBINFO builds.
CMAKE_C_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG
//Libraries linked by default with all C applications.
CMAKE_C_STANDARD_LIBRARIES:STRING=-latomic -lm
//Path to a program.
CMAKE_DLLTOOL:FILEPATH=/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-dlltool
//Flags used by the linker.
CMAKE_EXE_LINKER_FLAGS:STRING=
//Flags used by the linker during DEBUG builds.
CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING=
//Flags used by the linker during MINSIZEREL builds.
CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING=
//Flags used by the linker during RELEASE builds.
CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING=
//Flags used by the linker during RELWITHDEBINFO builds.
CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING=
//No help, variable specified on the command line.
CMAKE_EXPORT_COMPILE_COMMANDS:UNINITIALIZED=ON
//Install path prefix, prepended onto install directories.
CMAKE_INSTALL_PREFIX:PATH=/usr/local
//No help, variable specified on the command line.
CMAKE_LIBRARY_OUTPUT_DIRECTORY:UNINITIALIZED=/home/pierre/dev/geosector/app/build/app/intermediates/cxx/release/3j2a1x3f/obj/arm64-v8a
//Path to a program.
CMAKE_LINKER:FILEPATH=/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/ld.lld
//No help, variable specified on the command line.
CMAKE_MAKE_PROGRAM:UNINITIALIZED=/home/pierre/Android/Sdk/cmake/3.22.1/bin/ninja
//Flags used by the linker during the creation of modules.
CMAKE_MODULE_LINKER_FLAGS:STRING=
//Flags used by the linker during the creation of modules during
// DEBUG builds.
CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING=
//Flags used by the linker during the creation of modules during
// MINSIZEREL builds.
CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING=
//Flags used by the linker during the creation of modules during
// RELEASE builds.
CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING=
//Flags used by the linker during the creation of modules during
// RELWITHDEBINFO builds.
CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING=
//Path to a program.
CMAKE_NM:FILEPATH=/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-nm
//Path to a program.
CMAKE_OBJCOPY:FILEPATH=/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-objcopy
//Path to a program.
CMAKE_OBJDUMP:FILEPATH=/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-objdump
//Value Computed by CMake
CMAKE_PROJECT_DESCRIPTION:STATIC=
//Value Computed by CMake
CMAKE_PROJECT_HOMEPAGE_URL:STATIC=
//Value Computed by CMake
CMAKE_PROJECT_NAME:STATIC=Project
//Ranlib
CMAKE_RANLIB:FILEPATH=/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ranlib
//Path to a program.
CMAKE_READELF:FILEPATH=/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-readelf
//No help, variable specified on the command line.
CMAKE_RUNTIME_OUTPUT_DIRECTORY:UNINITIALIZED=/home/pierre/dev/geosector/app/build/app/intermediates/cxx/release/3j2a1x3f/obj/arm64-v8a
//Flags used by the linker during the creation of dll's.
CMAKE_SHARED_LINKER_FLAGS:STRING=
//Flags used by the linker during the creation of shared libraries
// during DEBUG builds.
CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING=
//Flags used by the linker during the creation of shared libraries
// during MINSIZEREL builds.
CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING=
//Flags used by the linker during the creation of shared libraries
// during RELEASE builds.
CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING=
//Flags used by the linker during the creation of shared libraries
// during RELWITHDEBINFO builds.
CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING=
//If set, runtime paths are not added when installing shared libraries,
// but are added when building.
CMAKE_SKIP_INSTALL_RPATH:BOOL=NO
//If set, runtime paths are not added when using shared libraries.
CMAKE_SKIP_RPATH:BOOL=NO
//Flags used by the linker during the creation of static libraries
// during all build types.
CMAKE_STATIC_LINKER_FLAGS:STRING=
//Flags used by the linker during the creation of static libraries
// during DEBUG builds.
CMAKE_STATIC_LINKER_FLAGS_DEBUG:STRING=
//Flags used by the linker during the creation of static libraries
// during MINSIZEREL builds.
CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL:STRING=
//Flags used by the linker during the creation of static libraries
// during RELEASE builds.
CMAKE_STATIC_LINKER_FLAGS_RELEASE:STRING=
//Flags used by the linker during the creation of static libraries
// during RELWITHDEBINFO builds.
CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO:STRING=
//Strip
CMAKE_STRIP:FILEPATH=/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip
//No help, variable specified on the command line.
CMAKE_SYSTEM_NAME:UNINITIALIZED=Android
//No help, variable specified on the command line.
CMAKE_SYSTEM_VERSION:UNINITIALIZED=24
//The CMake toolchain file
CMAKE_TOOLCHAIN_FILE:FILEPATH=/home/pierre/Android/Sdk/ndk/27.0.12077973/build/cmake/android.toolchain.cmake
//If this value is on, makefiles will be generated without the
// .SILENT directive, and all commands will be echoed to the console
// during the make. This is useful for debugging only. With Visual
// Studio IDE projects all commands are done without /nologo.
CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE
//Value Computed by CMake
Project_BINARY_DIR:STATIC=/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a
//Value Computed by CMake
Project_IS_TOP_LEVEL:STATIC=ON
//Value Computed by CMake
Project_SOURCE_DIR:STATIC=/home/pierre/dev/flutter/packages/flutter_tools/gradle/src/main/scripts
########################
# INTERNAL cache entries
########################
//ADVANCED property for variable: CMAKE_ADDR2LINE
CMAKE_ADDR2LINE-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_AR
CMAKE_AR-ADVANCED:INTERNAL=1
//This is the directory where this CMakeCache.txt was created
CMAKE_CACHEFILE_DIR:INTERNAL=/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a
//Major version of cmake used to create the current loaded cache
CMAKE_CACHE_MAJOR_VERSION:INTERNAL=3
//Minor version of cmake used to create the current loaded cache
CMAKE_CACHE_MINOR_VERSION:INTERNAL=22
//Patch version of cmake used to create the current loaded cache
CMAKE_CACHE_PATCH_VERSION:INTERNAL=1
//Path to CMake executable.
CMAKE_COMMAND:INTERNAL=/home/pierre/Android/Sdk/cmake/3.22.1/bin/cmake
//Path to cpack program executable.
CMAKE_CPACK_COMMAND:INTERNAL=/home/pierre/Android/Sdk/cmake/3.22.1/bin/cpack
//Path to ctest program executable.
CMAKE_CTEST_COMMAND:INTERNAL=/home/pierre/Android/Sdk/cmake/3.22.1/bin/ctest
//ADVANCED property for variable: CMAKE_CXX_COMPILER_AR
CMAKE_CXX_COMPILER_AR-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_CXX_COMPILER_RANLIB
CMAKE_CXX_COMPILER_RANLIB-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_CXX_FLAGS
CMAKE_CXX_FLAGS-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_CXX_FLAGS_DEBUG
CMAKE_CXX_FLAGS_DEBUG-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_CXX_FLAGS_MINSIZEREL
CMAKE_CXX_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELWITHDEBINFO
CMAKE_CXX_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_CXX_STANDARD_LIBRARIES
CMAKE_CXX_STANDARD_LIBRARIES-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_C_COMPILER_AR
CMAKE_C_COMPILER_AR-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_C_COMPILER_RANLIB
CMAKE_C_COMPILER_RANLIB-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_C_FLAGS
CMAKE_C_FLAGS-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_C_FLAGS_DEBUG
CMAKE_C_FLAGS_DEBUG-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_C_FLAGS_MINSIZEREL
CMAKE_C_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_RELEASE-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_C_FLAGS_RELWITHDEBINFO
CMAKE_C_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_C_STANDARD_LIBRARIES
CMAKE_C_STANDARD_LIBRARIES-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_DLLTOOL
CMAKE_DLLTOOL-ADVANCED:INTERNAL=1
//Whether to issue deprecation errors for macros and functions.
CMAKE_ERROR_DEPRECATED:INTERNAL=FALSE
//Executable file format
CMAKE_EXECUTABLE_FORMAT:INTERNAL=ELF
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS
CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG
CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL
CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE
CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO
CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
//Name of external makefile project generator.
CMAKE_EXTRA_GENERATOR:INTERNAL=
//Name of generator.
CMAKE_GENERATOR:INTERNAL=Ninja
//Generator instance identifier.
CMAKE_GENERATOR_INSTANCE:INTERNAL=
//Name of generator platform.
CMAKE_GENERATOR_PLATFORM:INTERNAL=
//Name of generator toolset.
CMAKE_GENERATOR_TOOLSET:INTERNAL=
//Source directory with the top level CMakeLists.txt file for this
// project
CMAKE_HOME_DIRECTORY:INTERNAL=/home/pierre/dev/flutter/packages/flutter_tools/gradle/src/main/scripts
//Install .so files without execute permission.
CMAKE_INSTALL_SO_NO_EXE:INTERNAL=1
//ADVANCED property for variable: CMAKE_LINKER
CMAKE_LINKER-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS
CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG
CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL
CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE
CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO
CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_NM
CMAKE_NM-ADVANCED:INTERNAL=1
//number of local generators
CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=1
//ADVANCED property for variable: CMAKE_OBJCOPY
CMAKE_OBJCOPY-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_OBJDUMP
CMAKE_OBJDUMP-ADVANCED:INTERNAL=1
//Platform information initialized
CMAKE_PLATFORM_INFO_INITIALIZED:INTERNAL=1
//ADVANCED property for variable: CMAKE_RANLIB
CMAKE_RANLIB-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_READELF
CMAKE_READELF-ADVANCED:INTERNAL=1
//Path to CMake installation.
CMAKE_ROOT:INTERNAL=/home/pierre/Android/Sdk/cmake/3.22.1/share/cmake-3.22
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS
CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG
CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL
CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE
CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO
CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_SKIP_INSTALL_RPATH
CMAKE_SKIP_INSTALL_RPATH-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_SKIP_RPATH
CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS
CMAKE_STATIC_LINKER_FLAGS-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_DEBUG
CMAKE_STATIC_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL
CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELEASE
CMAKE_STATIC_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO
CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
//ADVANCED property for variable: CMAKE_STRIP
CMAKE_STRIP-ADVANCED:INTERNAL=1
//Suppress errors that are meant for the author of the CMakeLists.txt
// files.
CMAKE_SUPPRESS_DEVELOPER_ERRORS:INTERNAL=TRUE
//Suppress Warnings that are meant for the author of the CMakeLists.txt
// files.
CMAKE_SUPPRESS_DEVELOPER_WARNINGS:INTERNAL=TRUE
//uname command
CMAKE_UNAME:INTERNAL=/usr/bin/uname
//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE
CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1
//Whether to issue warnings for deprecated functionality.
CMAKE_WARN_DEPRECATED:INTERNAL=FALSE

View File

@@ -1,72 +0,0 @@
set(CMAKE_C_COMPILER "/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/clang")
set(CMAKE_C_COMPILER_ARG1 "")
set(CMAKE_C_COMPILER_ID "Clang")
set(CMAKE_C_COMPILER_VERSION "18.0.1")
set(CMAKE_C_COMPILER_VERSION_INTERNAL "")
set(CMAKE_C_COMPILER_WRAPPER "")
set(CMAKE_C_STANDARD_COMPUTED_DEFAULT "17")
set(CMAKE_C_EXTENSIONS_COMPUTED_DEFAULT "ON")
set(CMAKE_C_COMPILE_FEATURES "c_std_90;c_function_prototypes;c_std_99;c_restrict;c_variadic_macros;c_std_11;c_static_assert;c_std_17;c_std_23")
set(CMAKE_C90_COMPILE_FEATURES "c_std_90;c_function_prototypes")
set(CMAKE_C99_COMPILE_FEATURES "c_std_99;c_restrict;c_variadic_macros")
set(CMAKE_C11_COMPILE_FEATURES "c_std_11;c_static_assert")
set(CMAKE_C17_COMPILE_FEATURES "c_std_17")
set(CMAKE_C23_COMPILE_FEATURES "c_std_23")
set(CMAKE_C_PLATFORM_ID "Linux")
set(CMAKE_C_SIMULATE_ID "")
set(CMAKE_C_COMPILER_FRONTEND_VARIANT "GNU")
set(CMAKE_C_SIMULATE_VERSION "")
set(CMAKE_AR "/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar")
set(CMAKE_C_COMPILER_AR "/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar")
set(CMAKE_RANLIB "/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ranlib")
set(CMAKE_C_COMPILER_RANLIB "/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ranlib")
set(CMAKE_LINKER "/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/ld.lld")
set(CMAKE_MT "")
set(CMAKE_COMPILER_IS_GNUCC )
set(CMAKE_C_COMPILER_LOADED 1)
set(CMAKE_C_COMPILER_WORKS TRUE)
set(CMAKE_C_ABI_COMPILED TRUE)
set(CMAKE_C_COMPILER_ENV_VAR "CC")
set(CMAKE_C_COMPILER_ID_RUN 1)
set(CMAKE_C_SOURCE_FILE_EXTENSIONS c;m)
set(CMAKE_C_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC)
set(CMAKE_C_LINKER_PREFERENCE 10)
# Save compiler ABI information.
set(CMAKE_C_SIZEOF_DATA_PTR "8")
set(CMAKE_C_COMPILER_ABI "ELF")
set(CMAKE_C_BYTE_ORDER "LITTLE_ENDIAN")
set(CMAKE_C_LIBRARY_ARCHITECTURE "")
if(CMAKE_C_SIZEOF_DATA_PTR)
set(CMAKE_SIZEOF_VOID_P "${CMAKE_C_SIZEOF_DATA_PTR}")
endif()
if(CMAKE_C_COMPILER_ABI)
set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_C_COMPILER_ABI}")
endif()
if(CMAKE_C_LIBRARY_ARCHITECTURE)
set(CMAKE_LIBRARY_ARCHITECTURE "")
endif()
set(CMAKE_C_CL_SHOWINCLUDES_PREFIX "")
if(CMAKE_C_CL_SHOWINCLUDES_PREFIX)
set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_C_CL_SHOWINCLUDES_PREFIX}")
endif()
set(CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES "/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/lib/clang/18/include;/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/aarch64-linux-android;/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include")
set(CMAKE_C_IMPLICIT_LINK_LIBRARIES "-l:libunwind.a;dl;c;-l:libunwind.a;dl")
set(CMAKE_C_IMPLICIT_LINK_DIRECTORIES "/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/lib/clang/18/lib/linux/aarch64;/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/24;/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android;/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib")
set(CMAKE_C_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "")

View File

@@ -1,83 +0,0 @@
set(CMAKE_CXX_COMPILER "/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++")
set(CMAKE_CXX_COMPILER_ARG1 "")
set(CMAKE_CXX_COMPILER_ID "Clang")
set(CMAKE_CXX_COMPILER_VERSION "18.0.1")
set(CMAKE_CXX_COMPILER_VERSION_INTERNAL "")
set(CMAKE_CXX_COMPILER_WRAPPER "")
set(CMAKE_CXX_STANDARD_COMPUTED_DEFAULT "17")
set(CMAKE_CXX_EXTENSIONS_COMPUTED_DEFAULT "ON")
set(CMAKE_CXX_COMPILE_FEATURES "cxx_std_98;cxx_template_template_parameters;cxx_std_11;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates;cxx_std_14;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates;cxx_std_17;cxx_std_20;cxx_std_23")
set(CMAKE_CXX98_COMPILE_FEATURES "cxx_std_98;cxx_template_template_parameters")
set(CMAKE_CXX11_COMPILE_FEATURES "cxx_std_11;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates")
set(CMAKE_CXX14_COMPILE_FEATURES "cxx_std_14;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates")
set(CMAKE_CXX17_COMPILE_FEATURES "cxx_std_17")
set(CMAKE_CXX20_COMPILE_FEATURES "cxx_std_20")
set(CMAKE_CXX23_COMPILE_FEATURES "cxx_std_23")
set(CMAKE_CXX_PLATFORM_ID "Linux")
set(CMAKE_CXX_SIMULATE_ID "")
set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "GNU")
set(CMAKE_CXX_SIMULATE_VERSION "")
set(CMAKE_AR "/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar")
set(CMAKE_CXX_COMPILER_AR "/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar")
set(CMAKE_RANLIB "/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ranlib")
set(CMAKE_CXX_COMPILER_RANLIB "/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ranlib")
set(CMAKE_LINKER "/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/ld.lld")
set(CMAKE_MT "")
set(CMAKE_COMPILER_IS_GNUCXX )
set(CMAKE_CXX_COMPILER_LOADED 1)
set(CMAKE_CXX_COMPILER_WORKS TRUE)
set(CMAKE_CXX_ABI_COMPILED TRUE)
set(CMAKE_CXX_COMPILER_ENV_VAR "CXX")
set(CMAKE_CXX_COMPILER_ID_RUN 1)
set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;m;mm;mpp;CPP;ixx;cppm)
set(CMAKE_CXX_IGNORE_EXTENSIONS inl;h;hpp;HPP;H;o;O;obj;OBJ;def;DEF;rc;RC)
foreach (lang C OBJC OBJCXX)
if (CMAKE_${lang}_COMPILER_ID_RUN)
foreach(extension IN LISTS CMAKE_${lang}_SOURCE_FILE_EXTENSIONS)
list(REMOVE_ITEM CMAKE_CXX_SOURCE_FILE_EXTENSIONS ${extension})
endforeach()
endif()
endforeach()
set(CMAKE_CXX_LINKER_PREFERENCE 30)
set(CMAKE_CXX_LINKER_PREFERENCE_PROPAGATES 1)
# Save compiler ABI information.
set(CMAKE_CXX_SIZEOF_DATA_PTR "8")
set(CMAKE_CXX_COMPILER_ABI "ELF")
set(CMAKE_CXX_BYTE_ORDER "LITTLE_ENDIAN")
set(CMAKE_CXX_LIBRARY_ARCHITECTURE "")
if(CMAKE_CXX_SIZEOF_DATA_PTR)
set(CMAKE_SIZEOF_VOID_P "${CMAKE_CXX_SIZEOF_DATA_PTR}")
endif()
if(CMAKE_CXX_COMPILER_ABI)
set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_CXX_COMPILER_ABI}")
endif()
if(CMAKE_CXX_LIBRARY_ARCHITECTURE)
set(CMAKE_LIBRARY_ARCHITECTURE "")
endif()
set(CMAKE_CXX_CL_SHOWINCLUDES_PREFIX "")
if(CMAKE_CXX_CL_SHOWINCLUDES_PREFIX)
set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_CXX_CL_SHOWINCLUDES_PREFIX}")
endif()
set(CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES "/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/c++/v1;/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/lib/clang/18/include;/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/aarch64-linux-android;/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include")
set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "c++;m;-l:libunwind.a;dl;c;-l:libunwind.a;dl")
set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/lib/clang/18/lib/linux/aarch64;/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/24;/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android;/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib")
set(CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "")

View File

@@ -1,15 +0,0 @@
set(CMAKE_HOST_SYSTEM "Linux-6.12.38+deb13-amd64")
set(CMAKE_HOST_SYSTEM_NAME "Linux")
set(CMAKE_HOST_SYSTEM_VERSION "6.12.38+deb13-amd64")
set(CMAKE_HOST_SYSTEM_PROCESSOR "x86_64")
include("/home/pierre/Android/Sdk/ndk/27.0.12077973/build/cmake/android.toolchain.cmake")
set(CMAKE_SYSTEM "Android-1")
set(CMAKE_SYSTEM_NAME "Android")
set(CMAKE_SYSTEM_VERSION "1")
set(CMAKE_SYSTEM_PROCESSOR "aarch64")
set(CMAKE_CROSSCOMPILING "TRUE")
set(CMAKE_SYSTEM_LOADED 1)

View File

@@ -1,803 +0,0 @@
#ifdef __cplusplus
# error "A C++ compiler has been selected for C."
#endif
#if defined(__18CXX)
# define ID_VOID_MAIN
#endif
#if defined(__CLASSIC_C__)
/* cv-qualifiers did not exist in K&R C */
# define const
# define volatile
#endif
#if !defined(__has_include)
/* If the compiler does not have __has_include, pretend the answer is
always no. */
# define __has_include(x) 0
#endif
/* Version number components: V=Version, R=Revision, P=Patch
Version date components: YYYY=Year, MM=Month, DD=Day */
#if defined(__INTEL_COMPILER) || defined(__ICC)
# define COMPILER_ID "Intel"
# if defined(_MSC_VER)
# define SIMULATE_ID "MSVC"
# endif
# if defined(__GNUC__)
# define SIMULATE_ID "GNU"
# endif
/* __INTEL_COMPILER = VRP prior to 2021, and then VVVV for 2021 and later,
except that a few beta releases use the old format with V=2021. */
# if __INTEL_COMPILER < 2021 || __INTEL_COMPILER == 202110 || __INTEL_COMPILER == 202111
# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100)
# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10)
# if defined(__INTEL_COMPILER_UPDATE)
# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER_UPDATE)
# else
# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER % 10)
# endif
# else
# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER)
# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER_UPDATE)
/* The third version component from --version is an update index,
but no macro is provided for it. */
# define COMPILER_VERSION_PATCH DEC(0)
# endif
# if defined(__INTEL_COMPILER_BUILD_DATE)
/* __INTEL_COMPILER_BUILD_DATE = YYYYMMDD */
# define COMPILER_VERSION_TWEAK DEC(__INTEL_COMPILER_BUILD_DATE)
# endif
# if defined(_MSC_VER)
/* _MSC_VER = VVRR */
# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
# endif
# if defined(__GNUC__)
# define SIMULATE_VERSION_MAJOR DEC(__GNUC__)
# elif defined(__GNUG__)
# define SIMULATE_VERSION_MAJOR DEC(__GNUG__)
# endif
# if defined(__GNUC_MINOR__)
# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__)
# endif
# if defined(__GNUC_PATCHLEVEL__)
# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
# endif
#elif (defined(__clang__) && defined(__INTEL_CLANG_COMPILER)) || defined(__INTEL_LLVM_COMPILER)
# define COMPILER_ID "IntelLLVM"
#if defined(_MSC_VER)
# define SIMULATE_ID "MSVC"
#endif
#if defined(__GNUC__)
# define SIMULATE_ID "GNU"
#endif
/* __INTEL_LLVM_COMPILER = VVVVRP prior to 2021.2.0, VVVVRRPP for 2021.2.0 and
* later. Look for 6 digit vs. 8 digit version number to decide encoding.
* VVVV is no smaller than the current year when a version is released.
*/
#if __INTEL_LLVM_COMPILER < 1000000L
# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/100)
# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/10 % 10)
# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER % 10)
#else
# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/10000)
# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/100 % 100)
# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER % 100)
#endif
#if defined(_MSC_VER)
/* _MSC_VER = VVRR */
# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
#endif
#if defined(__GNUC__)
# define SIMULATE_VERSION_MAJOR DEC(__GNUC__)
#elif defined(__GNUG__)
# define SIMULATE_VERSION_MAJOR DEC(__GNUG__)
#endif
#if defined(__GNUC_MINOR__)
# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__)
#endif
#if defined(__GNUC_PATCHLEVEL__)
# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
#endif
#elif defined(__PATHCC__)
# define COMPILER_ID "PathScale"
# define COMPILER_VERSION_MAJOR DEC(__PATHCC__)
# define COMPILER_VERSION_MINOR DEC(__PATHCC_MINOR__)
# if defined(__PATHCC_PATCHLEVEL__)
# define COMPILER_VERSION_PATCH DEC(__PATHCC_PATCHLEVEL__)
# endif
#elif defined(__BORLANDC__) && defined(__CODEGEARC_VERSION__)
# define COMPILER_ID "Embarcadero"
# define COMPILER_VERSION_MAJOR HEX(__CODEGEARC_VERSION__>>24 & 0x00FF)
# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF)
# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__ & 0xFFFF)
#elif defined(__BORLANDC__)
# define COMPILER_ID "Borland"
/* __BORLANDC__ = 0xVRR */
# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8)
# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF)
#elif defined(__WATCOMC__) && __WATCOMC__ < 1200
# define COMPILER_ID "Watcom"
/* __WATCOMC__ = VVRR */
# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100)
# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10)
# if (__WATCOMC__ % 10) > 0
# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10)
# endif
#elif defined(__WATCOMC__)
# define COMPILER_ID "OpenWatcom"
/* __WATCOMC__ = VVRP + 1100 */
# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100)
# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10)
# if (__WATCOMC__ % 10) > 0
# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10)
# endif
#elif defined(__SUNPRO_C)
# define COMPILER_ID "SunPro"
# if __SUNPRO_C >= 0x5100
/* __SUNPRO_C = 0xVRRP */
# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_C>>12)
# define COMPILER_VERSION_MINOR HEX(__SUNPRO_C>>4 & 0xFF)
# define COMPILER_VERSION_PATCH HEX(__SUNPRO_C & 0xF)
# else
/* __SUNPRO_CC = 0xVRP */
# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_C>>8)
# define COMPILER_VERSION_MINOR HEX(__SUNPRO_C>>4 & 0xF)
# define COMPILER_VERSION_PATCH HEX(__SUNPRO_C & 0xF)
# endif
#elif defined(__HP_cc)
# define COMPILER_ID "HP"
/* __HP_cc = VVRRPP */
# define COMPILER_VERSION_MAJOR DEC(__HP_cc/10000)
# define COMPILER_VERSION_MINOR DEC(__HP_cc/100 % 100)
# define COMPILER_VERSION_PATCH DEC(__HP_cc % 100)
#elif defined(__DECC)
# define COMPILER_ID "Compaq"
/* __DECC_VER = VVRRTPPPP */
# define COMPILER_VERSION_MAJOR DEC(__DECC_VER/10000000)
# define COMPILER_VERSION_MINOR DEC(__DECC_VER/100000 % 100)
# define COMPILER_VERSION_PATCH DEC(__DECC_VER % 10000)
#elif defined(__IBMC__) && defined(__COMPILER_VER__)
# define COMPILER_ID "zOS"
/* __IBMC__ = VRP */
# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100)
# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10)
# define COMPILER_VERSION_PATCH DEC(__IBMC__ % 10)
#elif defined(__ibmxl__) && defined(__clang__)
# define COMPILER_ID "XLClang"
# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__)
# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__)
# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__)
# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__)
#elif defined(__IBMC__) && !defined(__COMPILER_VER__) && __IBMC__ >= 800
# define COMPILER_ID "XL"
/* __IBMC__ = VRP */
# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100)
# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10)
# define COMPILER_VERSION_PATCH DEC(__IBMC__ % 10)
#elif defined(__IBMC__) && !defined(__COMPILER_VER__) && __IBMC__ < 800
# define COMPILER_ID "VisualAge"
/* __IBMC__ = VRP */
# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100)
# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10)
# define COMPILER_VERSION_PATCH DEC(__IBMC__ % 10)
#elif defined(__NVCOMPILER)
# define COMPILER_ID "NVHPC"
# define COMPILER_VERSION_MAJOR DEC(__NVCOMPILER_MAJOR__)
# define COMPILER_VERSION_MINOR DEC(__NVCOMPILER_MINOR__)
# if defined(__NVCOMPILER_PATCHLEVEL__)
# define COMPILER_VERSION_PATCH DEC(__NVCOMPILER_PATCHLEVEL__)
# endif
#elif defined(__PGI)
# define COMPILER_ID "PGI"
# define COMPILER_VERSION_MAJOR DEC(__PGIC__)
# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__)
# if defined(__PGIC_PATCHLEVEL__)
# define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__)
# endif
#elif defined(_CRAYC)
# define COMPILER_ID "Cray"
# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR)
# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR)
#elif defined(__TI_COMPILER_VERSION__)
# define COMPILER_ID "TI"
/* __TI_COMPILER_VERSION__ = VVVRRRPPP */
# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000)
# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000 % 1000)
# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__ % 1000)
#elif defined(__CLANG_FUJITSU)
# define COMPILER_ID "FujitsuClang"
# define COMPILER_VERSION_MAJOR DEC(__FCC_major__)
# define COMPILER_VERSION_MINOR DEC(__FCC_minor__)
# define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__)
# define COMPILER_VERSION_INTERNAL_STR __clang_version__
#elif defined(__FUJITSU)
# define COMPILER_ID "Fujitsu"
# if defined(__FCC_version__)
# define COMPILER_VERSION __FCC_version__
# elif defined(__FCC_major__)
# define COMPILER_VERSION_MAJOR DEC(__FCC_major__)
# define COMPILER_VERSION_MINOR DEC(__FCC_minor__)
# define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__)
# endif
# if defined(__fcc_version)
# define COMPILER_VERSION_INTERNAL DEC(__fcc_version)
# elif defined(__FCC_VERSION)
# define COMPILER_VERSION_INTERNAL DEC(__FCC_VERSION)
# endif
#elif defined(__ghs__)
# define COMPILER_ID "GHS"
/* __GHS_VERSION_NUMBER = VVVVRP */
# ifdef __GHS_VERSION_NUMBER
# define COMPILER_VERSION_MAJOR DEC(__GHS_VERSION_NUMBER / 100)
# define COMPILER_VERSION_MINOR DEC(__GHS_VERSION_NUMBER / 10 % 10)
# define COMPILER_VERSION_PATCH DEC(__GHS_VERSION_NUMBER % 10)
# endif
#elif defined(__TINYC__)
# define COMPILER_ID "TinyCC"
#elif defined(__BCC__)
# define COMPILER_ID "Bruce"
#elif defined(__SCO_VERSION__)
# define COMPILER_ID "SCO"
#elif defined(__ARMCC_VERSION) && !defined(__clang__)
# define COMPILER_ID "ARMCC"
#if __ARMCC_VERSION >= 1000000
/* __ARMCC_VERSION = VRRPPPP */
# define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000)
# define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100)
# define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000)
#else
/* __ARMCC_VERSION = VRPPPP */
# define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000)
# define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10)
# define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000)
#endif
#elif defined(__clang__) && defined(__apple_build_version__)
# define COMPILER_ID "AppleClang"
# if defined(_MSC_VER)
# define SIMULATE_ID "MSVC"
# endif
# define COMPILER_VERSION_MAJOR DEC(__clang_major__)
# define COMPILER_VERSION_MINOR DEC(__clang_minor__)
# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__)
# if defined(_MSC_VER)
/* _MSC_VER = VVRR */
# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
# endif
# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__)
#elif defined(__clang__) && defined(__ARMCOMPILER_VERSION)
# define COMPILER_ID "ARMClang"
# define COMPILER_VERSION_MAJOR DEC(__ARMCOMPILER_VERSION/1000000)
# define COMPILER_VERSION_MINOR DEC(__ARMCOMPILER_VERSION/10000 % 100)
# define COMPILER_VERSION_PATCH DEC(__ARMCOMPILER_VERSION % 10000)
# define COMPILER_VERSION_INTERNAL DEC(__ARMCOMPILER_VERSION)
#elif defined(__clang__)
# define COMPILER_ID "Clang"
# if defined(_MSC_VER)
# define SIMULATE_ID "MSVC"
# endif
# define COMPILER_VERSION_MAJOR DEC(__clang_major__)
# define COMPILER_VERSION_MINOR DEC(__clang_minor__)
# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__)
# if defined(_MSC_VER)
/* _MSC_VER = VVRR */
# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
# endif
#elif defined(__GNUC__)
# define COMPILER_ID "GNU"
# define COMPILER_VERSION_MAJOR DEC(__GNUC__)
# if defined(__GNUC_MINOR__)
# define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__)
# endif
# if defined(__GNUC_PATCHLEVEL__)
# define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
# endif
#elif defined(_MSC_VER)
# define COMPILER_ID "MSVC"
/* _MSC_VER = VVRR */
# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100)
# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100)
# if defined(_MSC_FULL_VER)
# if _MSC_VER >= 1400
/* _MSC_FULL_VER = VVRRPPPPP */
# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000)
# else
/* _MSC_FULL_VER = VVRRPPPP */
# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000)
# endif
# endif
# if defined(_MSC_BUILD)
# define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD)
# endif
#elif defined(__VISUALDSPVERSION__) || defined(__ADSPBLACKFIN__) || defined(__ADSPTS__) || defined(__ADSP21000__)
# define COMPILER_ID "ADSP"
#if defined(__VISUALDSPVERSION__)
/* __VISUALDSPVERSION__ = 0xVVRRPP00 */
# define COMPILER_VERSION_MAJOR HEX(__VISUALDSPVERSION__>>24)
# define COMPILER_VERSION_MINOR HEX(__VISUALDSPVERSION__>>16 & 0xFF)
# define COMPILER_VERSION_PATCH HEX(__VISUALDSPVERSION__>>8 & 0xFF)
#endif
#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC)
# define COMPILER_ID "IAR"
# if defined(__VER__) && defined(__ICCARM__)
# define COMPILER_VERSION_MAJOR DEC((__VER__) / 1000000)
# define COMPILER_VERSION_MINOR DEC(((__VER__) / 1000) % 1000)
# define COMPILER_VERSION_PATCH DEC((__VER__) % 1000)
# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__)
# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__) || defined(__ICCRISCV__) || defined(__ICCV850__) || defined(__ICC8051__) || defined(__ICCSTM8__))
# define COMPILER_VERSION_MAJOR DEC((__VER__) / 100)
# define COMPILER_VERSION_MINOR DEC((__VER__) - (((__VER__) / 100)*100))
# define COMPILER_VERSION_PATCH DEC(__SUBVERSION__)
# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__)
# endif
#elif defined(__SDCC_VERSION_MAJOR) || defined(SDCC)
# define COMPILER_ID "SDCC"
# if defined(__SDCC_VERSION_MAJOR)
# define COMPILER_VERSION_MAJOR DEC(__SDCC_VERSION_MAJOR)
# define COMPILER_VERSION_MINOR DEC(__SDCC_VERSION_MINOR)
# define COMPILER_VERSION_PATCH DEC(__SDCC_VERSION_PATCH)
# else
/* SDCC = VRP */
# define COMPILER_VERSION_MAJOR DEC(SDCC/100)
# define COMPILER_VERSION_MINOR DEC(SDCC/10 % 10)
# define COMPILER_VERSION_PATCH DEC(SDCC % 10)
# endif
/* These compilers are either not known or too old to define an
identification macro. Try to identify the platform and guess that
it is the native compiler. */
#elif defined(__hpux) || defined(__hpua)
# define COMPILER_ID "HP"
#else /* unknown compiler */
# define COMPILER_ID ""
#endif
/* Construct the string literal in pieces to prevent the source from
getting matched. Store it in a pointer rather than an array
because some compilers will just produce instructions to fill the
array rather than assigning a pointer to a static array. */
char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]";
#ifdef SIMULATE_ID
char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]";
#endif
#ifdef __QNXNTO__
char const* qnxnto = "INFO" ":" "qnxnto[]";
#endif
#if defined(__CRAYXT_COMPUTE_LINUX_TARGET)
char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]";
#endif
#define STRINGIFY_HELPER(X) #X
#define STRINGIFY(X) STRINGIFY_HELPER(X)
/* Identify known platforms by name. */
#if defined(__linux) || defined(__linux__) || defined(linux)
# define PLATFORM_ID "Linux"
#elif defined(__MSYS__)
# define PLATFORM_ID "MSYS"
#elif defined(__CYGWIN__)
# define PLATFORM_ID "Cygwin"
#elif defined(__MINGW32__)
# define PLATFORM_ID "MinGW"
#elif defined(__APPLE__)
# define PLATFORM_ID "Darwin"
#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
# define PLATFORM_ID "Windows"
#elif defined(__FreeBSD__) || defined(__FreeBSD)
# define PLATFORM_ID "FreeBSD"
#elif defined(__NetBSD__) || defined(__NetBSD)
# define PLATFORM_ID "NetBSD"
#elif defined(__OpenBSD__) || defined(__OPENBSD)
# define PLATFORM_ID "OpenBSD"
#elif defined(__sun) || defined(sun)
# define PLATFORM_ID "SunOS"
#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__)
# define PLATFORM_ID "AIX"
#elif defined(__hpux) || defined(__hpux__)
# define PLATFORM_ID "HP-UX"
#elif defined(__HAIKU__)
# define PLATFORM_ID "Haiku"
#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS)
# define PLATFORM_ID "BeOS"
#elif defined(__QNX__) || defined(__QNXNTO__)
# define PLATFORM_ID "QNX"
#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__)
# define PLATFORM_ID "Tru64"
#elif defined(__riscos) || defined(__riscos__)
# define PLATFORM_ID "RISCos"
#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__)
# define PLATFORM_ID "SINIX"
#elif defined(__UNIX_SV__)
# define PLATFORM_ID "UNIX_SV"
#elif defined(__bsdos__)
# define PLATFORM_ID "BSDOS"
#elif defined(_MPRAS) || defined(MPRAS)
# define PLATFORM_ID "MP-RAS"
#elif defined(__osf) || defined(__osf__)
# define PLATFORM_ID "OSF1"
#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv)
# define PLATFORM_ID "SCO_SV"
#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX)
# define PLATFORM_ID "ULTRIX"
#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX)
# define PLATFORM_ID "Xenix"
#elif defined(__WATCOMC__)
# if defined(__LINUX__)
# define PLATFORM_ID "Linux"
# elif defined(__DOS__)
# define PLATFORM_ID "DOS"
# elif defined(__OS2__)
# define PLATFORM_ID "OS2"
# elif defined(__WINDOWS__)
# define PLATFORM_ID "Windows3x"
# elif defined(__VXWORKS__)
# define PLATFORM_ID "VxWorks"
# else /* unknown platform */
# define PLATFORM_ID
# endif
#elif defined(__INTEGRITY)
# if defined(INT_178B)
# define PLATFORM_ID "Integrity178"
# else /* regular Integrity */
# define PLATFORM_ID "Integrity"
# endif
#else /* unknown platform */
# define PLATFORM_ID
#endif
/* For windows compilers MSVC and Intel we can determine
the architecture of the compiler being used. This is because
the compilers do not have flags that can change the architecture,
but rather depend on which compiler is being used
*/
#if defined(_WIN32) && defined(_MSC_VER)
# if defined(_M_IA64)
# define ARCHITECTURE_ID "IA64"
# elif defined(_M_ARM64EC)
# define ARCHITECTURE_ID "ARM64EC"
# elif defined(_M_X64) || defined(_M_AMD64)
# define ARCHITECTURE_ID "x64"
# elif defined(_M_IX86)
# define ARCHITECTURE_ID "X86"
# elif defined(_M_ARM64)
# define ARCHITECTURE_ID "ARM64"
# elif defined(_M_ARM)
# if _M_ARM == 4
# define ARCHITECTURE_ID "ARMV4I"
# elif _M_ARM == 5
# define ARCHITECTURE_ID "ARMV5I"
# else
# define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM)
# endif
# elif defined(_M_MIPS)
# define ARCHITECTURE_ID "MIPS"
# elif defined(_M_SH)
# define ARCHITECTURE_ID "SHx"
# else /* unknown architecture */
# define ARCHITECTURE_ID ""
# endif
#elif defined(__WATCOMC__)
# if defined(_M_I86)
# define ARCHITECTURE_ID "I86"
# elif defined(_M_IX86)
# define ARCHITECTURE_ID "X86"
# else /* unknown architecture */
# define ARCHITECTURE_ID ""
# endif
#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC)
# if defined(__ICCARM__)
# define ARCHITECTURE_ID "ARM"
# elif defined(__ICCRX__)
# define ARCHITECTURE_ID "RX"
# elif defined(__ICCRH850__)
# define ARCHITECTURE_ID "RH850"
# elif defined(__ICCRL78__)
# define ARCHITECTURE_ID "RL78"
# elif defined(__ICCRISCV__)
# define ARCHITECTURE_ID "RISCV"
# elif defined(__ICCAVR__)
# define ARCHITECTURE_ID "AVR"
# elif defined(__ICC430__)
# define ARCHITECTURE_ID "MSP430"
# elif defined(__ICCV850__)
# define ARCHITECTURE_ID "V850"
# elif defined(__ICC8051__)
# define ARCHITECTURE_ID "8051"
# elif defined(__ICCSTM8__)
# define ARCHITECTURE_ID "STM8"
# else /* unknown architecture */
# define ARCHITECTURE_ID ""
# endif
#elif defined(__ghs__)
# if defined(__PPC64__)
# define ARCHITECTURE_ID "PPC64"
# elif defined(__ppc__)
# define ARCHITECTURE_ID "PPC"
# elif defined(__ARM__)
# define ARCHITECTURE_ID "ARM"
# elif defined(__x86_64__)
# define ARCHITECTURE_ID "x64"
# elif defined(__i386__)
# define ARCHITECTURE_ID "X86"
# else /* unknown architecture */
# define ARCHITECTURE_ID ""
# endif
#elif defined(__TI_COMPILER_VERSION__)
# if defined(__TI_ARM__)
# define ARCHITECTURE_ID "ARM"
# elif defined(__MSP430__)
# define ARCHITECTURE_ID "MSP430"
# elif defined(__TMS320C28XX__)
# define ARCHITECTURE_ID "TMS320C28x"
# elif defined(__TMS320C6X__) || defined(_TMS320C6X)
# define ARCHITECTURE_ID "TMS320C6x"
# else /* unknown architecture */
# define ARCHITECTURE_ID ""
# endif
#else
# define ARCHITECTURE_ID
#endif
/* Convert integer to decimal digit literals. */
#define DEC(n) \
('0' + (((n) / 10000000)%10)), \
('0' + (((n) / 1000000)%10)), \
('0' + (((n) / 100000)%10)), \
('0' + (((n) / 10000)%10)), \
('0' + (((n) / 1000)%10)), \
('0' + (((n) / 100)%10)), \
('0' + (((n) / 10)%10)), \
('0' + ((n) % 10))
/* Convert integer to hex digit literals. */
#define HEX(n) \
('0' + ((n)>>28 & 0xF)), \
('0' + ((n)>>24 & 0xF)), \
('0' + ((n)>>20 & 0xF)), \
('0' + ((n)>>16 & 0xF)), \
('0' + ((n)>>12 & 0xF)), \
('0' + ((n)>>8 & 0xF)), \
('0' + ((n)>>4 & 0xF)), \
('0' + ((n) & 0xF))
/* Construct a string literal encoding the version number. */
#ifdef COMPILER_VERSION
char const* info_version = "INFO" ":" "compiler_version[" COMPILER_VERSION "]";
/* Construct a string literal encoding the version number components. */
#elif defined(COMPILER_VERSION_MAJOR)
char const info_version[] = {
'I', 'N', 'F', 'O', ':',
'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[',
COMPILER_VERSION_MAJOR,
# ifdef COMPILER_VERSION_MINOR
'.', COMPILER_VERSION_MINOR,
# ifdef COMPILER_VERSION_PATCH
'.', COMPILER_VERSION_PATCH,
# ifdef COMPILER_VERSION_TWEAK
'.', COMPILER_VERSION_TWEAK,
# endif
# endif
# endif
']','\0'};
#endif
/* Construct a string literal encoding the internal version number. */
#ifdef COMPILER_VERSION_INTERNAL
char const info_version_internal[] = {
'I', 'N', 'F', 'O', ':',
'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_',
'i','n','t','e','r','n','a','l','[',
COMPILER_VERSION_INTERNAL,']','\0'};
#elif defined(COMPILER_VERSION_INTERNAL_STR)
char const* info_version_internal = "INFO" ":" "compiler_version_internal[" COMPILER_VERSION_INTERNAL_STR "]";
#endif
/* Construct a string literal encoding the version number components. */
#ifdef SIMULATE_VERSION_MAJOR
char const info_simulate_version[] = {
'I', 'N', 'F', 'O', ':',
's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[',
SIMULATE_VERSION_MAJOR,
# ifdef SIMULATE_VERSION_MINOR
'.', SIMULATE_VERSION_MINOR,
# ifdef SIMULATE_VERSION_PATCH
'.', SIMULATE_VERSION_PATCH,
# ifdef SIMULATE_VERSION_TWEAK
'.', SIMULATE_VERSION_TWEAK,
# endif
# endif
# endif
']','\0'};
#endif
/* Construct the string literal in pieces to prevent the source from
getting matched. Store it in a pointer rather than an array
because some compilers will just produce instructions to fill the
array rather than assigning a pointer to a static array. */
char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]";
char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]";
#if !defined(__STDC__) && !defined(__clang__)
# if defined(_MSC_VER) || defined(__ibmxl__) || defined(__IBMC__)
# define C_VERSION "90"
# else
# define C_VERSION
# endif
#elif __STDC_VERSION__ > 201710L
# define C_VERSION "23"
#elif __STDC_VERSION__ >= 201710L
# define C_VERSION "17"
#elif __STDC_VERSION__ >= 201000L
# define C_VERSION "11"
#elif __STDC_VERSION__ >= 199901L
# define C_VERSION "99"
#else
# define C_VERSION "90"
#endif
const char* info_language_standard_default =
"INFO" ":" "standard_default[" C_VERSION "]";
const char* info_language_extensions_default = "INFO" ":" "extensions_default["
/* !defined(_MSC_VER) to exclude Clang's MSVC compatibility mode. */
#if (defined(__clang__) || defined(__GNUC__) || \
defined(__TI_COMPILER_VERSION__)) && \
!defined(__STRICT_ANSI__) && !defined(_MSC_VER)
"ON"
#else
"OFF"
#endif
"]";
/*--------------------------------------------------------------------------*/
#ifdef ID_VOID_MAIN
void main() {}
#else
# if defined(__CLASSIC_C__)
int main(argc, argv) int argc; char *argv[];
# else
int main(int argc, char* argv[])
# endif
{
int require = 0;
require += info_compiler[argc];
require += info_platform[argc];
require += info_arch[argc];
#ifdef COMPILER_VERSION_MAJOR
require += info_version[argc];
#endif
#ifdef COMPILER_VERSION_INTERNAL
require += info_version_internal[argc];
#endif
#ifdef SIMULATE_ID
require += info_simulate[argc];
#endif
#ifdef SIMULATE_VERSION_MAJOR
require += info_simulate_version[argc];
#endif
#if defined(__CRAYXT_COMPUTE_LINUX_TARGET)
require += info_cray[argc];
#endif
require += info_language_standard_default[argc];
require += info_language_extensions_default[argc];
(void)argv;
return require;
}
#endif

View File

@@ -1,791 +0,0 @@
/* This source file must have a .cpp extension so that all C++ compilers
recognize the extension without flags. Borland does not know .cxx for
example. */
#ifndef __cplusplus
# error "A C compiler has been selected for C++."
#endif
#if !defined(__has_include)
/* If the compiler does not have __has_include, pretend the answer is
always no. */
# define __has_include(x) 0
#endif
/* Version number components: V=Version, R=Revision, P=Patch
Version date components: YYYY=Year, MM=Month, DD=Day */
#if defined(__COMO__)
# define COMPILER_ID "Comeau"
/* __COMO_VERSION__ = VRR */
# define COMPILER_VERSION_MAJOR DEC(__COMO_VERSION__ / 100)
# define COMPILER_VERSION_MINOR DEC(__COMO_VERSION__ % 100)
#elif defined(__INTEL_COMPILER) || defined(__ICC)
# define COMPILER_ID "Intel"
# if defined(_MSC_VER)
# define SIMULATE_ID "MSVC"
# endif
# if defined(__GNUC__)
# define SIMULATE_ID "GNU"
# endif
/* __INTEL_COMPILER = VRP prior to 2021, and then VVVV for 2021 and later,
except that a few beta releases use the old format with V=2021. */
# if __INTEL_COMPILER < 2021 || __INTEL_COMPILER == 202110 || __INTEL_COMPILER == 202111
# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100)
# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10)
# if defined(__INTEL_COMPILER_UPDATE)
# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER_UPDATE)
# else
# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER % 10)
# endif
# else
# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER)
# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER_UPDATE)
/* The third version component from --version is an update index,
but no macro is provided for it. */
# define COMPILER_VERSION_PATCH DEC(0)
# endif
# if defined(__INTEL_COMPILER_BUILD_DATE)
/* __INTEL_COMPILER_BUILD_DATE = YYYYMMDD */
# define COMPILER_VERSION_TWEAK DEC(__INTEL_COMPILER_BUILD_DATE)
# endif
# if defined(_MSC_VER)
/* _MSC_VER = VVRR */
# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
# endif
# if defined(__GNUC__)
# define SIMULATE_VERSION_MAJOR DEC(__GNUC__)
# elif defined(__GNUG__)
# define SIMULATE_VERSION_MAJOR DEC(__GNUG__)
# endif
# if defined(__GNUC_MINOR__)
# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__)
# endif
# if defined(__GNUC_PATCHLEVEL__)
# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
# endif
#elif (defined(__clang__) && defined(__INTEL_CLANG_COMPILER)) || defined(__INTEL_LLVM_COMPILER)
# define COMPILER_ID "IntelLLVM"
#if defined(_MSC_VER)
# define SIMULATE_ID "MSVC"
#endif
#if defined(__GNUC__)
# define SIMULATE_ID "GNU"
#endif
/* __INTEL_LLVM_COMPILER = VVVVRP prior to 2021.2.0, VVVVRRPP for 2021.2.0 and
* later. Look for 6 digit vs. 8 digit version number to decide encoding.
* VVVV is no smaller than the current year when a version is released.
*/
#if __INTEL_LLVM_COMPILER < 1000000L
# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/100)
# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/10 % 10)
# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER % 10)
#else
# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/10000)
# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/100 % 100)
# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER % 100)
#endif
#if defined(_MSC_VER)
/* _MSC_VER = VVRR */
# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
#endif
#if defined(__GNUC__)
# define SIMULATE_VERSION_MAJOR DEC(__GNUC__)
#elif defined(__GNUG__)
# define SIMULATE_VERSION_MAJOR DEC(__GNUG__)
#endif
#if defined(__GNUC_MINOR__)
# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__)
#endif
#if defined(__GNUC_PATCHLEVEL__)
# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
#endif
#elif defined(__PATHCC__)
# define COMPILER_ID "PathScale"
# define COMPILER_VERSION_MAJOR DEC(__PATHCC__)
# define COMPILER_VERSION_MINOR DEC(__PATHCC_MINOR__)
# if defined(__PATHCC_PATCHLEVEL__)
# define COMPILER_VERSION_PATCH DEC(__PATHCC_PATCHLEVEL__)
# endif
#elif defined(__BORLANDC__) && defined(__CODEGEARC_VERSION__)
# define COMPILER_ID "Embarcadero"
# define COMPILER_VERSION_MAJOR HEX(__CODEGEARC_VERSION__>>24 & 0x00FF)
# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF)
# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__ & 0xFFFF)
#elif defined(__BORLANDC__)
# define COMPILER_ID "Borland"
/* __BORLANDC__ = 0xVRR */
# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8)
# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF)
#elif defined(__WATCOMC__) && __WATCOMC__ < 1200
# define COMPILER_ID "Watcom"
/* __WATCOMC__ = VVRR */
# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100)
# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10)
# if (__WATCOMC__ % 10) > 0
# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10)
# endif
#elif defined(__WATCOMC__)
# define COMPILER_ID "OpenWatcom"
/* __WATCOMC__ = VVRP + 1100 */
# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100)
# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10)
# if (__WATCOMC__ % 10) > 0
# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10)
# endif
#elif defined(__SUNPRO_CC)
# define COMPILER_ID "SunPro"
# if __SUNPRO_CC >= 0x5100
/* __SUNPRO_CC = 0xVRRP */
# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>12)
# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xFF)
# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF)
# else
/* __SUNPRO_CC = 0xVRP */
# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>8)
# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xF)
# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF)
# endif
#elif defined(__HP_aCC)
# define COMPILER_ID "HP"
/* __HP_aCC = VVRRPP */
# define COMPILER_VERSION_MAJOR DEC(__HP_aCC/10000)
# define COMPILER_VERSION_MINOR DEC(__HP_aCC/100 % 100)
# define COMPILER_VERSION_PATCH DEC(__HP_aCC % 100)
#elif defined(__DECCXX)
# define COMPILER_ID "Compaq"
/* __DECCXX_VER = VVRRTPPPP */
# define COMPILER_VERSION_MAJOR DEC(__DECCXX_VER/10000000)
# define COMPILER_VERSION_MINOR DEC(__DECCXX_VER/100000 % 100)
# define COMPILER_VERSION_PATCH DEC(__DECCXX_VER % 10000)
#elif defined(__IBMCPP__) && defined(__COMPILER_VER__)
# define COMPILER_ID "zOS"
/* __IBMCPP__ = VRP */
# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100)
# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10)
# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10)
#elif defined(__ibmxl__) && defined(__clang__)
# define COMPILER_ID "XLClang"
# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__)
# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__)
# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__)
# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__)
#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ >= 800
# define COMPILER_ID "XL"
/* __IBMCPP__ = VRP */
# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100)
# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10)
# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10)
#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ < 800
# define COMPILER_ID "VisualAge"
/* __IBMCPP__ = VRP */
# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100)
# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10)
# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10)
#elif defined(__NVCOMPILER)
# define COMPILER_ID "NVHPC"
# define COMPILER_VERSION_MAJOR DEC(__NVCOMPILER_MAJOR__)
# define COMPILER_VERSION_MINOR DEC(__NVCOMPILER_MINOR__)
# if defined(__NVCOMPILER_PATCHLEVEL__)
# define COMPILER_VERSION_PATCH DEC(__NVCOMPILER_PATCHLEVEL__)
# endif
#elif defined(__PGI)
# define COMPILER_ID "PGI"
# define COMPILER_VERSION_MAJOR DEC(__PGIC__)
# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__)
# if defined(__PGIC_PATCHLEVEL__)
# define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__)
# endif
#elif defined(_CRAYC)
# define COMPILER_ID "Cray"
# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR)
# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR)
#elif defined(__TI_COMPILER_VERSION__)
# define COMPILER_ID "TI"
/* __TI_COMPILER_VERSION__ = VVVRRRPPP */
# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000)
# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000 % 1000)
# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__ % 1000)
#elif defined(__CLANG_FUJITSU)
# define COMPILER_ID "FujitsuClang"
# define COMPILER_VERSION_MAJOR DEC(__FCC_major__)
# define COMPILER_VERSION_MINOR DEC(__FCC_minor__)
# define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__)
# define COMPILER_VERSION_INTERNAL_STR __clang_version__
#elif defined(__FUJITSU)
# define COMPILER_ID "Fujitsu"
# if defined(__FCC_version__)
# define COMPILER_VERSION __FCC_version__
# elif defined(__FCC_major__)
# define COMPILER_VERSION_MAJOR DEC(__FCC_major__)
# define COMPILER_VERSION_MINOR DEC(__FCC_minor__)
# define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__)
# endif
# if defined(__fcc_version)
# define COMPILER_VERSION_INTERNAL DEC(__fcc_version)
# elif defined(__FCC_VERSION)
# define COMPILER_VERSION_INTERNAL DEC(__FCC_VERSION)
# endif
#elif defined(__ghs__)
# define COMPILER_ID "GHS"
/* __GHS_VERSION_NUMBER = VVVVRP */
# ifdef __GHS_VERSION_NUMBER
# define COMPILER_VERSION_MAJOR DEC(__GHS_VERSION_NUMBER / 100)
# define COMPILER_VERSION_MINOR DEC(__GHS_VERSION_NUMBER / 10 % 10)
# define COMPILER_VERSION_PATCH DEC(__GHS_VERSION_NUMBER % 10)
# endif
#elif defined(__SCO_VERSION__)
# define COMPILER_ID "SCO"
#elif defined(__ARMCC_VERSION) && !defined(__clang__)
# define COMPILER_ID "ARMCC"
#if __ARMCC_VERSION >= 1000000
/* __ARMCC_VERSION = VRRPPPP */
# define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000)
# define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100)
# define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000)
#else
/* __ARMCC_VERSION = VRPPPP */
# define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000)
# define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10)
# define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000)
#endif
#elif defined(__clang__) && defined(__apple_build_version__)
# define COMPILER_ID "AppleClang"
# if defined(_MSC_VER)
# define SIMULATE_ID "MSVC"
# endif
# define COMPILER_VERSION_MAJOR DEC(__clang_major__)
# define COMPILER_VERSION_MINOR DEC(__clang_minor__)
# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__)
# if defined(_MSC_VER)
/* _MSC_VER = VVRR */
# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
# endif
# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__)
#elif defined(__clang__) && defined(__ARMCOMPILER_VERSION)
# define COMPILER_ID "ARMClang"
# define COMPILER_VERSION_MAJOR DEC(__ARMCOMPILER_VERSION/1000000)
# define COMPILER_VERSION_MINOR DEC(__ARMCOMPILER_VERSION/10000 % 100)
# define COMPILER_VERSION_PATCH DEC(__ARMCOMPILER_VERSION % 10000)
# define COMPILER_VERSION_INTERNAL DEC(__ARMCOMPILER_VERSION)
#elif defined(__clang__)
# define COMPILER_ID "Clang"
# if defined(_MSC_VER)
# define SIMULATE_ID "MSVC"
# endif
# define COMPILER_VERSION_MAJOR DEC(__clang_major__)
# define COMPILER_VERSION_MINOR DEC(__clang_minor__)
# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__)
# if defined(_MSC_VER)
/* _MSC_VER = VVRR */
# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
# endif
#elif defined(__GNUC__) || defined(__GNUG__)
# define COMPILER_ID "GNU"
# if defined(__GNUC__)
# define COMPILER_VERSION_MAJOR DEC(__GNUC__)
# else
# define COMPILER_VERSION_MAJOR DEC(__GNUG__)
# endif
# if defined(__GNUC_MINOR__)
# define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__)
# endif
# if defined(__GNUC_PATCHLEVEL__)
# define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
# endif
#elif defined(_MSC_VER)
# define COMPILER_ID "MSVC"
/* _MSC_VER = VVRR */
# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100)
# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100)
# if defined(_MSC_FULL_VER)
# if _MSC_VER >= 1400
/* _MSC_FULL_VER = VVRRPPPPP */
# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000)
# else
/* _MSC_FULL_VER = VVRRPPPP */
# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000)
# endif
# endif
# if defined(_MSC_BUILD)
# define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD)
# endif
#elif defined(__VISUALDSPVERSION__) || defined(__ADSPBLACKFIN__) || defined(__ADSPTS__) || defined(__ADSP21000__)
# define COMPILER_ID "ADSP"
#if defined(__VISUALDSPVERSION__)
/* __VISUALDSPVERSION__ = 0xVVRRPP00 */
# define COMPILER_VERSION_MAJOR HEX(__VISUALDSPVERSION__>>24)
# define COMPILER_VERSION_MINOR HEX(__VISUALDSPVERSION__>>16 & 0xFF)
# define COMPILER_VERSION_PATCH HEX(__VISUALDSPVERSION__>>8 & 0xFF)
#endif
#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC)
# define COMPILER_ID "IAR"
# if defined(__VER__) && defined(__ICCARM__)
# define COMPILER_VERSION_MAJOR DEC((__VER__) / 1000000)
# define COMPILER_VERSION_MINOR DEC(((__VER__) / 1000) % 1000)
# define COMPILER_VERSION_PATCH DEC((__VER__) % 1000)
# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__)
# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__) || defined(__ICCRISCV__) || defined(__ICCV850__) || defined(__ICC8051__) || defined(__ICCSTM8__))
# define COMPILER_VERSION_MAJOR DEC((__VER__) / 100)
# define COMPILER_VERSION_MINOR DEC((__VER__) - (((__VER__) / 100)*100))
# define COMPILER_VERSION_PATCH DEC(__SUBVERSION__)
# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__)
# endif
/* These compilers are either not known or too old to define an
identification macro. Try to identify the platform and guess that
it is the native compiler. */
#elif defined(__hpux) || defined(__hpua)
# define COMPILER_ID "HP"
#else /* unknown compiler */
# define COMPILER_ID ""
#endif
/* Construct the string literal in pieces to prevent the source from
getting matched. Store it in a pointer rather than an array
because some compilers will just produce instructions to fill the
array rather than assigning a pointer to a static array. */
char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]";
#ifdef SIMULATE_ID
char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]";
#endif
#ifdef __QNXNTO__
char const* qnxnto = "INFO" ":" "qnxnto[]";
#endif
#if defined(__CRAYXT_COMPUTE_LINUX_TARGET)
char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]";
#endif
#define STRINGIFY_HELPER(X) #X
#define STRINGIFY(X) STRINGIFY_HELPER(X)
/* Identify known platforms by name. */
#if defined(__linux) || defined(__linux__) || defined(linux)
# define PLATFORM_ID "Linux"
#elif defined(__MSYS__)
# define PLATFORM_ID "MSYS"
#elif defined(__CYGWIN__)
# define PLATFORM_ID "Cygwin"
#elif defined(__MINGW32__)
# define PLATFORM_ID "MinGW"
#elif defined(__APPLE__)
# define PLATFORM_ID "Darwin"
#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
# define PLATFORM_ID "Windows"
#elif defined(__FreeBSD__) || defined(__FreeBSD)
# define PLATFORM_ID "FreeBSD"
#elif defined(__NetBSD__) || defined(__NetBSD)
# define PLATFORM_ID "NetBSD"
#elif defined(__OpenBSD__) || defined(__OPENBSD)
# define PLATFORM_ID "OpenBSD"
#elif defined(__sun) || defined(sun)
# define PLATFORM_ID "SunOS"
#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__)
# define PLATFORM_ID "AIX"
#elif defined(__hpux) || defined(__hpux__)
# define PLATFORM_ID "HP-UX"
#elif defined(__HAIKU__)
# define PLATFORM_ID "Haiku"
#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS)
# define PLATFORM_ID "BeOS"
#elif defined(__QNX__) || defined(__QNXNTO__)
# define PLATFORM_ID "QNX"
#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__)
# define PLATFORM_ID "Tru64"
#elif defined(__riscos) || defined(__riscos__)
# define PLATFORM_ID "RISCos"
#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__)
# define PLATFORM_ID "SINIX"
#elif defined(__UNIX_SV__)
# define PLATFORM_ID "UNIX_SV"
#elif defined(__bsdos__)
# define PLATFORM_ID "BSDOS"
#elif defined(_MPRAS) || defined(MPRAS)
# define PLATFORM_ID "MP-RAS"
#elif defined(__osf) || defined(__osf__)
# define PLATFORM_ID "OSF1"
#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv)
# define PLATFORM_ID "SCO_SV"
#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX)
# define PLATFORM_ID "ULTRIX"
#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX)
# define PLATFORM_ID "Xenix"
#elif defined(__WATCOMC__)
# if defined(__LINUX__)
# define PLATFORM_ID "Linux"
# elif defined(__DOS__)
# define PLATFORM_ID "DOS"
# elif defined(__OS2__)
# define PLATFORM_ID "OS2"
# elif defined(__WINDOWS__)
# define PLATFORM_ID "Windows3x"
# elif defined(__VXWORKS__)
# define PLATFORM_ID "VxWorks"
# else /* unknown platform */
# define PLATFORM_ID
# endif
#elif defined(__INTEGRITY)
# if defined(INT_178B)
# define PLATFORM_ID "Integrity178"
# else /* regular Integrity */
# define PLATFORM_ID "Integrity"
# endif
#else /* unknown platform */
# define PLATFORM_ID
#endif
/* For windows compilers MSVC and Intel we can determine
the architecture of the compiler being used. This is because
the compilers do not have flags that can change the architecture,
but rather depend on which compiler is being used
*/
#if defined(_WIN32) && defined(_MSC_VER)
# if defined(_M_IA64)
# define ARCHITECTURE_ID "IA64"
# elif defined(_M_ARM64EC)
# define ARCHITECTURE_ID "ARM64EC"
# elif defined(_M_X64) || defined(_M_AMD64)
# define ARCHITECTURE_ID "x64"
# elif defined(_M_IX86)
# define ARCHITECTURE_ID "X86"
# elif defined(_M_ARM64)
# define ARCHITECTURE_ID "ARM64"
# elif defined(_M_ARM)
# if _M_ARM == 4
# define ARCHITECTURE_ID "ARMV4I"
# elif _M_ARM == 5
# define ARCHITECTURE_ID "ARMV5I"
# else
# define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM)
# endif
# elif defined(_M_MIPS)
# define ARCHITECTURE_ID "MIPS"
# elif defined(_M_SH)
# define ARCHITECTURE_ID "SHx"
# else /* unknown architecture */
# define ARCHITECTURE_ID ""
# endif
#elif defined(__WATCOMC__)
# if defined(_M_I86)
# define ARCHITECTURE_ID "I86"
# elif defined(_M_IX86)
# define ARCHITECTURE_ID "X86"
# else /* unknown architecture */
# define ARCHITECTURE_ID ""
# endif
#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC)
# if defined(__ICCARM__)
# define ARCHITECTURE_ID "ARM"
# elif defined(__ICCRX__)
# define ARCHITECTURE_ID "RX"
# elif defined(__ICCRH850__)
# define ARCHITECTURE_ID "RH850"
# elif defined(__ICCRL78__)
# define ARCHITECTURE_ID "RL78"
# elif defined(__ICCRISCV__)
# define ARCHITECTURE_ID "RISCV"
# elif defined(__ICCAVR__)
# define ARCHITECTURE_ID "AVR"
# elif defined(__ICC430__)
# define ARCHITECTURE_ID "MSP430"
# elif defined(__ICCV850__)
# define ARCHITECTURE_ID "V850"
# elif defined(__ICC8051__)
# define ARCHITECTURE_ID "8051"
# elif defined(__ICCSTM8__)
# define ARCHITECTURE_ID "STM8"
# else /* unknown architecture */
# define ARCHITECTURE_ID ""
# endif
#elif defined(__ghs__)
# if defined(__PPC64__)
# define ARCHITECTURE_ID "PPC64"
# elif defined(__ppc__)
# define ARCHITECTURE_ID "PPC"
# elif defined(__ARM__)
# define ARCHITECTURE_ID "ARM"
# elif defined(__x86_64__)
# define ARCHITECTURE_ID "x64"
# elif defined(__i386__)
# define ARCHITECTURE_ID "X86"
# else /* unknown architecture */
# define ARCHITECTURE_ID ""
# endif
#elif defined(__TI_COMPILER_VERSION__)
# if defined(__TI_ARM__)
# define ARCHITECTURE_ID "ARM"
# elif defined(__MSP430__)
# define ARCHITECTURE_ID "MSP430"
# elif defined(__TMS320C28XX__)
# define ARCHITECTURE_ID "TMS320C28x"
# elif defined(__TMS320C6X__) || defined(_TMS320C6X)
# define ARCHITECTURE_ID "TMS320C6x"
# else /* unknown architecture */
# define ARCHITECTURE_ID ""
# endif
#else
# define ARCHITECTURE_ID
#endif
/* Convert integer to decimal digit literals. */
#define DEC(n) \
('0' + (((n) / 10000000)%10)), \
('0' + (((n) / 1000000)%10)), \
('0' + (((n) / 100000)%10)), \
('0' + (((n) / 10000)%10)), \
('0' + (((n) / 1000)%10)), \
('0' + (((n) / 100)%10)), \
('0' + (((n) / 10)%10)), \
('0' + ((n) % 10))
/* Convert integer to hex digit literals. */
#define HEX(n) \
('0' + ((n)>>28 & 0xF)), \
('0' + ((n)>>24 & 0xF)), \
('0' + ((n)>>20 & 0xF)), \
('0' + ((n)>>16 & 0xF)), \
('0' + ((n)>>12 & 0xF)), \
('0' + ((n)>>8 & 0xF)), \
('0' + ((n)>>4 & 0xF)), \
('0' + ((n) & 0xF))
/* Construct a string literal encoding the version number. */
#ifdef COMPILER_VERSION
char const* info_version = "INFO" ":" "compiler_version[" COMPILER_VERSION "]";
/* Construct a string literal encoding the version number components. */
#elif defined(COMPILER_VERSION_MAJOR)
char const info_version[] = {
'I', 'N', 'F', 'O', ':',
'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[',
COMPILER_VERSION_MAJOR,
# ifdef COMPILER_VERSION_MINOR
'.', COMPILER_VERSION_MINOR,
# ifdef COMPILER_VERSION_PATCH
'.', COMPILER_VERSION_PATCH,
# ifdef COMPILER_VERSION_TWEAK
'.', COMPILER_VERSION_TWEAK,
# endif
# endif
# endif
']','\0'};
#endif
/* Construct a string literal encoding the internal version number. */
#ifdef COMPILER_VERSION_INTERNAL
char const info_version_internal[] = {
'I', 'N', 'F', 'O', ':',
'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_',
'i','n','t','e','r','n','a','l','[',
COMPILER_VERSION_INTERNAL,']','\0'};
#elif defined(COMPILER_VERSION_INTERNAL_STR)
char const* info_version_internal = "INFO" ":" "compiler_version_internal[" COMPILER_VERSION_INTERNAL_STR "]";
#endif
/* Construct a string literal encoding the version number components. */
#ifdef SIMULATE_VERSION_MAJOR
char const info_simulate_version[] = {
'I', 'N', 'F', 'O', ':',
's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[',
SIMULATE_VERSION_MAJOR,
# ifdef SIMULATE_VERSION_MINOR
'.', SIMULATE_VERSION_MINOR,
# ifdef SIMULATE_VERSION_PATCH
'.', SIMULATE_VERSION_PATCH,
# ifdef SIMULATE_VERSION_TWEAK
'.', SIMULATE_VERSION_TWEAK,
# endif
# endif
# endif
']','\0'};
#endif
/* Construct the string literal in pieces to prevent the source from
getting matched. Store it in a pointer rather than an array
because some compilers will just produce instructions to fill the
array rather than assigning a pointer to a static array. */
char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]";
char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]";
#if defined(__INTEL_COMPILER) && defined(_MSVC_LANG) && _MSVC_LANG < 201403L
# if defined(__INTEL_CXX11_MODE__)
# if defined(__cpp_aggregate_nsdmi)
# define CXX_STD 201402L
# else
# define CXX_STD 201103L
# endif
# else
# define CXX_STD 199711L
# endif
#elif defined(_MSC_VER) && defined(_MSVC_LANG)
# define CXX_STD _MSVC_LANG
#else
# define CXX_STD __cplusplus
#endif
const char* info_language_standard_default = "INFO" ":" "standard_default["
#if CXX_STD > 202002L
"23"
#elif CXX_STD > 201703L
"20"
#elif CXX_STD >= 201703L
"17"
#elif CXX_STD >= 201402L
"14"
#elif CXX_STD >= 201103L
"11"
#else
"98"
#endif
"]";
const char* info_language_extensions_default = "INFO" ":" "extensions_default["
/* !defined(_MSC_VER) to exclude Clang's MSVC compatibility mode. */
#if (defined(__clang__) || defined(__GNUC__) || \
defined(__TI_COMPILER_VERSION__)) && \
!defined(__STRICT_ANSI__) && !defined(_MSC_VER)
"ON"
#else
"OFF"
#endif
"]";
/*--------------------------------------------------------------------------*/
int main(int argc, char* argv[])
{
int require = 0;
require += info_compiler[argc];
require += info_platform[argc];
#ifdef COMPILER_VERSION_MAJOR
require += info_version[argc];
#endif
#ifdef COMPILER_VERSION_INTERNAL
require += info_version_internal[argc];
#endif
#ifdef SIMULATE_ID
require += info_simulate[argc];
#endif
#ifdef SIMULATE_VERSION_MAJOR
require += info_simulate_version[argc];
#endif
#if defined(__CRAYXT_COMPUTE_LINUX_TARGET)
require += info_cray[argc];
#endif
require += info_language_standard_default[argc];
require += info_language_extensions_default[argc];
(void)argv;
return require;
}

View File

@@ -1,2 +0,0 @@
/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a/CMakeFiles/edit_cache.dir
/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a/CMakeFiles/rebuild_cache.dir

View File

@@ -1 +0,0 @@
# This file is generated by cmake for dependency checking of the CMakeCache.txt file

View File

@@ -1,45 +0,0 @@
# CMAKE generated file: DO NOT EDIT!
# Generated by "Ninja" Generator, CMake Version 3.22
# This file contains all the rules used to get the outputs files
# built from the input files.
# It is included in the main 'build.ninja'.
# =============================================================================
# Project: Project
# Configurations: release
# =============================================================================
# =============================================================================
#############################################
# Rule for running custom commands.
rule CUSTOM_COMMAND
command = $COMMAND
description = $DESC
#############################################
# Rule for re-running cmake.
rule RERUN_CMAKE
command = /home/pierre/Android/Sdk/cmake/3.22.1/bin/cmake --regenerate-during-build -S/home/pierre/dev/flutter/packages/flutter_tools/gradle/src/main/scripts -B/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a
description = Re-running CMake...
generator = 1
#############################################
# Rule for cleaning all built files.
rule CLEAN
command = /home/pierre/Android/Sdk/cmake/3.22.1/bin/ninja $FILE_ARG -t clean $TARGETS
description = Cleaning all built files...
#############################################
# Rule for printing all primary targets available.
rule HELP
command = /home/pierre/Android/Sdk/cmake/3.22.1/bin/ninja -t targets
description = All primary targets available:

View File

@@ -1,28 +0,0 @@
{
"buildFiles": [
"/home/pierre/dev/flutter/packages/flutter_tools/gradle/src/main/scripts/CMakeLists.txt"
],
"cleanCommandsComponents": [
[
"/home/pierre/Android/Sdk/cmake/3.22.1/bin/ninja",
"-C",
"/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a",
"clean"
]
],
"buildTargetsCommandComponents": [
"/home/pierre/Android/Sdk/cmake/3.22.1/bin/ninja",
"-C",
"/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a",
"{LIST_OF_TARGETS_TO_BUILD}"
],
"libraries": {},
"toolchains": {
"toolchain": {
"cCompilerExecutable": "/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/clang.lld",
"cppCompilerExecutable": "/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++.lld"
}
},
"cFileExtensions": [],
"cppFileExtensions": []
}

View File

@@ -1,20 +0,0 @@
{
"buildFiles": [
"/home/pierre/dev/flutter/packages/flutter_tools/gradle/src/main/scripts/CMakeLists.txt"
],
"cleanCommandsComponents": [
[
"/home/pierre/Android/Sdk/cmake/3.22.1/bin/ninja",
"-C",
"/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a",
"clean"
]
],
"buildTargetsCommandComponents": [
"/home/pierre/Android/Sdk/cmake/3.22.1/bin/ninja",
"-C",
"/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a",
"{LIST_OF_TARGETS_TO_BUILD}"
],
"libraries": {}
}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
/home/pierre/dev/flutter/packages/flutter_tools/gradle/src/main/scripts/CMakeLists.txt

View File

@@ -1,54 +0,0 @@
# Install script for directory: /home/pierre/dev/flutter/packages/flutter_tools/gradle/src/main/scripts
# Set the install prefix
if(NOT DEFINED CMAKE_INSTALL_PREFIX)
set(CMAKE_INSTALL_PREFIX "/usr/local")
endif()
string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
# Set the install configuration name.
if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)
if(BUILD_TYPE)
string(REGEX REPLACE "^[^A-Za-z0-9_]+" ""
CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}")
else()
set(CMAKE_INSTALL_CONFIG_NAME "release")
endif()
message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"")
endif()
# Set the component getting installed.
if(NOT CMAKE_INSTALL_COMPONENT)
if(COMPONENT)
message(STATUS "Install component: \"${COMPONENT}\"")
set(CMAKE_INSTALL_COMPONENT "${COMPONENT}")
else()
set(CMAKE_INSTALL_COMPONENT)
endif()
endif()
# Install shared libraries without execute permission?
if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE)
set(CMAKE_INSTALL_SO_NO_EXE "1")
endif()
# Is this installation the result of a crosscompile?
if(NOT DEFINED CMAKE_CROSSCOMPILING)
set(CMAKE_CROSSCOMPILING "TRUE")
endif()
# Set default install directory permissions.
if(NOT DEFINED CMAKE_OBJDUMP)
set(CMAKE_OBJDUMP "/home/pierre/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-objdump")
endif()
if(CMAKE_INSTALL_COMPONENT)
set(CMAKE_INSTALL_MANIFEST "install_manifest_${CMAKE_INSTALL_COMPONENT}.txt")
else()
set(CMAKE_INSTALL_MANIFEST "install_manifest.txt")
endif()
string(REPLACE ";" "\n" CMAKE_INSTALL_MANIFEST_CONTENT
"${CMAKE_INSTALL_MANIFEST_FILES}")
file(WRITE "/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a/${CMAKE_INSTALL_MANIFEST}"
"${CMAKE_INSTALL_MANIFEST_CONTENT}")

View File

@@ -1,28 +0,0 @@
C/C++ Structured LogZ
X
V/home/pierre/dev/flutter/packages/flutter_tools/gradle/src/main/scripts/CMakeLists.txtC
A
?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  ܉<><DC89><EFBFBD>3<18> ј<>Á3e
c
a/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a/additional_project_files.txt  ݉<><DD89><EFBFBD>3  <20><><EFBFBD><EFBFBD><EFBFBD>3b
`
^/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a/android_gradle_build.json  ݉<><DD89><EFBFBD>3<18> ĉ<><C489><EFBFBD>3g
e
c/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a/android_gradle_build_mini.json  ݉<><DD89><EFBFBD>3<18> ȉ<><C889><EFBFBD>3T
R
P/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a/build.ninja  ݉<><DD89><EFBFBD>3۸ <20><><EFBFBD><EFBFBD><EFBFBD>3X
V
T/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a/build.ninja.txt  ݉<><DD89><EFBFBD>3]
[
Y/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a/build_file_index.txt  ݉<><DD89><EFBFBD>3
V ȉ<><C889><EFBFBD>3^
\
Z/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a/compile_commands.json  ݉<><DD89><EFBFBD>3 b
`
^/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a/compile_commands.json.bin  ݉<><DD89><EFBFBD>3
h
f
d/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a/metadata_generation_command.txt  ݉<><DD89><EFBFBD>3 <18> ȉ<><C889><EFBFBD>3[
Y
W/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a/prefab_config.json  ݉<><DD89><EFBFBD>3
 ( ȉ<><C889><EFBFBD>3`

View File

@@ -1,20 +0,0 @@
-H/home/pierre/dev/flutter/packages/flutter_tools/gradle/src/main/scripts
-DCMAKE_SYSTEM_NAME=Android
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
-DCMAKE_SYSTEM_VERSION=24
-DANDROID_PLATFORM=android-24
-DANDROID_ABI=arm64-v8a
-DCMAKE_ANDROID_ARCH_ABI=arm64-v8a
-DANDROID_NDK=/home/pierre/Android/Sdk/ndk/27.0.12077973
-DCMAKE_ANDROID_NDK=/home/pierre/Android/Sdk/ndk/27.0.12077973
-DCMAKE_TOOLCHAIN_FILE=/home/pierre/Android/Sdk/ndk/27.0.12077973/build/cmake/android.toolchain.cmake
-DCMAKE_MAKE_PROGRAM=/home/pierre/Android/Sdk/cmake/3.22.1/bin/ninja
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=/home/pierre/dev/geosector/app/build/app/intermediates/cxx/release/3j2a1x3f/obj/arm64-v8a
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=/home/pierre/dev/geosector/app/build/app/intermediates/cxx/release/3j2a1x3f/obj/arm64-v8a
-B/home/pierre/dev/geosector/app/build/.cxx/release/3j2a1x3f/arm64-v8a
-GNinja
-Wno-dev
--no-warn-unused-cli
-DCMAKE_BUILD_TYPE=release
Build command args: []
Version: 2

View File

@@ -1,4 +0,0 @@
{
"enabled": false,
"packages": []
}

Some files were not shown because too many files have changed in this diff Show More