diff --git a/.styleci.yml b/.styleci.yml index 916d27e..0285f17 100644 --- a/.styleci.yml +++ b/.styleci.yml @@ -1,3 +1 @@ preset: laravel - -linting: true diff --git a/.travis.yml b/.travis.yml index ae5cfb1..769f7ae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,9 +7,9 @@ cache: matrix: include: - php: 7.1 - env: ILLUMINATE_VERSION=5.6.* + env: ILLUMINATE_VERSION=5.7.* - php: 7.2 - env: ILLUMINATE_VERSION=5.6.* + env: ILLUMINATE_VERSION=5.7.* before_install: travis_retry composer require "illuminate/database:${ILLUMINATE_VERSION}" "illuminate/events:${ILLUMINATE_VERSION}" --no-update -v diff --git a/README.md b/README.md index 065ca4f..3829129 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Laravel Make User -## v3.0.0 +## v4.0.0 [![Build Status](https://travis-ci.org/michaeldyrynda/laravel-make-user.svg?branch=master)](https://travis-ci.org/michaeldyrynda/laravel-make-user) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/michaeldyrynda/laravel-make-user/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/michaeldyrynda/laravel-make-user/?branch=master) @@ -11,7 +11,7 @@ ## Introduction -Out of the box, Laravel makes it really simple to scaffold out with its [authentication quickstart](https://laravel.com/docs/5.4/authentication#authentication-quickstart). Whilst this makes it really easy to register and authenticate users, for many of the applications I find myself building, we usually remove the ability for visitors to register themselves. +Out of the box, Laravel makes it really simple to scaffold out with its [authentication quickstart](https://laravel.com/docs/5.7/authentication#authentication-quickstart). Whilst this makes it really easy to register and authenticate users, for many of the applications I find myself building, we usually remove the ability for visitors to register themselves. I still need a way to get users into those applications, however, and whilst they're in early development this usually involves firing up Laravel Tinker. This can be a tedious process, and one that I repeat many times over. @@ -24,45 +24,26 @@ Laravel | Package 5.4.* | 1.0.* 5.5.* | 2.0.* 5.6.* | 3.0.* +5.7.* | 4.0.* ## Code Samples This package exposes a `make:user` command, which is accessed via the Artisan command line utility. The package will use the model defined in your `auth.providers.users.model` configuration value. ``` -php artisan make:user email {--name=NAME} {--password=PASSWORD} {--send-reset} {--fields=FIELDS} {--force} +php artisan make:user ``` -If the password is not specified, the `--send-reset` option is implicit, sending the default password reset notification to the user. This package does not currently provide support to customise the content or notification sent as my general practice is to create a user account, then have the user manually perform a password reset. The implied `--send-reset` saves a manual step in this process. - -This package runs on the assumption that you are using Laravel's default `users` table structure. If you have additional columns in your database, they can be specified using the `--fields` option, separating each key/value pair with a comma: - -``` -php artisan make:user user@example.com --fields="admin:true,other_field:other value" -``` - -This will create a new user with the email address `user@example.com`, a randomly generated password, send the password reset email to `user@example.com`, and set the `admin` field to `true`. Should you need to circumvent your user model's guarded fields, you can pass the `--force` option, and the user model will be created using the `forceCreate` method. +This package runs on the assumption that you are using Laravel's default `users` table structure. You can specify additional fields when prompted. ## Installation This package is installed via [Composer](https://getcomposer.org/). To install, run the following command. ```bash -composer require "dyrynda/laravel-make-user:~3.0" +composer require "dyrynda/laravel-make-user:~4.0" ``` -Then add the service provider to your `config/app.php` file: - -```php -'providers' => [ - // ... - Dyrynda\Artisan\MakeUserServiceProvider::class, - // ... -] -``` - -Note, this package has support for Laravel's auto package discovery, which will be available from version 5.5 onwards. - ## Support If you are having general issues with this package, feel free to contact me on [Twitter](https://twitter.com/michaeldyrynda). diff --git a/composer.json b/composer.json index fc394e8..f532206 100644 --- a/composer.json +++ b/composer.json @@ -11,12 +11,12 @@ } ], "require": { - "php": ">=7.1.3", - "illuminate/support": "5.6.*", - "illuminate/console": "5.6.*", - "illuminate/database": "5.6.*", - "illuminate/auth": "5.6.*", - "illuminate/notifications": "5.6.*" + "php": "^7.1.3", + "illuminate/support": "5.7.*", + "illuminate/console": "5.7.*", + "illuminate/database": "5.7.*", + "illuminate/auth": "5.7.*", + "illuminate/notifications": "5.7.*" }, "autoload": { "psr-4": { @@ -24,8 +24,9 @@ } }, "require-dev": { + "mockery/mockery": "^1.0", "phpunit/phpunit": "~7.0", - "orchestra/testbench": "~3.0" + "orchestra/testbench": "^3.7" }, "autoload-dev": { "psr-4": { diff --git a/phpunit.xml b/phpunit.xml index 0152405..4b2674b 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -19,4 +19,7 @@ src/ + + + diff --git a/src/Console/Commands/MakeUser.php b/src/Console/Commands/MakeUser.php index bb2b7a0..96fe144 100644 --- a/src/Console/Commands/MakeUser.php +++ b/src/Console/Commands/MakeUser.php @@ -14,11 +14,7 @@ class MakeUser extends Command * * @var string */ - protected $signature = 'make:user {email} {--name= : Set the name for the new user} - {--password= : The password to set for the new user} - {--send-reset : Send a password reset email for the new user} - {--fields= : Additional database fields to set on the user} - {--force : Create the user model circumventing guarded fields}'; + protected $signature = 'make:user'; /** * The console command description. @@ -27,6 +23,13 @@ class MakeUser extends Command */ protected $description = 'Create a new application user'; + /** + * Array of custom fields to attach to the user. + * + * @var array + */ + protected $customFields = []; + /** * Execute the console command. * @@ -36,20 +39,24 @@ class MakeUser extends Command */ public function handle() { - $email = $this->argument('email'); - $name = $this->option('name') ?: ''; - $password = bcrypt($this->option('password') ?: str_random(32)); - $modelCommand = $this->option('force') ? 'forceCreate' : 'create'; - $sendReset = ! $this->option('password') || $this->option('send-reset'); + $email = $this->ask("What is the new user's email address?"); + $name = $this->ask("What is the new user's name?") ?: ''; + $password = bcrypt($this->secret("What is the new user's password? (blank generates a random one)", str_random(32))); + $sendReset = $this->confirm('Do you want to send a password reset email?'); + + while ($custom = $this->ask('Do you have any custom user fields to add? Field=Value (blank continues)', false)) { + list($key, $value) = explode('=', $custom); + $this->customFields[$key] = value($value); + } try { app('db')->beginTransaction(); $this->validateEmail($email); - app(config('auth.providers.users.model'))->{$modelCommand}(array_merge( + app(config('auth.providers.users.model'))->create(array_merge( compact('email', 'name', 'password'), - $this->additionalFields() + $this->customFields )); if ($sendReset) { @@ -88,45 +95,4 @@ private function validateEmail($email) throw MakeUserException::emailExists($email); } } - - /** - * Return any additional database fields passed by the --fields option. - * - * @return array - */ - private function additionalFields() - { - if (! $this->option('fields')) { - return []; - } - - return collect(explode(',', $this->option('fields')))->mapWithKeys(function ($field) { - list($column, $value) = explode(':', $field); - - return [trim($column) => $this->normaliseValue($value)]; - })->toArray(); - } - - /** - * Normalise the given (database) field input value. - * - * @param mixed $value - * @return mixed - */ - private function normaliseValue($value) - { - if ($value == 'null') { - return; - } - - if (in_array($value, [1, 'true', true], true)) { - return true; - } - - if (in_array($value, [0, 'false', false], true)) { - return false; - } - - return trim($value); - } } diff --git a/tests/MakeUserTest.php b/tests/MakeUserTest.php index e2daa8a..3d1fef8 100644 --- a/tests/MakeUserTest.php +++ b/tests/MakeUserTest.php @@ -2,116 +2,28 @@ namespace Tests; -use Illuminate\Support\Facades\Hash; -use Illuminate\Support\Facades\Artisan; -use Illuminate\Support\Facades\Notification; -use Illuminate\Auth\Notifications\ResetPassword; - class MakeUserTest extends TestCase { /** @test */ - public function it_requires_a_valid_email_address() - { - Artisan::call('make:user', ['email' => 'invalidemail']); - - $this->assertFalse(User::where('email', 'invalidemail')->exists()); - } - - /** @test */ - public function it_requires_a_unique_email_address() - { - User::create(['name' => 'Adam Wathan', 'email' => 'adamwathan@example.com', 'password' => '']); - - $exitCode = Artisan::call('make:user', ['email' => 'adamwathan@example.com']); - - $this->assertContains('The user was not created', Artisan::output()); - $this->assertEquals(1, User::where('email', 'adamwathan@example.com')->count()); - } - - /** @test */ - public function it_hashes_the_password_when_specified() - { - Artisan::call('make:user', ['email' => 'michael@dyrynda.com.au', '--password' => 'secret']); - - tap(User::first(), function ($user) { - $this->assertTrue(Hash::check('secret', $user->password)); - }); - } - - /** @test */ - public function it_sends_the_password_reset_email_when_generating_a_password() - { - Notification::fake(); - - Artisan::call('make:user', ['email' => 'michael@dyrynda.com.au', '--name' => 'Michael Dyrynda']); - - Notification::assertSentTo(User::first(), ResetPassword::class); - - tap(['email' => 'michael@dyrynda.com.au', 'name' => 'Michael Dyrynda'], function ($credentials) { - $this->assertTrue(User::where($credentials)->exists()); - $this->assertEquals(1, User::where($credentials)->count()); - }); - } - - /** @test */ - public function it_does_not_send_the_password_reset_email_when_the_password_is_specified() - { - Notification::fake(); - - Artisan::call('make:user', ['email' => 'michael@dyrynda.com.au', '--password' => 'secret']); - - Notification::assertNotSentTo(User::first(), ResetPassword::class); - - tap(['email' => 'michael@dyrynda.com.au'], function ($credentials) { - $this->assertTrue(User::where($credentials)->exists()); - $this->assertEquals(1, User::where($credentials)->count()); - }); - } - - /** @test */ - public function it_sends_the_password_reset_email_when_flagged_to_do_so() - { - Notification::fake(); - - Artisan::call('make:user', ['email' => 'michael@dyrynda.com.au', '--password' => 'secret', '--send-reset' => true]); - - Notification::assertSentTo(User::first(), ResetPassword::class); - } - - /** @test */ - public function it_fills_additional_fields_when_specified() + public function it_creates_a_new_user() { - Artisan::call('make:user', ['email' => 'michael@dyrynda.com.au', '--password' => 'secret', '--fields' => 'admin:true']); - - $this->assertTrue(User::where([ - 'email' => 'michael@dyrynda.com.au', - 'admin' => true, - ])->exists()); + $this->artisan('make:user') + ->expectsQuestion("What is the new user's email address?", 'user@example.com') + ->expectsQuestion("What is the new user's name?", 'Test User') + ->expectsQuestion("What is the new user's password? (blank generates a random one)", '') + ->expectsQuestion('Do you want to send a password reset email?', 'no') + ->expectsQuestion('Do you have any custom user fields to add? Field=Value (blank continues)', ''); } /** @test */ - public function it_handles_null_field_values_correctly() + public function it_creates_a_new_user_with_additional_fields() { - Artisan::call('make:user', ['email' => 'michael@dyrynda.com.au', '--fields' => 'force_filled:null']); - - tap(User::first(), function ($user) { - $this->assertNull($user->force_filled); - }); - } - - /** @test */ - public function it_force_filles_guarded_properties_when_instructed() - { - Artisan::call('make:user', [ - 'email' => 'michael@dyrynda.com.au', - '--password' => 'secret', - '--force' => true, - '--fields' => 'admin:false,force_filled:string field', - ]); - - tap(User::first(), function ($user) { - $this->assertFalse($user->admin); - $this->assertEquals('string field', $user->force_filled); - }); + $this->artisan('make:user') + ->expectsQuestion("What is the new user's email address?", 'user@example.com') + ->expectsQuestion("What is the new user's name?", 'Test User') + ->expectsQuestion("What is the new user's password? (blank generates a random one)", '') + ->expectsQuestion('Do you want to send a password reset email?', 'no') + ->expectsQuestion('Do you have any custom user fields to add? Field=Value (blank continues)', 'field=value') + ->expectsQuestion('Do you have any custom user fields to add? Field=Value (blank continues)', ''); } } diff --git a/tests/TestCase.php b/tests/TestCase.php index 079ac8f..ba96d9c 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -7,29 +7,10 @@ abstract class TestCase extends Orchestra { - public function setUp() - { - parent::setUp(); - - $this->loadLaravelMigrations('testing'); - - $this->loadMigrationsFrom(realpath(__DIR__.'/migrations')); - } - protected function getPackageProviders($app) { return [ MakeUserServiceProvider::class, ]; } - - protected function getEnvironmentSetUp($app) - { - $app['config']->set('database.connections.testing', [ - 'driver' => 'sqlite', - 'database' => ':memory:', - ]); - $app['config']->set('auth.providers.users.model', User::class); - $app['router']->get('/password/reset')->name('password.reset'); - } } diff --git a/tests/User.php b/tests/User.php deleted file mode 100644 index 9a74f95..0000000 --- a/tests/User.php +++ /dev/null @@ -1,21 +0,0 @@ - 'bool']; -} diff --git a/tests/migrations/2017_06_09_203800_add_test_user_fields.php b/tests/migrations/2017_06_09_203800_add_test_user_fields.php deleted file mode 100644 index a9c2796..0000000 --- a/tests/migrations/2017_06_09_203800_add_test_user_fields.php +++ /dev/null @@ -1,31 +0,0 @@ -boolean('admin')->default(false); - $table->string('force_filled')->nullable()->default(null); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - // - } -}