Skip to content

Commit b8870b6

Browse files
authored
Register api (#73)
* ✨ Ajout des events et listeners pour la creation de compte * 🗃️ refactoring et ajout du seeder pour le role company * 👽 Ajout de l'api de creation de compte simple et via google
1 parent 17605cd commit b8870b6

19 files changed

+333
-16
lines changed

app/Events/ApiRegistered.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace App\Events;
4+
5+
use App\Models\User;
6+
use Illuminate\Queue\SerializesModels;
7+
8+
class ApiRegistered
9+
{
10+
use SerializesModels;
11+
12+
/**
13+
* Create a new event instance.
14+
*
15+
* @return void
16+
*/
17+
public function __construct(public User $user)
18+
{
19+
}
20+
}

app/Http/Controllers/Api/Auth/LoginController.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class LoginController extends Controller
1616
{
1717
public function login(LoginRequest $request): JsonResponse
1818
{
19+
/** @var User $user */
1920
$user = User::query()
2021
->with(['roles', 'permissions'])
2122
->where('email', strtolower($request->input('email')))
@@ -27,7 +28,7 @@ public function login(LoginRequest $request): JsonResponse
2728
];
2829

2930
if (empty($user) || !Auth::attempt($sanitized)) {
30-
throw ValidationException::withMessages([
31+
throw ValidationException::withMessages([
3132
'email' => 'Les informations d\'identification fournies sont incorrectes.',
3233
]);
3334
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
3+
namespace App\Http\Controllers\Api\Auth;
4+
5+
use App\Events\ApiRegistered;
6+
use App\Http\Controllers\Controller;
7+
use App\Http\Requests\Api\RegisterRequest;
8+
use App\Http\Resources\AuthenticateUserResource;
9+
use App\Models\SocialAccount;
10+
use App\Models\User;
11+
use Carbon\Carbon;
12+
use Illuminate\Http\JsonResponse;
13+
use Illuminate\Http\Request;
14+
use Illuminate\Support\Facades\Hash;
15+
16+
class RegisterController extends Controller
17+
{
18+
public function register(RegisterRequest $request): JsonResponse
19+
{
20+
/** @var User $user */
21+
$user = User::query()->create([
22+
'name' => $request->input('name'),
23+
'username' => $request->input('name'),
24+
'email' => strtolower($request->input('email')),
25+
'password' => Hash::make($request->input('password')),
26+
]);
27+
28+
$user->assignRole('company');
29+
30+
//TODO: Send new company registration notification on Slack
31+
event(new ApiRegistered($user));
32+
33+
return response()->json(array_merge(
34+
['message' => 'Votre compte a été créé avec succès. Un e-mail de vérification vous a été envoyé.'],
35+
$this->userMetaData($user)
36+
)
37+
);
38+
}
39+
40+
public function googleAuthenticator(Request $request): JsonResponse
41+
{
42+
$socialUser = $request->input('socialUser');
43+
44+
$user = User::query()->where('email', $socialUser['email'])->first();
45+
46+
if (! $user) {
47+
/** @var User $user */
48+
$user = User::query()->create([
49+
'name' => $socialUser['name'],
50+
'email' => $socialUser['email'],
51+
'username' => $socialUser['id'],
52+
'email_verified_at' => now(),
53+
'avatar_type' => strtolower($socialUser['provider']),
54+
]);
55+
56+
$user->assignRole('company');
57+
}
58+
59+
if ($user->hasRole('user')) {
60+
return response()->json(['error' => 'Vous n\'êtes pas autorisé à accéder à cette section avec cette adresse e-mail.'], 401);
61+
}
62+
63+
if (! $user->hasProvider($socialUser['provider'])) {
64+
$user->providers()->save(new SocialAccount([
65+
'provider' => $socialUser['provider'],
66+
'provider_id' => $socialUser['id'],
67+
'token' => $socialUser['idToken'],
68+
'avatar' => $socialUser['photoUrl'],
69+
]));
70+
}
71+
72+
$user->providers()->update([
73+
'token' => $socialUser['idToken'],
74+
'avatar' => $socialUser['photoUrl'],
75+
]);
76+
77+
//TODO: Send welcome email to user 1 hour after registration
78+
79+
//TODO: Send new company registration notification on Slack
80+
81+
$user->last_login_at = Carbon::now();
82+
$user->last_login_ip = $request->ip();
83+
$user->save();
84+
85+
return response()->json($this->userMetaData($user));
86+
}
87+
88+
private function userMetaData(User $user): array
89+
{
90+
return [
91+
'user' => new AuthenticateUserResource($user),
92+
'token' => $user->createToken($user->email)->plainTextToken,
93+
'roles' => $user->roles()->pluck('name'),
94+
'permissions' => $user->permissions()->pluck('name'),
95+
];
96+
}
97+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace App\Http\Controllers\Api\Auth;
4+
5+
use App\Http\Controllers\Controller;
6+
use Illuminate\Http\JsonResponse;
7+
use Illuminate\Http\Request;
8+
use Illuminate\Auth\Events\Verified;
9+
use Illuminate\Http\RedirectResponse;
10+
use App\Models\User;
11+
12+
class VerifyEmailController extends Controller
13+
{
14+
public function verify(Request $request): RedirectResponse
15+
{
16+
/** @var User $user */
17+
$user = User::find($request->route('id'));
18+
19+
if ($user->hasVerifiedEmail()) {
20+
return redirect(env('FRONTEND_APP_URL') . '/email/verify/already-success');
21+
}
22+
23+
if ($user->markEmailAsVerified()) {
24+
event(new Verified($user));
25+
}
26+
27+
return redirect(env('FRONTEND_APP_URL') . '/email/verify/success');
28+
}
29+
30+
public function resend(Request $request): JsonResponse
31+
{
32+
$request->user()->sendEmailVerificationNotification();
33+
34+
return response()->json(['message', 'Un nouveau lien de Verification a été envoyé!']);
35+
}
36+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace App\Http\Requests\Api;
4+
5+
use Illuminate\Foundation\Http\FormRequest;
6+
7+
class RegisterRequest extends FormRequest
8+
{
9+
/**
10+
* Determine if the user is authorized to make this request.
11+
*
12+
* @return bool
13+
*/
14+
public function authorize(): bool
15+
{
16+
return true;
17+
}
18+
19+
/**
20+
* Get the validation rules that apply to the request.
21+
*
22+
* @return array<string, mixed>
23+
*/
24+
public function rules(): array
25+
{
26+
return [
27+
'name' => 'required|string|max:255',
28+
'email' => 'required|email|max:255|unique:users',
29+
'password' => 'required|min:6',
30+
];
31+
}
32+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace App\Listeners;
4+
5+
use App\Events\ApiRegistered;
6+
use App\Models\User;
7+
use Illuminate\Contracts\Queue\ShouldQueue;
8+
use Illuminate\Queue\InteractsWithQueue;
9+
10+
final class SendCompanyEmailVerificationNotification implements ShouldQueue
11+
{
12+
use InteractsWithQueue;
13+
14+
/**
15+
* Handle the event.
16+
*
17+
* @param ApiRegistered $event
18+
* @return void
19+
*/
20+
public function handle(ApiRegistered $event): void
21+
{
22+
$user = $event->user;
23+
}
24+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace App\Listeners;
4+
5+
use App\Events\ApiRegistered;
6+
use Illuminate\Contracts\Queue\ShouldQueue;
7+
use Illuminate\Queue\InteractsWithQueue;
8+
9+
class SendWelcomeCompanyNotification implements ShouldQueue
10+
{
11+
use InteractsWithQueue;
12+
13+
/**
14+
* Handle the event.
15+
*
16+
* @param ApiRegistered $event
17+
* @return void
18+
*/
19+
public function handle(ApiRegistered $event): void
20+
{
21+
$user = $event->user;
22+
}
23+
}

app/Models/User.php

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace App\Models;
44

55
use App\Traits\HasProfilePhoto;
6+
use App\Traits\HasUsername;
67
use App\Traits\Reacts;
78
use Illuminate\Contracts\Auth\MustVerifyEmail;
89
use Illuminate\Database\Eloquent\Builder;
@@ -34,6 +35,7 @@ class User extends Authenticatable implements MustVerifyEmail, HasMedia
3435
use InteractsWithMedia;
3536
use Notifiable;
3637
use Reacts;
38+
use HasUsername;
3739

3840
/**
3941
* The attributes that are mass assignable.
@@ -149,17 +151,12 @@ public function registerMediaCollections(): void
149151
->acceptsMimeTypes(['image/jpg', 'image/jpeg', 'image/png', 'image/gif']);
150152
}
151153

152-
public static function findByUsername(string $username): self
153-
{
154-
return static::where('username', $username)->firstOrFail();
155-
}
156-
157154
public static function findByEmailAddress(string $emailAddress): self
158155
{
159156
return static::where('email', $emailAddress)->firstOrFail();
160157
}
161158

162-
public static function findOrCreateSocialUserProvider($socialUser, string $provider): self
159+
public static function findOrCreateSocialUserProvider($socialUser, string $provider, string $role = 'user'): self
163160
{
164161
$socialEmail = $socialUser->email ?? "{$socialUser->id}@{$provider}.com";
165162

@@ -176,7 +173,7 @@ public static function findOrCreateSocialUserProvider($socialUser, string $provi
176173
'avatar_type' => $provider,
177174
]);
178175

179-
$user->assignRole('user');
176+
$user->assignRole($role);
180177
}
181178

182179
return $user;

app/Providers/EventServiceProvider.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,19 @@
22

33
namespace App\Providers;
44

5+
use App\Events\ApiRegistered;
56
use App\Events\ArticleWasSubmittedForApproval;
67
use App\Events\CommentWasAdded;
78
use App\Events\ReplyWasCreated;
89
use App\Events\ThreadWasCreated;
910
use App\Listeners\NotifyMentionedUsers;
1011
use App\Listeners\PostNewThreadNotification;
12+
use App\Listeners\SendCompanyEmailVerificationNotification;
1113
use App\Listeners\SendNewArticleNotification;
1214
use App\Listeners\SendNewCommentNotification;
1315
use App\Listeners\SendNewReplyNotification;
1416
use App\Listeners\SendNewThreadNotification;
17+
use App\Listeners\SendWelcomeCompanyNotification;
1518
use App\Listeners\SendWelcomeMailNotification;
1619
use Illuminate\Auth\Events\Registered;
1720
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
@@ -46,5 +49,10 @@ class EventServiceProvider extends ServiceProvider
4649
\SocialiteProviders\Manager\SocialiteWasCalled::class => [
4750
\SocialiteProviders\Twitter\TwitterExtendSocialite::class.'@handle',
4851
],
52+
53+
ApiRegistered::class => [
54+
SendCompanyEmailVerificationNotification::class,
55+
SendWelcomeCompanyNotification::class,
56+
],
4957
];
5058
}

app/Traits/HasUsername.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
namespace App\Traits;
4+
5+
use Illuminate\Support\Str;
6+
7+
trait HasUsername
8+
{
9+
public function username(): string
10+
{
11+
return $this->username;
12+
}
13+
14+
public function setUsernameAttribute(string $username): void
15+
{
16+
$this->attributes['username'] = $this->generateUniqueUsername($username);
17+
}
18+
19+
public static function findByUsername(string $username): self
20+
{
21+
return static::where('username', $username)->firstOrFail();
22+
}
23+
24+
private function generateUniqueUsername(string $value): string
25+
{
26+
$username = $originalUsername = $value ?: Str::random(6);
27+
$counter = 0;
28+
29+
while ($this->usernameExists($username, $this->exists ? $this->id : null)) {
30+
$counter++;
31+
$username = $originalUsername.$counter;
32+
}
33+
34+
return $username;
35+
}
36+
37+
private function usernameExists(string $username, int $ignoreId = null): bool
38+
{
39+
$query = $this->where('username', $username);
40+
41+
if ($ignoreId) {
42+
$query->where('id', '!=', $ignoreId);
43+
}
44+
45+
return $query->exists();
46+
}
47+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace Database\Seeders;
4+
5+
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
6+
use Illuminate\Database\Seeder;
7+
use Spatie\Permission\Models\Role;
8+
9+
class AddEnterpriseRoleSeeder extends Seeder
10+
{
11+
/**
12+
* Run the database seeds.
13+
*
14+
* @return void
15+
*/
16+
public function run(): void
17+
{
18+
Role::create(['name' => 'company']);
19+
}
20+
}

0 commit comments

Comments
 (0)