mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-18 07:23:13 +00:00
Merge branch 'master' of https://github.com/alchemy-fr/Phraseanet into PHRAS-3189_Admin_expose_setting
This commit is contained in:
2
.env
2
.env
@@ -68,7 +68,7 @@ PHRASEANET_SWFTOOLS_TIMEOUT=120
|
||||
PHRASEANET_UNOCON_TIMEOUT=120
|
||||
PHRASEANET_EXIFTOOL_TIMEOUT=120
|
||||
|
||||
# network
|
||||
# network : comma separated list of IP ou SUBNETS
|
||||
|
||||
PHRASEANET_TRUSTED_PROXIES=
|
||||
|
||||
|
@@ -40,6 +40,7 @@ use Alchemy\Phrasea\Command\Plugin\AddPlugin;
|
||||
use Alchemy\Phrasea\Command\Plugin\RemovePlugin;
|
||||
use Alchemy\Phrasea\Command\CheckConfig;
|
||||
use Alchemy\Phrasea\Command\SearchEngine\MappingUpdateCommand;
|
||||
use Alchemy\Phrasea\Command\SendValidationRemindersCommand;
|
||||
use Alchemy\Phrasea\Command\Setup\H264ConfigurationDumper;
|
||||
use Alchemy\Phrasea\Command\Setup\H264MappingGenerator;
|
||||
use Alchemy\Phrasea\Command\Setup\XSendFileConfigurationDumper;
|
||||
@@ -169,6 +170,8 @@ $cli->command(new WorkerExecuteCommand());
|
||||
$cli->command(new WorkerRunServiceCommand());
|
||||
$cli->command(new WorkerShowConfigCommand());
|
||||
|
||||
$cli->command(new SendValidationRemindersCommand());
|
||||
|
||||
$cli->loadPlugins();
|
||||
|
||||
$cli->run();
|
||||
|
@@ -16,7 +16,10 @@ if [ -f "$FILE" ]; then
|
||||
bin/setup system:config set registry.general.title $PHRASEANET_PROJECT_NAME
|
||||
fi
|
||||
if [[ -n $PHRASEANET_TRUSTED_PROXIES ]]; then
|
||||
bin/setup system:config add trusted-proxies $PHRASEANET_TRUSTED_PROXIES
|
||||
for i in $(echo $PHRASEANET_TRUSTED_PROXIES | sed "s/,/ /g")
|
||||
do
|
||||
bin/setup system:config add trusted-proxies $i
|
||||
done
|
||||
fi
|
||||
|
||||
bin/setup system:config set main.binaries.ffmpeg_timeout $PHRASEANET_FFMPEG_TIMEOUT
|
||||
|
@@ -114,14 +114,17 @@ abstract class Command extends SymfoCommand implements CommandInterface
|
||||
*/
|
||||
public function getFormattedDuration($seconds)
|
||||
{
|
||||
$duration = ceil($seconds) . ' seconds';
|
||||
|
||||
if ($duration > 60) {
|
||||
$duration = round($duration / 60, 1) . ' minutes';
|
||||
} elseif ($duration > 3600) {
|
||||
$duration = round($duration / (60 * 60), 1) . ' hours';
|
||||
} elseif ($duration > (24 * 60 * 60)) {
|
||||
$duration = round($duration / (24 * 60 * 60), 1) . ' days';
|
||||
if ($seconds > (24 * 3600)) {
|
||||
$duration = round($seconds / (24 * 3600), 1) . ' days';
|
||||
}
|
||||
elseif ($seconds > 3600) {
|
||||
$duration = round($seconds / (3600), 1) . ' hours';
|
||||
}
|
||||
elseif ($seconds > 60) {
|
||||
$duration = round($seconds / 60, 1) . ' minutes';
|
||||
}
|
||||
else {
|
||||
$duration = ceil($seconds) . ' seconds';
|
||||
}
|
||||
|
||||
return $duration;
|
||||
|
351
lib/Alchemy/Phrasea/Command/SendValidationRemindersCommand.php
Normal file
351
lib/Alchemy/Phrasea/Command/SendValidationRemindersCommand.php
Normal file
@@ -0,0 +1,351 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2020 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Command;
|
||||
|
||||
use Alchemy\Phrasea\Application\Helper\NotifierAware;
|
||||
use Alchemy\Phrasea\Core\Configuration\PropertyAccess;
|
||||
use Alchemy\Phrasea\Core\LazyLocator;
|
||||
use Alchemy\Phrasea\Model\Entities\Basket;
|
||||
use Alchemy\Phrasea\Model\Entities\User;
|
||||
use Alchemy\Phrasea\Model\Entities\ValidationParticipant;
|
||||
use Alchemy\Phrasea\Model\Repositories\TokenRepository;
|
||||
use Alchemy\Phrasea\Model\Repositories\ValidationParticipantRepository;
|
||||
use Alchemy\Phrasea\Notification\Emitter;
|
||||
use Alchemy\Phrasea\Notification\Mail\MailInfoValidationReminder;
|
||||
use Alchemy\Phrasea\Notification\Receiver;
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Exception;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class SendValidationRemindersCommand extends Command
|
||||
{
|
||||
use NotifierAware;
|
||||
|
||||
const DATE_FMT = "Y-m-d H:i:s";
|
||||
|
||||
/** @var InputInterface */
|
||||
private $input;
|
||||
|
||||
/** @var OutputInterface */
|
||||
private $output;
|
||||
|
||||
/** @var bool */
|
||||
private $dry;
|
||||
|
||||
/** @var DateTime */
|
||||
private $now;
|
||||
|
||||
private $days;
|
||||
|
||||
public function __construct( /** @noinspection PhpUnusedParameterInspection */ $name = null)
|
||||
{
|
||||
parent::__construct('validation:remind');
|
||||
|
||||
$this->setDescription('Send validation reminders. <comment>(experimental)</comment>');
|
||||
$this->addOption('dry',null, InputOption::VALUE_NONE,'dry run, list but don\'t act');
|
||||
$this->addOption('now', null,InputArgument::OPTIONAL, 'fake today');
|
||||
$this->addOption('days', null,InputArgument::OPTIONAL, 'overwrite validation-reminder-days');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* sanity check the cmd line options
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function sanitizeArgs()
|
||||
{
|
||||
$r = true;
|
||||
|
||||
// --dry
|
||||
$this->dry = $this->input->getOption('dry') ? true : false;
|
||||
|
||||
// --now
|
||||
if(($v = $this->input->getOption('now')) !== null) {
|
||||
try {
|
||||
$this->now = new DateTime($v);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$this->output->writeln(sprintf('<error>bad --date "%s"</error>', $v));
|
||||
$r = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->now = new DateTime();
|
||||
}
|
||||
|
||||
// --days
|
||||
if(($v = $this->input->getOption('days')) !== null) {
|
||||
if(($this->days = (int)$v) <= 0) {
|
||||
$this->output->writeln(sprintf('<error>--days must be > 0 (bad value "%s")</error>', $v));
|
||||
$r = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->days = (int)$this->getConf()->get(['registry', 'actions', 'validation-reminder-days']);
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
protected function doExecute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->input = $input;
|
||||
$this->output = $output;
|
||||
|
||||
$this->setDelivererLocator(new LazyLocator($this->container, 'notification.deliverer'));
|
||||
|
||||
if(!$this->sanitizeArgs()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
$date_to = clone($this->now);
|
||||
$interval = sprintf('P%dD', $this->days);
|
||||
try {
|
||||
$date_to->add(new DateInterval($interval));
|
||||
}
|
||||
catch(Exception $e) {
|
||||
$this->output->writeln(sprintf('<error>Bad interval "%s" ?</error>', $interval));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if($this->dry) {
|
||||
$this->output->writeln('<info>dry mode : emails will NOT be sent</info>');
|
||||
}
|
||||
|
||||
$output->writeln(sprintf('from "%s" to "%s" (days=%d), ', $this->now->format(self::DATE_FMT), $date_to->format(self::DATE_FMT), $this->days));
|
||||
|
||||
$fmt = ' participant: %-11s user: %-10s %s token: %-10s ';
|
||||
//$output->writeln(sprintf($fmt, 'session', 'basket', 'participant', 'user', 'token', 'email'));
|
||||
|
||||
$last_session = null;
|
||||
foreach ($this->getValidationParticipantRepository()->findNotConfirmedAndNotRemindedParticipantsByExpireDate($date_to, $this->now) as $participant) {
|
||||
$validationSession = $participant->getSession();
|
||||
$basket = $validationSession->getBasket();
|
||||
|
||||
// change session ? display header
|
||||
if($validationSession->getId() !== $last_session) {
|
||||
try {
|
||||
$basket_name = $basket->getName();
|
||||
}
|
||||
catch(Exception $e) {
|
||||
// basket not found ?
|
||||
$basket_name = '?';
|
||||
}
|
||||
|
||||
try {
|
||||
$initiator_email = $validationSession->getInitiator()->getEmail();
|
||||
}
|
||||
catch(Exception $e) {
|
||||
// initiator user not found ?
|
||||
$initiator_email = '?';
|
||||
}
|
||||
|
||||
$output->writeln('');
|
||||
$output->writeln(sprintf('session_id: %s (created %s by "%s", expire %s), basket_id: %s ("%s")',
|
||||
$validationSession->getId(),
|
||||
$validationSession->getCreated()->format(self::DATE_FMT),
|
||||
$initiator_email,
|
||||
$validationSession->getExpires()->format(self::DATE_FMT),
|
||||
$basket->getId(),
|
||||
$basket_name
|
||||
));
|
||||
|
||||
$last_session = $validationSession->getId();
|
||||
}
|
||||
|
||||
// now display participant
|
||||
$can_send = true;
|
||||
|
||||
// fu..ing doctrine : we can get user id if user does not exists ! we must try to hydrate to get an exception !
|
||||
$user = $participant->getUser(); // always ok !
|
||||
try {
|
||||
$str_email = $user->getEmail(); // force to hydrate
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$str_email = 'user not found';
|
||||
$can_send = false;
|
||||
}
|
||||
|
||||
// find the token if exists
|
||||
// nb : a validation may have not generated tokens if forcing auth was required upon creation
|
||||
$token = null;
|
||||
try {
|
||||
$token = $this->getTokenRepository()->findValidationToken($basket, $user);
|
||||
if($token) {
|
||||
$str_token = sprintf('%s (cre. %s, exp. %s)',
|
||||
$this->dotdot($token->getValue(), 10),
|
||||
$token->getCreated()->format(self::DATE_FMT),
|
||||
($token->getExpiration())? $token->getExpiration()->format(self::DATE_FMT): "null"
|
||||
);
|
||||
}
|
||||
else {
|
||||
$str_token = '(no token))'; // token not found
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
// not unique token ? should not happen
|
||||
$str_token = sprintf('<error>%s</error>', $e->getMessage());
|
||||
$can_send = false;
|
||||
}
|
||||
|
||||
$output->writeln(sprintf($fmt,
|
||||
$this->dotdot($participant->getId(), 10),
|
||||
$this->dotdot($user->getId(), 10),
|
||||
$this->dotdot($str_email, 30, 'left', '"', '"'),
|
||||
$str_token
|
||||
)
|
||||
);
|
||||
|
||||
if(!$can_send) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!is_null($token)) {
|
||||
$url = $this->container->url('lightbox_validation', ['basket' => $basket->getId(), 'LOG' => $token->getValue()]);
|
||||
}
|
||||
else {
|
||||
$url = $this->container->url('lightbox_validation', ['basket' => $basket->getId()]);
|
||||
}
|
||||
|
||||
// $this->dispatch(PhraseaEvents::VALIDATION_REMINDER, new ValidationEvent($participant, $basket, $url));
|
||||
$this->doRemind($participant, $basket, $url);
|
||||
}
|
||||
|
||||
$this->getEntityManager()->flush();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* format a string to a specified length
|
||||
*
|
||||
* @param string $s
|
||||
* @param int $l
|
||||
* @param string $align 'left' or 'right'
|
||||
* @param string $pfx prefix to add, e.g '("'
|
||||
* @param string $sfx suffix to add, e.g '")'
|
||||
* @return string
|
||||
*/
|
||||
private function dotdot($s, $l, $align='left', $pfx='', $sfx='')
|
||||
{
|
||||
$l -= (strlen($pfx) + strlen($sfx));
|
||||
if(strlen($s) > $l) {
|
||||
$s = $pfx . substr($s, 0, $l-1) . "\xE2\x80\xA6" . $sfx;
|
||||
}
|
||||
else {
|
||||
$spc = str_repeat(' ', $l-strlen($s));
|
||||
$s = $align=='left' ? ($pfx . $s . $sfx . $spc) : ($spc . $pfx . $s . $sfx);
|
||||
}
|
||||
|
||||
return $s;
|
||||
}
|
||||
|
||||
private function doRemind(ValidationParticipant $participant, Basket $basket, $url)
|
||||
{
|
||||
$params = [
|
||||
'from' => $basket->getValidation()->getInitiator()->getId(),
|
||||
'to' => $participant->getUser()->getId(),
|
||||
'ssel_id' => $basket->getId(),
|
||||
'url' => $url,
|
||||
];
|
||||
|
||||
$datas = json_encode($params);
|
||||
|
||||
$mailed = false;
|
||||
|
||||
$user_from = $basket->getValidation()->getInitiator();
|
||||
$user_to = $participant->getUser();
|
||||
|
||||
if ($this->shouldSendNotificationFor($participant->getUser(), 'eventsmanager_notify_validationreminder')) {
|
||||
$readyToSend = false;
|
||||
$title = $receiver = $emitter = null;
|
||||
try {
|
||||
$title = $basket->getName();
|
||||
|
||||
$receiver = Receiver::fromUser($user_to);
|
||||
$emitter = Emitter::fromUser($user_from);
|
||||
|
||||
$readyToSend = true;
|
||||
}
|
||||
catch (Exception $e) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
if ($readyToSend) {
|
||||
$this->output->writeln(sprintf(' -> remind "<info>%s</info>" from "<info>%s</info>" to "<info>%s</info>"', $title, $emitter->getEmail(), $receiver->getEmail()));
|
||||
if(!$this->dry) {
|
||||
// for real
|
||||
$mail = MailInfoValidationReminder::create($this->container, $receiver, $emitter);
|
||||
$mail->setButtonUrl($params['url']);
|
||||
$mail->setTitle($title);
|
||||
|
||||
$this->deliver($mail);
|
||||
$mailed = true;
|
||||
|
||||
$participant->setReminded(new DateTime('now'));
|
||||
$this->getEntityManager()->persist($participant);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->container['events-manager']->notify($params['to'], 'eventsmanager_notify_validationreminder', $datas, $mailed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return EntityManagerInterface
|
||||
*/
|
||||
private function getEntityManager()
|
||||
{
|
||||
return $this->container['orm.em'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PropertyAccess
|
||||
*/
|
||||
protected function getConf()
|
||||
{
|
||||
return $this->container['conf'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ValidationParticipantRepository
|
||||
*/
|
||||
private function getValidationParticipantRepository()
|
||||
{
|
||||
return $this->container['repo.validation-participants'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TokenRepository
|
||||
*/
|
||||
private function getTokenRepository()
|
||||
{
|
||||
return $this->container['repo.tokens'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param $type
|
||||
* @return mixed
|
||||
*/
|
||||
protected function shouldSendNotificationFor(User $user, $type)
|
||||
{
|
||||
return $this->container['settings']->getUserNotificationSetting($user, $type);
|
||||
}
|
||||
}
|
@@ -18,8 +18,10 @@ use Alchemy\Phrasea\Model\Entities\Basket;
|
||||
use Alchemy\Phrasea\Model\Entities\FeedEntry;
|
||||
use Alchemy\Phrasea\Model\Entities\Token;
|
||||
use Alchemy\Phrasea\Model\Entities\ValidationData;
|
||||
use Alchemy\Phrasea\Model\Manipulator\TokenManipulator;
|
||||
use Alchemy\Phrasea\Model\Repositories\BasketElementRepository;
|
||||
use Alchemy\Phrasea\Model\Repositories\BasketRepository;
|
||||
use Alchemy\Phrasea\Model\Repositories\TokenRepository;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
@@ -416,6 +418,7 @@ class LightboxController extends Controller
|
||||
/**
|
||||
* @param Basket $basket
|
||||
* @return Response
|
||||
* @throws \Doctrine\ORM\NonUniqueResultException
|
||||
*/
|
||||
public function ajaxSetReleaseAction(Basket $basket)
|
||||
{
|
||||
@@ -431,8 +434,17 @@ class LightboxController extends Controller
|
||||
$this->assertAtLeastOneElementAgreed($basket);
|
||||
$participant = $basket->getValidation()->getParticipant($this->getAuthenticatedUser());
|
||||
|
||||
/** @var Token $token */
|
||||
$token = $this->app['manipulator.token']->createBasketValidationToken($basket);
|
||||
// find / create a "validate" token so the initator of the session can view results (no expiration)
|
||||
$initiatorUser = $basket->getValidation()->getInitiator();
|
||||
|
||||
if(is_null($token = $this->getTokenRepository()->findValidationToken($basket, $initiatorUser))) {
|
||||
// should not happen since when a validation is created, the initiator is force-included as a participant
|
||||
$token = $this->getTokenManipulator()->createBasketValidationToken($basket, $initiatorUser, null);
|
||||
}
|
||||
else {
|
||||
// a token already exists for the initiator
|
||||
$token->setExpiration(null); // the expiration for initiator should already be null...
|
||||
}
|
||||
$url = $this->app->url('lightbox', ['LOG' => $token->getValue()]);
|
||||
|
||||
$this->dispatch(PhraseaEvents::VALIDATION_DONE, new ValidationEvent($participant, $basket, $url));
|
||||
@@ -443,7 +455,8 @@ class LightboxController extends Controller
|
||||
$this->app['orm.em']->flush();
|
||||
|
||||
$data = ['error' => false, 'datas' => $this->app->trans('Envoie avec succes')];
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$data = ['error' => true, 'datas' => $e->getMessage()];
|
||||
}
|
||||
|
||||
@@ -510,4 +523,21 @@ class LightboxController extends Controller
|
||||
$message = $this->app->trans('You have to give your feedback at least on one document to send a report');
|
||||
throw new Exception($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TokenManipulator
|
||||
*/
|
||||
private function getTokenManipulator()
|
||||
{
|
||||
return $this->app['manipulator.token'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TokenRepository
|
||||
*/
|
||||
private function getTokenRepository()
|
||||
{
|
||||
return $this->app['repo.tokens'];
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@
|
||||
*/
|
||||
namespace Alchemy\Phrasea\Controller\Prod;
|
||||
|
||||
use ACL;
|
||||
use Alchemy\Phrasea\Application\Helper\DataboxLoggerAware;
|
||||
use Alchemy\Phrasea\Application\Helper\DispatcherAware;
|
||||
use Alchemy\Phrasea\Application\Helper\EntityManagerAware;
|
||||
@@ -28,13 +29,22 @@ use Alchemy\Phrasea\Model\Entities\ValidationParticipant;
|
||||
use Alchemy\Phrasea\Model\Entities\ValidationSession;
|
||||
use Alchemy\Phrasea\Model\Manipulator\TokenManipulator;
|
||||
use Alchemy\Phrasea\Model\Manipulator\UserManipulator;
|
||||
use Alchemy\Phrasea\Model\Repositories\BasketRepository;
|
||||
use Alchemy\Phrasea\Model\Repositories\TokenRepository;
|
||||
use Alchemy\Phrasea\Model\Repositories\UserRepository;
|
||||
use Alchemy\Phrasea\Model\Repositories\UsrListRepository;
|
||||
use DateTime;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Exception;
|
||||
use RandomLib\Generator;
|
||||
use record_adapter;
|
||||
use Session_Logger;
|
||||
use Swift_Validate;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use User_Query;
|
||||
|
||||
class PushController extends Controller
|
||||
{
|
||||
@@ -53,6 +63,16 @@ class PushController extends Controller
|
||||
return $this->renderPushTemplate($request, 'Feedback');
|
||||
}
|
||||
|
||||
|
||||
/** ----------------------------------------------------------------------------------
|
||||
* a simple push is made by the current user to many "receivers" (=participants)
|
||||
*
|
||||
* this is the same code as "validation" request, except here we don't create a validation session
|
||||
*
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function sendAction(Request $request)
|
||||
{
|
||||
$ret = [
|
||||
@@ -86,7 +106,7 @@ class PushController extends Controller
|
||||
try {
|
||||
/** @var User $user_receiver */
|
||||
$user_receiver = $this->getUserRepository()->find($receiver['usr_id']);
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
throw new ControllerException(
|
||||
$this->app->trans('Unknown user %user_id%', ['%user_id%' => $receiver['usr_id']])
|
||||
);
|
||||
@@ -114,19 +134,19 @@ class PushController extends Controller
|
||||
$this->getAclForUser($user_receiver)->grant_hd_on(
|
||||
$basketElement->getRecord($this->app),
|
||||
$this->getAuthenticatedUser(),
|
||||
\ACL::GRANT_ACTION_PUSH
|
||||
ACL::GRANT_ACTION_PUSH
|
||||
);
|
||||
} else {
|
||||
$this->getAclForUser($user_receiver)->grant_preview_on(
|
||||
$basketElement->getRecord($this->app),
|
||||
$this->getAuthenticatedUser(),
|
||||
\ACL::GRANT_ACTION_PUSH
|
||||
ACL::GRANT_ACTION_PUSH
|
||||
);
|
||||
}
|
||||
|
||||
$this->getDataboxLogger($element->getDatabox())->log(
|
||||
$element,
|
||||
\Session_Logger::EVENT_VALIDATE,
|
||||
Session_Logger::EVENT_VALIDATE,
|
||||
$user_receiver->getId(),
|
||||
''
|
||||
);
|
||||
@@ -138,9 +158,15 @@ class PushController extends Controller
|
||||
'basket' => $Basket->getId(),
|
||||
];
|
||||
|
||||
if (!$this->getConf()->get(['registry', 'actions', 'enable-push-authentication'])
|
||||
|| !$request->get('force_authentication')
|
||||
) {
|
||||
// here we send an email to each participant
|
||||
//
|
||||
// if we don't request the user to auth (=type his login/pwd),
|
||||
// we generate a !!!! 'view' !!!! token to be included as 'LOG' parameter in url
|
||||
//
|
||||
// - the 'view' token is created to give access to lightbox in "compare" mode, NOT "validation"
|
||||
// - the 'view' token has no expiration
|
||||
//
|
||||
if (!$this->getConf()->get(['registry', 'actions', 'enable-push-authentication']) || !$request->get('force_authentication') ) {
|
||||
$arguments['LOG'] = $this->getTokenManipulator()->createBasketAccessToken($Basket, $user_receiver)->getValue();
|
||||
}
|
||||
|
||||
@@ -176,6 +202,18 @@ class PushController extends Controller
|
||||
return $this->app->json($ret);
|
||||
}
|
||||
|
||||
|
||||
/** ----------------------------------------------------------------------------------
|
||||
* a validation request is made by the current user to many participants
|
||||
*
|
||||
* this is the same code as "send" request (=simple push), except here we create a validation session,
|
||||
* register participants and data...
|
||||
*
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
* @throws Exception
|
||||
*/
|
||||
public function validateAction(Request $request)
|
||||
{
|
||||
$ret = [
|
||||
@@ -205,9 +243,13 @@ class PushController extends Controller
|
||||
throw new ControllerException($this->app->trans('No elements to validate'));
|
||||
}
|
||||
|
||||
// a validation must apply to a basket...
|
||||
//
|
||||
if ($pusher->is_basket()) {
|
||||
$basket = $pusher->get_original_basket();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// ...so if we got a list of elements (records), we create a basket for those
|
||||
$basket = new Basket();
|
||||
$basket->setName($validation_name);
|
||||
$basket->setDescription($validation_description);
|
||||
@@ -230,24 +272,35 @@ class PushController extends Controller
|
||||
|
||||
$manager->refresh($basket);
|
||||
|
||||
// if the basket is already under validation, we work on it
|
||||
// else we create a validationSession
|
||||
//
|
||||
$expireDate = null;
|
||||
if (!$basket->getValidation()) {
|
||||
// create the validationSession
|
||||
$Validation = new ValidationSession();
|
||||
$Validation->setInitiator($this->getAuthenticatedUser());
|
||||
$Validation->setBasket($basket);
|
||||
|
||||
// add an expiration date if a duration was specified
|
||||
$duration = (int)$request->request->get('duration');
|
||||
|
||||
if ($duration > 0) {
|
||||
$date = new \DateTime('+' . $duration . ' day' . ($duration > 1 ? 's' : ''));
|
||||
$Validation->setExpires($date);
|
||||
$expireDate = new DateTime('+' . $duration . ' day' . ($duration > 1 ? 's' : ''));
|
||||
$Validation->setExpires($expireDate);
|
||||
}
|
||||
|
||||
$basket->setValidation($Validation);
|
||||
$manager->persist($Validation);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// go on with existing validationSession
|
||||
$Validation = $basket->getValidation();
|
||||
$expireDate = $Validation->getExpires();
|
||||
}
|
||||
|
||||
// we always add the author of the validation request (current user) to the participants
|
||||
//
|
||||
$found = false;
|
||||
foreach ($participants as $participant) {
|
||||
if ($participant['usr_id'] === $this->getAuthenticatedUser()->getId()) {
|
||||
@@ -265,7 +318,11 @@ class PushController extends Controller
|
||||
];
|
||||
}
|
||||
|
||||
// add participants to the validationSession
|
||||
//
|
||||
foreach ($participants as $key => $participant) {
|
||||
|
||||
// sanity check
|
||||
foreach (['see_others', 'usr_id', 'agree', 'HD'] as $mandatoryParam) {
|
||||
if (!array_key_exists($mandatoryParam, $participant)) {
|
||||
throw new ControllerException(
|
||||
@@ -277,17 +334,21 @@ class PushController extends Controller
|
||||
try {
|
||||
/** @var User $participantUser */
|
||||
$participantUser = $this->getUserRepository()->find($participant['usr_id']);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
catch (Exception $e) {
|
||||
throw new ControllerException(
|
||||
$this->app->trans('Unknown user %usr_id%', ['%usr_id%' => $participant['usr_id']])
|
||||
);
|
||||
}
|
||||
// end of sanity check
|
||||
|
||||
// if participant already exists, skip insertion
|
||||
try {
|
||||
$Validation->getParticipant($participantUser);
|
||||
continue;
|
||||
} catch (NotFoundHttpException $e) {
|
||||
|
||||
}
|
||||
catch (NotFoundHttpException $e) {
|
||||
// participant not yet exists, create
|
||||
}
|
||||
|
||||
$validationParticipant = new ValidationParticipant();
|
||||
@@ -309,13 +370,14 @@ class PushController extends Controller
|
||||
$this->getAclForUser($participantUser)->grant_hd_on(
|
||||
$basketElement->getRecord($this->app),
|
||||
$this->getAuthenticatedUser(),
|
||||
\ACL::GRANT_ACTION_VALIDATE
|
||||
ACL::GRANT_ACTION_VALIDATE
|
||||
);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$this->getAclForUser($participantUser)->grant_preview_on(
|
||||
$basketElement->getRecord($this->app),
|
||||
$this->getAuthenticatedUser(),
|
||||
\ACL::GRANT_ACTION_VALIDATE
|
||||
ACL::GRANT_ACTION_VALIDATE
|
||||
);
|
||||
}
|
||||
|
||||
@@ -324,7 +386,7 @@ class PushController extends Controller
|
||||
|
||||
$this->getDataboxLogger($basketElement->getRecord($this->app)->getDatabox())->log(
|
||||
$basketElement->getRecord($this->app),
|
||||
\Session_Logger::EVENT_PUSH,
|
||||
Session_Logger::EVENT_PUSH,
|
||||
$participantUser->getId(),
|
||||
''
|
||||
);
|
||||
@@ -332,6 +394,7 @@ class PushController extends Controller
|
||||
$validationParticipant->addData($validationData);
|
||||
}
|
||||
|
||||
/** @var ValidationParticipant $validationParticipant */
|
||||
$validationParticipant = $manager->merge($validationParticipant);
|
||||
|
||||
$manager->flush();
|
||||
@@ -340,10 +403,22 @@ class PushController extends Controller
|
||||
'basket' => $basket->getId(),
|
||||
];
|
||||
|
||||
if (!$this->getConf()->get(['registry', 'actions', 'enable-push-authentication'])
|
||||
|| !$request->get('force_authentication')
|
||||
) {
|
||||
$arguments['LOG'] = $this->getTokenManipulator()->createBasketAccessToken($basket, $participantUser)->getValue();
|
||||
// here we send an email to each participant
|
||||
//
|
||||
// if we don't request the user to auth (=type his login/pwd),
|
||||
// we generate a !!!! 'validate' !!!! token to be included as 'LOG' parameter in url
|
||||
//
|
||||
// - the 'validate' token has same expiration as validation-session (except for initiator)
|
||||
//
|
||||
if (!$this->getConf()->get(['registry', 'actions', 'enable-push-authentication']) || !$request->get('force_authentication') ) {
|
||||
if($participantUser->getId() === $this->getAuthenticatedUser()->getId()) {
|
||||
// the initiator of the validation gets a no-expire token (so he can see result after validation expiration)
|
||||
$arguments['LOG'] = $this->getTokenManipulator()->createBasketValidationToken($basket, $participantUser, null)->getValue();
|
||||
}
|
||||
else {
|
||||
// a "normal" participant/user gets a expiring token
|
||||
$arguments['LOG'] = $this->getTokenManipulator()->createBasketValidationToken($basket, $participantUser, $expireDate)->getValue();
|
||||
}
|
||||
}
|
||||
|
||||
$url = $this->app->url('lightbox_validation', $arguments);
|
||||
@@ -390,12 +465,16 @@ class PushController extends Controller
|
||||
return $this->app->json($ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $usr_id
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function getUserAction($usr_id)
|
||||
{
|
||||
$data = null;
|
||||
|
||||
$query = $this->createUserQuery();
|
||||
$query->on_bases_where_i_am($this->getAclForUser($this->getAuthenticatedUser()), [\ACL::CANPUSH]);
|
||||
$query->on_bases_where_i_am($this->getAclForUser($this->getAuthenticatedUser()), [ACL::CANPUSH]);
|
||||
|
||||
$query->in([$usr_id]);
|
||||
|
||||
@@ -412,6 +491,10 @@ class PushController extends Controller
|
||||
return $this->app->json($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $list_id
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function getListAction($list_id)
|
||||
{
|
||||
$data = null;
|
||||
@@ -426,12 +509,17 @@ class PushController extends Controller
|
||||
return $this->app->json($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
* @throws Exception
|
||||
*/
|
||||
public function addUserAction(Request $request)
|
||||
{
|
||||
$result = ['success' => false, 'message' => '', 'user' => null];
|
||||
|
||||
try {
|
||||
if (!$this->getAclForUser($this->getAuthenticatedUser())->has_right(\ACL::CANADMIN))
|
||||
if (!$this->getAclForUser($this->getAuthenticatedUser())->has_right(ACL::CANADMIN))
|
||||
throw new ControllerException($this->app->trans('You are not allowed to add users'));
|
||||
|
||||
if (!$request->request->get('firstname'))
|
||||
@@ -443,7 +531,7 @@ class PushController extends Controller
|
||||
if (!$request->request->get('email'))
|
||||
throw new ControllerException($this->app->trans('Email is required'));
|
||||
|
||||
if (!\Swift_Validate::email($request->request->get('email')))
|
||||
if (!Swift_Validate::email($request->request->get('email')))
|
||||
throw new ControllerException($this->app->trans('Email is invalid'));
|
||||
} catch (ControllerException $e) {
|
||||
$result['message'] = $e->getMessage();
|
||||
@@ -490,13 +578,17 @@ class PushController extends Controller
|
||||
$result['message'] = $this->app->trans('User successfully created');
|
||||
$result['success'] = true;
|
||||
$result['user'] = $this->formatUser($user);
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
$result['message'] = $this->app->trans('Error while creating user');
|
||||
}
|
||||
|
||||
return $this->app->json($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return string
|
||||
*/
|
||||
public function getAddUserFormAction(Request $request)
|
||||
{
|
||||
$params = ['callback' => $request->query->get('callback')];
|
||||
@@ -504,17 +596,21 @@ class PushController extends Controller
|
||||
return $this->render('prod/User/Add.html.twig', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function searchUserAction(Request $request)
|
||||
{
|
||||
$query = $this->createUserQuery();
|
||||
$query->on_bases_where_i_am($this->getAclForUser($this->getAuthenticatedUser()), [\ACL::CANPUSH]);
|
||||
$query->on_bases_where_i_am($this->getAclForUser($this->getAuthenticatedUser()), [ACL::CANPUSH]);
|
||||
$query
|
||||
->like(\User_Query::LIKE_FIRSTNAME, $request->query->get('query'))
|
||||
->like(\User_Query::LIKE_LASTNAME, $request->query->get('query'))
|
||||
->like(\User_Query::LIKE_LOGIN, $request->query->get('query'))
|
||||
->like(\User_Query::LIKE_EMAIL, $request->query->get('query'))
|
||||
->like(\User_Query::LIKE_COMPANY, $request->query->get('query'))
|
||||
->like_match(\User_Query::LIKE_MATCH_OR);
|
||||
->like(User_Query::LIKE_FIRSTNAME, $request->query->get('query'))
|
||||
->like(User_Query::LIKE_LASTNAME, $request->query->get('query'))
|
||||
->like(User_Query::LIKE_LOGIN, $request->query->get('query'))
|
||||
->like(User_Query::LIKE_EMAIL, $request->query->get('query'))
|
||||
->like(User_Query::LIKE_COMPANY, $request->query->get('query'))
|
||||
->like_match(User_Query::LIKE_MATCH_OR);
|
||||
|
||||
$result = $query
|
||||
->include_phantoms()
|
||||
@@ -541,18 +637,23 @@ class PushController extends Controller
|
||||
return $this->app->json($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param $list_id
|
||||
* @return Response
|
||||
*/
|
||||
public function editListAction(Request $request, $list_id)
|
||||
{
|
||||
$repository = $this->getUserListRepository();
|
||||
$list = $repository->findUserListByUserAndId($this->getAuthenticatedUser(), $list_id);
|
||||
|
||||
$query = $this->createUserQuery();
|
||||
$query->on_bases_where_i_am($this->getAclForUser($this->getAuthenticatedUser()), [\ACL::CANPUSH]);
|
||||
$query->on_bases_where_i_am($this->getAclForUser($this->getAuthenticatedUser()), [ACL::CANPUSH]);
|
||||
|
||||
if ($request->get('query')) {
|
||||
$query
|
||||
->like($request->get('like_field'), $request->get('query'))
|
||||
->like_match(\User_Query::LIKE_MATCH_OR);
|
||||
->like_match(User_Query::LIKE_MATCH_OR);
|
||||
}
|
||||
|
||||
if (is_array($request->get('EmailDomain'))) {
|
||||
@@ -606,38 +707,75 @@ class PushController extends Controller
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* update the expiration date of a validation session
|
||||
* also update the expiration of the participants validation tokens
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
* @throws Exception
|
||||
*/
|
||||
public function updateExpirationAction(Request $request)
|
||||
{
|
||||
$ret = [
|
||||
'success' => false,
|
||||
'message' => $this->app->trans('Unable to save the expiration date')
|
||||
];
|
||||
// sanity check
|
||||
if (is_null($request->request->get('date'))) {
|
||||
$ret['message'] = $this->app->trans('The provided date is null!');
|
||||
return $this->app->json($ret);
|
||||
throw new Exception('The provided date is null!');
|
||||
}
|
||||
$repository = $this->app['repo.baskets'];
|
||||
|
||||
$manager = $this->getEntityManager();
|
||||
$manager->beginTransaction();
|
||||
try {
|
||||
$basket = $repository->findUserBasket($request->request->get('basket_id'), $this->app->getAuthenticatedUser(), true);
|
||||
$date = new \DateTime($request->request->get('date') . " 23:59:59");
|
||||
$basket = $this->getBasketRepository()->findUserBasket($request->request->get('basket_id'), $this->app->getAuthenticatedUser(), true);
|
||||
$expirationDate = new DateTime($request->request->get('date') . " 23:59:59");
|
||||
$validation = $basket->getValidation();
|
||||
if (is_null($validation)) {
|
||||
return $this->app->json($ret);
|
||||
throw new Exception('Unable to find the validation session');
|
||||
}
|
||||
$validation->setExpires($date);
|
||||
|
||||
// update validation tokens expiration
|
||||
//
|
||||
/** @var ValidationParticipant $participant */
|
||||
foreach($validation->getParticipants() as $participant) {
|
||||
try {
|
||||
if(!is_null($token = $this->getTokenRepository()->findValidationToken($basket, $participant->getUser()))) {
|
||||
if($participant->getUser()->getId() === $validation->getInitiator()->getId()) {
|
||||
// the initiator keeps a no-expiration token
|
||||
$token->setExpiration(null); // shoud already be null, but who knows...
|
||||
}
|
||||
else {
|
||||
// the "normal" user token is fixed
|
||||
$token->setExpiration($expirationDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
// not unique token ? should not happen.
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
|
||||
$validation->setExpires($expirationDate);
|
||||
$manager->persist($validation);
|
||||
$manager->flush();
|
||||
$manager->commit();
|
||||
$ret['message'] = 'Expiration date successfully updated!';
|
||||
} catch (\Exception $e) {
|
||||
$ret['message'] = $e->getMessage();
|
||||
$ret = [
|
||||
'success' => true,
|
||||
'message' => $this->app->trans('Expiration date successfully updated!')
|
||||
];
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$ret = [
|
||||
'success' => false,
|
||||
'message' => $e->getMessage()
|
||||
];
|
||||
$manager->rollback();
|
||||
}
|
||||
|
||||
return $this->app->json($ret);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private function formatUser(User $user)
|
||||
{
|
||||
$subtitle = array_filter([$user->getJob(), $user->getCompany()]);
|
||||
@@ -674,8 +812,8 @@ class PushController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|\record_adapter[] $selection
|
||||
* @return User[]
|
||||
* @param array|record_adapter[] $selection
|
||||
* @return ArrayCollection Users
|
||||
*/
|
||||
private function getUsersInSelectionExtractor($selection)
|
||||
{
|
||||
@@ -773,4 +911,20 @@ class PushController extends Controller
|
||||
return $this->app['random.medium'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BasketRepository
|
||||
*/
|
||||
private function getBasketRepository()
|
||||
{
|
||||
return $this->app['repo.baskets'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TokenRepository
|
||||
*/
|
||||
private function getTokenRepository()
|
||||
{
|
||||
return $this->app['repo.tokens'];
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -55,6 +55,7 @@ use Alchemy\Phrasea\Form\Login\PhraseaAuthenticationForm;
|
||||
use Alchemy\Phrasea\Form\Login\PhraseaForgotPasswordForm;
|
||||
use Alchemy\Phrasea\Form\Login\PhraseaRecoverPasswordForm;
|
||||
use Alchemy\Phrasea\Form\Login\PhraseaRegisterForm;
|
||||
use DateTime;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Neutron\ReCaptcha\ReCaptcha;
|
||||
use RandomLib\Generator;
|
||||
@@ -153,7 +154,7 @@ class LoginController extends Controller
|
||||
'great' => $this->app->trans('Great'),
|
||||
]);
|
||||
|
||||
$response->setExpires(new \DateTime('+1 day'));
|
||||
$response->setExpires(new DateTime('+1 day'));
|
||||
|
||||
return $response;
|
||||
}
|
||||
@@ -593,25 +594,41 @@ class LoginController extends Controller
|
||||
// move this in an event
|
||||
public function postAuthProcess(Request $request, User $user)
|
||||
{
|
||||
$date = new \DateTime('+' . (int) $this->getConf()->get(['registry', 'actions', 'validation-reminder-days']) . ' days');
|
||||
$date = new DateTime('+' . (int) $this->getConf()->get(['registry', 'actions', 'validation-reminder-days']) . ' days');
|
||||
$manager = $this->getEntityManager();
|
||||
|
||||
/*
|
||||
* PHRAS-3214_validation-tokens-refacto : This code is moved to console command "SendValidationRemindersCommand.php"
|
||||
*
|
||||
foreach ($this->getValidationParticipantRepository()->findNotConfirmedAndNotRemindedParticipantsByExpireDate($date) as $participant) {
|
||||
$validationSession = $participant->getSession();
|
||||
$basket = $validationSession->getBasket();
|
||||
|
||||
if (null === $token = $this->getTokenRepository()->findValidationToken($basket, $participant->getUser())) {
|
||||
continue;
|
||||
// find the token if exists
|
||||
// nb : a validation may have not generated tokens if forcing auth was required upon creation
|
||||
try {
|
||||
$token = $this->getTokenRepository()->findValidationToken($basket, $participant->getUser());
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
// not unique token ? should not happen
|
||||
$token = null;
|
||||
}
|
||||
|
||||
if(!is_null($token)) {
|
||||
$url = $this->app->url('lightbox_validation', ['basket' => $basket->getId(), 'LOG' => $token->getValue()]);
|
||||
}
|
||||
else {
|
||||
$url = $this->app->url('lightbox_validation', ['basket' => $basket->getId()]);
|
||||
}
|
||||
|
||||
$url = $this->app->url('lightbox_validation', ['basket' => $basket->getId(), 'LOG' => $token->getValue()]);
|
||||
$this->dispatch(PhraseaEvents::VALIDATION_REMINDER, new ValidationEvent($participant, $basket, $url));
|
||||
|
||||
$participant->setReminded(new \DateTime('now'));
|
||||
$participant->setReminded(new DateTime('now'));
|
||||
$manager->persist($participant);
|
||||
}
|
||||
|
||||
$manager->flush();
|
||||
*/
|
||||
|
||||
$session = $this->getAuthenticator()->openAccount($user);
|
||||
|
||||
|
@@ -108,6 +108,9 @@ class ValidationSubscriber extends AbstractNotificationSubscriber
|
||||
return $this->app['events-manager']->notify($params['to'], 'eventsmanager_notify_validationdone', $datas, $mailed);
|
||||
}
|
||||
|
||||
/*
|
||||
* PHRAS-3214_validation-tokens-refacto : This code is moved to console command "SendValidationRemindersCommand.php"
|
||||
*
|
||||
public function onRemind(ValidationEvent $event)
|
||||
{
|
||||
$params = [
|
||||
@@ -150,13 +153,15 @@ class ValidationSubscriber extends AbstractNotificationSubscriber
|
||||
|
||||
return $this->app['events-manager']->notify($params['to'], 'eventsmanager_notify_validationreminder', $datas, $mailed);
|
||||
}
|
||||
*/
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
PhraseaEvents::VALIDATION_CREATE => 'onCreate',
|
||||
PhraseaEvents::VALIDATION_DONE => 'onFinish',
|
||||
PhraseaEvents::VALIDATION_REMINDER => 'onRemind',
|
||||
// PHRAS-3214_validation-tokens-refacto : This code is moved to console command "SendValidationRemindersCommand.php"
|
||||
// PhraseaEvents::VALIDATION_REMINDER => 'onRemind',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@@ -11,6 +11,9 @@
|
||||
|
||||
namespace Alchemy\Phrasea\Model\Entities;
|
||||
|
||||
use DateTime;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
@@ -63,11 +66,11 @@ class ValidationParticipant
|
||||
private $session;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* ValidationParticipant constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->datas = new \Doctrine\Common\Collections\ArrayCollection();
|
||||
$this->datas = new ArrayCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,7 +94,7 @@ class ValidationParticipant
|
||||
/**
|
||||
* @param User $user
|
||||
*
|
||||
* @return AggregateToken
|
||||
* @return self
|
||||
*/
|
||||
public function setUser(User $user)
|
||||
{
|
||||
@@ -158,7 +161,7 @@ class ValidationParticipant
|
||||
* Set can_agree
|
||||
*
|
||||
* @param boolean $canAgree
|
||||
* @return ValidationParticipant
|
||||
* @return self
|
||||
*/
|
||||
public function setCanAgree($canAgree)
|
||||
{
|
||||
@@ -181,7 +184,7 @@ class ValidationParticipant
|
||||
* Set can_see_others
|
||||
*
|
||||
* @param boolean $canSeeOthers
|
||||
* @return ValidationParticipant
|
||||
* @return self
|
||||
*/
|
||||
public function setCanSeeOthers($canSeeOthers)
|
||||
{
|
||||
@@ -203,7 +206,7 @@ class ValidationParticipant
|
||||
/**
|
||||
* Set reminded
|
||||
*
|
||||
* @param \DateTime $reminded
|
||||
* @param DateTime $reminded
|
||||
* @return ValidationParticipant
|
||||
*/
|
||||
public function setReminded($reminded)
|
||||
@@ -216,7 +219,7 @@ class ValidationParticipant
|
||||
/**
|
||||
* Get reminded
|
||||
*
|
||||
* @return \DateTime
|
||||
* @return DateTime
|
||||
*/
|
||||
public function getReminded()
|
||||
{
|
||||
@@ -249,7 +252,7 @@ class ValidationParticipant
|
||||
/**
|
||||
* Get datas
|
||||
*
|
||||
* @return \Doctrine\Common\Collections\Collection
|
||||
* @return Collection
|
||||
*/
|
||||
public function getDatas()
|
||||
{
|
||||
|
@@ -12,6 +12,9 @@
|
||||
namespace Alchemy\Phrasea\Model\Entities;
|
||||
|
||||
use Alchemy\Phrasea\Application;
|
||||
use DateTime;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Gedmo\Mapping\Annotation as Gedmo;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
@@ -70,7 +73,7 @@ class ValidationSession
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->participants = new \Doctrine\Common\Collections\ArrayCollection();
|
||||
$this->participants = new ArrayCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,10 +121,10 @@ class ValidationSession
|
||||
/**
|
||||
* Set created
|
||||
*
|
||||
* @param \DateTime $created
|
||||
* @param DateTime $created
|
||||
* @return ValidationSession
|
||||
*/
|
||||
public function setCreated(\DateTime $created)
|
||||
public function setCreated(DateTime $created)
|
||||
{
|
||||
$this->created = $created;
|
||||
|
||||
@@ -131,7 +134,7 @@ class ValidationSession
|
||||
/**
|
||||
* Get created
|
||||
*
|
||||
* @return \DateTime
|
||||
* @return DateTime
|
||||
*/
|
||||
public function getCreated()
|
||||
{
|
||||
@@ -141,10 +144,10 @@ class ValidationSession
|
||||
/**
|
||||
* Set updated
|
||||
*
|
||||
* @param \DateTime $updated
|
||||
* @param DateTime $updated
|
||||
* @return ValidationSession
|
||||
*/
|
||||
public function setUpdated(\DateTime $updated)
|
||||
public function setUpdated(DateTime $updated)
|
||||
{
|
||||
$this->updated = $updated;
|
||||
|
||||
@@ -154,7 +157,7 @@ class ValidationSession
|
||||
/**
|
||||
* Get updated
|
||||
*
|
||||
* @return \DateTime
|
||||
* @return DateTime
|
||||
*/
|
||||
public function getUpdated()
|
||||
{
|
||||
@@ -164,7 +167,7 @@ class ValidationSession
|
||||
/**
|
||||
* Set expires
|
||||
*
|
||||
* @param \DateTime $expires
|
||||
* @param DateTime $expires
|
||||
* @return ValidationSession
|
||||
*/
|
||||
public function setExpires($expires)
|
||||
@@ -177,7 +180,7 @@ class ValidationSession
|
||||
/**
|
||||
* Get expires
|
||||
*
|
||||
* @return \DateTime
|
||||
* @return DateTime|null
|
||||
*/
|
||||
public function getExpires()
|
||||
{
|
||||
@@ -233,7 +236,7 @@ class ValidationSession
|
||||
/**
|
||||
* Get participants
|
||||
*
|
||||
* @return \Doctrine\Common\Collections\Collection
|
||||
* @return Collection
|
||||
*/
|
||||
public function getParticipants()
|
||||
{
|
||||
@@ -246,7 +249,7 @@ class ValidationSession
|
||||
return null;
|
||||
}
|
||||
|
||||
$date_obj = new \DateTime();
|
||||
$date_obj = new DateTime();
|
||||
|
||||
return $date_obj > $this->getExpires();
|
||||
}
|
||||
@@ -261,16 +264,18 @@ class ValidationSession
|
||||
return $app->trans('Vous avez envoye cette demande a %n% utilisateurs', ['%n%' => count($this->getParticipants()) - 1]);
|
||||
} else {
|
||||
if ($this->getParticipant($user)->getCanSeeOthers()) {
|
||||
return $app->trans('Processus de validation recu de %user% et concernant %n% utilisateurs', ['%user%' => $this->getInitiator($app)->getDisplayName(), '%n%' => count($this->getParticipants()) - 1]);
|
||||
return $app->trans('Processus de validation recu de %user% et concernant %n% utilisateurs', ['%user%' => $this->getInitiator()->getDisplayName(), '%n%' => count($this->getParticipants()) - 1]);
|
||||
}
|
||||
|
||||
return $app->trans('Processus de validation recu de %user%', ['%user%' => $this->getInitiator($app)->getDisplayName()]);
|
||||
return $app->trans('Processus de validation recu de %user%', ['%user%' => $this->getInitiator()->getDisplayName()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a participant
|
||||
*
|
||||
* @param User $user
|
||||
*
|
||||
* @return ValidationParticipant
|
||||
*/
|
||||
public function getParticipant(User $user)
|
||||
|
@@ -16,8 +16,11 @@ use Alchemy\Phrasea\Model\Entities\FeedEntry;
|
||||
use Alchemy\Phrasea\Model\Entities\Token;
|
||||
use Alchemy\Phrasea\Model\Entities\User;
|
||||
use Alchemy\Phrasea\Model\Repositories\TokenRepository;
|
||||
use DateTime;
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use InvalidArgumentException;
|
||||
use RandomLib\Generator;
|
||||
use RuntimeException;
|
||||
|
||||
class TokenManipulator implements ManipulatorInterface
|
||||
{
|
||||
@@ -56,19 +59,19 @@ class TokenManipulator implements ManipulatorInterface
|
||||
/**
|
||||
* @param User|null $user
|
||||
* @param string $type
|
||||
* @param \DateTime|null $expiration
|
||||
* @param DateTime|null $expiration
|
||||
* @param mixed|null $data
|
||||
*
|
||||
* @return Token
|
||||
*/
|
||||
public function create(User $user = null, $type, \DateTime $expiration = null, $data = null)
|
||||
public function create($user, $type, $expiration = null, $data = null)
|
||||
{
|
||||
$this->removeExpiredTokens();
|
||||
|
||||
$n = 0;
|
||||
do {
|
||||
if ($n++ > 1024) {
|
||||
throw new \RuntimeException('Unable to create a token.');
|
||||
throw new RuntimeException('Unable to create a token.');
|
||||
}
|
||||
$value = $this->random->generateString(32, self::LETTERS_AND_NUMBERS);
|
||||
$found = null !== $this->om->getRepository('Phraseanet:Token')->find($value);
|
||||
@@ -90,17 +93,18 @@ class TokenManipulator implements ManipulatorInterface
|
||||
|
||||
/**
|
||||
* @param Basket $basket
|
||||
* @param User $user
|
||||
* @param User $user
|
||||
* @param DateTime|null $expiration
|
||||
*
|
||||
* @return Token
|
||||
*/
|
||||
public function createBasketValidationToken(Basket $basket, User $user = null)
|
||||
public function createBasketValidationToken(Basket $basket, User $user, $expiration)
|
||||
{
|
||||
if (null === $basket->getValidation()) {
|
||||
throw new \InvalidArgumentException('A validation token requires a validation basket.');
|
||||
throw new InvalidArgumentException('A validation token requires a validation basket.');
|
||||
}
|
||||
|
||||
return $this->create($user ?: $basket->getValidation()->getInitiator(), self::TYPE_VALIDATE, new \DateTime('+10 days'), $basket->getId());
|
||||
return $this->create($user, self::TYPE_VALIDATE, $expiration, $basket->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,7 +135,6 @@ class TokenManipulator implements ManipulatorInterface
|
||||
* @param User[] $users
|
||||
* @param FeedEntry $entry
|
||||
* @return Token[]
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
public function createFeedEntryTokens($users, FeedEntry $entry)
|
||||
{
|
||||
@@ -165,7 +168,7 @@ class TokenManipulator implements ManipulatorInterface
|
||||
*/
|
||||
public function createDownloadToken(User $user, $data)
|
||||
{
|
||||
return $this->create($user, self::TYPE_DOWNLOAD, new \DateTime('+3 hours'), $data);
|
||||
return $this->create($user, self::TYPE_DOWNLOAD, new DateTime('+3 hours'), $data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -175,7 +178,7 @@ class TokenManipulator implements ManipulatorInterface
|
||||
*/
|
||||
public function createEmailExportToken($data)
|
||||
{
|
||||
return $this->create(null, self::TYPE_EMAIL, new \DateTime('+1 day'), $data);
|
||||
return $this->create(null, self::TYPE_EMAIL, new DateTime('+1 day'), $data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,7 +189,7 @@ class TokenManipulator implements ManipulatorInterface
|
||||
*/
|
||||
public function createResetEmailToken(User $user, $email)
|
||||
{
|
||||
return $this->create($user, self::TYPE_EMAIL_RESET, new \DateTime('+1 day'), $email);
|
||||
return $this->create($user, self::TYPE_EMAIL_RESET, new DateTime('+1 day'), $email);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,17 +199,18 @@ class TokenManipulator implements ManipulatorInterface
|
||||
*/
|
||||
public function createAccountUnlockToken(User $user)
|
||||
{
|
||||
return $this->create($user, self::TYPE_ACCOUNT_UNLOCK, new \DateTime('+3 days'));
|
||||
return $this->create($user, self::TYPE_ACCOUNT_UNLOCK, new DateTime('+3 days'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param string $email
|
||||
*
|
||||
* @return Token
|
||||
*/
|
||||
public function createAccountDeleteToken(User $user, $email)
|
||||
{
|
||||
return $this->create($user, self::TYPE_ACCOUNT_DELETE, new \DateTime('+1 hour'), $email);
|
||||
return $this->create($user, self::TYPE_ACCOUNT_DELETE, new DateTime('+1 hour'), $email);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,7 +220,7 @@ class TokenManipulator implements ManipulatorInterface
|
||||
*/
|
||||
public function createResetPasswordToken(User $user)
|
||||
{
|
||||
return $this->create($user, self::TYPE_PASSWORD, new \DateTime('+1 day'));
|
||||
return $this->create($user, self::TYPE_PASSWORD, new DateTime('+1 day'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -6,7 +6,9 @@ use Alchemy\Phrasea\Model\Entities\Basket;
|
||||
use Alchemy\Phrasea\Model\Entities\Token;
|
||||
use Alchemy\Phrasea\Model\Entities\User;
|
||||
use Alchemy\Phrasea\Model\Manipulator\TokenManipulator;
|
||||
use DateTime;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\NonUniqueResultException;
|
||||
|
||||
/**
|
||||
* TokenRepository
|
||||
@@ -20,7 +22,7 @@ class TokenRepository extends EntityRepository
|
||||
* @param Basket $basket
|
||||
* @param User $user
|
||||
* @return Token|null
|
||||
* @throws \Doctrine\ORM\NonUniqueResultException
|
||||
* @throws NonUniqueResultException
|
||||
*/
|
||||
public function findValidationToken(Basket $basket, User $user)
|
||||
{
|
||||
@@ -44,7 +46,7 @@ class TokenRepository extends EntityRepository
|
||||
/**
|
||||
* @param string $value
|
||||
* @return Token|null
|
||||
* @throws \Doctrine\ORM\NonUniqueResultException
|
||||
* @throws NonUniqueResultException
|
||||
*/
|
||||
public function findValidToken($value)
|
||||
{
|
||||
@@ -68,7 +70,7 @@ class TokenRepository extends EntityRepository
|
||||
WHERE t.expiration < :date';
|
||||
|
||||
$query = $this->_em->createQuery($dql);
|
||||
$query->setParameters([':date' => new \DateTime()]);
|
||||
$query->setParameters([':date' => new DateTime()]);
|
||||
|
||||
return $query->getResult();
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@
|
||||
namespace Alchemy\Phrasea\Model\Repositories;
|
||||
|
||||
use Alchemy\Phrasea\Model\Entities\ValidationParticipant;
|
||||
use DateTime;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
|
||||
@@ -21,10 +22,12 @@ class ValidationParticipantRepository extends EntityRepository
|
||||
/**
|
||||
* Retrieve all not reminded participants where the validation has not expired
|
||||
*
|
||||
* @param $expireDate The expiration Date
|
||||
* @param $expireDate DateTime The expiration Date
|
||||
* @param $today DateTime fake "today" to allow to get past/future events
|
||||
* (used by SendValidationRemindersCommand.php to debug with --dry)
|
||||
* @return ValidationParticipant[]
|
||||
*/
|
||||
public function findNotConfirmedAndNotRemindedParticipantsByExpireDate(\DateTime $expireDate)
|
||||
public function findNotConfirmedAndNotRemindedParticipantsByExpireDate(DateTime $expireDate, DateTime $today=null)
|
||||
{
|
||||
$dql = '
|
||||
SELECT p, s
|
||||
@@ -33,10 +36,14 @@ class ValidationParticipantRepository extends EntityRepository
|
||||
JOIN s.basket b
|
||||
WHERE p.is_confirmed = 0
|
||||
AND p.reminded IS NULL
|
||||
AND s.expires < :date AND s.expires > CURRENT_TIMESTAMP()';
|
||||
AND s.expires < :date AND s.expires > ' . ($today===null ? 'CURRENT_TIMESTAMP()' : ':today');
|
||||
|
||||
return $this->_em->createQuery($dql)
|
||||
->setParameter('date', $expireDate, Type::DATETIME)
|
||||
->getResult();
|
||||
$q = $this->_em->createQuery($dql)
|
||||
->setParameter('date', $expireDate, Type::DATETIME);
|
||||
if($today !== null) {
|
||||
$q->setParameter('today', $today, Type::DATETIME);
|
||||
}
|
||||
|
||||
return $q->getResult();
|
||||
}
|
||||
}
|
||||
|
@@ -2076,9 +2076,11 @@ class LoginTest extends \PhraseanetAuthenticatedWebTestCase
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
/*
|
||||
$repo->expects($participants ? $this->once() : $this->never())
|
||||
->method('findNotConfirmedAndNotRemindedParticipantsByExpireDate')
|
||||
->will($this->returnValue([]));
|
||||
*/
|
||||
|
||||
$app['repo.validation-participants'] = $repo;
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ namespace Alchemy\Tests\Phrasea\Model\Manipulator;
|
||||
|
||||
use Alchemy\Phrasea\Model\Entities\Token;
|
||||
use Alchemy\Phrasea\Model\Manipulator\TokenManipulator;
|
||||
use DateTime;
|
||||
|
||||
/**
|
||||
* @group functional
|
||||
@@ -35,37 +36,38 @@ class TokenManipulatorTest extends \PhraseanetTestCase
|
||||
return [
|
||||
[true, TokenManipulator::TYPE_RSS, null, null],
|
||||
[false, TokenManipulator::TYPE_RSS, null, null],
|
||||
[false, TokenManipulator::TYPE_RSS, new \DateTime('-1 day'), 'data'],
|
||||
[false, TokenManipulator::TYPE_RSS, new DateTime('-1 day'), 'data'],
|
||||
];
|
||||
}
|
||||
|
||||
public function testCreateBasketValidationToken()
|
||||
{
|
||||
$manipulator = new TokenManipulator(self::$DI['app']['orm.em'], self::$DI['app']['random.low'], self::$DI['app']['repo.tokens'], self::$DI['app']['tmp.download.path']);
|
||||
$token = $manipulator->createBasketValidationToken(self::$DI['basket_4'], self::$DI['user_1']);
|
||||
$expire = new DateTime('+10 days');
|
||||
$token = $manipulator->createBasketValidationToken(self::$DI['basket_4'], self::$DI['user_1'], $expire);
|
||||
|
||||
$this->assertSame(self::$DI['basket_4']->getId(), $token->getData());
|
||||
$this->assertSame(self::$DI['user_1'], $token->getUser());
|
||||
$this->assertSame(TokenManipulator::TYPE_VALIDATE, $token->getType());
|
||||
$this->assertDateNear('+10 days', $token->getExpiration());
|
||||
$this->assertSame($expire, $token->getExpiration());
|
||||
}
|
||||
|
||||
public function testCreateBasketValidationTokenWithoutUser()
|
||||
public function testCreateBasketValidationTokenWithoutExpiration()
|
||||
{
|
||||
$manipulator = new TokenManipulator(self::$DI['app']['orm.em'], self::$DI['app']['random.low'], self::$DI['app']['repo.tokens'], self::$DI['app']['tmp.download.path']);
|
||||
$token = $manipulator->createBasketValidationToken(self::$DI['basket_4']);
|
||||
$token = $manipulator->createBasketValidationToken(self::$DI['basket_4'], self::$DI['user_1'], null);
|
||||
|
||||
$this->assertSame(self::$DI['basket_4']->getId(), $token->getData());
|
||||
$this->assertSame(self::$DI['basket_4']->getValidation()->getInitiator(), $token->getUser());
|
||||
$this->assertSame(self::$DI['user_1'], $token->getUser());
|
||||
$this->assertSame(TokenManipulator::TYPE_VALIDATE, $token->getType());
|
||||
$this->assertDateNear('+10 days', $token->getExpiration());
|
||||
$this->assertSame(null, $token->getExpiration());
|
||||
}
|
||||
|
||||
public function testCreateBasketValidationTokenWithInvalidBasket()
|
||||
{
|
||||
$manipulator = new TokenManipulator(self::$DI['app']['orm.em'], self::$DI['app']['random.low'], self::$DI['app']['repo.tokens'], self::$DI['app']['tmp.download.path']);
|
||||
$this->setExpectedException('InvalidArgumentException', 'A validation token requires a validation basket.');
|
||||
$manipulator->createBasketValidationToken(self::$DI['basket_1']);
|
||||
$manipulator->createBasketValidationToken(self::$DI['basket_1'], self::$DI['user_1'], null);
|
||||
}
|
||||
|
||||
public function testCreateBasketAccessToken()
|
||||
|
Reference in New Issue
Block a user