Files
crm_ecosplay/templates/dns_report/index.html.twig

130 lines
7.2 KiB
Twig
Raw Normal View History

feat: page web de rapport DNS detaille + simplification du mail src/Controller/DnsReportController.php (nouveau): - Route /email/configuration/{token} accessible via le lien dans le mail - Utilise le messageId de l'EmailTracking comme token d'acces (seuls les destinataires du mail ont le lien) - Execute tous les checks en temps reel: DnsCheckService (SPF, DMARC, MX, Bounce via dig @1.1.1.1), AwsSesService (domaine, 3 DKIM CNAME, MAIL FROM MX/TXT, bounce notif), CloudflareService (zone, records), MailcowService (domaine, DKIM, MX, autodiscover, autoconfig, SRV, MTA-STS) - Enrichit chaque check avec la colonne Cloudflare - Passe les resultats au template Twig pour affichage complet templates/dns_report/index.html.twig (nouveau): - Page glassmorphism avec header glass - Resume en haut: 3 cards (verifications OK, erreurs, avertissements) avec bordures laterales colorees vert/rouge/jaune - Tableau par domaine avec 6 colonnes: Source (badge colore par type: orange AWS, violet Mailcow, bleu Cloudflare, gris DNS), Verification, Attendu, Dig (actuel), Cloudflare, Statut (rond colore) - Section erreurs detaillees avec liste - Section avertissements avec liste - Footer "Esy-Infra - Service de monitoring d'infra" templates/emails/dns_report.html.twig (simplifie): - Mail ne contient plus les details: seulement un tableau avec chaque domaine et son statut (OK vert / WARN jaune / KO rouge) - Bouton "Voir le rapport complet" avec lien vers la page web (VML fallback pour Outlook) - Le lien utilise le placeholder __DNS_REPORT_URL__ remplace par le MailerService avec le messageId du mail src/Service/MailerService.php: - Ajout du remplacement de __DNS_REPORT_URL__ par l'URL absolue /email/configuration/{messageId} dans sendEmail(), au meme endroit que __VIEW_URL__ Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 21:57:28 +02:00
{% extends 'base.html.twig' %}
feat: gestion complete Devis + Avis de paiement + DocuSeal signature + mails Devis : - Entity DevisLine (pos, title, description, priceHt) liee a Devis (OneToMany cascade/orphanRemoval) - Champs ajoutes sur Devis : customer (ManyToOne), submissionId, state machine (created/send/accepted/refused/cancel), raisonMessage, totaux HT/TVA/TTC, updatedAt, setUpdatedAt public - Relation Devis <-> Advert changee de ManyToOne a OneToOne nullable - Vich Attribute (migration Annotation -> Attribute) pour unsignedPdf/signedPdf/auditPdf - DevisController CRUD complet : create (form repeater lignes + boutons rapides TarificationService), edit, cancel (libere OrderNumber), generate-pdf, send, resend, create-advert, events - DevisPdf (FPDF/FPDI) : header legacy (logo, num, date, client), body lignes, summary totaux, footer SITECONSEIL + pagination, champ signature DocuSeal sur page devis + derniere page CGV - OrderNumberService : preview() et generate() reutilisent les OrderNumber non utilises (isUsed=false) en priorite - OrderNumber::markAsUnused() ajoute DocuSeal integration devis : - DocuSealService : sendDevisForSignature (avec completed_redirect_url), resendDevisSignature (archive ancienne submission), getSubmitterSlug, downloadSignedDevis (sauvegarde via Vich UploadedFile test=true) - WebhookDocuSealController : dispatch par doc_type devis/attestation, handleDevisEvent (form.completed -> STATE_ACCEPTED + download PDF signe/audit, form.declined -> STATE_REFUSED + raison) - DocusealEvent entity pour tracer form.viewed/started/completed/declined en temps reel - Page evenements admin /admin/devis/{id}/events avec badges et payload JSON Signature client : - DevisProcessController : page publique /devis/process/{id}/{hmac} securisee par HMAC, boutons Signer (redirect DocuSeal) / Refuser (motif optionnel) - Pages confirmation : signed.html.twig (merci + recap) et refused.html.twig (confirmation refus + motif) - Nelmio whitelist : signature.esy-web.dev + signature.siteconseil.fr Avis de paiement : - Entity AdvertLine (pos, title, description, priceHt) liee a Advert - Advert refactorise : customer, state, totaux, raisonMessage, submissionId, advertFile (Vich mapping advert_pdf), lines collection, updatedAt - AdvertController : generate-pdf, send (mail + PJ + lien paiement), resend (rappel), cancel (delie devis, libere OrderNumber), search Meilisearch - AdvertPdf (FPDF/FPDI) : QR code Endroid pointant vers /order/{numOrder}, texte "Scannez pour payer" - OrderPaymentController : page publique /order/{numOrder} avec detail prestations, totaux, options paiement (placeholder) - Creation auto depuis devis signe : copie client, totaux, lignes, meme OrderNumber Meilisearch : - Index customer_devis et customer_advert avec searchable (numOrder, customerName, customerEmail, state) et filterable (customerId, state) - CRUD indexation sur chaque action (create, edit, send, cancel, create-advert) - Recherche AJAX dans tabs Devis et Avis avec debounce + dropdown glassmorphism - Sync admin : boutons syncDevis / syncAdverts + compteurs dans /admin/sync Emails : - MailerService : VCF auto (fiche contact SARL SITECONSEIL) en PJ sur tous les mails, bloc HTML pieces jointes injecte automatiquement (exclut .asc/.p7z/smime) avec icone trombone + taille fichier - Templates : devis_to_sign, devis_signed_client/admin (PJ signed+audit), devis_refused_client/admin, advert_send (PJ + bouton paiement), ndd_expiration - TestMailCommand : option --force-dsn pour envoyer via un DSN SMTP specifique (test prod depuis dev) Commande NDD : - app:ndd:check : verifie expiration domaines <= 30j, envoie mail groupe a monitor@siteconseil.fr - Cron quotidien 8h (docker + ansible) Divers : - Titles templates : CRM SITECONSEIL -> SARL SITECONSEIL (52 fichiers) - VAULT_URL dev = https://kms.esy-web.dev (comme prod) - app.js : initDevisLines (repeater + drag & drop), initTabSearch, toggle refus devis - app.scss : styles drag & drop - setasign/fpdi-fpdf installe pour fusion PDF - 5 migrations Doctrine Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 09:44:35 +02:00
{% block title %}Rapport DNS - SARL SITECONSEIL{% endblock %}
feat: page web de rapport DNS detaille + simplification du mail src/Controller/DnsReportController.php (nouveau): - Route /email/configuration/{token} accessible via le lien dans le mail - Utilise le messageId de l'EmailTracking comme token d'acces (seuls les destinataires du mail ont le lien) - Execute tous les checks en temps reel: DnsCheckService (SPF, DMARC, MX, Bounce via dig @1.1.1.1), AwsSesService (domaine, 3 DKIM CNAME, MAIL FROM MX/TXT, bounce notif), CloudflareService (zone, records), MailcowService (domaine, DKIM, MX, autodiscover, autoconfig, SRV, MTA-STS) - Enrichit chaque check avec la colonne Cloudflare - Passe les resultats au template Twig pour affichage complet templates/dns_report/index.html.twig (nouveau): - Page glassmorphism avec header glass - Resume en haut: 3 cards (verifications OK, erreurs, avertissements) avec bordures laterales colorees vert/rouge/jaune - Tableau par domaine avec 6 colonnes: Source (badge colore par type: orange AWS, violet Mailcow, bleu Cloudflare, gris DNS), Verification, Attendu, Dig (actuel), Cloudflare, Statut (rond colore) - Section erreurs detaillees avec liste - Section avertissements avec liste - Footer "Esy-Infra - Service de monitoring d'infra" templates/emails/dns_report.html.twig (simplifie): - Mail ne contient plus les details: seulement un tableau avec chaque domaine et son statut (OK vert / WARN jaune / KO rouge) - Bouton "Voir le rapport complet" avec lien vers la page web (VML fallback pour Outlook) - Le lien utilise le placeholder __DNS_REPORT_URL__ remplace par le MailerService avec le messageId du mail src/Service/MailerService.php: - Ajout du remplacement de __DNS_REPORT_URL__ par l'URL absolue /email/configuration/{messageId} dans sendEmail(), au meme endroit que __VIEW_URL__ Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 21:57:28 +02:00
{% block header %}
<header class="sticky top-0 z-50 glass-heavy" style="border-radius: 0;">
<div class="flex justify-center items-center h-16">
<a href="{{ path('app_home') }}" aria-label="CRM SITECONSEIL - Accueil">
<img class="h-10 md:h-12 w-auto" src="{{ 'logo_facture.png' | imagine_filter('logo') }}" alt="CRM SITECONSEIL" loading="eager">
</a>
</div>
</header>
{% endblock %}
{% block body %}
<div class="page-container">
<h1 class="text-2xl font-bold heading-page mb-4">Rapport de configuration DNS</h1>
<p class="text-sm text-gray-500 mb-8">Genere le {{ date|date('d/m/Y H:i:s') }} par <strong>Esy-Infra</strong></p>
{# ─── Resume ─── #}
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-8">
<div class="glass p-4" style="border-left: 3px solid #16a34a;">
<p class="text-2xl font-bold text-green-600">{{ successes|length }}</p>
<p class="text-xs font-bold uppercase tracking-wider text-gray-500">Verifications OK</p>
</div>
{% if errors|length > 0 %}
<div class="glass p-4" style="border-left: 3px solid #dc2626;">
<p class="text-2xl font-bold text-red-600">{{ errors|length }}</p>
<p class="text-xs font-bold uppercase tracking-wider text-gray-500">Erreurs</p>
</div>
{% endif %}
{% if warnings|length > 0 %}
<div class="glass p-4" style="border-left: 3px solid #f59e0b;">
<p class="text-2xl font-bold text-amber-600">{{ warnings|length }}</p>
<p class="text-xs font-bold uppercase tracking-wider text-gray-500">Avertissements</p>
</div>
{% endif %}
</div>
{# ─── Detail par domaine ─── #}
{% for domainData in domainResults %}
<div class="mb-8">
<h2 class="text-xl font-bold mb-4" style="border-bottom: 2px solid #fabf04; padding-bottom: 4px; display: inline-block;">{{ domainData.domain }}</h2>
<div class="glass overflow-hidden">
<table class="w-full text-xs">
<thead>
<tr class="glass-dark" style="border-radius: 0;">
<th class="px-3 py-2 text-left font-bold uppercase tracking-wider text-white/80" style="width: 90px;">Source</th>
<th class="px-3 py-2 text-left font-bold uppercase tracking-wider text-white/80">Verification</th>
<th class="px-3 py-2 text-left font-bold uppercase tracking-wider text-white/80">Attendu</th>
<th class="px-3 py-2 text-left font-bold uppercase tracking-wider text-white/80">Dig (actuel)</th>
<th class="px-3 py-2 text-left font-bold uppercase tracking-wider text-white/80">Cloudflare</th>
<th class="px-3 py-2 text-center font-bold uppercase tracking-wider text-white/80" style="width: 50px;">Statut</th>
</tr>
</thead>
<tbody>
{% for check in domainData.checks %}
<tr class="border-b border-white/10 hover:bg-white/30 transition-colors">
<td class="px-3 py-2 font-bold text-gray-500 align-top">
<span class="inline-block px-1.5 py-0.5 rounded text-[9px] font-bold
{% if 'AWS' in check.type %}bg-orange-500/20 text-orange-700
{% elseif 'Mailcow' in check.type %}bg-purple-500/20 text-purple-700
{% elseif 'Cloudflare' in check.type %}bg-blue-500/20 text-blue-700
{% else %}bg-gray-500/20 text-gray-600{% endif %}">
{{ check.type }}
</span>
</td>
<td class="px-3 py-2 font-bold align-top">{{ check.label }}</td>
<td class="px-3 py-2 text-gray-500 align-top break-all">{{ check.expected|default('—') }}</td>
<td class="px-3 py-2 align-top break-all
{% if check.status == 'ok' %}text-green-600
{% elseif check.status == 'error' %}text-red-600
{% else %}text-amber-600{% endif %}">
{{ check.dig|default('—') }}
</td>
<td class="px-3 py-2 align-top break-all
{% if check.cf_status|default('') == 'ok' %}text-green-600
{% elseif check.cf_status|default('') == 'error' %}text-red-600
{% else %}text-gray-400{% endif %}">
{{ check.cloudflare|default('—') }}
</td>
<td class="px-3 py-2 text-center align-top">
{% if check.status == 'ok' %}
<span class="inline-block w-5 h-5 rounded-full bg-green-500/20 text-green-600 font-bold leading-5">&#10003;</span>
{% elseif check.status == 'error' %}
<span class="inline-block w-5 h-5 rounded-full bg-red-500/20 text-red-600 font-bold leading-5">&#10007;</span>
{% else %}
<span class="inline-block w-5 h-5 rounded-full bg-amber-500/20 text-amber-600 font-bold leading-5">&#9888;</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endfor %}
{# ─── Erreurs detaillees ─── #}
{% if errors|length > 0 %}
<div class="mb-6">
<h2 class="text-lg font-bold text-red-600 mb-3">Erreurs a corriger</h2>
<div class="glass p-4" style="border-left: 3px solid #dc2626;">
<ul class="text-sm space-y-1">
{% for error in errors %}
<li class="text-red-700">&#10007; {{ error }}</li>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
{% if warnings|length > 0 %}
<div class="mb-6">
<h2 class="text-lg font-bold text-amber-600 mb-3">Avertissements</h2>
<div class="glass p-4" style="border-left: 3px solid #f59e0b;">
<ul class="text-sm space-y-1">
{% for warning in warnings %}
<li class="text-amber-700">&#9888; {{ warning }}</li>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
<p class="text-xs text-gray-400 mt-8">Rapport par <strong>Esy-Infra</strong> - Service de monitoring d'infra</p>
</div>
{% endblock %}