142 lines
5.9 KiB
PHP
142 lines
5.9 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Auth;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Requests\AccountEmailRequest;
|
|
use App\Http\Requests\ResetAccountPasswordRequest;
|
|
use App\Models\User;
|
|
use App\Services\AccountEmailService;
|
|
use Illuminate\Auth\Events\PasswordReset;
|
|
use Illuminate\Auth\Events\Verified;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Password;
|
|
use Illuminate\Support\Str;
|
|
use Inertia\Inertia;
|
|
use Inertia\Response;
|
|
use Throwable;
|
|
|
|
class AccountAccessController extends Controller
|
|
{
|
|
public function forgot(Request $request): Response
|
|
{
|
|
return $this->page($request, 'forgot');
|
|
}
|
|
|
|
public function sendResetLink(AccountEmailRequest $request): RedirectResponse
|
|
{
|
|
try {
|
|
Password::broker('web_users')->sendResetLink($request->safe()->only('email'));
|
|
} catch (Throwable $exception) {
|
|
report($exception);
|
|
|
|
return back()->with('error', __('Не удалось отправить письмо. Попробуй ещё раз через минуту.'))->onlyInput('email');
|
|
}
|
|
|
|
return back()->with('status', __('Если аккаунт с такой почтой существует, письмо со ссылкой для восстановления придёт в течение нескольких минут. Проверь также папку «Спам».'))->onlyInput('email');
|
|
}
|
|
|
|
public function reset(Request $request, string $token): Response
|
|
{
|
|
return $this->page($request, 'reset', ['token' => $token]);
|
|
}
|
|
|
|
public function updatePassword(ResetAccountPasswordRequest $request): RedirectResponse
|
|
{
|
|
// Keep token validation, password update and token consumption atomic.
|
|
$status = DB::transaction(function () use ($request): string {
|
|
User::where('email', $request->string('email')->toString())->lockForUpdate()->first();
|
|
|
|
return Password::broker('web_users')->reset(
|
|
$request->safe()->only(['email', 'password', 'password_confirmation', 'token']),
|
|
function (User $user, string $password): void {
|
|
$user->forceFill(['password' => $password, 'remember_token' => Str::random(60)])->save();
|
|
event(new PasswordReset($user));
|
|
},
|
|
);
|
|
});
|
|
|
|
if ($status !== Password::PASSWORD_RESET) {
|
|
return back()->withErrors(['token' => __('Ссылка недействительна или срок её действия истёк. Запроси новое письмо.')])->onlyInput('email');
|
|
}
|
|
|
|
return redirect()->route('login')->with('status', __('Пароль обновлён. Войди в аккаунт с новым паролем.'));
|
|
}
|
|
|
|
public function notice(Request $request): Response
|
|
{
|
|
return $this->page($request, 'verification');
|
|
}
|
|
|
|
public function resend(AccountEmailRequest $request, AccountEmailService $emails): RedirectResponse
|
|
{
|
|
$user = User::whereRaw('LOWER(email) = ?', [$request->string('email')->toString()])->first();
|
|
if ($user !== null) {
|
|
$emails->sendVerification($user);
|
|
}
|
|
|
|
return back()->with('status', __('Если этот email ожидает подтверждения, мы отправим письмо. Повторный запрос доступен через минуту. Проверь также папку «Спам».'))->onlyInput('email');
|
|
}
|
|
|
|
public function verify(Request $request, string $id, string $hash): Response
|
|
{
|
|
if (! $request->hasValidSignature()) {
|
|
return $this->page($request, 'invalid');
|
|
}
|
|
|
|
$user = User::find($id);
|
|
if ($user === null || ! hash_equals(sha1($user->getEmailForVerification()), $hash)) {
|
|
return $this->page($request, 'invalid');
|
|
}
|
|
|
|
if (! $user->hasVerifiedEmail() && $user->markEmailAsVerified()) {
|
|
event(new Verified($user));
|
|
}
|
|
|
|
return $this->page($request, 'verified');
|
|
}
|
|
|
|
private function page(Request $request, string $mode, array $extra = []): Response
|
|
{
|
|
$email = $mode === 'reset'
|
|
? $request->query('email', '')
|
|
: $request->old('email', $mode === 'verification' ? $request->session()->get('verification_email', '') : '');
|
|
|
|
return Inertia::render('Auth/AccountAccess', [
|
|
'site' => [
|
|
'name' => config('moonwell.realm.server_name'),
|
|
'tagline' => config('moonwell.realm.tagline'),
|
|
],
|
|
'auth' => [
|
|
'authenticated' => $request->user() !== null,
|
|
'username' => $request->user()?->username,
|
|
'access_label' => $request->user()?->accessLabel(),
|
|
'is_admin' => $request->user()?->canAccessAdminPanel() ?? false,
|
|
],
|
|
'urls' => [
|
|
'home' => route('landing.index'),
|
|
'login' => route('login'),
|
|
'cabinet' => route('cabinet.index'),
|
|
'logout' => route('logout'),
|
|
'forgot' => route('password.request'),
|
|
'send_reset' => route('password.email'),
|
|
'reset' => route('password.update'),
|
|
'verification' => route('verification.notice'),
|
|
'resend' => route('verification.send'),
|
|
'offer' => config('moonwell.legal.offer_published') ? route('legal.offer') : null,
|
|
'privacy' => config('moonwell.legal.privacy_published') ? route('legal.privacy') : null,
|
|
'rules' => config('moonwell.legal.rules_published') ? route('legal.rules') : null,
|
|
],
|
|
'flash' => [
|
|
'status' => $request->session()->get('status'),
|
|
'error' => $request->session()->get('error'),
|
|
],
|
|
'mode' => $mode,
|
|
'email' => is_string($email) ? $email : '',
|
|
...$extra,
|
|
]);
|
|
}
|
|
}
|