Files
wevads-platform/scripts/office365-hub.php
2026-02-26 04:53:11 +01:00

550 lines
28 KiB
PHP
Executable File

<?php
/**
* OFFICE 365 HUB - API & Automation Complete
* Workflow 8 étapes, FreeDNS, PowerShell, Graph API
*/
$pdo = new PDO("pgsql:host=localhost;dbname=adx_system", "admin", "admin123");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Stats Office 365
$stats = [];
try {
$stats['tenants'] = $pdo->query("SELECT COUNT(*) FROM admin.office_accounts")->fetchColumn() ?: 0;
$stats['domains_verified'] = $pdo->query("SELECT COUNT(*) FROM admin.office_domains WHERE verification_status='Verified'")->fetchColumn() ?: 0;
$stats['freedns'] = $pdo->query("SELECT COUNT(*) FROM admin.domain_pool WHERE source='freedns_registry'")->fetchColumn() ?: 0;
$stats['connectors'] = $pdo->query("SELECT COUNT(*) FROM admin.office_connectors")->fetchColumn() ?: 0;
} catch(Exception $e) {
$stats = ['tenants' => 0, 'domains_verified' => 0, 'freedns' => 0, 'connectors' => 0];
}
// Messages
$msg = '';
$msgType = '';
// Actions API
if ($_POST) {
$action = $_POST['action'] ?? '';
// Test Graph API Connection
if ($action === 'test_graph_api') {
$tenant_id = $_POST['tenant_id'] ?? '';
$client_id = $_POST['client_id'] ?? '';
$client_secret = $_POST['client_secret'] ?? '';
if ($tenant_id && $client_id && $client_secret) {
// Get OAuth Token
$tokenUrl = "https://login.microsoftonline.com/{$tenant_id}/oauth2/v2.0/token";
$postData = [
'grant_type' => 'client_credentials',
'client_id' => $client_id,
'client_secret' => $client_secret,
'scope' => 'https://graph.microsoft.com/.default'
];
$ch = curl_init($tokenUrl);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
$token = json_decode($response, true);
if (isset($token['access_token'])) {
$msg = "✅ Graph API connecté! Token valide pour " . ($token['expires_in']/60) . " minutes";
$msgType = 'success';
}
} else {
$msg = "❌ Erreur Graph API: " . $response;
$msgType = 'error';
}
}
}
}
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Office 365 Hub - WEVAL</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: linear-gradient(135deg, #0f172a 0%, #1e3a5f 50%, #0f172a 100%); min-height: 100vh; color: #e2e8f0; }
.container { max-width: 1600px; margin: 0 auto; padding: 20px; }
.header { text-align: center; padding: 30px; background: rgba(255,255,255,0.03); border-radius: 20px; margin-bottom: 30px; border: 1px solid rgba(255,255,255,0.1); }
.header h1 { font-size: 32px; margin-bottom: 10px; display: flex; align-items: center; justify-content: center; gap: 15px; }
.header h1 .ms-logo { color: #00a4ef; font-size: 40px; }
.header p { color: #64748b; }
.nav { display: flex; justify-content: center; gap: 10px; margin-top: 20px; flex-wrap: wrap; }
.nav a { padding: 10px 20px; background: rgba(0,164,239,0.2); color: #00a4ef; text-decoration: none; border-radius: 10px; font-size: 13px; transition: all 0.3s; }
.nav a:hover { background: rgba(0,164,239,0.4); transform: translateY(-2px); }
.msg { padding: 15px 25px; border-radius: 12px; margin-bottom: 25px; }
.msg.success { background: rgba(52,211,153,0.15); border: 1px solid rgba(52,211,153,0.3); color: #6ee7b7; }
.msg.error { background: rgba(239,68,68,0.15); border: 1px solid rgba(239,68,68,0.3); color: #f87171; }
.stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; margin-bottom: 30px; }
.stat-card { background: rgba(255,255,255,0.03); border-radius: 16px; padding: 25px; text-align: center; border: 1px solid rgba(255,255,255,0.08); }
.stat-card .icon { font-size: 32px; margin-bottom: 15px; color: #00a4ef; }
.stat-card .value { font-size: 42px; font-weight: 700; color: #00a4ef; }
.stat-card .label { color: #64748b; font-size: 13px; margin-top: 8px; }
.tabs { display: flex; gap: 5px; margin-bottom: 25px; background: rgba(255,255,255,0.03); padding: 8px; border-radius: 12px; flex-wrap: wrap; }
.tab { padding: 12px 20px; background: transparent; border: none; color: #94a3b8; cursor: pointer; border-radius: 8px; font-size: 13px; transition: all 0.3s; }
.tab:hover { background: rgba(255,255,255,0.05); }
.tab.active { background: linear-gradient(135deg, #00a4ef, #0078d4); color: white; }
.tab-content { display: none; }
.tab-content.active { display: block; }
.card { background: rgba(255,255,255,0.03); border-radius: 16px; padding: 25px; border: 1px solid rgba(255,255,255,0.08); margin-bottom: 25px; }
.card h3 { font-size: 16px; margin-bottom: 20px; display: flex; align-items: center; gap: 10px; color: #00a4ef; }
.workflow-steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: 15px; }
.step { padding: 20px; background: rgba(0,164,239,0.05); border-radius: 12px; border: 1px solid rgba(0,164,239,0.2); text-align: center; position: relative; }
.step::after { content: '→'; position: absolute; right: -20px; top: 50%; transform: translateY(-50%); color: #00a4ef; font-size: 20px; }
.step:last-child::after { display: none; }
.step .num { width: 30px; height: 30px; background: #00a4ef; color: white; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 10px; font-weight: 600; }
.step .title { font-weight: 600; font-size: 13px; margin-bottom: 5px; }
.step .desc { font-size: 11px; color: #64748b; }
.api-section { background: rgba(0,0,0,0.3); padding: 20px; border-radius: 12px; margin-bottom: 20px; }
.api-section h4 { color: #00a4ef; margin-bottom: 15px; font-size: 14px; }
.api-section pre { background: rgba(0,0,0,0.4); padding: 15px; border-radius: 8px; font-size: 11px; color: #94a3b8; overflow-x: auto; }
.form-group { margin-bottom: 15px; }
.form-group label { display: block; font-size: 12px; color: #94a3b8; margin-bottom: 6px; }
.form-group input, .form-group select { width: 100%; padding: 12px; background: rgba(0,0,0,0.3); border: 1px solid rgba(255,255,255,0.1); border-radius: 10px; color: #e2e8f0; font-size: 13px; }
.btn { padding: 12px 25px; border: none; border-radius: 10px; cursor: pointer; font-weight: 600; font-size: 14px; transition: all 0.3s; display: inline-flex; align-items: center; gap: 8px; }
.btn-primary { background: linear-gradient(135deg, #00a4ef, #0078d4); color: white; }
.btn-primary:hover { transform: translateY(-2px); box-shadow: 0 5px 20px rgba(0,164,239,0.4); }
.btn-success { background: rgba(52,211,153,0.2); color: #34d399; }
.btn-warning { background: rgba(251,191,36,0.2); color: #fbbf24; }
.grid { display: grid; gap: 20px; }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.powershell-box { background: #012456; padding: 20px; border-radius: 12px; font-family: 'Consolas', monospace; font-size: 12px; color: #fff; overflow-x: auto; }
.powershell-box .comment { color: #608b4e; }
.powershell-box .cmdlet { color: #dcdcaa; }
.powershell-box .param { color: #9cdcfe; }
.powershell-box .string { color: #ce9178; }
.endpoint-list { display: flex; flex-direction: column; gap: 10px; }
.endpoint { padding: 12px 15px; background: rgba(0,0,0,0.3); border-radius: 8px; display: flex; align-items: center; gap: 15px; }
.endpoint .method { padding: 4px 10px; border-radius: 5px; font-size: 11px; font-weight: 600; }
.endpoint .method.get { background: rgba(52,211,153,0.2); color: #34d399; }
.endpoint .method.post { background: rgba(251,191,36,0.2); color: #fbbf24; }
.endpoint .method.delete { background: rgba(239,68,68,0.2); color: #f87171; }
.endpoint .path { font-family: monospace; font-size: 12px; color: #94a3b8; }
.endpoint .desc { font-size: 11px; color: #64748b; margin-left: auto; }
@media (max-width: 1200px) { .workflow-steps, .grid-3 { grid-template-columns: repeat(2, 1fr); } .stats-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 768px) { .workflow-steps, .grid-2, .grid-3, .stats-grid { grid-template-columns: 1fr; } .step::after { display: none; } }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1><span class="ms-logo"><i class="fab fa-microsoft"></i></span> Office 365 Hub</h1>
<p>Graph API • PowerShell Automation • FreeDNS Integration • Workflow 8 Étapes • Connector Management</p>
<div class="nav">
<a href="deliverability-hub.php"><i class="fas fa-chart-line"></i> Deliverability Hub</a>
<a href="warmup-pro.php"><i class="fas fa-fire"></i> Warmup Pro</a>
<a href="freedns-config.php"><i class="fas fa-globe"></i> FreeDNS Config</a>
<a href="hamid-dashboard.php"><i class="fas fa-robot"></i> WEVAL MIND</a>
</div>
</div>
<?php if ($msg): ?><div class="msg <?= $msgType ?>"><?= $msg ?></div><?php endif; ?>
<!-- Stats -->
<div class="stats-grid">
<div class="stat-card">
<div class="icon"><i class="fas fa-building"></i></div>
<div class="value"><?= $stats['tenants'] ?></div>
<div class="label">Tenants O365</div>
</div>
<div class="stat-card">
<div class="icon"><i class="fas fa-check-circle"></i></div>
<div class="value"><?= $stats['domains_verified'] ?></div>
<div class="label">Domaines Vérifiés</div>
</div>
<div class="stat-card">
<div class="icon"><i class="fas fa-globe"></i></div>
<div class="value"><?= $stats['freedns'] ?></div>
<div class="label">FreeDNS Subdomains</div>
</div>
<div class="stat-card">
<div class="icon"><i class="fas fa-plug"></i></div>
<div class="value"><?= $stats['connectors'] ?></div>
<div class="label">Connectors</div>
</div>
</div>
<!-- Tabs -->
<div class="tabs">
<button class="tab active" onclick="showTab('workflow')"><i class="fas fa-tasks"></i> Workflow 8 Étapes</button>
<button class="tab" onclick="showTab('graphapi')"><i class="fas fa-code"></i> Graph API</button>
<button class="tab" onclick="showTab('powershell')"><i class="fas fa-terminal"></i> PowerShell</button>
<button class="tab" onclick="showTab('freedns')"><i class="fas fa-globe"></i> FreeDNS</button>
<button class="tab" onclick="showTab('limits')"><i class="fas fa-tachometer-alt"></i> Limites & Quotas</button>
</div>
<!-- TAB: Workflow -->
<div id="workflow" class="tab-content active">
<div class="card">
<h3><i class="fas fa-route"></i> Workflow Automatisation Office 365 - 8 Étapes</h3>
<div class="workflow-steps">
<div class="step">
<div class="num">1</div>
<div class="title">Récupération Compte</div>
<div class="desc">Connexion tenant, vérif credentials, admin backdoor</div>
</div>
<div class="step">
<div class="num">2</div>
<div class="title">Test Licence</div>
<div class="desc">Business Basic, E3, SMTP AUTH activé</div>
</div>
<div class="step">
<div class="num">3</div>
<div class="title">Azure AD Credentials</div>
<div class="desc">App Registration, Client Secret, Tenant ID</div>
</div>
<div class="step">
<div class="num">4</div>
<div class="title">Créer Domaines FreeDNS</div>
<div class="desc">5 subdomains auto, DNS propagation</div>
</div>
<div class="step">
<div class="num">5</div>
<div class="title">Ajouter Domaines O365</div>
<div class="desc">Import domains, TXT verification</div>
</div>
<div class="step">
<div class="num">6</div>
<div class="title">Vérifier Domaines</div>
<div class="desc">TXT records auto, DNS propagation check</div>
</div>
<div class="step">
<div class="num">7</div>
<div class="title">Config Anti-Spam</div>
<div class="desc">Désactiver Spam Filter, Safe Links, Safe Attachments</div>
</div>
<div class="step">
<div class="num">8</div>
<div class="title">Créer Connecteur</div>
<div class="desc">Partner Connector, Smart Host PMTA, TLS</div>
</div>
</div>
</div>
<div class="grid grid-2">
<div class="card">
<h3><i class="fas fa-info-circle"></i> Prérequis</h3>
<ul style="color:#94a3b8;font-size:13px;line-height:2;padding-left:20px">
<li>Tenant Office 365 avec licence Business Basic minimum</li>
<li>Accès Admin Global au tenant</li>
<li>Azure AD App Registration avec permissions Mail.Send</li>
<li>Compte FreeDNS pour subdomains</li>
<li>Serveur PMTA configuré (Smart Host)</li>
</ul>
</div>
<div class="card">
<h3><i class="fas fa-exclamation-triangle"></i> Limites Office 365</h3>
<ul style="color:#94a3b8;font-size:13px;line-height:2;padding-left:20px">
<li><strong style="color:#f87171">10,000 emails/jour</strong> par tenant</li>
<li><strong style="color:#fbbf24">30 messages/minute</strong> max rate</li>
<li><strong style="color:#34d399">Warmup 4 semaines</strong> recommandé</li>
<li>500 recipients max par message</li>
<li>35 MB taille max message</li>
</ul>
</div>
</div>
</div>
<!-- TAB: Graph API -->
<div id="graphapi" class="tab-content">
<div class="card">
<h3><i class="fas fa-plug"></i> Tester Connexion Graph API</h3>
<form method="POST" class="grid grid-3">
<input type="hidden" name="action" value="test_graph_api">
<div class="form-group">
<label>Tenant ID</label>
<input type="text" name="tenant_id" placeholder="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx">
</div>
<div class="form-group">
<label>Client ID (App ID)</label>
<input type="text" name="client_id" placeholder="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx">
</div>
<div class="form-group">
<label>Client Secret</label>
<input type="password" name="client_secret" placeholder="Secret value">
</div>
<div style="grid-column:span 3">
<button type="submit" class="btn btn-primary"><i class="fas fa-bolt"></i> Tester Connexion</button>
</div>
</form>
</div>
<div class="card">
<h3><i class="fas fa-list"></i> Endpoints Graph API Utilisés</h3>
<div class="endpoint-list">
<div class="endpoint">
<span class="method post">POST</span>
<span class="path">/oauth2/v2.0/token</span>
<span class="desc">Obtenir Access Token</span>
</div>
<div class="endpoint">
<span class="method get">GET</span>
<span class="path">/v1.0/domains</span>
<span class="desc">Lister domaines du tenant</span>
</div>
<div class="endpoint">
<span class="method post">POST</span>
<span class="path">/v1.0/domains</span>
<span class="desc">Ajouter un domaine</span>
</div>
<div class="endpoint">
<span class="method post">POST</span>
<span class="path">/v1.0/domains/{id}/verify</span>
<span class="desc">Vérifier un domaine</span>
</div>
<div class="endpoint">
<span class="method get">GET</span>
<span class="path">/v1.0/domains/{id}/verificationDnsRecords</span>
<span class="desc">Obtenir records DNS requis</span>
</div>
<div class="endpoint">
<span class="method post">POST</span>
<span class="path">/v1.0/users/{id}/sendMail</span>
<span class="desc">Envoyer email</span>
</div>
<div class="endpoint">
<span class="method get">GET</span>
<span class="path">/v1.0/users</span>
<span class="desc">Lister utilisateurs</span>
</div>
<div class="endpoint">
<span class="method delete">DELETE</span>
<span class="path">/v1.0/domains/{id}</span>
<span class="desc">Supprimer domaine</span>
</div>
</div>
</div>
<div class="api-section">
<h4><i class="fas fa-code"></i> Exemple: Obtenir Token</h4>
<pre>POST https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_id={client_id}
&client_secret={client_secret}
&scope=https://graph.microsoft.com/.default</pre>
</div>
<div class="api-section">
<h4><i class="fas fa-envelope"></i> Exemple: Envoyer Email via Graph API</h4>
<pre>POST https://graph.microsoft.com/v1.0/users/{user_id}/sendMail
Authorization: Bearer {access_token}
Content-Type: application/json
{
"message": {
"subject": "Test Email",
"body": {
"contentType": "HTML",
"content": "&lt;h1&gt;Hello&lt;/h1&gt;"
},
"toRecipients": [
{ "emailAddress": { "address": "recipient@example.com" } }
]
}
}</pre>
</div>
</div>
<!-- TAB: PowerShell -->
<div id="powershell" class="tab-content">
<div class="card">
<h3><i class="fas fa-terminal"></i> Scripts PowerShell Automatisation</h3>
<div class="api-section">
<h4>1. Connexion Exchange Online</h4>
<div class="powershell-box">
<span class="comment"># Install module si nécessaire</span>
<span class="cmdlet">Install-Module</span> <span class="param">-Name</span> ExchangeOnlineManagement
<span class="comment"># Connexion</span>
<span class="cmdlet">Connect-ExchangeOnline</span> <span class="param">-UserPrincipalName</span> <span class="string">"admin@tenant.onmicrosoft.com"</span>
</div>
</div>
<div class="api-section">
<h4>2. Désactiver Anti-Spam Outbound</h4>
<div class="powershell-box">
<span class="comment"># Désactiver le filtre spam sortant</span>
<span class="cmdlet">Set-HostedOutboundSpamFilterPolicy</span> <span class="param">-Identity</span> <span class="string">"Default"</span> `
<span class="param">-RecipientLimitExternalPerHour</span> 0 `
<span class="param">-RecipientLimitInternalPerHour</span> 0 `
<span class="param">-RecipientLimitPerDay</span> 0 `
<span class="param">-ActionWhenThresholdReached</span> Alert
<span class="comment"># Désactiver Safe Links</span>
<span class="cmdlet">Set-SafeLinksPolicy</span> <span class="param">-Identity</span> <span class="string">"Built-In Protection Policy"</span> <span class="param">-EnableSafeLinksForEmail</span> $false
</div>
</div>
<div class="api-section">
<h4>3. Créer Connecteur Outbound</h4>
<div class="powershell-box">
<span class="comment"># Créer connecteur vers PMTA</span>
<span class="cmdlet">New-OutboundConnector</span> <span class="param">-Name</span> <span class="string">"PMTA-Connector"</span> `
<span class="param">-ConnectorType</span> Partner `
<span class="param">-SmartHosts</span> <span class="string">"89.167.40.150"</span> `
<span class="param">-TlsSettings</span> EncryptionOnly `
<span class="param">-UseMXRecord</span> $false `
<span class="param">-Enabled</span> $true
</div>
</div>
<div class="api-section">
<h4>4. Ajouter & Vérifier Domaine</h4>
<div class="powershell-box">
<span class="comment"># Ajouter domaine</span>
<span class="cmdlet">New-AcceptedDomain</span> <span class="param">-Name</span> <span class="string">"mydomain.freedns.org"</span> <span class="param">-DomainName</span> <span class="string">"mydomain.freedns.org"</span>
<span class="comment"># Obtenir TXT record pour vérification</span>
<span class="cmdlet">Get-MsolDomainVerificationDns</span> <span class="param">-DomainName</span> <span class="string">"mydomain.freedns.org"</span> <span class="param">-Mode</span> DnsTxtRecord
<span class="comment"># Vérifier après création TXT</span>
<span class="cmdlet">Confirm-MsolDomain</span> <span class="param">-DomainName</span> <span class="string">"mydomain.freedns.org"</span>
</div>
</div>
</div>
</div>
<!-- TAB: FreeDNS -->
<div id="freedns" class="tab-content">
<div class="card">
<h3><i class="fas fa-globe"></i> Intégration FreeDNS pour Office 365</h3>
<p style="color:#94a3b8;margin-bottom:20px">FreeDNS permet de créer des subdomains gratuits pour vérification Office 365 via HTTP (.well-known)</p>
<div class="grid grid-2">
<div class="api-section">
<h4>Workflow FreeDNS</h4>
<ol style="color:#94a3b8;font-size:13px;line-height:2;padding-left:20px">
<li>Créer subdomain sur FreeDNS (ex: mymail.mooo.com)</li>
<li>Pointer vers tracking server (151.80.235.110)</li>
<li>Créer fichier .well-known/microsoft-identity-association.json</li>
<li>Ajouter domaine dans Office 365</li>
<li>Microsoft vérifie via HTTP automatiquement</li>
<li>Domaine vérifié en 1-5 minutes!</li>
</ol>
</div>
<div class="api-section">
<h4>Fichier Vérification HTTP</h4>
<pre>/.well-known/microsoft-identity-association.json
{
"associatedApplications": [
{
"applicationId": "{client_id}"
}
]
}</pre>
</div>
</div>
<div style="text-align:center;margin-top:25px">
<a href="freedns-config.php" class="btn btn-primary"><i class="fas fa-cog"></i> Ouvrir FreeDNS Manager</a>
</div>
</div>
</div>
<!-- TAB: Limits -->
<div id="limits" class="tab-content">
<div class="card">
<h3><i class="fas fa-tachometer-alt"></i> Limites & Quotas Office 365</h3>
<table style="width:100%;font-size:13px;border-collapse:collapse">
<tr style="background:rgba(0,164,239,0.1)">
<th style="padding:15px;text-align:left;color:#00a4ef">Limite</th>
<th style="padding:15px;text-align:center;color:#00a4ef">Valeur</th>
<th style="padding:15px;text-align:left;color:#00a4ef">Notes</th>
</tr>
<tr style="border-bottom:1px solid rgba(255,255,255,0.05)">
<td style="padding:12px"><strong>Emails par jour</strong></td>
<td style="text-align:center;color:#f87171;font-weight:600">10,000</td>
<td>Par tenant, reset à minuit UTC</td>
</tr>
<tr style="border-bottom:1px solid rgba(255,255,255,0.05)">
<td style="padding:12px"><strong>Messages par minute</strong></td>
<td style="text-align:center;color:#fbbf24;font-weight:600">30</td>
<td>Rate limit strict</td>
</tr>
<tr style="border-bottom:1px solid rgba(255,255,255,0.05)">
<td style="padding:12px"><strong>Recipients par message</strong></td>
<td style="text-align:center;color:#34d399;font-weight:600">500</td>
<td>To + Cc + Bcc combinés</td>
</tr>
<tr style="border-bottom:1px solid rgba(255,255,255,0.05)">
<td style="padding:12px"><strong>Taille message max</strong></td>
<td style="text-align:center;color:#22d3ee;font-weight:600">35 MB</td>
<td>Après encodage base64</td>
</tr>
<tr style="border-bottom:1px solid rgba(255,255,255,0.05)">
<td style="padding:12px"><strong>Domaines par tenant</strong></td>
<td style="text-align:center;color:#a78bfa;font-weight:600">900</td>
<td>Domaines vérifiés max</td>
</tr>
<tr>
<td style="padding:12px"><strong>Warmup recommandé</strong></td>
<td style="text-align:center;color:#ec4899;font-weight:600">4 semaines</td>
<td>50 → 100 → 500 → 2000 → 10000/jour</td>
</tr>
</table>
</div>
<div class="card">
<h3><i class="fas fa-calendar-alt"></i> Planning Warmup Office 365</h3>
<table style="width:100%;font-size:12px;border-collapse:collapse">
<tr style="background:rgba(0,164,239,0.1)">
<th style="padding:12px;color:#00a4ef">Jour</th>
<th style="padding:12px;color:#00a4ef">Volume</th>
<th style="padding:12px;color:#00a4ef">Jour</th>
<th style="padding:12px;color:#00a4ef">Volume</th>
</tr>
<tr><td style="padding:10px;border-bottom:1px solid rgba(255,255,255,0.05)">J1-3</td><td>50/jour</td><td style="border-bottom:1px solid rgba(255,255,255,0.05)">J15-17</td><td>1000/jour</td></tr>
<tr><td style="padding:10px;border-bottom:1px solid rgba(255,255,255,0.05)">J4-7</td><td>100/jour</td><td style="border-bottom:1px solid rgba(255,255,255,0.05)">J18-21</td><td>2000/jour</td></tr>
<tr><td style="padding:10px;border-bottom:1px solid rgba(255,255,255,0.05)">J8-10</td><td>200/jour</td><td style="border-bottom:1px solid rgba(255,255,255,0.05)">J22-25</td><td>5000/jour</td></tr>
<tr><td style="padding:10px">J11-14</td><td>500/jour</td><td>J26+</td><td style="color:#34d399;font-weight:600">10000/jour</td></tr>
</table>
</div>
</div>
</div>
<script>
function showTab(tab) {
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
event.target.classList.add('active');
document.getElementById(tab).classList.add('active');
}
</script>
<?php include("includes/chatbot-widget.php"); ?>
</body>
</html>