Compare commits
70 Commits
74d42d7496
...
667fc4b731
Author | SHA1 | Date |
---|---|---|
|
667fc4b731 | |
|
50a5d6216b | |
|
cc1c12d9f1 | |
|
5653489fa6 | |
|
dbdadde542 | |
|
e664255d7c | |
|
612b782c9b | |
|
e5b2e1799f | |
|
110ad9d978 | |
|
0cb6f9111e | |
|
aceb2b0a73 | |
|
36412a7e90 | |
|
5c8a597fef | |
|
becd5881c3 | |
|
de508aa8ce | |
|
bafdb86f95 | |
|
31d9b38814 | |
|
1e5bd6127c | |
|
c52995aeb7 | |
|
98f567b6cd | |
|
0d04d9ee99 | |
|
4877b59f46 | |
|
5263c2c976 | |
|
494fc30d21 | |
|
3199a2d5fb | |
|
bc55d19ed0 | |
|
9333b1e562 | |
|
019f421c9b | |
|
a0091ec995 | |
|
969406313d | |
|
43e1fd4080 | |
|
a51258bef9 | |
|
5b52d94390 | |
|
99f32d49f8 | |
|
e5916c65df | |
|
17beda5524 | |
|
45ccc16979 | |
|
818a72e133 | |
|
01512705e3 | |
|
004a3b7a0f | |
|
5518f54f0c | |
|
4351dab663 | |
|
c27bf43b4a | |
|
582d252e36 | |
|
e197c236d6 | |
|
4da1e01296 | |
|
689614ee93 | |
|
9d5122b13f | |
|
66561ad43e | |
|
867cf99a44 | |
|
b0a8cf5d1b | |
|
5c925dd92b | |
|
963f8c02a9 | |
|
5c4c9f130b | |
|
a76da98d61 | |
|
04addccde5 | |
|
e4d1df6a28 | |
|
17f3aff307 | |
|
3a0ebb2483 | |
|
4b89bbfda4 | |
|
4188f0733c | |
|
f93a0efed2 | |
|
6b40951b9e | |
|
ddaa1a5027 | |
|
f3a3f3cd22 | |
|
22740f8aff | |
|
751ef3891b | |
|
645825765d | |
|
75dc0d9769 | |
|
9fc8548504 |
|
@ -1,5 +1,9 @@
|
||||||
# Letzte Änderungen
|
# Letzte Änderungen
|
||||||
|
|
||||||
|
### 1.11.4
|
||||||
|
|
||||||
|
- Fix: Nicht an Präventions-Unterlagen für vergangene Veranstaltungen erinnern
|
||||||
|
|
||||||
### 1.11.1
|
### 1.11.1
|
||||||
|
|
||||||
- Es kann nun auch das Feld "Datenweiterverwendung" über Adrema gepflegt werden.
|
- Es kann nun auch das Feld "Datenweiterverwendung" über Adrema gepflegt werden.
|
||||||
|
|
|
@ -17,7 +17,12 @@ class PreventionRememberAction
|
||||||
|
|
||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
$query = Participant::whereHas('form', fn ($form) => $form->where('needs_prevention', true))
|
$query = Participant::whereHas(
|
||||||
|
'form',
|
||||||
|
fn ($form) => $form
|
||||||
|
->where('needs_prevention', true)
|
||||||
|
->where('from', '>=', now())
|
||||||
|
)
|
||||||
->where(
|
->where(
|
||||||
fn ($q) => $q
|
fn ($q) => $q
|
||||||
->where('last_remembered_at', '<=', now()->subWeeks(2))
|
->where('last_remembered_at', '<=', now()->subWeeks(2))
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Auth;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Providers\RouteServiceProvider;
|
|
||||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Inertia\Response;
|
|
||||||
|
|
||||||
class LoginController extends Controller
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Login Controller
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| This controller handles authenticating users for the application and
|
|
||||||
| redirecting them to your home screen. The controller uses a trait
|
|
||||||
| to conveniently provide its functionality to your applications.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
use AuthenticatesUsers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Where to redirect users after login.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $redirectTo = RouteServiceProvider::HOME;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new controller instance.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->middleware('guest')->except('logout');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function showLoginForm(): Response
|
|
||||||
{
|
|
||||||
session()->put('title', 'Anmelden');
|
|
||||||
|
|
||||||
return \Inertia::render('authentication/VLogin');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate the user login request.
|
|
||||||
*/
|
|
||||||
protected function validateLogin(Request $request): void
|
|
||||||
{
|
|
||||||
$request->validate([
|
|
||||||
$this->username() => 'required|max:255|string|email',
|
|
||||||
'password' => 'required|string',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Auth;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Providers\RouteServiceProvider;
|
|
||||||
use App\User;
|
|
||||||
use Illuminate\Foundation\Auth\RegistersUsers;
|
|
||||||
use Illuminate\Support\Facades\Hash;
|
|
||||||
use Illuminate\Support\Facades\Validator;
|
|
||||||
|
|
||||||
class RegisterController extends Controller
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Register Controller
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| This controller handles the registration of new users as well as their
|
|
||||||
| validation and creation. By default this controller uses a trait to
|
|
||||||
| provide this functionality without requiring any additional code.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
use RegistersUsers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Where to redirect users after registration.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $redirectTo = RouteServiceProvider::HOME;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new controller instance.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->middleware('guest');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a validator for an incoming registration request.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Contracts\Validation\Validator
|
|
||||||
*/
|
|
||||||
protected function validator(array $data)
|
|
||||||
{
|
|
||||||
return Validator::make($data, [
|
|
||||||
'name' => ['required', 'string', 'max:255'],
|
|
||||||
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
|
|
||||||
'password' => ['required', 'string', 'min:8', 'confirmed'],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new user instance after a valid registration.
|
|
||||||
*
|
|
||||||
* @return \App\User
|
|
||||||
*/
|
|
||||||
protected function create(array $data)
|
|
||||||
{
|
|
||||||
return User::create([
|
|
||||||
'name' => $data['name'],
|
|
||||||
'email' => $data['email'],
|
|
||||||
'password' => Hash::make($data['password']),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,11 +2,11 @@
|
||||||
|
|
||||||
namespace App;
|
namespace App;
|
||||||
|
|
||||||
use App\Auth\ResetPassword;
|
|
||||||
use Database\Factories\UserFactory;
|
use Database\Factories\UserFactory;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
|
use Modules\Auth\Mails\ResetPassword;
|
||||||
|
|
||||||
class User extends Authenticatable
|
class User extends Authenticatable
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\View\Page;
|
||||||
|
|
||||||
|
use Illuminate\View\Component;
|
||||||
|
|
||||||
|
class Full extends Component
|
||||||
|
{
|
||||||
|
|
||||||
|
public function __construct(public string $title = '', public ?string $heading = null)
|
||||||
|
{
|
||||||
|
session()->put('title', $title);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return <<<'HTML'
|
||||||
|
<div class="min-w-[16rem] sm:min-w-[18rem] md:min-w-[24rem] bg-gray-800 rounded-xl overflow-hidden shadow-lg @if($heading === null) p-6 md:p-10 @endif">
|
||||||
|
@if ($heading)
|
||||||
|
<div class="h-24 p-6 md:px-10 bg-primary-800 flex justify-between items-center w-full">
|
||||||
|
<span class="text-primary-500 text-xl">{{$heading}}</span>
|
||||||
|
<img src="{{asset('img/dpsg.gif')}}" class="w-24" />
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<div @if($heading !== null) class="p-6 md:p-10" @endif>
|
||||||
|
{{ $slot }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
HTML;
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,9 +7,10 @@ use Illuminate\View\Component;
|
||||||
class Layout extends Component
|
class Layout extends Component
|
||||||
{
|
{
|
||||||
|
|
||||||
public function __construct(public string $pageClass = '', public string $title = '')
|
public function __construct(public string $pageClass = '', public string $title = '', public string $menu = '')
|
||||||
{
|
{
|
||||||
session()->put('title', $title);
|
session()->put('title', $title);
|
||||||
|
session()->put('menu', $menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function userName(): string
|
public function userName(): string
|
||||||
|
|
|
@ -18,13 +18,12 @@ class SettingLayout extends Component
|
||||||
'is_active' => get_class($setting) === $active,
|
'is_active' => get_class($setting) === $active,
|
||||||
'title' => $setting->title(),
|
'title' => $setting->title(),
|
||||||
])->toArray();
|
])->toArray();
|
||||||
session()->put('menu', 'setting');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
return <<<'HTML'
|
return <<<'HTML'
|
||||||
<x-page::layout :title="$active::title()">
|
<x-page::layout :title="$active::title()" menu="setting">
|
||||||
<x-slot:right>
|
<x-slot:right>
|
||||||
{{ $right ?? '' }}
|
{{ $right ?? '' }}
|
||||||
</x-slot:right>
|
</x-slot:right>
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\View\Ui;
|
||||||
|
|
||||||
|
use Illuminate\View\Component;
|
||||||
|
|
||||||
|
class Button extends Component
|
||||||
|
{
|
||||||
|
|
||||||
|
public function __construct(public string $type = 'button')
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return <<<'HTML'
|
||||||
|
<button type="{{$type}}" class="px-3 py-2 uppercase no-underline text-sm items-center justify-center bg-primary-700 rounded text-primary-300">
|
||||||
|
{{$slot}}
|
||||||
|
</button>
|
||||||
|
HTML;
|
||||||
|
}
|
||||||
|
}
|
|
@ -183,6 +183,7 @@ return [
|
||||||
Modules\Invoice\InvoiceServiceProvider::class,
|
Modules\Invoice\InvoiceServiceProvider::class,
|
||||||
Modules\Mailgateway\MailgatewayServiceProvider::class,
|
Modules\Mailgateway\MailgatewayServiceProvider::class,
|
||||||
Modules\Nami\NamiServiceProvider::class,
|
Modules\Nami\NamiServiceProvider::class,
|
||||||
|
Modules\Auth\AuthServiceProvider::class,
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -27,4 +27,9 @@ class UserFactory extends Factory
|
||||||
'lastname' => $this->faker->lastName,
|
'lastname' => $this->faker->lastName,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function loginData(string $email, string $password): self
|
||||||
|
{
|
||||||
|
return $this->state(['email' => $email, 'password' => Hash::make($password)]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\Auth;
|
||||||
|
|
||||||
|
use Illuminate\Routing\Router;
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
use Modules\Auth\Components\LoginForm;
|
||||||
|
use Modules\Auth\Components\PasswordReset;
|
||||||
|
|
||||||
|
class AuthServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Register services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot()
|
||||||
|
{
|
||||||
|
app(Router::class)->middleware(['web', 'guest'])->group(function ($router) {
|
||||||
|
$router->get('/login', LoginForm::class)->name('login');
|
||||||
|
$router->get('/password/reset', PasswordReset::class)->name('password.request');
|
||||||
|
$router->get('/password/reseta', PasswordReset::class)->name('password.reset');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\Auth\Components;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||||
|
use Illuminate\Foundation\Auth\ThrottlesLogins;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
use Livewire\Attributes\Layout;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class LoginForm extends Component
|
||||||
|
{
|
||||||
|
|
||||||
|
use AuthenticatesUsers;
|
||||||
|
use ThrottlesLogins;
|
||||||
|
|
||||||
|
public string $email = '';
|
||||||
|
public string $password = '';
|
||||||
|
|
||||||
|
public function validateLogin(Request $request)
|
||||||
|
{
|
||||||
|
$this->validate([
|
||||||
|
'email' => 'required|max:255|string|email',
|
||||||
|
'password' => 'required|string',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function credentials(Request $request)
|
||||||
|
{
|
||||||
|
return ['email' => $this->email, 'password' => $this->password];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function sendLoginResponse(Request $request)
|
||||||
|
{
|
||||||
|
return redirect()->intended('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function submit()
|
||||||
|
{
|
||||||
|
return $this->login(request());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Layout('components.layouts.full')]
|
||||||
|
public function render(): string
|
||||||
|
{
|
||||||
|
return <<<'HTML'
|
||||||
|
<x-page::full heading="Login" title="Login">
|
||||||
|
<form wire:submit="submit">
|
||||||
|
<div class="grid gap-5">
|
||||||
|
<x-form::text name="email" wire:model="email" label="E-Mail-Adresse"></x-form::text>
|
||||||
|
<x-form::text name="password" wire:model="password" type="password" label="Passwort"></x-form::text>
|
||||||
|
<x-ui::button type="submit">Login</x-ui::button>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<a href="{{route('password.request')}}" class="text-gray-500 text-sm hover:text-gray-300">Passwort vergessen?</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</x-page::full>
|
||||||
|
HTML;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\Auth\Components;
|
||||||
|
|
||||||
|
use App\User;
|
||||||
|
use Illuminate\Auth\Events\Lockout;
|
||||||
|
use Tests\TestCase;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
use Illuminate\Support\Facades\Event;
|
||||||
|
use Livewire\Livewire;
|
||||||
|
|
||||||
|
uses(TestCase::class);
|
||||||
|
uses(DatabaseTransactions::class);
|
||||||
|
|
||||||
|
it('redirects to login', function () {
|
||||||
|
test()->get('/')->assertRedirect('/login');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays component', function () {
|
||||||
|
test()->get('/login')->assertSeeLivewire(LoginForm::class)->assertDontSee('Dashboard');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays form', function () {
|
||||||
|
Livewire::test(LoginForm::class)
|
||||||
|
->assertSee('Login')
|
||||||
|
->assertSee('Passwort vergessen')
|
||||||
|
->assertSee(route('password.request'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loggs in', function () {
|
||||||
|
User::factory()->loginData('admin@example.com', 'secret')->create();
|
||||||
|
Livewire::test(LoginForm::class)
|
||||||
|
->set('email', 'admin@example.com')
|
||||||
|
->set('password', 'secret')
|
||||||
|
->call('submit')
|
||||||
|
->assertRedirect('/');
|
||||||
|
|
||||||
|
$this->assertEquals('admin@example.com', auth()->user()->email);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays failed login response', function () {
|
||||||
|
Livewire::test(LoginForm::class)
|
||||||
|
->set('email', 'admin@example.com')
|
||||||
|
->set('password', 'secret')
|
||||||
|
->call('submit')
|
||||||
|
->assertHasErrors(['email' => 'Login fehlgeschlagen.']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('increments login attempts', function () {
|
||||||
|
Event::fake([Lockout::class]);
|
||||||
|
Livewire::test(LoginForm::class)
|
||||||
|
->set('email', 'admin@example.com')
|
||||||
|
->set('password', 'secret')
|
||||||
|
->call('submit')
|
||||||
|
->call('submit')
|
||||||
|
->call('submit')
|
||||||
|
->call('submit')
|
||||||
|
->call('submit')
|
||||||
|
->call('submit');
|
||||||
|
Event::assertDispatchedTimes(Lockout::class);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('requires email and password', function () {
|
||||||
|
User::factory()->loginData('admin@example.com', 'secret')->create();
|
||||||
|
Livewire::test(LoginForm::class)
|
||||||
|
->set('email', '')
|
||||||
|
->set('password', '')
|
||||||
|
->call('submit')
|
||||||
|
->assertHasErrors(['email', 'password']);
|
||||||
|
});
|
|
@ -0,0 +1,66 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\Auth\Components;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
use Livewire\Attributes\Layout;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class PasswordReset extends Component
|
||||||
|
{
|
||||||
|
|
||||||
|
use SendsPasswordResetEmails;
|
||||||
|
|
||||||
|
public string $email = '';
|
||||||
|
|
||||||
|
protected function validateEmail(Request $request)
|
||||||
|
{
|
||||||
|
$this->validate([
|
||||||
|
'email' => 'required|max:255|string|email',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function sendResetLinkFailedResponse(Request $request, $response)
|
||||||
|
{
|
||||||
|
throw ValidationException::withMessages([
|
||||||
|
'email' => [trans($response)],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function credentials(Request $request)
|
||||||
|
{
|
||||||
|
return ['email' => $this->email];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function submit()
|
||||||
|
{
|
||||||
|
$this->sendResetLinkEmail(request());
|
||||||
|
$this->dispatch('success', 'Du hast weitere Instruktionen per E-Mail erhalten.');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Layout('components.layouts.full')]
|
||||||
|
public function render(): string
|
||||||
|
{
|
||||||
|
return <<<'HTML'
|
||||||
|
<x-page::full heading="Passwort vergessen" title="Passwort vergessen">
|
||||||
|
<form wire: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
|
||||||
|
>
|
||||||
|
<x-form::text name="email" wire:model="email" label="E-Mail-Adresse"></x-form::text>
|
||||||
|
<x-ui::button type="submit">Passwort zurücksetzen</x-ui::button>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<a href="/login" class="text-gray-500 text-sm hover:text-gray-300">Zurück zum Login</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</x-page::full>
|
||||||
|
HTML;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\Auth\Components;
|
||||||
|
|
||||||
|
use Modules\Auth\Mails\ResetPassword;
|
||||||
|
use App\User;
|
||||||
|
use Tests\TestCase;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
use Illuminate\Support\Facades\Notification;
|
||||||
|
use Livewire\Livewire;
|
||||||
|
|
||||||
|
uses(TestCase::class);
|
||||||
|
uses(DatabaseTransactions::class);
|
||||||
|
|
||||||
|
it('displays component', function () {
|
||||||
|
test()->get(route('password.request'))->assertSeeLivewire(PasswordReset::class)->assertDontSee('Dashboard');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows intro', function () {
|
||||||
|
Livewire::test(PasswordReset::class)->assertSee('Hier kannst du dein Passwort zurücksetzen.');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('it needs email address', function (string $email, string $error) {
|
||||||
|
Livewire::test(PasswordReset::class)
|
||||||
|
->set('email', $email)
|
||||||
|
->call('submit')
|
||||||
|
->assertHasErrors(['email' => $error]);
|
||||||
|
})
|
||||||
|
->with([
|
||||||
|
['', 'E-Mail Adresse ist erforderlich.'],
|
||||||
|
['aaa', 'E-Mail Adresse muss eine gültige E-Mail-Adresse sein.'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
it('displays error when user doesnt exsst', function () {
|
||||||
|
Livewire::test(PasswordReset::class)
|
||||||
|
->set('email', 'nowhere@example.com')
|
||||||
|
->call('submit')
|
||||||
|
->assertHasErrors(['email' => 'Es konnte leider kein Nutzer mit dieser E-Mail-Adresse gefunden werden.']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('requests link', function () {
|
||||||
|
Notification::fake();
|
||||||
|
$user = User::factory()->loginData('admin@example.com', 'secret')->create();
|
||||||
|
Livewire::test(PasswordReset::class)
|
||||||
|
->set('email', 'admin@example.com')
|
||||||
|
->call('submit')
|
||||||
|
->assertDispatched('success', 'Du hast weitere Instruktionen per E-Mail erhalten.');
|
||||||
|
|
||||||
|
Notification::assertSentTo($user, ResetPassword::class);
|
||||||
|
});
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Auth;
|
namespace Modules\Auth\Mails;
|
||||||
|
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Support\Facades\Lang;
|
use Illuminate\Support\Facades\Lang;
|
||||||
|
@ -17,7 +17,7 @@ class ResetPassword extends BaseResetPassword
|
||||||
protected function buildMailMessage($url)
|
protected function buildMailMessage($url)
|
||||||
{
|
{
|
||||||
return (new MailMessage)
|
return (new MailMessage)
|
||||||
->subject(Lang::get('Passwort zurücksetzen | Adrema'))
|
->subject(Lang::get('Passwort zurücksetzen | ' . config('app.name')))
|
||||||
->line(Lang::get('Du erhälst diese E-Mail, weil du eine Anfrage zum zurücksetzen deines Account-Passworts gestellt hast.'))
|
->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)
|
->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('Dieser Link wird in :count Minuten ablaufen.', ['count' => config('auth.passwords.' . config('auth.defaults.passwords') . '.expire')]))
|
|
@ -12,16 +12,13 @@ class DashboardComponent extends Component
|
||||||
|
|
||||||
public function mount(DashboardFactory $factory): void
|
public function mount(DashboardFactory $factory): void
|
||||||
{
|
{
|
||||||
session()->put('menu', 'dashboard');
|
|
||||||
session()->put('title', 'Dashboard');
|
|
||||||
|
|
||||||
$this->blocks = $factory->load();
|
$this->blocks = $factory->load();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): string
|
public function render(): string
|
||||||
{
|
{
|
||||||
return <<<'HTML'
|
return <<<'HTML'
|
||||||
<x-page::layout>
|
<x-page::layout title="Dashboard" menu="dashboard">
|
||||||
<div class="gap-6 md:grid-cols-2 xl:grid-cols-4 grid p-6">
|
<div class="gap-6 md:grid-cols-2 xl:grid-cols-4 grid p-6">
|
||||||
@foreach($this->blocks as $block)
|
@foreach($this->blocks as $block)
|
||||||
<x-ui::box title="{{$block->title()}}" :second="true">
|
<x-ui::box title="{{$block->title()}}" :second="true">
|
||||||
|
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
@ -1,10 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="h-24 p-6 md:px-10 bg-primary-800 flex justify-between items-center w-full">
|
|
||||||
<span class="text-primary-500 text-xl"><slot></slot></span>
|
|
||||||
<img src="../../../img/dpsg.gif" class="w-24" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {};
|
|
||||||
</script>
|
|
|
@ -1,36 +0,0 @@
|
||||||
<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" label="E-Mail-Adresse"></f-text>
|
|
||||||
<f-text id="password" v-model="values.password" type="password" label="Passwort"></f-text>
|
|
||||||
<button type="submit" class="btn btn-primary">Login</button>
|
|
||||||
</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>
|
|
|
@ -1,39 +0,0 @@
|
||||||
<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" label="E-Mail-Adresse"></f-text>
|
|
||||||
<f-text id="password" v-model="values.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>
|
|
|
@ -12,6 +12,6 @@ return [
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'failed' => 'Diese Kombination aus Zugangsdaten wurde nicht in unserer Datenbank gefunden.',
|
'failed' => 'Login fehlgeschlagen.',
|
||||||
'throttle' => 'Zu viele Loginversuche. Versuchen Sie es bitte in :seconds Sekunden nochmal.',
|
'throttle' => 'Zu viele Loginversuche. Versuchen Sie es bitte in :seconds Sekunden nochmal.',
|
||||||
];
|
];
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
|
||||||
|
|
||||||
|
<title>{{ session()->get('title') }} | {{ config('app.name') }}</title>
|
||||||
|
<meta name="socketport" content="{{env('SOCKET_PORT')}}" />
|
||||||
|
<meta name="adrema_base_url" content="/">
|
||||||
|
@if(auth()->id())
|
||||||
|
<meta name="meilisearch_key" content="{{config('scout.meilisearch.key')}}" />
|
||||||
|
@endif
|
||||||
|
@vite('resources/livewire-js/app.js')
|
||||||
|
</head>
|
|
@ -1,17 +1,6 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html class="h-full" lang="de">
|
<html class="h-full" lang="de">
|
||||||
<head>
|
<x-head></x-head>
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
|
|
||||||
|
|
||||||
<title>{{ session()->get('title') }} | {{ config('app.name') }}</title>
|
|
||||||
<meta name="socketport" content="{{env('SOCKET_PORT')}}" />
|
|
||||||
<meta name="adrema_base_url" content="/">
|
|
||||||
@if(auth()->id())
|
|
||||||
<meta name="meilisearch_key" content="{{config('scout.meilisearch.key')}}" />
|
|
||||||
@endif
|
|
||||||
@vite('resources/livewire-js/app.js')
|
|
||||||
</head>
|
|
||||||
<body class="min-h-full flex flex-col">
|
<body class="min-h-full flex flex-col">
|
||||||
<livewire:page.sidebar />
|
<livewire:page.sidebar />
|
||||||
{{ $slot }}
|
{{ $slot }}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="h-full" lang="de">
|
||||||
|
<x-head></x-head>
|
||||||
|
<body class="min-h-full flex justify-center items-center bg-gray-900">
|
||||||
|
{{ $slot }}
|
||||||
|
@livewireScriptConfig
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -76,9 +76,7 @@ use App\Membership\Actions\MembershipStoreAction;
|
||||||
use App\Membership\Actions\MembershipUpdateAction;
|
use App\Membership\Actions\MembershipUpdateAction;
|
||||||
use App\Payment\SubscriptionController;
|
use App\Payment\SubscriptionController;
|
||||||
|
|
||||||
Route::group(['namespace' => 'App\\Http\\Controllers'], function (): void {
|
|
||||||
Auth::routes(['register' => false]);
|
|
||||||
});
|
|
||||||
|
|
||||||
Route::group(['middleware' => 'auth:web'], function (): void {
|
Route::group(['middleware' => 'auth:web'], function (): void {
|
||||||
Route::post('/nami/login-check', NamiLoginCheckAction::class)->name('nami.login-check');
|
Route::post('/nami/login-check', NamiLoginCheckAction::class)->name('nami.login-check');
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
<?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();
|
|
||||||
$this->get('/password/reset')->assertComponent('authentication/PasswordReset');
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -39,6 +39,18 @@ class PreventionTest extends TestCase
|
||||||
$this->assertEquals(now()->format('Y-m-d'), $participant->fresh()->last_remembered_at->format('Y-m-d'));
|
$this->assertEquals(now()->format('Y-m-d'), $participant->fresh()->last_remembered_at->format('Y-m-d'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testItDoesntRememberPastEvents(): void
|
||||||
|
{
|
||||||
|
Mail::fake();
|
||||||
|
$form = $this->createForm();
|
||||||
|
$participant = $this->createParticipant($form);
|
||||||
|
$form->update(['from' => now()->subDay()]);
|
||||||
|
|
||||||
|
PreventionRememberAction::run();
|
||||||
|
|
||||||
|
$this->assertNull($participant->fresh()->last_remembered_at);
|
||||||
|
}
|
||||||
|
|
||||||
public function testItDoesntRememberWhenConditionDoesntMatch(): void
|
public function testItDoesntRememberWhenConditionDoesntMatch(): void
|
||||||
{
|
{
|
||||||
Mail::fake();
|
Mail::fake();
|
||||||
|
|
Loading…
Reference in New Issue