Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 120 additions & 12 deletions libraries/src/Console/AddUserCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

namespace Joomla\CMS\Console;

use Joomla\CMS\Form\Form;
use Joomla\CMS\Form\Rule\PasswordRule;
use Joomla\CMS\User\User;
use Joomla\Console\Command\AbstractCommand;
use Joomla\Database\DatabaseAwareTrait;
Expand Down Expand Up @@ -128,12 +130,15 @@ public function __construct(DatabaseInterface $db)
*/
protected function doExecute(InputInterface $input, OutputInterface $output): int
{
$language = $this->getApplication()->getLanguage();
$language->load('lib_joomla', JPATH_ADMINISTRATOR, 'en-GB', true);
$this->configureIO($input, $output);
$this->ioStyle->title('Add User');

$this->user = $this->getStringFromOption('username', 'Please enter a username');
$this->name = $this->getStringFromOption('name', 'Please enter a name (full name of user)');
$this->email = $this->getStringFromOption('email', 'Please enter an email address');
$this->password = $this->getStringFromOption('password', 'Please enter a password');
$this->password = $this->getPasswordFromOption();
$this->userGroups = $this->getUserGroups();

if (\in_array("error", $this->userGroups)) {
Expand All @@ -142,36 +147,59 @@ protected function doExecute(InputInterface $input, OutputInterface $output): in
return Command::FAILURE;
}

// Get filter to remove invalid characters
$filter = new InputFilter();

$user = [
'username' => $filter->clean($this->user, 'USERNAME'),
'password' => $this->password,
'name' => $filter->clean($this->name, 'STRING'),
'email' => $this->email,
'groups' => $this->userGroups,
$data = [
'username' => $filter->clean($this->user, 'USERNAME'),
'password' => $this->password,
'password2' => $this->password,
'name' => $filter->clean($this->name, 'STRING'),
'email' => $this->email,
'groups' => $this->userGroups,
];

$form = new Form('com_users.user', ['control' => 'jform']);
$xmlPath = JPATH_ADMINISTRATOR . '/components/com_users/forms/user.xml';

if (!is_file($xmlPath) || !$form->loadFile($xmlPath)) {
$this->ioStyle->error('Unable to load user form XML: ' . $xmlPath);

return Command::FAILURE;
}

$validated = $form->validate($data);
$this->clearMessageQueue();

if ($validated === false) {
$errors = $form->getErrors();

foreach ($errors as $error) {
$this->ioStyle->error($error->getMessage());
}

return Command::FAILURE;
}

$userObj = User::getInstance();
$userObj->bind($user);
$userObj->bind($data);

if (!$userObj->save()) {
switch ($userObj->getError()) {
case "JLIB_DATABASE_ERROR_USERNAME_INUSE":
case "Username in use.":
$this->ioStyle->error("The username already exists!");
break;
case "JLIB_DATABASE_ERROR_EMAIL_INUSE":
case "The email address you entered is already in use. Please enter another email address.":
$this->ioStyle->error("The email address already exists!");
break;
case "JLIB_DATABASE_ERROR_VALID_MAIL":
case "The email address you entered is invalid. Please enter another email address.":
$this->ioStyle->error("The email address is invalid!");
break;
}

return 1;
}

$this->clearMessageQueue();
$this->ioStyle->success("User created!");

return Command::SUCCESS;
Expand Down Expand Up @@ -224,6 +252,37 @@ public function getStringFromOption($option, $question): string
return $answer;
}

/**
* Method to get and validate password from option
*
* @return string
*
* @since __DEPLOY_VERSION__
*/
public function getPasswordFromOption(): string
{
$password = (string) $this->cliInput->getOption('password');

while (!$password) {
$password = (string) $this->ioStyle->askHidden('Please enter a password');

if ($password) {
$errors = $this->validatePassword($password);

if ($errors) {
foreach ($errors as $error) {
$this->ioStyle->error($error);
}
$password = '';
}
}
}

$this->clearMessageQueue();

return $password;
}

/**
* Method to get a value from option
*
Expand Down Expand Up @@ -316,4 +375,53 @@ protected function configure(): void
$this->setDescription('Add a user');
$this->setHelp($help);
}

/**
* Method to validate password using Joomla's PasswordRule
*
* @param string $password The password to validate
*
* @return array Array of error messages, empty if valid
*
* @since __DEPLOY_VERSION__
*/
protected function validatePassword($password): array
{
$errors = [];

// Construct the XML field element matching password rules
$element = new \SimpleXMLElement('<field name="password" type="password" validate="password" required="true" />');

// Instantiate and execute the rule
$rule = new PasswordRule();
$isValid = $rule->test($element, $password);

$app = $this->getApplication();


$messageQueue = $app->getMessageQueue(true);

if (!$isValid) {
foreach ($messageQueue as $message) {
$errors[] = $message;
}
}

return $errors;
}

/**
* Clears the application's message queue.
*
* @return void
*
* @since __DEPLOY_VERSION__
*/
private function clearMessageQueue(): void
{
$app = $this->getApplication();

$property = new \ReflectionProperty($app, 'messages');
$property->setValue($app, []);
}
}