From 2048e0899ccce805e66ff2b01404b623277d437c Mon Sep 17 00:00:00 2001 From: James Brooks Date: Thu, 2 Jun 2016 11:45:10 +0100 Subject: [PATCH] Added Team Member API. Closes #1822 --- .../Commands/User/AddTeamMemberCommand.php | 5 +- .../Commands/User/UpdateTeamMemberCommand.php | 90 +++++++++++++++++++ app/Bus/Events/User/UserWasUpdatedEvent.php | 41 +++++++++ .../User/UpdateTeamMemberCommandHandler.php | 63 +++++++++++++ .../Providers/EventServiceProvider.php | 3 + app/Http/Controllers/Api/UserController.php | 87 ++++++++++++++++++ app/Http/Routes/ApiRoutes.php | 3 + tests/Api/UserTest.php | 57 ++++++++++++ .../User/UpdateTeamMemberCommandTest.php | 59 ++++++++++++ 9 files changed, 406 insertions(+), 2 deletions(-) create mode 100644 app/Bus/Commands/User/UpdateTeamMemberCommand.php create mode 100644 app/Bus/Events/User/UserWasUpdatedEvent.php create mode 100644 app/Bus/Handlers/Commands/User/UpdateTeamMemberCommandHandler.php create mode 100644 app/Http/Controllers/Api/UserController.php create mode 100644 tests/Api/UserTest.php create mode 100644 tests/Bus/Commands/User/UpdateTeamMemberCommandTest.php diff --git a/app/Bus/Commands/User/AddTeamMemberCommand.php b/app/Bus/Commands/User/AddTeamMemberCommand.php index 655b73427..875c6955b 100644 --- a/app/Bus/Commands/User/AddTeamMemberCommand.php +++ b/app/Bus/Commands/User/AddTeamMemberCommand.php @@ -48,8 +48,9 @@ final class AddTeamMemberCommand */ public $rules = [ 'name' => 'required|string', - 'password' => 'string', - 'level' => 'int', + 'email' => 'required|email', + 'password' => 'required|string', + 'level' => 'int|min:1|max:2', ]; /** diff --git a/app/Bus/Commands/User/UpdateTeamMemberCommand.php b/app/Bus/Commands/User/UpdateTeamMemberCommand.php new file mode 100644 index 000000000..0b039e757 --- /dev/null +++ b/app/Bus/Commands/User/UpdateTeamMemberCommand.php @@ -0,0 +1,90 @@ + + */ +final class UpdateTeamMemberCommand +{ + /** + * The user to update. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * The user username. + * + * @var string + */ + public $username; + + /** + * The user password. + * + * @var string + */ + public $password; + + /** + * The user email. + * + * @var string + */ + public $email; + + /** + * The user level. + * + * @var int + */ + public $level; + + /** + * The validation rules. + * + * @var string[] + */ + public $rules = [ + 'user' => 'required', + 'name' => 'required|string', + 'email' => 'required|email', + 'password' => 'required|string', + 'level' => 'int|min:1|max:2', + ]; + + /** + * Create a new add team member command instance. + * + * @param \CachetHQ\Cachet\Models\User $user + * @param string $username + * @param string $password + * @param string $email + * @param int $level + * + * @return void + */ + public function __construct(User $user, $username, $password, $email, $level) + { + $this->user = $user; + $this->username = $username; + $this->password = $password; + $this->email = $email; + $this->level = $level; + } +} diff --git a/app/Bus/Events/User/UserWasUpdatedEvent.php b/app/Bus/Events/User/UserWasUpdatedEvent.php new file mode 100644 index 000000000..338535cfa --- /dev/null +++ b/app/Bus/Events/User/UserWasUpdatedEvent.php @@ -0,0 +1,41 @@ + + */ +final class UserWasUpdatedEvent implements UserEventInterface +{ + /** + * The user that has been updated. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * Create a new user was updated event instance. + * + * @param \CachetHQ\Cachet\Models\User $user + * + * @return void + */ + public function __construct(User $user) + { + $this->user = $user; + } +} diff --git a/app/Bus/Handlers/Commands/User/UpdateTeamMemberCommandHandler.php b/app/Bus/Handlers/Commands/User/UpdateTeamMemberCommandHandler.php new file mode 100644 index 000000000..7f3894050 --- /dev/null +++ b/app/Bus/Handlers/Commands/User/UpdateTeamMemberCommandHandler.php @@ -0,0 +1,63 @@ + + */ +class UpdateTeamMemberCommandHandler +{ + /** + * Handle the add team member command. + * + * @param \CachetHQ\Cachet\Bus\Commands\User\UpdateTeamMemberCommand $command + * + * @return \CachetHQ\Cachet\Models\User + */ + public function handle(UpdateTeamMemberCommand $command) + { + $user = $command->user; + + $user->update($this->filter($command)); + + event(new UserWasUpdatedEvent($user)); + + return $user; + } + + /** + * Filter the command data. + * + * @param \CachetHQ\Cachet\Bus\Commands\User\UpdateTeamMemberCommand $command + * + * @return array + */ + protected function filter(UpdateTeamMemberCommand $command) + { + $params = [ + 'username' => $command->username, + 'password' => $command->password, + 'email' => $command->email, + 'level' => $command->level, + ]; + + return array_filter($params, function ($val) { + return $val !== null; + }); + } +} diff --git a/app/Foundation/Providers/EventServiceProvider.php b/app/Foundation/Providers/EventServiceProvider.php index b8f18b9bc..aa7704824 100644 --- a/app/Foundation/Providers/EventServiceProvider.php +++ b/app/Foundation/Providers/EventServiceProvider.php @@ -90,5 +90,8 @@ class EventServiceProvider extends ServiceProvider 'CachetHQ\Cachet\Bus\Events\User\UserWasInvitedEvent' => [ 'CachetHQ\Cachet\Bus\Handlers\Events\User\SendInviteUserEmailHandler', ], + 'CachetHQ\Cachet\Bus\Events\User\UserWasUpdatedEvent' => [ + // + ], ]; } diff --git a/app/Http/Controllers/Api/UserController.php b/app/Http/Controllers/Api/UserController.php new file mode 100644 index 000000000..38e59b219 --- /dev/null +++ b/app/Http/Controllers/Api/UserController.php @@ -0,0 +1,87 @@ + + */ +class UserController extends AbstractApiController +{ + /** + * Create a new user. + * + * @return \Illuminate\Http\JsonResponse + */ + public function postUsers() + { + try { + $user = dispatch(new AddTeamMemberCommand( + Binput::get('username'), + Binput::get('password'), + Binput::get('email'), + Binput::get('level', User::LEVEL_USER) + )); + } catch (QueryException $e) { + throw new BadRequestHttpException(); + } + + return $this->item($user); + } + + /** + * Update an existing user. + * + * @param \CachetHQ\Cachet\Models\User $user + * + * @return \Illuminate\Http\JsonResponse + */ + public function putUser(User $user) + { + try { + dispatch(new UpdateTeamMemberCommand( + $user, + Binput::get('username'), + Binput::get('password'), + Binput::get('email'), + Binput::get('level') + )); + } catch (QueryException $e) { + throw new BadRequestHttpException(); + } + + return $this->item($user); + } + + /** + * Delete a user from the system. + * + * @param \CachetHQ\Cachet\Models\User $user + * + * @return \Illuminate\Http\JsonResponse + */ + public function deleteUser(User $user) + { + dispatch(new RemoveUserCommand($user)); + + return $this->noContent(); + } +} diff --git a/app/Http/Routes/ApiRoutes.php b/app/Http/Routes/ApiRoutes.php index 93db043d2..37da447eb 100644 --- a/app/Http/Routes/ApiRoutes.php +++ b/app/Http/Routes/ApiRoutes.php @@ -67,6 +67,7 @@ class ApiRoutes $router->post('metrics/{metric}/points', 'MetricPointController@postMetricPoints'); $router->post('subscribers', 'SubscriberController@postSubscribers'); $router->post('tags', 'TagController@postTags'); + $router->post('users', 'UserController@postUsers'); $router->put('components/groups/{component_group}', 'ComponentGroupController@putGroup'); $router->put('components/{component}', 'ComponentController@putComponent'); @@ -75,6 +76,7 @@ class ApiRoutes $router->put('metrics/{metric}', 'MetricController@putMetric'); $router->put('metrics/{metric}/points/{metric_point}', 'MetricPointController@putMetricPoint'); $router->put('tags/{tag}', 'TagController@putTag'); + $router->put('users/{user}', 'UserController@putUser'); $router->delete('components/groups/{component_group}', 'ComponentGroupController@deleteGroup'); $router->delete('components/tags', 'ComponentTagController@deleteTag'); @@ -86,6 +88,7 @@ class ApiRoutes $router->delete('subscribers/{subscriber}', 'SubscriberController@deleteSubscriber'); $router->delete('subscriptions/{subscription}', 'SubscriberController@deleteSubscription'); $router->delete('tags/{tag}', 'TagController@deleteTag'); + $router->delete('users/{user}', 'UserController@deleteUser'); }); }); } diff --git a/tests/Api/UserTest.php b/tests/Api/UserTest.php new file mode 100644 index 000000000..b592e3df1 --- /dev/null +++ b/tests/Api/UserTest.php @@ -0,0 +1,57 @@ + + */ +class UserTest extends AbstractApiTestCase +{ + public function testCreateUser() + { + $this->beUser(); + + $this->post('/api/v1/users', [ + 'username' => 'Alt Three', + 'email' => 'support@alt-three.com', + 'password' => 'AltTheeWinsLife', + ]); + $this->assertResponseOk(); + $this->seeHeader('Content-Type', 'application/json'); + $this->seeJson(['email' => 'support@alt-three.com']); + } + + public function testUpdateUser() + { + $this->beUser(); + + $user = factory('CachetHQ\Cachet\Models\User')->create(); + + $this->put("/api/v1/users/{$user->id}", [ + 'username' => 'jbrooksuk', + ]); + + $this->seeHeader('Content-Type', 'application/json'); + $this->seeJson(['username' => 'jbrooksuk']); + } + + public function testDeleteUser() + { + $this->beUser(); + + $user = factory('CachetHQ\Cachet\Models\User')->create(); + $this->delete("/api/v1/users/{$user->id}"); + $this->assertResponseStatus(204); + } +} diff --git a/tests/Bus/Commands/User/UpdateTeamMemberCommandTest.php b/tests/Bus/Commands/User/UpdateTeamMemberCommandTest.php new file mode 100644 index 000000000..22afcb43c --- /dev/null +++ b/tests/Bus/Commands/User/UpdateTeamMemberCommandTest.php @@ -0,0 +1,59 @@ + + */ +class UpdateTeamMemberCommandTest extends AbstractTestCase +{ + use CommandTrait; + + protected function getObjectAndParams() + { + $params = [ + 'user' => new User(), + 'username' => 'Test', + 'password' => 'fooey', + 'email' => 'test@test.com', + 'level' => 1, + ]; + + $object = new UpdateTeamMemberCommand( + $params['user'], + $params['username'], + $params['password'], + $params['email'], + $params['level'] + ); + + return compact('params', 'object'); + } + + protected function objectHasRules() + { + return true; + } + + protected function getHandlerClass() + { + return UpdateTeamMemberCommandHandler::class; + } +}