Add Password Reset
This commit is contained in:
parent
6f4ee0b02d
commit
17eaa2e564
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace App\Auth;
|
||||
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Support\Facades\Lang;
|
||||
use Illuminate\Auth\Notifications\ResetPassword as BaseResetPassword;
|
||||
|
||||
class ResetPassword extends BaseResetPassword
|
||||
{
|
||||
/**
|
||||
* Get the reset password notification mail message for the given URL.
|
||||
*
|
||||
* @param string $url
|
||||
* @return MailMessage
|
||||
*/
|
||||
protected function buildMailMessage($url)
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject(Lang::get('Passwort zurücksetzen | Adrema'))
|
||||
->line(Lang::get('Du erhälst diese E-Mail, weil du eine Anfrage zum zurücksetzen deines Account-Passworts gestellt hast.'))
|
||||
->action(Lang::get('Passwort zurücksetzen'), $url)
|
||||
->line(Lang::get('Dieser Link wird in :count Minuten ablaufen.', ['count' => config('auth.passwords.' . config('auth.defaults.passwords') . '.expire')]))
|
||||
->line(Lang::get('Wenn du die Anfrage nicht selbst gestellt hast, ist keine weitere Aktion erforderlich.'));
|
||||
}
|
||||
}
|
|
@ -4,6 +4,8 @@ namespace App\Http\Controllers\Auth;
|
|||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
||||
use Inertia\Inertia;
|
||||
use Inertia\Response;
|
||||
|
||||
class ForgotPasswordController extends Controller
|
||||
{
|
||||
|
@ -19,4 +21,9 @@ class ForgotPasswordController extends Controller
|
|||
*/
|
||||
|
||||
use SendsPasswordResetEmails;
|
||||
|
||||
public function showLinkRequestForm(): Response
|
||||
{
|
||||
return Inertia::render('authentication/PasswordReset');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ class LoginController extends Controller
|
|||
{
|
||||
session()->put('title', 'Anmelden');
|
||||
|
||||
return \Inertia::render('VLogin');
|
||||
return \Inertia::render('authentication/VLogin');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,6 +5,9 @@ namespace App\Http\Controllers\Auth;
|
|||
use App\Http\Controllers\Controller;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||
use Illuminate\Http\Request;
|
||||
use Inertia\Inertia;
|
||||
use Inertia\Response;
|
||||
|
||||
class ResetPasswordController extends Controller
|
||||
{
|
||||
|
@ -27,4 +30,21 @@ class ResetPasswordController extends Controller
|
|||
* @var string
|
||||
*/
|
||||
protected $redirectTo = RouteServiceProvider::HOME;
|
||||
|
||||
/**
|
||||
* Display the password reset view for the given token.
|
||||
*
|
||||
* If no token is present, display the link request form.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
*/
|
||||
public function showResetForm(Request $request): Response
|
||||
{
|
||||
$token = $request->route()->parameter('token');
|
||||
|
||||
return Inertia::render('authentication/PasswordResetConfirm', [
|
||||
'token' => $token,
|
||||
'email' => $request->email,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
12
app/User.php
12
app/User.php
|
@ -2,12 +2,24 @@
|
|||
|
||||
namespace App;
|
||||
|
||||
use App\Auth\ResetPassword;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
class User extends Authenticatable
|
||||
{
|
||||
use HasFactory;
|
||||
use Notifiable;
|
||||
|
||||
public $guarded = [];
|
||||
|
||||
/**
|
||||
* @param string $token
|
||||
* @return void
|
||||
*/
|
||||
public function sendPasswordResetNotification($token)
|
||||
{
|
||||
$this->notify(new ResetPassword($token));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('password_resets', function (Blueprint $table) {
|
||||
$table->string('email')->index();
|
||||
$table->string('token');
|
||||
$table->timestamp('created_at')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('password_resets');
|
||||
}
|
||||
};
|
|
@ -0,0 +1,44 @@
|
|||
<template>
|
||||
<page-full-layout banner>
|
||||
<template #heading>
|
||||
<page-full-heading-banner>Passwort vergessen</page-full-heading-banner>
|
||||
</template>
|
||||
<form @submit.prevent="submit">
|
||||
<div class="grid gap-5">
|
||||
<span class="text-gray-500 text-sm"
|
||||
>Hier kannst du dein Passwort zurücksetzen.<br />
|
||||
Gebe dafür die E-Mail-Adresse deines Benutzerkontos ein.<br />
|
||||
Anschließend bekommst du eine E-Mail<br />
|
||||
mit weiteren Anweisungen.</span
|
||||
>
|
||||
<f-text id="email" v-model="values.email" name="email" label="E-Mail-Adresse"></f-text>
|
||||
<button type="submit" class="btn btn-primary">Passwort zurücksetzen</button>
|
||||
<div class="flex justify-center">
|
||||
<button type="button" class="text-gray-500 text-sm hover:text-gray-300" @click.prevent="$inertia.visit('/login')">Zurück zum Login</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</page-full-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FullLayout from '../../layouts/FullLayout.vue';
|
||||
|
||||
export default {
|
||||
layout: FullLayout,
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
values: {
|
||||
email: '',
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async submit() {
|
||||
await this.axios.post('/password/email', this.values);
|
||||
this.$success('Du hast weitere Instruktionen per E-Mail erhalten.');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,62 @@
|
|||
<template>
|
||||
<page-full-layout banner>
|
||||
<template #heading>
|
||||
<page-full-heading-banner>Passwort vergessen</page-full-heading-banner>
|
||||
</template>
|
||||
<form @submit.prevent="submit">
|
||||
<div class="grid gap-5">
|
||||
<span class="text-gray-500 text-sm"
|
||||
>Hier kannst du dein Passwort zurücksetzen.<br />
|
||||
Gebe dafür ein neues Passwort ein.<br />
|
||||
Merke oder notiere dir dieses Passwort, bevor du das Formular absendest.<br />
|
||||
Danach wirst du zum Dashboard weitergeleitet.</span
|
||||
>
|
||||
<f-text id="password" v-model="values.password" type="password" name="password" label="Neues Passwort"></f-text>
|
||||
<f-text id="password_confirmation" v-model="values.password_confirmation" type="password" name="password_confirmation" label="Neues Passwort widerholen"></f-text>
|
||||
<button type="submit" class="btn btn-primary">Passwort zurücksetzen</button>
|
||||
<div class="flex justify-center">
|
||||
<button type="button" class="text-gray-500 text-sm hover:text-gray-300" @click.prevent="$inertia.visit('/login')">Zurück zum Login</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</page-full-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FullLayout from '../../layouts/FullLayout.vue';
|
||||
|
||||
export default {
|
||||
layout: FullLayout,
|
||||
|
||||
props: {
|
||||
token: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
email: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
values: {
|
||||
password: '',
|
||||
password_confirmation: '',
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async submit() {
|
||||
await this.axios.post('/password/reset', {
|
||||
...this.values,
|
||||
email: this.email,
|
||||
token: this.token,
|
||||
});
|
||||
this.$success('Dein Passwort wurde zurückgesetzt.');
|
||||
this.$inertia.visit('/');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,40 @@
|
|||
<template>
|
||||
<page-full-layout banner>
|
||||
<template #heading>
|
||||
<page-full-heading-banner>Login</page-full-heading-banner>
|
||||
</template>
|
||||
<form @submit.prevent="submit">
|
||||
<div class="grid gap-5">
|
||||
<f-text id="email" v-model="values.email" name="email" label="E-Mail-Adresse"></f-text>
|
||||
<f-text id="password" v-model="values.password" name="password" type="password" label="Passwort"></f-text>
|
||||
<button type="submit" class="btn btn-primary">Login</button>
|
||||
<div class="flex justify-center">
|
||||
<button type="button" class="text-gray-500 text-sm hover:text-gray-300"
|
||||
@click.prevent="$inertia.visit('/password/reset')">Passwort vergessen?</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</page-full-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FullLayout from '../../layouts/FullLayout.vue';
|
||||
|
||||
export default {
|
||||
layout: FullLayout,
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
values: {
|
||||
email: '',
|
||||
password: '',
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
submit() {
|
||||
this.$inertia.post('/login', this.values);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Authentication;
|
||||
|
||||
use App\Auth\ResetPassword;
|
||||
use App\User;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ForgotPasswordTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
|
||||
public function testItShowsResetForm(): void
|
||||
{
|
||||
$this->withoutExceptionHandling();
|
||||
$response = $this->get('/password/reset');
|
||||
|
||||
$this->assertComponent('authentication/PasswordReset', $response);
|
||||
}
|
||||
|
||||
public function testItRequiresAnEmailAddress(): void
|
||||
{
|
||||
$this->postJson('/password/email')->assertJsonValidationErrors(['email' => 'E-Mail Adresse ist erforderlich.']);
|
||||
}
|
||||
|
||||
public function testItNeedsAnActiveUser(): void
|
||||
{
|
||||
$this->postJson('/password/email', [
|
||||
'email' => 'test@aa.de',
|
||||
])->assertJsonValidationErrors(['email' => 'Es konnte leider kein Nutzer mit dieser E-Mail-Adresse gefunden werden.']);
|
||||
}
|
||||
|
||||
public function testItSendsPasswordResetLink(): void
|
||||
{
|
||||
Notification::fake();
|
||||
|
||||
$user = User::factory()->create(['email' => 'test@aa.de']);
|
||||
$this->postJson('/password/email', [
|
||||
'email' => 'test@aa.de',
|
||||
])->assertOk();
|
||||
|
||||
Notification::assertSentTo($user, ResetPassword::class);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue