Skip to content

Commit

Permalink
Merge pull request #1164 from kenjis/feat-command-user-create-g-option
Browse files Browse the repository at this point in the history
feat: add -g option to `shield:user create`
  • Loading branch information
kenjis authored Aug 21, 2024
2 parents 2554481 + 2e7c54b commit 60f1ae3
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 22 deletions.
14 changes: 13 additions & 1 deletion phpstan-baseline.php
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,12 @@
'count' => 1,
'path' => __DIR__ . '/src/Collectors/Auth.php',
];
$ignoreErrors[] = [
// identifier: codeigniter.factoriesClassConstFetch
'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\GroupModel\\:\\:class is discouraged\\.$#',
'count' => 1,
'path' => __DIR__ . '/src/Commands/User.php',
];
$ignoreErrors[] = [
// identifier: codeigniter.factoriesClassConstFetch
'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserModel\\:\\:class is discouraged\\.$#',
Expand Down Expand Up @@ -259,7 +265,7 @@
$ignoreErrors[] = [
// identifier: codeigniter.factoriesClassConstFetch
'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\GroupModel\\:\\:class is discouraged\\.$#',
'count' => 2,
'count' => 4,
'path' => __DIR__ . '/src/Entities/User.php',
];
$ignoreErrors[] = [
Expand Down Expand Up @@ -330,6 +336,12 @@
'count' => 1,
'path' => __DIR__ . '/src/Models/UserIdentityModel.php',
];
$ignoreErrors[] = [
// identifier: codeigniter.factoriesClassConstFetch
'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\GroupModel\\:\\:class is discouraged\\.$#',
'count' => 1,
'path' => __DIR__ . '/src/Models/UserModel.php',
];
$ignoreErrors[] = [
// identifier: codeigniter.factoriesClassConstFetch
'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserIdentityModel\\:\\:class is discouraged\\.$#',
Expand Down
20 changes: 7 additions & 13 deletions src/Authorization/Traits/Authorizable.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ public function addGroup(string ...$groups): self
{
$this->populateGroups();

$configGroups = $this->getConfigGroups();

$groupCount = count($this->groupCache);

foreach ($groups as $group) {
Expand All @@ -45,8 +43,11 @@ public function addGroup(string ...$groups): self
continue;
}

/** @var GroupModel $groupModel */
$groupModel = model(GroupModel::class);

// make sure it's a valid group
if (! in_array($group, $configGroups, true)) {
if (! $groupModel->isValidGroup($group)) {
throw AuthorizationException::forUnknownGroup($group);
}

Expand Down Expand Up @@ -96,10 +97,11 @@ public function syncGroups(string ...$groups): self
{
$this->populateGroups();

$configGroups = $this->getConfigGroups();
/** @var GroupModel $groupModel */
$groupModel = model(GroupModel::class);

foreach ($groups as $group) {
if (! in_array($group, $configGroups, true)) {
if (! $groupModel->isValidGroup($group)) {
throw AuthorizationException::forUnknownGroup($group);
}
}
Expand Down Expand Up @@ -398,14 +400,6 @@ private function saveGroupsOrPermissions(string $type, $model, array $cache): vo
}
}

/**
* @return list<string>
*/
private function getConfigGroups(): array
{
return array_keys(setting('AuthGroups.groups'));
}

/**
* @return list<string>
*/
Expand Down
33 changes: 28 additions & 5 deletions src/Commands/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use CodeIgniter\Shield\Config\Auth;
use CodeIgniter\Shield\Entities\User as UserEntity;
use CodeIgniter\Shield\Exceptions\UserNotFoundException;
use CodeIgniter\Shield\Models\GroupModel;
use CodeIgniter\Shield\Models\UserModel;
use CodeIgniter\Shield\Validation\ValidationRules;
use Config\Services;
Expand Down Expand Up @@ -53,6 +54,7 @@ class User extends BaseCommand
shield:user <action> options
shield:user create -n newusername -e newuser@example.com
shield:user create -n newusername -e newuser@example.com -g mygroup
shield:user activate -n username
shield:user activate -e user@example.com
Expand Down Expand Up @@ -159,7 +161,7 @@ public function run(array $params): int
try {
switch ($action) {
case 'create':
$this->create($username, $email);
$this->create($username, $email, $group);
break;

case 'activate':
Expand Down Expand Up @@ -252,8 +254,9 @@ private function setValidationRules(): void
*
* @param string|null $username User name to create (optional)
* @param string|null $email User email to create (optional)
* @param string|null $group Group to add user to (optional)
*/
private function create(?string $username = null, ?string $email = null): void
private function create(?string $username = null, ?string $email = null, ?string $group = null): void
{
$data = [];

Expand Down Expand Up @@ -303,6 +306,11 @@ private function create(?string $username = null, ?string $email = null): void

$user = new UserEntity($data);

// Validate the group
if ($group !== null && ! $this->validateGroup($group)) {
throw new CancelException('Invalid group: "' . $group . '"');
}

if ($username === null) {
$userModel->allowEmptyInserts()->save($user);
$this->write('New User created', 'green');
Expand All @@ -311,11 +319,26 @@ private function create(?string $username = null, ?string $email = null): void
$this->write('User "' . $username . '" created', 'green');
}

// Add to default group
$user = $userModel->findById($userModel->getInsertID());
$userModel->addToDefaultGroup($user);

$this->write('The user is added to the default group.', 'green');
if ($group === null) {
// Add to default group
$userModel->addToDefaultGroup($user);

$this->write('The user is added to the default group.', 'green');
} else {
$user->addGroup($group);

$this->write('The user is added to group "' . $group . '".', 'green');
}
}

private function validateGroup(string $group): bool
{
/** @var GroupModel $groupModel */
$groupModel = model(GroupModel::class);

return $groupModel->isValidGroup($group);
}

/**
Expand Down
10 changes: 10 additions & 0 deletions src/Models/GroupModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,14 @@ public function deleteNotIn($userId, $cache): void

$this->checkQueryReturn($return);
}

/**
* @param non-empty-string $group Group name
*/
public function isValidGroup(string $group): bool
{
$allowedGroups = array_keys(setting('AuthGroups.groups'));

return in_array($group, $allowedGroups, true);
}
}
8 changes: 5 additions & 3 deletions src/Models/UserModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,12 @@ private function assignIdentities(array $data, array $identities): array
*/
public function addToDefaultGroup(User $user): void
{
$defaultGroup = setting('AuthGroups.defaultGroup');
$allowedGroups = array_keys(setting('AuthGroups.groups'));
$defaultGroup = setting('AuthGroups.defaultGroup');

if (empty($defaultGroup) || ! in_array($defaultGroup, $allowedGroups, true)) {
/** @var GroupModel $groupModel */
$groupModel = model(GroupModel::class);

if (empty($defaultGroup) || ! $groupModel->isValidGroup($defaultGroup)) {
throw new InvalidArgumentException(lang('Auth.unknownGroup', [$defaultGroup ?? '--not found--']));
}

Expand Down
53 changes: 53 additions & 0 deletions tests/Commands/UserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,59 @@ public function testCreate(): void
]);
}

public function testCreateWithGroupBeta(): void
{
$this->setMockIo([
'Secret Passw0rd!',
'Secret Passw0rd!',
]);

command('shield:user create -n user1 -e user1@example.com -g beta');

$this->assertStringContainsString(
'User "user1" created',
$this->io->getFirstOutput()
);
$this->assertStringContainsString(
'The user is added to group "beta"',
$this->io->getFirstOutput()
);

$users = model(UserModel::class);
$user = $users->findByCredentials(['email' => 'user1@example.com']);
$this->seeInDatabase($this->tables['identities'], [
'user_id' => $user->id,
'secret' => 'user1@example.com',
]);
$this->seeInDatabase($this->tables['users'], [
'id' => $user->id,
'active' => 0,
]);
$this->seeInDatabase($this->tables['groups_users'], [
'user_id' => $user->id,
'group' => 'beta',
]);
}

public function testCreateWithInvalidGroup(): void
{
$this->setMockIo([
'Secret Passw0rd!',
'Secret Passw0rd!',
]);

command('shield:user create -n user1 -e user1@example.com -g invalid');

$this->assertStringContainsString(
'Invalid group: "invalid"',
$this->io->getFirstOutput()
);

$users = model(UserModel::class);
$user = $users->findByCredentials(['email' => 'user1@example.com']);
$this->assertNull($user);
}

public function testCreateNotUniqueName(): void
{
$user = $this->createUser([
Expand Down

0 comments on commit 60f1ae3

Please sign in to comment.