diff --git a/app/Commands/Invite/ClaimInviteCommand.php b/app/Commands/Invite/ClaimInviteCommand.php new file mode 100644 index 00000000..7e49c0f7 --- /dev/null +++ b/app/Commands/Invite/ClaimInviteCommand.php @@ -0,0 +1,34 @@ +invite = $invite; + } +} diff --git a/app/Commands/User/SignupUserCommand.php b/app/Commands/User/SignupUserCommand.php new file mode 100644 index 00000000..597950ba --- /dev/null +++ b/app/Commands/User/SignupUserCommand.php @@ -0,0 +1,73 @@ + 'required|string', + 'password' => 'string', + 'email' => 'required|string|email', + 'level' => 'int', + ]; + + /** + * Create a new signup user command instance. + * + * @param string $username + * @param string $password + * @param string $email + * @param int $level + * + * @return void + */ + public function __construct($username, $password, $email, $level) + { + $this->username = $username; + $this->password = $password; + $this->email = $email; + $this->level = $level; + } +} diff --git a/app/Events/Invite/InviteWasClaimed.php b/app/Events/Invite/InviteWasClaimed.php new file mode 100644 index 00000000..18e89e9a --- /dev/null +++ b/app/Events/Invite/InviteWasClaimed.php @@ -0,0 +1,34 @@ +invite = $invite; + } +} diff --git a/app/Handlers/Commands/Invite/ClaimInviteCommandHandler.php b/app/Handlers/Commands/Invite/ClaimInviteCommandHandler.php new file mode 100644 index 00000000..fd1bac34 --- /dev/null +++ b/app/Handlers/Commands/Invite/ClaimInviteCommandHandler.php @@ -0,0 +1,36 @@ +invite; + + $invite->claimed_at = Carbon::now(); + $invite->save(); + + event(new InviteWasClaimed($invite)); + } +} diff --git a/app/Handlers/Commands/User/InviteTeamMemberCommandHandler.php b/app/Handlers/Commands/User/InviteTeamMemberCommandHandler.php index 2692c546..28b6b718 100644 --- a/app/Handlers/Commands/User/InviteTeamMemberCommandHandler.php +++ b/app/Handlers/Commands/User/InviteTeamMemberCommandHandler.php @@ -12,7 +12,7 @@ namespace CachetHQ\Cachet\Handlers\Commands\User; use CachetHQ\Cachet\Commands\User\InviteTeamMemberCommand; -use CachetHQ\Cachet\Events\User\UserWasAddedEvent; +use CachetHQ\Cachet\Events\User\UserWasInvitedEvent; use CachetHQ\Cachet\Models\Invite; class InviteTeamMemberCommandHandler @@ -28,7 +28,7 @@ class InviteTeamMemberCommandHandler { foreach ($command->emails as $email) { $invite = Invite::create([ - 'email' => $command->email, + 'email' => $email, ]); event(new UserWasInvitedEvent($invite)); diff --git a/app/Handlers/Commands/User/SignupUserCommandHandler.php b/app/Handlers/Commands/User/SignupUserCommandHandler.php new file mode 100644 index 00000000..71a8d126 --- /dev/null +++ b/app/Handlers/Commands/User/SignupUserCommandHandler.php @@ -0,0 +1,40 @@ + $command->username, + 'password' => $command->password, + 'email' => $command->email, + 'level' => 2, + ]); + + event(new UserWasAddedEvent($user)); + + return $user; + } +} diff --git a/app/Handlers/Events/User/SendInviteUserEmailHandler.php b/app/Handlers/Events/User/SendInviteUserEmailHandler.php index d8ebd21d..ccb78df4 100644 --- a/app/Handlers/Events/User/SendInviteUserEmailHandler.php +++ b/app/Handlers/Events/User/SendInviteUserEmailHandler.php @@ -11,7 +11,7 @@ namespace CachetHQ\Cachet\Handlers\Events\User; -use CachetHQ\Cachet\Events\Subscriber\UserWasInvitedEvent; +use CachetHQ\Cachet\Events\User\UserWasInvitedEvent; use Illuminate\Contracts\Mail\MailQueue; use Illuminate\Mail\Message; @@ -48,7 +48,7 @@ class SendInviteUserEmailHandler $mail = [ 'email' => $event->invite->email, 'subject' => 'You have been invited.', - 'link' => route('invite.signup', ['code' => $event->invite->code]), + 'link' => route('signup.invite', ['code' => $event->invite->code]), 'app_url' => env('APP_URL'), ]; diff --git a/app/Http/Controllers/Dashboard/TeamController.php b/app/Http/Controllers/Dashboard/TeamController.php index 8f6ff744..c8da2d28 100644 --- a/app/Http/Controllers/Dashboard/TeamController.php +++ b/app/Http/Controllers/Dashboard/TeamController.php @@ -13,6 +13,7 @@ namespace CachetHQ\Cachet\Http\Controllers\Dashboard; use AltThree\Validator\ValidationException; use CachetHQ\Cachet\Commands\User\AddTeamMemberCommand; +use CachetHQ\Cachet\Commands\User\InviteTeamMemberCommand; use CachetHQ\Cachet\Commands\User\RemoveUserCommand; use CachetHQ\Cachet\Models\User; use GrahamCampbell\Binput\Facades\Binput; diff --git a/app/Http/Controllers/SignupController.php b/app/Http/Controllers/SignupController.php new file mode 100644 index 00000000..2a7d9448 --- /dev/null +++ b/app/Http/Controllers/SignupController.php @@ -0,0 +1,88 @@ +first(); + + if (!$invite || $invite->claimed()) { + throw new BadRequestHttpException(); + } + + return View::make('signup') + ->withPageTitle(Setting::get('app_name')) + ->withAboutApp(Markdown::convertToHtml(Setting::get('app_about'))) + ->withCode($invite->code); + } + + /** + * Handle the unsubscribe. + * + * @param string|null $code + * + * @return \Illuminate\View\View + */ + public function postSignup($code = null) + { + if (is_null($code)) { + throw new NotFoundHttpException(); + } + + $invite = Invite::where('code', '=', $code)->first(); + + if (!$invite || $invite->claimed()) { + throw new BadRequestHttpException(); + } + + $this->dispatch(new SignupUserCommand( + Binput::get('username'), + Binput::get('password'), + Binput::get('email'), + 2 + )); + + $this->dispatch(new ClaimInviteCommand($invite)); + + return Redirect::route('status-page') + ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('cachet.subscriber.email.unsubscribed'))); + } +} diff --git a/app/Http/Routes/SignupRoutes.php b/app/Http/Routes/SignupRoutes.php new file mode 100644 index 00000000..6777d666 --- /dev/null +++ b/app/Http/Routes/SignupRoutes.php @@ -0,0 +1,45 @@ + + */ +class SignupRoutes +{ + /** + * Define the signup routes. + * + * @param \Illuminate\Contracts\Routing\Registrar $router + */ + public function map(Registrar $router) + { + $router->group([ + 'middleware' => ['app.hasSetting', 'guest'], + 'setting' => 'app_name', + 'as' => 'signup.', + ], function ($router) { + $router->get('signup/invite/{code}', [ + 'as' => 'invite', + 'uses' => 'SignupController@getSignup', + ]); + + $router->post('signup/invite/{code}', [ + 'uses' => 'SignupController@postSignup', + ]); + }); + } +} diff --git a/app/Models/Invite.php b/app/Models/Invite.php index 8fcf38e7..752439f5 100644 --- a/app/Models/Invite.php +++ b/app/Models/Invite.php @@ -41,8 +41,28 @@ class Invite extends Model self::creating(function ($invite) { if (!$invite->code) { - $invite->code = self::generateVerifyCode(); + $invite->code = self::generateInviteCode(); } }); } + + /** + * Returns an invite code. + * + * @return string + */ + public static function generateInviteCode() + { + return str_random(20); + } + + /** + * Determines if the invite was claimed. + * + * @return bool + */ + public function claimed() + { + return !is_null($this->claimed_at); + } } diff --git a/app/Providers/ComposerServiceProvider.php b/app/Providers/ComposerServiceProvider.php index d6e410fd..54dcc96c 100644 --- a/app/Providers/ComposerServiceProvider.php +++ b/app/Providers/ComposerServiceProvider.php @@ -33,8 +33,8 @@ class ComposerServiceProvider extends ServiceProvider $factory->composer('*', AppComposer::class); $factory->composer('*', CurrentUserComposer::class); $factory->composer(['index'], MetricsComposer::class); - $factory->composer(['index', 'incident', 'subscribe'], StatusPageComposer::class); - $factory->composer(['index', 'incident', 'subscribe', 'dashboard.settings.theme'], ThemeComposer::class); + $factory->composer(['index', 'incident', 'subscribe', 'signup'], StatusPageComposer::class); + $factory->composer(['index', 'incident', 'subscribe', 'signup', 'dashboard.settings.theme'], ThemeComposer::class); $factory->composer('dashboard.*', DashboardComposer::class); $factory->composer(['setup', 'dashboard.settings.localization'], TimezoneLocaleComposer::class); } diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index c163b674..5ae75828 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -31,7 +31,7 @@ class EventServiceProvider extends ServiceProvider 'CachetHQ\Cachet\Handlers\Events\Subscriber\SendSubscriberVerificationEmailHandler', ], 'CachetHQ\Cachet\Events\User\UserWasInvitedEvent' => [ - 'CachetHQ\Cachet\Handlers\Events\User\SendInviteEmailHandler', + 'CachetHQ\Cachet\Handlers\Events\User\SendInviteUserEmailHandler', ], 'CachetHQ\Cachet\Events\User\UserWasAddedEvent' => [ // diff --git a/resources/views/signup.blade.php b/resources/views/signup.blade.php new file mode 100644 index 00000000..64fe08de --- /dev/null +++ b/resources/views/signup.blade.php @@ -0,0 +1,48 @@ +@extends('layout.master') + +@section('content') +
+

+
+ +
+ + @if($bannerImage = Setting::get('app_banner')) +
+
+ + @if($app_url = Setting::get('app_domain')) + + @else + + @endif +
+
+ @endif + + @include('dashboard.partials.errors') + +
+
+ {{ trans('cachet.subscriber.subscribe') }} +
+
+
+ +
+ + +
+
+ + +
+
+ + +
+ +
+
+
+@stop