1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Copyright 2014 SURFnet bv |
5
|
|
|
* |
6
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
7
|
|
|
* you may not use this file except in compliance with the License. |
8
|
|
|
* You may obtain a copy of the License at |
9
|
|
|
* |
10
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0 |
11
|
|
|
* |
12
|
|
|
* Unless required by applicable law or agreed to in writing, software |
13
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS, |
14
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
15
|
|
|
* See the License for the specific language governing permissions and |
16
|
|
|
* limitations under the License. |
17
|
|
|
*/ |
18
|
|
|
|
19
|
|
|
namespace Surfnet\StepupMiddleware\MiddlewareBundle\Console\Command; |
20
|
|
|
|
21
|
|
|
use Assert\Assertion; |
22
|
|
|
use DateInterval; |
23
|
|
|
use DateTime; |
24
|
|
|
use Exception; |
25
|
|
|
use InvalidArgumentException; |
26
|
|
|
use Psr\Log\LoggerInterface; |
27
|
|
|
use Rhumsaa\Uuid\Uuid; |
28
|
|
|
use Surfnet\StepupMiddleware\CommandHandlingBundle\EventHandling\BufferedEventBus; |
29
|
|
|
use Surfnet\StepupMiddleware\CommandHandlingBundle\Identity\Command\SendVerifiedSecondFactorRemindersCommand; |
30
|
|
|
use Surfnet\StepupMiddleware\CommandHandlingBundle\Pipeline\TransactionAwarePipeline; |
31
|
|
|
use Surfnet\StepupMiddleware\MiddlewareBundle\Service\DBALConnectionHelper; |
32
|
|
|
use Symfony\Component\Console\Command\Command; |
33
|
|
|
use Symfony\Component\Console\Input\InputInterface; |
34
|
|
|
use Symfony\Component\Console\Input\InputOption; |
35
|
|
|
use Symfony\Component\Console\Output\OutputInterface; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* The EmailVerifiedSecondFactorRemindersCommand can be run to send reminders to token registrants. |
39
|
|
|
* |
40
|
|
|
* The command utilizes a specific service for this task (VerifiedSecondFactorReminderService). Input validation is |
41
|
|
|
* performed on the incoming request parameters. |
42
|
|
|
* |
43
|
|
|
* @SuppressWarnings(PHPMD.CouplingBetweenObjects) |
44
|
|
|
*/ |
45
|
|
|
final class EmailVerifiedSecondFactorRemindersCommand extends Command |
46
|
|
|
{ |
47
|
|
|
/** |
48
|
|
|
* @var TransactionAwarePipeline |
49
|
|
|
*/ |
50
|
|
|
private $pipeline; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @var BufferedEventBus |
54
|
|
|
*/ |
55
|
|
|
private $eventBus; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* @var DBALConnectionHelper |
59
|
|
|
*/ |
60
|
|
|
private $connection; |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* @var LoggerInterface |
64
|
|
|
*/ |
65
|
|
|
private $logger; |
66
|
|
|
|
67
|
|
|
protected function configure() |
68
|
|
|
{ |
69
|
|
|
$this |
70
|
|
|
->setName('middleware:cron:email-reminder') |
71
|
|
|
->setDescription('Sends email reminders to identities with verified tokens more than 7 days old.') |
72
|
|
|
->addOption( |
73
|
|
|
'dry-run', |
74
|
|
|
null, |
75
|
|
|
InputOption::VALUE_NONE, |
76
|
|
|
'Run in dry mode, not sending any email' |
77
|
|
|
) |
78
|
|
|
->addOption( |
79
|
|
|
'date', |
80
|
|
|
null, |
81
|
|
|
InputOption::VALUE_OPTIONAL, |
82
|
|
|
'The date (Y-m-d) that should be used for sending reminder email messages, defaults to TODAY - 7' |
83
|
|
|
); |
84
|
|
|
} |
85
|
|
|
|
86
|
|
View Code Duplication |
public function __construct( |
|
|
|
|
87
|
|
|
TransactionAwarePipeline $pipeline, |
88
|
|
|
BufferedEventBus $eventBus, |
89
|
|
|
DBALConnectionHelper $connection, |
90
|
|
|
LoggerInterface $logger |
91
|
|
|
) { |
92
|
|
|
$this->pipeline = $pipeline; |
93
|
|
|
$this->eventBus = $eventBus; |
94
|
|
|
$this->connection = $connection; |
95
|
|
|
$this->logger = $logger; |
96
|
|
|
parent::__construct(); |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
protected function execute(InputInterface $input, OutputInterface $output) |
100
|
|
|
{ |
101
|
|
|
try { |
102
|
|
|
$this->validateInput($input); |
103
|
|
|
} catch (InvalidArgumentException $e) { |
104
|
|
|
$output->writeln('<error>' . $e->getMessage() . '</error>'); |
105
|
|
|
$this->logger->error(sprintf('Invalid arguments passed to the %s', $this->getName()), [$e->getMessage()]); |
106
|
|
|
return 1; |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
$date = new DateTime(); |
110
|
|
|
$date->sub(new DateInterval('P7D')); |
111
|
|
|
if ($input->hasOption('date') && !is_null($input->getOption('date'))) { |
112
|
|
|
$date = DateTime::createFromFormat('Y-m-d', $input->getOption('date')); |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
$dryRun = false; |
116
|
|
|
if ($input->hasOption('dry-run') && !is_null($input->getOption('dry-run'))) { |
117
|
|
|
$dryRun = $input->getOption('dry-run'); |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
$command = new SendVerifiedSecondFactorRemindersCommand(); |
121
|
|
|
$command->requestedAt = $date; |
|
|
|
|
122
|
|
|
$command->dryRun = $dryRun; |
|
|
|
|
123
|
|
|
$command->UUID = Uuid::uuid4()->toString(); |
124
|
|
|
|
125
|
|
|
$this->connection->beginTransaction(); |
126
|
|
|
try { |
127
|
|
|
$this->pipeline->process($command); |
128
|
|
|
$this->eventBus->flush(); |
129
|
|
|
|
130
|
|
|
$this->connection->commit(); |
131
|
|
|
} catch (Exception $e) { |
132
|
|
|
$output->writeln('<error>An Error occurred while sending reminder email messages.</error>'); |
133
|
|
|
$this->connection->rollBack(); |
134
|
|
|
throw $e; |
135
|
|
|
} |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
private function validateInput(InputInterface $input) |
139
|
|
|
{ |
140
|
|
|
if ($input->hasOption('date')) { |
141
|
|
|
$date = $input->getOption('date'); |
142
|
|
|
Assertion::nullOrDate($date, 'Y-m-d', 'Expected date to be a string and formatted in the Y-m-d date format'); |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
if ($input->hasOption('dry-run')) { |
146
|
|
|
$dryRun = $input->getOption('dry-run'); |
147
|
|
|
Assertion::nullOrBoolean($dryRun, 'Expected dry-run parameter to be a boolean value.'); |
148
|
|
|
} |
149
|
|
|
} |
150
|
|
|
} |
151
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.