Commit bbc50df0 authored by Mat's avatar Mat

améliore, factorise, déplace une fonction, utilise les objets si possible

parent e6b8094f
......@@ -4,7 +4,6 @@ namespace PotageBundle\Command;
use PotageBundle\Entity\Offre;
use PotageBundle\Entity\User;
use PotageBundle\Services\LettreToken;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
......@@ -34,12 +33,13 @@ class CronOffreCommand extends ContainerAwareCommand
{
$this
->setName('potage:cron:offre')
->setDescription("Vérifie la date d'expiration des offres en cours");
->setDescription("Archive les offres qui sont expirées");
}
/**
* Vérifie que les offres en cours n'ont pas expiré.
* Si c'est le cas, le statut est changé et un mail est envoyé aux maraichers.
* Si c'est le cas, le statut est changé, les tokens associés sont révoqués
* et un mail est envoyé aux maraichers.
*
* @param InputInterface $input
* @param OutputInterface $output
......@@ -48,9 +48,11 @@ class CronOffreCommand extends ContainerAwareCommand
protected function execute(InputInterface $input, OutputInterface $output)
{
$em = $this->getContainer()->get('doctrine')->getManager();
$em = $this->getContainer()->get('doctrine')
->getManager();
$currentOffre = $em->getRepository('PotageBundle:Offre')
$currentOffre = $em
->getRepository('PotageBundle:Offre')
->findAllByStatusForRead('current');
$now = new \DateTime('now');
......@@ -62,16 +64,18 @@ class CronOffreCommand extends ContainerAwareCommand
{
if ($offre->getEndedAt() <= $now) {
// change le statut de l'offre
$offre->setStatus('closed');
$output->write(
"\n"
. $offre->getReference()
. ": offre expired since "
. date_format($offre->getEndedAt(), "d/m/Y H:i")
. ", change status to archive..\n");
$offre->setStatus('closed');
. ", change status to archive..\n"
);
$ret = $this->revoquePotageUsersTokens($offre);
// révoque les tokens
$ret = $this->lettreToken->revoquePotageUsersTokens($offre);
$output->writeln($ret);
// TODO envoyer un mail au gestionnaire pour notifier l'expiration de l'offre
......@@ -81,49 +85,6 @@ class CronOffreCommand extends ContainerAwareCommand
$output->write("\nDone\n");
}
/**
* On parcourt la table User, colonne tokenKey
* Chaque token est décodé et s'il correspond à l'offre expirée, on le supprime
*
* @param Offre $offre
* @return array
*/
private function revoquePotageUsersTokens(Offre $offre)
{
$em = $this->getContainer()
->get('doctrine')->getManager();
$usersTokenKeys = $em->getRepository('PotageBundle:User')
->findAllTokenKeys();
$log = array();
foreach ($usersTokenKeys as $userTokenKeys)
{
foreach ($userTokenKeys['tokenKey'] as $uTokenKey)
{
$uOffre = intval($this->lettreToken->decodePotageUserToken($uTokenKey)['offre_id']);
if ($uOffre === $offre->getId())
{
/**
* @var User $user
*/
$user = $em->getRepository('PotageBundle:User')
->find($userTokenKeys['id']);
$user->removeTokenKey($uTokenKey);
$log[] = " User ". $userTokenKeys['id'] . ", removing token ". $uTokenKey;
}
}
}
$em->flush();
count($log) === 0 ? $log[] = " No tokens detected for this offre !" : null ;
return $log;
}
......
......@@ -28,29 +28,19 @@ class DefaultController extends MasterController
*
* @param Request $request
* @param Newsletter $newsletter
* @param LettreToken $lettreToken
* @return \Symfony\Component\HttpFoundation\Response
* @throws \Twig_Error_Loader
* @throws \Twig_Error_Runtime
* @throws \Twig_Error_Syntax
*/
public function testAction(Request $request, Newsletter $newsletter, LettreToken $lettreToken)
public function testAction(Request $request, Newsletter $newsletter)
{
/**
* @var Lettre $lettre
*/
$lettre = $this->get('doctrine')->getManager()
->getRepository('PotageBundle:Lettre')
->findOneForSend(7);
$header = array(
'id' => $lettre->getId(),
'start' => $lettre->getStartedAt(),
'end' => $lettre->getEndedAt(),
'status' => $lettre->getStatus(),
'subject' =>$lettre->getSubject(),
'reference' => $lettre->getReference(),
);
->findOneForSend(5);
/**
* Initilalise un formulaire simple pour déclencher l'envoi
......@@ -66,12 +56,13 @@ class DefaultController extends MasterController
$retour = null;
if ($form->isSubmitted() && $form->isValid())
{
$retour = $newsletter->sendLettreToGroup($lettre, $lettreToken);
// Envoi de la newsletter
$retour = $newsletter->sendLettreToGroup($lettre);
}
return $this->render('@Potage/Default/test.html.twig', array(
'lettre' => $header,
'formEnvoi' => $form->createView(),
'lettre' => $lettre,
'retour'=> $retour,
));
}
......
......@@ -12,19 +12,6 @@ use Symfony\Component\Security\Core\User\UserInterface;
*/
class UserRepository extends \Doctrine\ORM\EntityRepository implements UserLoaderInterface
{
/**
* @param $id_utilisateur
* @return mixed
* @throws \Doctrine\ORM\NonUniqueResultException
*/
public function findOneByUtilisateur($id_utilisateur)
{
$qb = $this->createQueryBuilder('fu')
->join('fu.utilisateur', 'u')
->where('u.id = :id')
->setParameter(':id', $id_utilisateur);
return $qb->getQuery()->getOneOrNullResult();
}
/**
* Dans security, je ne peux me référer à une propriété, puisque token_key est un array sérialisé
......
......@@ -125,7 +125,6 @@ class UtilisateurRepository extends \Doctrine\ORM\EntityRepository
public function findAllByGroup($id_group)
{
$qb = $this->createQueryBuilder('u')
->select('u.id', 'u.nom', 'u.prenom', 'u.email')
->join('u.groupes', 'g')
->where('g.id = :id')
->setParameter(':id', $id_group);
......
......@@ -10,7 +10,7 @@
<h2>Infolettre #{{ lettre.id }}</h2>
<h3>{{ lettre.subject }}</h3>
<h4>Période du {{ lettre.start|date('d-m-Y') }} au {{ lettre.end|date('d-m-Y') }}</h4>
<h4>Période du {{ lettre.startedAt|date('d-m-Y') }} au {{ lettre.endedAt|date('d-m-Y') }}</h4>
<h3>Envoyer la lettre</h3>
{{ form(formEnvoi) }}
......@@ -19,11 +19,15 @@
<hr>
<div>
<h4>Référence: {{ lettre.reference }}</h4>
<h5>Statut: {{ lettre.status }}</h5>
<h5>Offre attachée: {{ lettre.offre.reference }} (#{{ lettre.offre.id }})</h5>
<h5>Envoi à :</h5>
<ul>
{% for item in retour %}
<li>{{ loop.index }}) {{ item.to }}{{ item.result }}</li>
{% for mail in retour %}
<li>{{ loop.index }}) {{ mail.tostring }} <span class="text-success">{{ mail.result }}</span><br>
<span class="small text-muted">→ token attached: {{ mail.to.token }}
{% if not mail.to.token %}<span class="text-danger">Null</span>{% endif %}
</span>
</li>
{% endfor %}
</ul>
</div>
......
......@@ -3,7 +3,7 @@
namespace PotageBundle\Services;
use PotageBundle\Entity\Lettre;
use PotageBundle\Entity\Offre;
use PotageBundle\Entity\User;
use Symfony\Component\DependencyInjection\ContainerInterface;
......@@ -36,23 +36,14 @@ class LettreToken
/**
* @param int $id_utilisateur
* @param Lettre $lettre
* Encode un token unique pour une offre et un user
*
* @param User $user
* @param Offre $offre
* @return mixed
*/
public function encodePotageUserToken($id_utilisateur, Lettre $lettre)
public function encodePotageUserToken(User $user, Offre $offre)
{
/**
* Si l'utilisateur n'est pas associé à un user, token => null
* TODO il faudra alors l'inviter à se créer un compte user,
* après quoi il accèdera à sa page today, qui lui affichera alors les offres liée à ses groupes.
* Et cela même s'il n'avait pas encore de compte user quand la lettre a été envoyée !
*
* @var User $user
*/
$user = $this->container->get('doctrine')
->getRepository('PotageBundle:User')
->findOneByUtilisateur($id_utilisateur);
if ($user !== null) {
......@@ -60,7 +51,7 @@ class LettreToken
* Vérifie d'abord qu'aucun token pour cette offre n'existe pour cet utilisateur.
* Pour cela on va parcourir le tableau, récupérer l'offre, et la retourner si elle existe
*/
$newOffre = $lettre->getOffre()->getId();
$newOffre = $offre->getId();
$userTokenKeys = $user->getTokenKey();
foreach ($userTokenKeys as $uTokenKey)
......@@ -68,7 +59,7 @@ class LettreToken
$uOffre = intval($this->decodePotageUserToken($uTokenKey)['offre_id']);
if ($uOffre === $newOffre)
{
return $uTokenKey;
return $uTokenKey; // on s'arrête là
}
}
......@@ -78,8 +69,8 @@ class LettreToken
$newKey = bin2hex(random_bytes(15));
$token = $newKey
.'_'. $lettre->getOffre()->getId()
.'_'. $lettre->getOffre()->getReference();
.'_'. $offre->getId()
.'_'. $offre->getReference();
$tokenKey = base64_encode($token);
......@@ -101,6 +92,8 @@ class LettreToken
/**
* Décode un token
*
* @param $token
* @return array
*/
......@@ -114,4 +107,55 @@ class LettreToken
'offre_ref' => $data[2],
);
}
/**
* Révoque les tokens d'une offre
*
* On parcourt la table User, colonne tokenKey
* Chaque token est décodé et s'il correspond à l'offre expirée, on le supprime
*
* @param Offre $offre
* @return array
*/
public function revoquePotageUsersTokens(Offre $offre)
{
$log = array();
$em = $this->container->get('doctrine')->getManager();
/**
* @var array $usersTokenKeys
*/
$usersTokenKeys = $em->getRepository('PotageBundle:User')
->findAllTokenKeys();
foreach ($usersTokenKeys as $userTokenKeys)
{
foreach ($userTokenKeys['tokenKey'] as $uTokenKey)
{
$uOffre = intval($this->decodePotageUserToken($uTokenKey)['offre_id']);
if ($uOffre === $offre->getId())
{
/**
* @var User $user
*/
$user = $em->getRepository('PotageBundle:User')
->find($userTokenKeys['id']);
// enlève le token
$user->removeTokenKey($uTokenKey);
$log[] = " User ". $userTokenKeys['id'] . ", removing token ". $uTokenKey;
}
}
}
$em->flush();
count($log) === 0 ? $log[] = " No tokens detected for this offre !" : null ;
return $log;
}
}
\ No newline at end of file
......@@ -2,7 +2,10 @@
namespace PotageBundle\Services;
use PotageBundle\Entity\Groupe;
use PotageBundle\Entity\Lettre;
use PotageBundle\Entity\Offre;
use PotageBundle\Entity\User;
use Symfony\Component\DependencyInjection\ContainerInterface;
class Newsletter
......@@ -11,22 +14,23 @@ class Newsletter
/**
* Expéditeur, l'application elle-même
* alternc sur grabuge: la mbox postmaster@potage.domainepublic.site est redirigée vers
* -> mathieu@grabuge.domainepublic.net
* -> jaummathieu@collectifs.net
*/
private $from = ['postmaster@potage.domainepublic.site' => 'Potage'];
private $container;
private $lettreToken;
/**
* Newsletter constructor.
*
* @param ContainerInterface $container
* @param LettreToken $lettreToken
*/
public function __construct(ContainerInterface $container)
public function __construct(ContainerInterface $container, LettreToken $lettreToken)
{
$this->container = $container;
$this->lettreToken = $lettreToken;
}
......@@ -139,46 +143,68 @@ class Newsletter
* (à son groupe d'utilisateurs)
*
* @param Lettre $lettre
* @param LettreToken $lettreToken
* @return array
* @throws \Twig_Error_Loader
* @throws \Twig_Error_Runtime
* @throws \Twig_Error_Syntax
*/
public function sendLettreToGroup(Lettre $lettre, LettreToken $lettreToken)
public function sendLettreToGroup(Lettre $lettre)
{
$subject = $lettre->getSubject();
/**
* A partir de l'infolettre on récupère les destinataires
* @var Offre $offre
* @var Groupe $groupe
*/
$offre = $lettre->getOffre();
$groupe = $lettre->getGroupe();
/**
* Les destinataires du groupe de l'infolettre,
* un tableau d'utilisteurs
*
* @var array $utilisateurs
*/
$groupe = $lettre->getGroupe()->getId();
$utilisateurs = $this->container->get('doctrine')
->getRepository('PotageBundle:Utilisateur')
->findAllByGroup($groupe);
->findAllByGroup($groupe->getId());
/**
* Boucle sur chaque utilisateur, envoie le mail,
* récupère le code de retour dans un tableau
*/
$ret = array();
$retour = array();
for ($i = 0; $i < count($utilisateurs); $i++)
{
/**
* @var User $user
*/
$user = $utilisateurs[$i]->getUser();
$token = null;
if ($user) {
$token = $this->lettreToken->encodePotageUserToken($user, $offre);
}
// TODO quid des utilisateurs qui n'ont pas encore de compte user ?
$to = array(
'id' => $utilisateurs[$i]['id'],
'fullName' => $utilisateurs[$i]['prenom'] .' '. $utilisateurs[$i]['nom'],
'email' => $utilisateurs[$i]['email'],
'token' => $lettreToken->encodePotageUserToken($utilisateurs[$i]['id'], $lettre)
);
dump($to);
'fullName' => $utilisateurs[$i]->getPrenom() .' '. $utilisateurs[$i]->getNom(),
'email' => $utilisateurs[$i]->getEmail(),
'token' => $token
); //dump($to);
$ret[$i] = array(
'to' => $this->parseMail($to),
'result' => $this->sendMail($to, $subject, $lettre) === 1 ? 'sent' : 'error'
// envoi du mail
$result = $this->sendMail($to, $subject, $lettre) === 1 ? 'Sent' : 'Error';
$retour[$i] = array(
'to' => $to,
'tostring' => $this->parseMail($to),
'result' => $result
);
}
return $ret;
return $retour;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment