Skip to content
This repository was archived by the owner on Oct 1, 2021. It is now read-only.

Commit 6b7a36c

Browse files
authored
feat: join recently registered user by invitation to the team (#48)
1 parent c2ed405 commit 6b7a36c

File tree

6 files changed

+175
-31
lines changed

6 files changed

+175
-31
lines changed

config/fortify.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,17 @@
6666

6767
'home' => config('home'),
6868

69+
/*
70+
|--------------------------------------------------------------------------
71+
| Accept invitation route name
72+
|--------------------------------------------------------------------------
73+
|
74+
| If there is a route for accept an user invitation it should be defined
75+
| here. Note that the route should accept the `$invitation` object
76+
|
77+
*/
78+
'accept_invitation_route' => 'invitations.accept',
79+
6980
/*
7081
|--------------------------------------------------------------------------
7182
| Fortify Routes Middleware

src/Actions/CreateNewUser.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ public function create(array $input)
4040

4141
if ($invitation) {
4242
$invitation->update(['user_id' => $user->id]);
43+
44+
$user->markEmailAsVerified();
4345
}
4446

4547
return $user;

src/Responses/RegisterResponse.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace ARKEcosystem\Fortify\Responses;
66

7+
use ARKEcosystem\Fortify\Models;
8+
use Illuminate\Contracts\Routing\UrlGenerator;
79
use Illuminate\Http\JsonResponse;
810
use Laravel\Fortify\Contracts\RegisterResponse as RegisterResponseContract;
911

@@ -22,6 +24,19 @@ public function toResponse($request)
2224
return new JsonResponse('', 201);
2325
}
2426

27+
if (config('fortify.accept_invitation_route')) {
28+
$invitationId = $request->get('invitation');
29+
if ($invitationId) {
30+
$invitation = Models::invitation()::findByUuid($invitationId);
31+
if ($invitation->user()->is($request->user())) {
32+
$urlGenerator = app(UrlGenerator::class);
33+
$url = $urlGenerator->route(config('fortify.accept_invitation_route'), $invitation);
34+
35+
return redirect()->to($url);
36+
}
37+
}
38+
}
39+
2540
return redirect()->route('verification.notice');
2641
}
2742
}

tests/Actions/CreateNewUserTest.php

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@
55
use ARKEcosystem\Fortify\Actions\CreateNewUser;
66
use ARKEcosystem\Fortify\Models;
77

8-
use Illuminate\Database\Eloquent\Model;
9-
use Illuminate\Support\Arr;
108
use Illuminate\Support\Facades\Config;
119
use Illuminate\Support\Facades\Hash;
12-
use Spatie\MediaLibrary\MediaCollections\Models\Concerns\HasUuid;
1310
use function Tests\expectValidationError;
11+
use Tests\stubs\TestUser;
1412

1513
beforeEach(function () {
1614
$this->validPassword = 'Pas3w05d&123456';
@@ -171,7 +169,7 @@
171169

172170
it('handles the invitation parameter', function () {
173171
Config::set('fortify.models.user', \ARKEcosystem\Fortify\Models\User::class);
174-
Config::set('fortify.models.invitation', CreateNewUserTest::class);
172+
Config::set('fortify.models.invitation', TestUser::class);
175173

176174
$user = (new CreateNewUser())->create([
177175
'name' => 'John Doe',
@@ -188,35 +186,34 @@
188186
$this->assertSame($user->id, $invitation->user_id);
189187
});
190188

191-
/**
192-
* @coversNothing
193-
*/
194-
class CreateNewUserTest extends Model
195-
{
196-
use HasUuid;
197-
198-
public ?string $uuid = null;
199-
200-
public ?int $user_id = null;
201-
202-
protected $guarded = [];
189+
it('marks the user email as verified if has an invitation', function () {
190+
Config::set('fortify.models.user', \ARKEcosystem\Fortify\Models\User::class);
191+
Config::set('fortify.models.invitation', TestUser::class);
203192

204-
public static $model = null;
193+
$user = (new CreateNewUser())->create([
194+
'name' => 'John Doe',
195+
'username' => 'alfonsobries',
196+
'email' => 'john@doe.com',
197+
'password' => $this->validPassword,
198+
'password_confirmation' => $this->validPassword,
199+
'terms' => true,
200+
'invitation' => 'uuid-uuid-uuid-uuid',
201+
]);
205202

206-
public static function findByUuid(string $uuid): ?Model
207-
{
208-
if (self::$model) {
209-
return self::$model;
210-
}
203+
$this->assertNotNull($user->email_verified_at);
204+
});
211205

212-
self::$model = new self(compact('uuid'));
206+
it('doesnt mark the user email as verified if no ivitation ', function () {
207+
Config::set('fortify.models.user', \ARKEcosystem\Fortify\Models\User::class);
213208

214-
return self::$model;
215-
}
209+
$user = (new CreateNewUser())->create([
210+
'name' => 'John Doe',
211+
'username' => 'alfonsobries',
212+
'email' => 'john@doe.com',
213+
'password' => $this->validPassword,
214+
'password_confirmation' => $this->validPassword,
215+
'terms' => true,
216+
]);
216217

217-
public function update(array $attributes = [], array $options = [])
218-
{
219-
$this->user_id = Arr::get($attributes, 'user_id', $this->user_id);
220-
$this->uuid = Arr::get($attributes, 'uuid', $this->uuid);
221-
}
222-
}
218+
$this->assertNull($user->email_verified_at);
219+
});

tests/Responses/RegisterResponseTest.php

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@
44

55
namespace Tests\Models\Concerns;
66

7+
use ARKEcosystem\Fortify\Models;
8+
use ARKEcosystem\Fortify\Models\User;
79
use ARKEcosystem\Fortify\Responses\RegisterResponse;
810
use Illuminate\Http\JsonResponse;
911
use Illuminate\Http\RedirectResponse;
12+
use Illuminate\Support\Facades\Config;
1013
use Mockery;
14+
use Mockery\MockInterface;
1115

1216
it('can return json', function () {
1317
$request = Mockery::mock(\Illuminate\Http\Request::class);
@@ -33,3 +37,66 @@
3337
expect($response->status())->toBe(302);
3438
expect($response->content())->toContain(route('verification.notice'));
3539
});
40+
41+
it('redirects to the accept invite route', function () {
42+
Config::set('fortify.models.invitation', \Tests\stubs\TestUser::class);
43+
Config::set('fortify.models.user', \ARKEcosystem\Fortify\Models\User::class);
44+
Config::set('fortify.accept_invitation_route', 'invitations.accept');
45+
46+
$user = User::factory()->create();
47+
48+
// Initialize the invitation
49+
$invitation = Models::invitation()::findByUuid('uuid-uuid-uuid-uuid');
50+
$invitation->update(['user_id' => $user->id]);
51+
52+
$this->mock(\Illuminate\Contracts\Routing\UrlGenerator::class, function (MockInterface $mock) use ($invitation) {
53+
$mock->shouldReceive('route')
54+
->with('invitations.accept', $invitation)
55+
->andReturn('http://localhost/accept-invite');
56+
});
57+
58+
$request = Mockery::mock(\Illuminate\Http\Request::class);
59+
60+
$request->shouldReceive('wantsJson')
61+
->once()
62+
->andReturnFalse();
63+
64+
$request->shouldReceive('get')
65+
->with('invitation')
66+
->once()
67+
->andReturn('uuid-uuid-uuid-uuid');
68+
69+
$request->shouldReceive('user')
70+
->once()
71+
->andReturn($user);
72+
73+
$response = (new RegisterResponse())->toResponse($request);
74+
75+
expect($response)->toBeInstanceOf(RedirectResponse::class);
76+
expect($response->status())->toBe(302);
77+
expect($response->content())->toContain('http://localhost/accept-invite');
78+
});
79+
80+
it('redirects to the default url if no route for accept an invitation is set', function () {
81+
Config::set('fortify.models.invitation', \Tests\stubs\TestUser::class);
82+
Config::set('fortify.models.user', \ARKEcosystem\Fortify\Models\User::class);
83+
Config::set('fortify.accept_invitation_route', null);
84+
85+
$user = User::factory()->create();
86+
87+
// Initialize the invitation
88+
$invitation = Models::invitation()::findByUuid('uuid-uuid-uuid-uuid');
89+
$invitation->update(['user_id' => $user->id]);
90+
91+
$request = Mockery::mock(\Illuminate\Http\Request::class);
92+
93+
$request->shouldReceive('wantsJson')
94+
->once()
95+
->andReturnFalse();
96+
97+
$response = (new RegisterResponse())->toResponse($request);
98+
99+
expect($response)->toBeInstanceOf(RedirectResponse::class);
100+
expect($response->status())->toBe(302);
101+
expect($response->content())->toContain(route('verification.notice'));
102+
});

tests/stubs/TestUser.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tests\stubs;
6+
7+
use ARKEcosystem\Fortify\Models;
8+
use Illuminate\Database\Eloquent\Model;
9+
use Illuminate\Support\Arr;
10+
use Spatie\MediaLibrary\MediaCollections\Models\Concerns\HasUuid;
11+
12+
/**
13+
* @coversNothing
14+
*/
15+
final class TestUser extends Model
16+
{
17+
use HasUuid;
18+
19+
public ?string $uuid = null;
20+
21+
public ?int $user_id = null;
22+
23+
protected $guarded = [];
24+
25+
public static $model = null;
26+
27+
public static function findByUuid(string $uuid): ?Model
28+
{
29+
if (self::$model) {
30+
return self::$model;
31+
}
32+
33+
self::$model = new self(compact('uuid'));
34+
35+
return self::$model;
36+
}
37+
38+
public function update(array $attributes = [], array $options = [])
39+
{
40+
$this->user_id = Arr::get($attributes, 'user_id', $this->user_id);
41+
$this->uuid = Arr::get($attributes, 'uuid', $this->uuid);
42+
}
43+
44+
public function user()
45+
{
46+
if (! $this->user_id) {
47+
return;
48+
}
49+
50+
return Models::user()::find($this->user_id);
51+
}
52+
}

0 commit comments

Comments
 (0)