Skip to content

Commit 59d494b

Browse files
committed
Fix #217: Add comprehensive data validation for admin:user:create command with detailed error messages and unit tests
1 parent 688ff75 commit 59d494b

File tree

2 files changed

+179
-5
lines changed

2 files changed

+179
-5
lines changed

src/PrestashopConsole/Command/Admin/User/CreateCommand.php

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int
6565
}
6666

6767
if (!Validate::isName($firstname)) {
68-
$firstname = $helper->ask($input, $output, $this->getCustomerQuestion('lastname'));
68+
$firstname = $helper->ask($input, $output, $this->getCustomerQuestion('firstname'));
6969
}
7070

7171
if (!Validate::isName($lastname)) {
7272
$lastname = $helper->ask($input, $output, $this->getCustomerQuestion('lastname'));
7373
}
7474

75-
// Error if employee with same email already exists
7675
if (Employee::employeeExists($email)) {
7776
$output->writeln('<error>Employee with this email already exists</error>');
7877

@@ -101,6 +100,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int
101100
$employee->default_tab = 1;
102101
$employee->bo_theme = 'default';
103102

103+
if (!$this->validateEmployeeData($employee, $output)) {
104+
return self::RESPONSE_ERROR;
105+
}
106+
104107
if (!$employee->save()) {
105108
$output->writeln('<error>Failed to create admin user</error>');
106109

@@ -172,13 +175,10 @@ protected function isValidPassword($password): bool
172175
if (method_exists('Validate', 'isAcceptablePasswordLength')) {
173176
return Validate::isAcceptablePasswordLength($password);
174177
}
175-
176-
// Fallback to old method for older PS versions
177178
if (method_exists('Validate', 'isPasswdAdmin')) {
178179
return Validate::isPasswdAdmin($password);
179180
}
180181

181-
// Basic validation if neither exists
182182
return strlen($password) >= 8;
183183
}
184184

@@ -202,4 +202,52 @@ protected function getCustomerQuestion(string $field): Question
202202

203203
return $question;
204204
}
205+
206+
/**
207+
* Validate employee data before saving
208+
*
209+
* @param Employee $employee
210+
* @param OutputInterface $output
211+
*
212+
* @return bool
213+
*/
214+
protected function validateEmployeeData(Employee $employee, OutputInterface $output): bool
215+
{
216+
$errors = [];
217+
218+
if (empty($employee->email) || !Validate::isEmail($employee->email)) {
219+
$errors[] = 'Invalid email format';
220+
}
221+
222+
if (empty($employee->firstname) || !Validate::isName($employee->firstname)) {
223+
$errors[] = 'Invalid firstname format';
224+
}
225+
226+
if (empty($employee->lastname) || !Validate::isName($employee->lastname)) {
227+
$errors[] = 'Invalid lastname format';
228+
}
229+
230+
if (empty($employee->passwd)) {
231+
$errors[] = 'Password is required';
232+
}
233+
234+
if (!Validate::isUnsignedId($employee->id_lang)) {
235+
$errors[] = 'Invalid language ID';
236+
}
237+
238+
if (!Validate::isUnsignedId($employee->id_profile)) {
239+
$errors[] = 'Invalid profile ID';
240+
}
241+
242+
if (!empty($errors)) {
243+
$output->writeln('<error>Validation errors:</error>');
244+
foreach ($errors as $error) {
245+
$output->writeln('<error> - ' . $error . '</error>');
246+
}
247+
248+
return false;
249+
}
250+
251+
return true;
252+
}
205253
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
<?php
2+
/**
3+
* NOTICE OF LICENSE
4+
*
5+
* This source file is subject to the Open Software License (OSL 3.0)
6+
* that is bundled with this package in the file LICENSE.txt.
7+
* It is also available through the world-wide-web at this URL:
8+
* https://opensource.org/licenses/OSL-3.0
9+
* If you did not receive a copy of the license and are unable to
10+
* obtain it through the world-wide-web, please send an email
11+
* to contact@h-hennes.fr so we can send you a copy immediately.
12+
*
13+
* @author Hennes Hervé <contact@h-hennes.fr>
14+
* @copyright since 2016 Hennes Hervé
15+
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
16+
* https://github.com/nenes25/prestashop_console
17+
* https://www.h-hennes.fr/blog/
18+
*/
19+
20+
use PrestashopConsole\Command\Admin\User\CreateCommand;
21+
use Symfony\Component\Console\Tester\CommandTester;
22+
use Symfony\Component\Console\Helper\HelperSet;
23+
use Symfony\Component\Console\Helper\QuestionHelper;
24+
use PHPUnit\Framework\TestCase;
25+
26+
class CreateAdminUserCommandTest extends TestCase
27+
{
28+
/** @var CommandTester */
29+
private $commandTester;
30+
31+
protected function setUp(): void
32+
{
33+
$command = new CreateCommand();
34+
$command->setHelperSet(new HelperSet([new QuestionHelper()]));
35+
$this->commandTester = new CommandTester(
36+
$command
37+
);
38+
parent::setUp();
39+
}
40+
41+
/**
42+
* @param array $datas
43+
* @dataProvider getCases
44+
*/
45+
public function testExecute($datas): void
46+
{
47+
if (isset($datas['expect_exception'])) {
48+
$this->expectException($datas['expect_exception']);
49+
$this->expectExceptionMessage($datas['response_message']);
50+
$this->commandTester->execute($datas['params']);
51+
return;
52+
}
53+
54+
// Check command status code
55+
$this->assertEquals(
56+
$datas['response_code'],
57+
$this->commandTester->execute(
58+
$datas['params']
59+
)
60+
);
61+
62+
// Check command message contains expected output
63+
$display = trim($this->commandTester->getDisplay());
64+
$this->assertStringContainsString(
65+
$datas['response_message'],
66+
$display
67+
);
68+
}
69+
70+
public function getCases(): Generator
71+
{
72+
$emailOkRandomString = sprintf('unittestadmin-%s@yopmail.com', time() * mt_rand(1, 1000));
73+
74+
yield 'Case ok - Valid admin creation' => [
75+
[
76+
'params' => [
77+
'--email' => $emailOkRandomString,
78+
'--password' => 'prestashop123',
79+
'--firstname' => 'Admin',
80+
'--lastname' => 'Test',
81+
],
82+
'response_message' => 'Admin user created successfully!',
83+
'response_code' => 0,
84+
]
85+
];
86+
87+
yield 'Case error - Invalid email' => [
88+
[
89+
'params' => [
90+
'--email' => 'invalid-email',
91+
'--password' => 'prestashop123',
92+
'--firstname' => 'Admin',
93+
'--lastname' => 'Test',
94+
],
95+
'response_message' => 'The email is empty or not valid',
96+
'expect_exception' => RuntimeException::class,
97+
]
98+
];
99+
100+
yield 'Case error - Empty firstname validated at final step' => [
101+
[
102+
'params' => [
103+
'--email' => sprintf('admin-%s@yopmail.com', time() * mt_rand(1, 1000)),
104+
'--password' => 'prestashop123',
105+
'--firstname' => '',
106+
'--lastname' => 'Test',
107+
],
108+
'response_message' => 'Invalid firstname format',
109+
'response_code' => 1,
110+
]
111+
];
112+
113+
yield 'Case error - Empty lastname validated at final step' => [
114+
[
115+
'params' => [
116+
'--email' => sprintf('admin-%s@yopmail.com', time() * mt_rand(1, 1000)),
117+
'--password' => 'prestashop123',
118+
'--firstname' => 'Admin',
119+
'--lastname' => '',
120+
],
121+
'response_message' => 'Invalid lastname format',
122+
'response_code' => 1,
123+
]
124+
];
125+
}
126+
}

0 commit comments

Comments
 (0)