<?php
/**
* Created by PhpStorm.
* User: grego
* Date: 07/11/2022
* Time: 12:25
*/
namespace App\Controller\AdminBundle;
use App\Entity\Badge;
use App\Entity\BatchFeedbackEmail;
use App\Entity\Recipient;
use App\Entity\RequestLog;
use App\Entity\Skill;
use App\Entity\User;
use App\Manager\CossManager;
use App\Manager\GamificationManager;
use App\Manager\MailerManager;
use App\Manager\MistralManager;
use App\Manager\PeopleDataLabsManager;
use App\Manager\UserManager;
use App\Repository\BatchFeedbackEmailRepository;
use App\Repository\RecipientRepository;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use Sonata\MediaBundle\Provider\Pool;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class CRONController extends AbstractController
{
private $CRON_TOKEN = "ffd6600b2594eafae3b2f0528a4cb51a";
/**
* @Route("/cron/sendFeedbackRecap/{type}/{token}")
*/
public function sendFeedbackRecapAction(Request $request, $type, $token, EntityManagerInterface $entityManager, MailerManager $mailerManager)
{
if($token == $this->CRON_TOKEN) {
set_time_limit(0);
ini_set('max_execution_time', 3600); //3600 seconds = 1 heur
$twoDays = new DateTime();
$twoDays->modify('-2 days');
$userRepository = $entityManager->getRepository(User::class);
$users = $userRepository->createQueryBuilder('u')
->select('distinct u')
->leftJoin('u.recipients', 'r')
->where("u.enabled = false or u.lastLogin is NULL or u.platform = 'browser'")
->andWhere('r.lastRecallDate <= :twoDays or r.lastRecallDate is NULL');
$users->setParameter('twoDays', $twoDays);
$users->orderBy('u.id');
$users = $users->getQuery()->getResult();
foreach ($users as $user) {
if($user->getLocale()){
$request->setLocale($user->getLocale());
} else {
$request->setLocale('fr');
}
\Sentry\withScope(function (\Sentry\State\Scope $scope) use ($user, $mailerManager, $type) {
$scope->setUser([
'id' => $user->getId(),
'email' => $user->getEmail(),
]);
$scope->setTag('type', 'email');
try {
$mailerManager->sendFeedbackRecap($user, $type);
} catch (\Throwable $e) {
\Sentry\captureException($e);
}
});
}
return New Response("", 200);
} else {
return New Response("access denied", 401);
}
}
/**
* @Route("/cron/debug/quality/{token}")
*/
public function debugQuality($token, EntityManagerInterface $entityManager, HttpClientInterface $httpClient, MailerManager $mailerManager, UserManager $userManager, CossManager $cossManager, GamificationManager $gamificationManager, PeopleDataLabsManager $peopleDataLabsManager, MistralManager $mistralManager, TranslatorInterface $translator, ParameterBagInterface $parameterBag, UrlGeneratorInterface $router){
set_time_limit(0);
ini_set('max_execution_time', 3600); //3600 seconds = 1 heure
ini_set('memory_limit', '-1');
$user = $entityManager->getRepository(User::class)->find(12);
//$userStats = $mistralManager->getUserStatisticsForMistral($user);
//$response = $mistralManager->analyzeUserStats($userStats);
//$newAiSynthesis = $mistralManager->saveUserAISynthesis($user, $response);
return New Response("OK", 200);
}
/**
* @Route("/cron/export/connections/{token}/{start}/{end}")
*/
public function exportConnections($token, $start, $end, EntityManagerInterface $entityManager)
{
if($token == $this->CRON_TOKEN) {
$startDate = DateTime::createFromFormat('d-m-Y', $start);
$endDate = DateTime::createFromFormat('d-m-Y', $end);
if($startDate && $endDate){
$response = new StreamedResponse();
$response->setCallback(function() use ($entityManager, $startDate, $endDate){
$handle = fopen('php://output', 'w+');
fwrite($handle, implode(';',
[
'"Id utilisateur"',
'"Prénom utilisateur"',
'"Nom utilisateur"',
'"Email utilisateur"',
'"Société utilisateur"',
'"Fonction utilisateur"',
'"Niveau hiérarchique utilisateur"',
'"Date connexion"',
'"Heure connexion"',
'"Date création"',
'"Date suppression"'
]) . PHP_EOL);
$connexions = $entityManager->getRepository(RequestLog::class)->getLogsBetweenDates($startDate, $endDate);
foreach ($connexions as $connexion){
fwrite($handle, implode(';',
[
$connexion->getUser()->getId(),
$connexion->getUser()->getFirstname(),
$connexion->getUser()->getLastname(),
$connexion->getUser()->getEmail(),
$connexion->getUser()->getCompany(),
$connexion->getUser()->getJobTitle(),
$connexion->getUser()->getHierarchicalLevel(),
$connexion->getCreatedAt()->format("d/m/Y"),
$connexion->getCreatedAt()->format("H:i:s"),
$connexion->getUser()->getCreatedAt() ? $connexion->getUser()->getCreatedAt()->format('d/m/Y'): "",
$connexion->getUser()->getDeletedAt() ? $connexion->getUser()->getDeletedAt()->format('d/m/Y') : ""
]) . PHP_EOL);
}
fclose($handle);
});
$date = new \DateTime();
$now = $date->format('d_m_Y_H_i_s');
$filename = "coss_b2c_connections_export".$now.".csv";
$response->setStatusCode(200);
$response->headers->set('Content-Type', 'text/csv; charset=utf-8');
$response->headers->set('Content-Disposition','attachment; filename='.$filename.'');
return $response;
} else {
return New Response("wrong dates param", 401);
}
} else {
return New Response("access denied", 401);
}
}
/**
* @Route("/cron/send/batch/feedback/email/{token}")
*/
public function sendBatchFeedbackEmail($token, Request $request, EntityManagerInterface $entityManager, MailerManager $mailerManager, Pool $pool, TranslatorInterface $translator)
{
if ($token == $this->CRON_TOKEN) {
$batchFeedbacks = $entityManager->getRepository(BatchFeedbackEmail::class)->getPendingBatchFeedbacksPastFiveMinuts();
$groupedFeedbacks = array();
foreach ($batchFeedbacks as $batchFeedback) {
$feedback = $batchFeedback->getFeedback();
$request->setLocale($feedback->getSender()->getLocale());
$senderRecipient = $feedback->getSender()->getId() . '-' . $feedback->getRecipient()->getId();
// Get sender's photo url and name
$featured = $feedback->getSender()->getImage();
if ($featured) {
$provider = $pool->getProvider($featured->getProviderName());
$format = $provider->getFormatName($featured, "reference");
$senderImage = $request->getSchemeAndHttpHost()."/uploads/media/".$provider->generatePrivateUrl($featured, $format);
} else {
$senderImage = null;
}
$senderName = $feedback->getSender()->getFirstname()." ".$feedback->getSender()->getLastname();
if($feedback->getSender()->getCompany() != null){
$senderCompany = $feedback->getSender()->getCompany();
} else {
$senderCompany = $translator->trans(
"Pas de société", array(), 'mail'
);
}
if (isset($groupedFeedbacks[$senderRecipient])) {
$groupedFeedbacks[$senderRecipient]["feedbacks"][] = $feedback;
$groupedFeedbacks[$senderRecipient]["batchFeedbacks"][] = $batchFeedback;
} else {
$groupedFeedbacks[$senderRecipient]["name"] = $senderName;
$groupedFeedbacks[$senderRecipient]["company"] = $senderCompany;
$groupedFeedbacks[$senderRecipient]["photo"] = $senderImage;
$groupedFeedbacks[$senderRecipient]["feedbacks"] = array($feedback);
$groupedFeedbacks[$senderRecipient]["batchFeedbacks"] = array($batchFeedback);
}
}
$mailerManager->sendBatchFeedbackEmail($groupedFeedbacks);
foreach ($groupedFeedbacks as $groupedFeedback){
foreach ($groupedFeedback['batchFeedbacks'] as $batchFeedback){
$batchFeedback->setStatus(BatchFeedbackEmailRepository::STATUS_TREATED);
$entityManager->persist($batchFeedback);
}
}
$entityManager->flush();
return New Response("", 200);
} else {
return New Response("access denied", 401);
}
}
/**
* @Route("/cron/disable/licences/badge/{token}")
*/
public function checkLicencesBadgesAccess($token, EntityManagerInterface $entityManager)
{
if($token == $this->CRON_TOKEN) {
$users = $entityManager->getRepository(User::class)->findAll();
foreach($users as $user){
$badgesAccessExpirationDate = $user->getLicenceEndDate();
if($badgesAccessExpirationDate){
$badgesAccessExpirationDate->modify('+12 months');
$today = new DateTime();
if ($badgesAccessExpirationDate >= $today) {
$user->setBadgesAccess(false);
$entityManager->persist($user);
}
} else {
$user->setBadgesAccess(false);
$entityManager->persist($user);
}
}
$entityManager->flush();
return New Response("", 200);
} else {
return New Response("access denied", 401);
}
}
/**
* @Route("/cron/analyse/recipients/{token}")
*/
public function analyseRecipients($token, EntityManagerInterface $entityManager, PeopleDataLabsManager $peopleDataLabsManager, MistralManager $mistralManager){
if($token == $this->CRON_TOKEN) {
set_time_limit(0);
ini_set('max_execution_time', 600); //600 seconds = 10min
$pendingRecipients = $entityManager->getRepository(Recipient::class)->findBy(array('status' => RecipientRepository::STATUS_PENDING, 'analysisStatus' => RecipientRepository::ANALYSIS_PENDING));
foreach ($pendingRecipients as $recipient) {
try {
$user = $recipient->getAppUser();
if(!$user->getValidator()){ // Analysis only for 5Feedback validation
$userData = $peopleDataLabsManager->getUserCareer($user);
if ($userData['found'] == true) {
$senderData = array(
"firstname" => $user->getFirstname(),
"lastname" => $user->getLastname(),
"email" => $user->getEmail(),
"career" => $userData['data']
);
} else {
$senderData = array(
"firstname" => $user->getFirstname(),
"lastname" => $user->getLastname(),
"email" => $user->getEmail(),
"career" => array(
"company" => $user->getCompany(),
"job_title" => $user->getJobTitle(),
)
);
}
$status = "Réseau professionnel";
switch ($recipient->getStatus()) {
case RecipientRepository::SUPERIOR_RECIPIENT:
$status = "Manager";
break;
case RecipientRepository::PAIR_RECIPIENT:
$status = "Collègue";
break;
case RecipientRepository::GUEST_RECIPIENT:
$status = "Réseau professionnel";
break;
}
$recipientData = array(
"status" => $status,
"firstname" => $recipient->getUser()->getFirstname(),
"lastname" => $recipient->getUser()->getLastname(),
"email" => $recipient->getUser()->getEmail(),
"company" => $recipient->getCompany(),
"job_title" => $recipient->getTitle()
);
$response = $mistralManager->validateRecipient($senderData, $recipientData);
if ($response['status'] == true) {
if (isset($response['data'])) {
$recipient->setAnalysisData($response['data']);
$recipient->setAnalysisStatus(RecipientRepository::ANALYSIS_DONE);
$entityManager->persist($recipient);
$entityManager->flush();
}
} else {
$iterations = $recipient->getAnalysisIteration();
$iterations++;
if ($iterations >= 5) {
$recipient->setAnalysisStatus(RecipientRepository::ANALYSIS_EXPIRED);
} else {
$recipient->setAnalysisIteration($iterations);
}
$entityManager->persist($recipient);
$entityManager->flush();
continue;
}
}
} catch (Exception $exception) {
$iterations = $recipient->getAnalysisIteration();
$iterations++;
if ($iterations >= 5) {
$recipient->setAnalysisStatus(RecipientRepository::ANALYSIS_EXPIRED);
} else {
$recipient->setAnalysisIteration($iterations);
}
$entityManager->persist($recipient);
$entityManager->flush();
continue;
}
}
return New Response("", 200);
} else {
return New Response("access denied", 401);
}
}
/**
* @Route("/cron/test-all-emails/{token}", name="cron_test_all_emails")
*/
public function testAllEmailsAction(
$token,
Request $request,
MailerInterface $mailer,
ParameterBagInterface $parameterBag,
TranslatorInterface $translator,
UrlGeneratorInterface $router
) {
if ($token !== $this->CRON_TOKEN) {
return new Response("Access denied", 401);
}
set_time_limit(0);
ini_set('max_execution_time', 600);
$targetEmail = $request->query->get('to', 'bertrandpon@yopmail.com');
$locale = $request->query->get('locale', 'fr');
$request->setLocale($locale);
$translator->setLocale($locale);
$projectDir = $parameterBag->get('kernel.project_dir');
$dummyImagePath = $projectDir . '/public/build/images/avatar-default.png';
if (!file_exists($dummyImagePath)) {
$dummyImagePath = null;
}
$defaultAvatarUrl = ($request->getSchemeAndHttpHost() ?: 'https://b2c-back.dev.globalcoss.com') . '/build/images/avatar-default.png';
// 1. Mock User Object
$dummyUser = new class($targetEmail) {
private $email;
public function __construct($email) { $this->email = $email; }
public function getId() { return 1; }
public function getFirstname() { return 'Bertrand'; }
public function getLastname() { return 'Pon'; }
public function getEmail() { return $this->email; }
public function getLocale() { return 'fr'; }
public function getCompany() { return 'COSS Corp'; }
public function getJobTitle() { return 'Directeur de Projet'; }
public function getRoles() { return ['ROLE_COSS_USER']; }
public function getRecipientProofGuestToken() { return 'dummy-proof-token-123456'; }
public function getStudentProofGuestToken() { return 'dummy-student-token-654321'; }
public function getImage() { return null; }
public function __toString() { return 'Bertrand Pon'; }
};
// 2. Mock Skills
$dummySkill1 = new class {
public function getId() { return 1; }
public function getTitle() { return 'Écoute active'; }
public function getDescription() { return 'Capacité à écouter attentivement et reformuler les besoins des interlocuteurs.'; }
public function __toString() { return 'Écoute active'; }
};
$dummySkill2 = new class {
public function getId() { return 2; }
public function getTitle() { return 'Leadership & Coopération'; }
public function getDescription() { return 'Aptitude à fédérer et inspirer une équipe autour d\'une vision partagée.'; }
public function __toString() { return 'Leadership & Coopération'; }
};
$dummySkill3 = new class {
public function getId() { return 3; }
public function getTitle() { return 'Prise de décision'; }
public function getDescription() { return 'Capacité à trancher avec discernement dans des situations d\'incertitude.'; }
public function __toString() { return 'Prise de décision'; }
};
// 3. Mock Feedbacks
$createDummyFeedback = function($id, $skill) use ($dummyUser) {
return new class($id, $skill, $dummyUser) {
private $id;
private $skill;
private $user;
public function __construct($id, $skill, $user) {
$this->id = $id;
$this->skill = $skill;
$this->user = $user;
}
public function getId() { return $this->id; }
public function getSkill() { return $this->skill; }
public function getSender() { return $this->user; }
public function getRecipient() { return $this->user; }
public function getGuestToken() { return 'dummy-token-' . $this->id; }
public function getGuestUrl() { return 'https://coss-b2c.web.app/guest-answer/dummy-token-' . $this->id . '/' . $this->id; }
public function getStatus() { return 1; }
};
};
$dummyFeedback1 = $createDummyFeedback(101, $dummySkill1);
$dummyFeedback2 = $createDummyFeedback(102, $dummySkill2);
$dummyFeedback3 = $createDummyFeedback(103, $dummySkill3);
$results = [];
$definitions = $this->getTestEmailDefinitions(
$dummyUser,
$dummyFeedback1,
$dummyFeedback2,
$dummyFeedback3,
$defaultAvatarUrl,
$dummyImagePath,
$targetEmail
);
foreach ($definitions as $defKey => $def) {
try {
$email = (new TemplatedEmail())
->from(new Address(MailerManager::SENDER_EMAIL, MailerManager::SENDER_LABEL))
->to($targetEmail)
->subject('[TEST] ' . $def['subject'])
->htmlTemplate($def['template'])
->context($def['params']);
foreach ($def['attachments'] as $att) {
if (!empty($att['path']) && file_exists($att['path'])) {
$email->attachFromPath($att['path'], $att['name'] ?? null);
}
}
$mailer->send($email);
$results[] = [
'key' => $defKey,
'name' => $def['name'],
'template' => $def['template'],
'subject' => $def['subject'],
'status' => 'SUCCESS',
];
} catch (\Throwable $e) {
$results[] = [
'key' => $defKey,
'name' => $def['name'],
'template' => $def['template'],
'subject' => $def['subject'],
'status' => 'ERROR',
'error' => $e->getMessage(),
];
}
}
$totalSent = count($results);
$successCount = count(array_filter($results, function($r) { return $r['status'] === 'SUCCESS'; }));
$errorCount = count(array_filter($results, function($r) { return $r['status'] === 'ERROR'; }));
return new JsonResponse([
'target_email' => $targetEmail,
'total' => $totalSent,
'success' => $successCount,
'errors' => $errorCount,
'details' => $results
]);
}
/**
* @Route("/cron/test-email/{templateKey}/{token}", name="cron_test_single_email", defaults={"templateKey"="badges_automatic_email"})
*/
public function testSingleEmailAction(
$templateKey,
$token,
Request $request,
MailerInterface $mailer,
TranslatorInterface $translator,
ParameterBagInterface $parameterBag,
\Twig\Environment $twig
) {
if ($token !== $this->CRON_TOKEN) {
return new Response("Access denied", 401);
}
$targetEmail = $request->query->get('to', 'bertrandpon@yopmail.com');
$locale = $request->query->get('locale', 'fr');
$preview = $request->query->getBoolean('preview', false);
$request->setLocale($locale);
$translator->setLocale($locale);
$projectDir = $parameterBag->get('kernel.project_dir');
$dummyImagePath = $projectDir . '/public/build/images/avatar-default.png';
if (!file_exists($dummyImagePath)) {
$dummyImagePath = null;
}
$defaultAvatarUrl = ($request->getSchemeAndHttpHost() ?: 'https://b2c-back.dev.globalcoss.com') . '/build/images/avatar-default.png';
$dummyUser = new class($targetEmail) {
private $email;
public function __construct($email) { $this->email = $email; }
public function getId() { return 1; }
public function getFirstname() { return 'Bertrand'; }
public function getLastname() { return 'Pon'; }
public function getEmail() { return $this->email; }
public function getLocale() { return 'fr'; }
public function getCompany() { return 'COSS Corp'; }
public function getJobTitle() { return 'Directeur de Projet'; }
public function getRoles() { return ['ROLE_SUPER_ADMIN']; }
public function getRecipientProofGuestToken() { return 'dummy-proof-token-123456'; }
public function getStudentProofGuestToken() { return 'dummy-student-token-654321'; }
public function getImage() { return null; }
public function __toString() { return 'Bertrand Pon'; }
};
$dummySkill1 = new class {
public function getId() { return 1; }
public function getTitle() { return 'Écoute active'; }
public function getDescription() { return 'Capacité à écouter attentivement et reformuler les besoins des interlocuteurs.'; }
public function __toString() { return 'Écoute active'; }
};
$dummySkill2 = new class {
public function getId() { return 2; }
public function getTitle() { return 'Leadership & Coopération'; }
public function getDescription() { return 'Aptitude à fédérer et inspirer une équipe autour d\'une vision partagée.'; }
public function __toString() { return 'Leadership & Coopération'; }
};
$dummySkill3 = new class {
public function getId() { return 3; }
public function getTitle() { return 'Prise de décision'; }
public function getDescription() { return 'Capacité à trancher avec discernement dans des situations d\'incertitude.'; }
public function __toString() { return 'Prise de décision'; }
};
$createDummyFeedback = function($id, $skill) use ($dummyUser) {
return new class($id, $skill, $dummyUser) {
private $id;
private $skill;
private $user;
public function __construct($id, $skill, $user) {
$this->id = $id;
$this->skill = $skill;
$this->user = $user;
}
public function getId() { return $this->id; }
public function getSkill() { return $this->skill; }
public function getSender() { return $this->user; }
public function getRecipient() { return $this->user; }
public function getGuestToken() { return 'dummy-token-' . $this->id; }
public function getGuestUrl() { return 'https://coss-b2c.web.app/guest-answer/dummy-token-' . $this->id . '/' . $this->id; }
public function getStatus() { return 1; }
};
};
$dummyFeedback1 = $createDummyFeedback(101, $dummySkill1);
$dummyFeedback2 = $createDummyFeedback(102, $dummySkill2);
$dummyFeedback3 = $createDummyFeedback(103, $dummySkill3);
$definitions = $this->getTestEmailDefinitions(
$dummyUser,
$dummyFeedback1,
$dummyFeedback2,
$dummyFeedback3,
$defaultAvatarUrl,
$dummyImagePath,
$targetEmail
);
$def = null;
if (isset($definitions[$templateKey])) {
$def = $definitions[$templateKey];
} else {
// Check by numeric index or prefix
foreach ($definitions as $k => $d) {
if ($k === $templateKey || str_starts_with($d['name'], $templateKey . '.')) {
$def = $d;
break;
}
}
}
if (!$def) {
return new JsonResponse([
'status' => 'ERROR',
'message' => "Unknown templateKey '{$templateKey}'. Available keys: " . implode(', ', array_keys($definitions)),
], 404);
}
if ($preview) {
$rendered = $twig->render($def['template'], $def['params']);
return new Response($rendered, 200, ['Content-Type' => 'text/html; charset=UTF-8']);
}
try {
$email = (new TemplatedEmail())
->from(new Address(MailerManager::SENDER_EMAIL, MailerManager::SENDER_LABEL))
->to($targetEmail)
->subject('[TEST] ' . $def['subject'])
->htmlTemplate($def['template'])
->context($def['params']);
foreach ($def['attachments'] as $att) {
if (!empty($att['path']) && file_exists($att['path'])) {
$email->attachFromPath($att['path'], $att['name'] ?? null);
}
}
$mailer->send($email);
return new JsonResponse([
'status' => 'SUCCESS',
'template_key' => $templateKey,
'template_file' => $def['template'],
'subject' => '[TEST] ' . $def['subject'],
'target_email' => $targetEmail,
'preview_url' => $request->getSchemeAndHttpHost() . '/cron/test-email/' . $templateKey . '/' . $token . '?preview=1'
]);
} catch (\Throwable $e) {
return new JsonResponse([
'status' => 'ERROR',
'template_key' => $templateKey,
'template_file' => $def['template'],
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
], 500);
}
}
/**
* Helper returning all 25 synchronized test email definitions.
*/
private function getTestEmailDefinitions(
$dummyUser,
$dummyFeedback1,
$dummyFeedback2,
$dummyFeedback3,
$defaultAvatarUrl,
$dummyImagePath,
$targetEmail
): array {
return [
// --- GROUP 1: Authentication & Account Creation ---
'coss_account_student' => [
'name' => '1. Compte Étudiant / Candidat',
'subject' => 'Accédez dès maintenant à votre certification COSS by ESSEC & PwC',
'template' => 'ApiBundle/Mail/coss_account_student.html.twig',
'params' => ['user' => $dummyUser, 'password' => 'TempPass123!'],
'attachments' => []
],
'coss_account_client_admin' => [
'name' => '2. Compte Administrateur Client',
'subject' => 'Création de votre compte administrateur pour COSS by ESSEC & PwC',
'template' => 'ApiBundle/Mail/coss_account_client_admin.html.twig',
'params' => ['user' => $dummyUser, 'password' => 'TempPass123!'],
'attachments' => []
],
'coss_account_coach' => [
'name' => '3. Compte Coach / Tuteur',
'subject' => 'Accès administrateur à COSS by ESSEC & PwC',
'template' => 'ApiBundle/Mail/coss_account_coach.html.twig',
'params' => ['user' => $dummyUser, 'password' => 'TempPass123!'],
'attachments' => []
],
'coss_account_admin' => [
'name' => '4. Compte Administrateur Back-Office',
'subject' => 'COSS - Création de votre compte Super Administrateur',
'template' => 'ApiBundle/Mail/coss_account_admin.html.twig',
'params' => ['user' => $dummyUser, 'password' => 'TempPass123!', 'role' => 'Super Administrateur'],
'attachments' => []
],
'two_factor_email' => [
'name' => '5. Code 2FA / Connexion',
'subject' => 'COSS - Authentification à deux facteurs',
'template' => 'ApiBundle/Mail/two_factor_email.html.twig',
'params' => ['authCode' => '748291'],
'attachments' => []
],
'reset_password' => [
'name' => '6. Réinitialisation mot de passe',
'subject' => 'COSS - Réinitialisation de votre mot de passe',
'template' => 'CossBundle/reset_password/email.html.twig',
'params' => ['resetToken' => (object)['token' => 'sample-reset-token-xyz'], 'resetType' => 'client'],
'attachments' => []
],
// --- GROUP 2: Demandes d\'évaluation & Relances ---
'batch_feedback_recap_email' => [
'name' => '7. Demande d\'évaluation groupée',
'subject' => 'Aidez Bertrand Pon à certifier ses soft skills',
'template' => 'ApiBundle/Mail/batch_feedback_recap_email.html.twig',
'params' => [
'firstnameSender' => 'Bertrand',
'lastnameSender' => 'Pon',
'feedbacksBySender' => [
'name' => 'Bertrand Pon',
'company' => 'COSS Corp',
'photo' => null,
'feedbacks' => [$dummyFeedback1, $dummyFeedback2, $dummyFeedback3]
],
'locale' => 'fr',
'defaultAvatar' => $defaultAvatarUrl
],
'attachments' => []
],
'recall_2_feedback_recap_email' => [
'name' => '8. Relance évaluation J+2',
'subject' => 'Relance - Certification de Bertrand Pon, votre réponse est attendue dans les 48 heures',
'template' => 'ApiBundle/Mail/recall_2_feedback_recap_email.html.twig',
'params' => [
'fullnameFirstFeedback' => 'Bertrand Pon',
'feedbacksBySender' => [
'name' => 'Bertrand Pon',
'company' => 'COSS Corp',
'photo' => null,
'feedbacks' => [$dummyFeedback1, $dummyFeedback2]
],
'locale' => 'fr',
'defaultAvatar' => $defaultAvatarUrl
],
'attachments' => []
],
'recall_7_feedback_recap_email' => [
'name' => '9. Relance évaluation J+7',
'subject' => 'Relance - Bertrand Pon a besoin de 8 réponses minimum',
'template' => 'ApiBundle/Mail/recall_7_feedback_recap_email.html.twig',
'params' => [
'fullnameFirstFeedback' => 'Bertrand Pon',
'feedbacksBySender' => [
'name' => 'Bertrand Pon',
'company' => 'COSS Corp',
'photo' => null,
'feedbacks' => [$dummyFeedback1, $dummyFeedback2]
],
'locale' => 'fr',
'defaultAvatar' => $defaultAvatarUrl
],
'attachments' => []
],
'recall_manual_feedback_recap_email' => [
'name' => '10. Relance évaluation manuelle',
'subject' => 'Bertrand Pon vous relance pour sa certification ESSEC & PwC',
'template' => 'ApiBundle/Mail/recall_manual_feedback_recap_email.html.twig',
'params' => [
'fullnameFirstFeedback' => 'Bertrand Pon',
'feedbacksBySender' => [
'name' => 'Bertrand Pon',
'company' => 'COSS Corp',
'photo' => null,
'feedbacks' => [$dummyFeedback1, $dummyFeedback2]
],
'locale' => 'fr',
'defaultAvatar' => $defaultAvatarUrl
],
'attachments' => []
],
'bad_rating_email' => [
'name' => '11. Alerte mauvaise note (< 2)',
'subject' => '[BO-COSS] Moyenne inférieure à 2 - Bertrand Pon',
'template' => 'ApiBundle/Mail/bad_rating_email.html.twig',
'params' => ['feedback' => $dummyFeedback1],
'attachments' => []
],
// --- GROUP 3: Validation des répondants (Recipients) ---
'recipient_list_changed' => [
'name' => '12. Demande validation liste répondants (Manager)',
'subject' => 'Pour validation – Certification ESSEC & PwC de Bertrand Pon',
'template' => 'ApiBundle/Mail/recipient_list_changed.html.twig',
'params' => ['user' => $dummyUser, 'guestUrl' => 'https://manager.coss-certification.com/recipients/list/validation/sample-token/1'],
'attachments' => []
],
'recipient_list_changed_recall' => [
'name' => '13. Relance validation liste répondants (Manager)',
'subject' => 'Rappel — Validation en attente pour la certification de Bertrand Pon',
'template' => 'ApiBundle/Mail/recipient_list_changed_recall.html.twig',
'params' => ['user' => $dummyUser, 'guestUrl' => 'https://manager.coss-certification.com/recipients/list/validation/sample-token/1'],
'attachments' => []
],
'all_recipients_validated' => [
'name' => '14. Contacts tous validés',
'subject' => 'Vos contacts pour votre certification COSS by ESSEC & PwC ont été validés',
'template' => 'ApiBundle/Mail/all_recipients_validated.html.twig',
'params' => [
'user' => $dummyUser,
'recipients' => [
'validated' => [
(object)['user' => (object)['email' => 'collegue1@entreprise.com']],
(object)['user' => (object)['email' => 'manager@entreprise.com']],
]
]
],
'attachments' => []
],
'all_recipients_deleted' => [
'name' => '15. Contacts tous refusés',
'subject' => 'Vos contacts pour votre certification COSS by ESSEC & PwC ont été refusés',
'template' => 'ApiBundle/Mail/all_recipients_deleted.html.twig',
'params' => [
'user' => $dummyUser,
'recipients' => [
'deleted' => [
(object)['user' => (object)['email' => 'fake1@perso.com'], 'comment' => 'Adresse email personnelle non autorisée'],
(object)['user' => (object)['email' => 'fake2@gmail.com'], 'comment' => 'Incohérence entreprise'],
]
]
],
'attachments' => []
],
'all_recipients_info' => [
'name' => '16. Contacts - Complément d\'informations requis',
'subject' => 'COSS by ESSEC & PwC – Besoin d’information complémentaires',
'template' => 'ApiBundle/Mail/all_recipients_info.html.twig',
'params' => [
'user' => $dummyUser,
'recipients' => [
'info' => [
(object)['user' => (object)['email' => 'contact1@gmail.com'], 'comment' => 'Merci de fournir une preuve professionnelle']
]
],
'link' => 'https://app.coss-certification.com/guest/recipients/proof/1/dummy-proof-token-123456'
],
'attachments' => []
],
'recipients_multi_cases' => [
'name' => '17. Contacts - Cas mixte (validés / infos / refusés)',
'subject' => 'COSS by ESSEC & PwC – Résultat de l’analyse de vos contacts',
'template' => 'ApiBundle/Mail/recipients_multi_cases.html.twig',
'params' => [
'user' => $dummyUser,
'recipients' => [
'validated' => [
(object)['user' => (object)['email' => 'valide@entreprise.com']]
],
'info' => [
(object)['user' => (object)['email' => 'douteux@gmail.com'], 'comment' => 'Lien LinkedIn requis']
],
'deleted' => [
(object)['user' => (object)['email' => 'refuse@jetable.fr'], 'comment' => 'Domaine jetable non autorisé']
]
],
'link' => 'https://app.coss-certification.com/guest/recipients/proof/1/dummy-proof-token-123456'
],
'attachments' => []
],
'coss_new_proof' => [
'name' => '18. Alerte admin - Nouvelle preuve ajoutée',
'subject' => 'Validation des répondants - Un utilisateur a ajouté une preuve',
'template' => 'ApiBundle/Mail/coss_new_proof.html.twig',
'params' => ['appUser' => $dummyUser, 'recipients' => [], 'proofs' => []],
'attachments' => []
],
// --- GROUP 4: Badges & Certifications ---
'badges_email' => [
'name' => '19. Envoi manuel Badge certifié',
'subject' => 'Votre certification COSS by ESSEC et PwC',
'template' => 'ApiBundle/Mail/badges_email.html.twig',
'params' => ['user' => $dummyUser, 'link' => 'https://app.coss-certification.com/badges/sample-token', 'skill' => 'Écoute active'],
'attachments' => $dummyImagePath ? [['path' => $dummyImagePath, 'name' => 'badge-ecoute-active.png']] : []
],
'badges_automatic_email' => [
'name' => '20. Félicitations Badge automatique certifié',
'subject' => 'Félicitations, vous avez certifié votre compétence Leadership',
'template' => 'ApiBundle/Mail/badges_automatic_email.html.twig',
'params' => [
'user' => $dummyUser,
'link' => 'https://app.coss-certification.com/badges/sample-token',
'linkedinUrl' => 'https://www.linkedin.com/profile/add?startTask=CERTIFICATION_NAME&name=' . urlencode('Leadership: 4.5/5') . '&organizationId=79273788&issueYear=' . date('Y') . '&issueMonth=' . date('n') . '&certUrl=' . urlencode('https://app.coss-certification.com/badges/sample-token'),
'badge' => ['skill' => 'Leadership', 'average' => 4.5, 'year' => date('Y'), 'month' => date('n')]
],
'attachments' => $dummyImagePath ? [['path' => $dummyImagePath, 'name' => 'badge-leadership.png']] : []
],
'badges_recap_email' => [
'name' => '21. Récapitulatif Badges certifiés',
'subject' => 'Vos certifications COSS',
'template' => 'ApiBundle/Mail/badges_recap_email.html.twig',
'params' => [
'user' => $dummyUser,
'links' => [
'https://app.coss-certification.com/badges/sample-token-1',
'https://app.coss-certification.com/badges/sample-token-2'
]
],
'attachments' => $dummyImagePath ? [['path' => $dummyImagePath, 'name' => 'badge-ecoute-active.png']] : []
],
// --- GROUP 5: Synthèse IA, Quiz IA & Justificatifs Étudiant ---
'synthesis_unlocked_email' => [
'name' => '22. Synthèse IA débloquée',
'subject' => 'Découvrez votre synthèse COSS personnalisée – Vos talents et vos axes de progression !',
'template' => 'ApiBundle/Mail/synthesis_unlocked_email.html.twig',
'params' => ['user' => $dummyUser],
'attachments' => []
],
'quiz_skill_recommendation' => [
'name' => '23. Recommandations Quiz IA',
'subject' => 'Quelles compétences certifier pour mon projet professionnel ?',
'template' => 'ApiBundle/Mail/quiz_skill_recommendation.html.twig',
'params' => [
'quizSkillRecommendation' => [
'data' => [
'skills' => [
['title' => 'Leadership & Influence', 'description' => 'Capacité à mobiliser et inspirer une équipe vers un objectif commun.'],
['title' => 'Communication interpersonnelle', 'description' => 'Aptitude à adapter son message et interagir efficacement avec tout profil.'],
['title' => 'Gestion du stress & Résilience', 'description' => 'Maintien de la performance et de la lucidité dans les contextes exigeants.'],
['title' => 'Résolution de problèmes complexes', 'description' => 'Approche méthodique pour déconstruire les enjeux et trouver des solutions viables.'],
['title' => 'Esprit critique & Agilité', 'description' => 'Capacité de remise en question constructive et d\'adaptation rapide aux évolutions.']
]
]
]
],
'attachments' => []
],
'student_proof_info' => [
'name' => '24. Demande justificatif tarif étudiant',
'subject' => 'COSS by ESSEC & PwC - Complément d’information pour valider votre éligibilité au tarif étudiant/jeune diplômé',
'template' => 'ApiBundle/Mail/student_proof_info.html.twig',
'params' => ['user' => $dummyUser, 'upload_link' => 'https://app.coss-certification.com/guest/student-proof/1/dummy-student-token-654321'],
'attachments' => []
],
'student_proof_declined' => [
'name' => '25. Justificatif étudiant refusé',
'subject' => 'Retour sur votre éligibilité au tarif étudiant/jeune diplômé – COSS by ESSEC & PwC',
'template' => 'ApiBundle/Mail/student_proof_declined.html.twig',
'params' => ['user' => $dummyUser, 'payment_link' => 'https://buy.stripe.com/9B63cvdpL2sCaAKfZEfnO02?prefilled_email=' . urlencode($targetEmail) . '&client_reference_id=upgrade_1'],
'attachments' => []
]
];
}
}