require 2fa if enabled
CI/CD / test_and_check_app (push) Failing after 47s
CI/CD / Publish immutable image (push) Skipped

This commit is contained in:
2026-10-08 11:29:28 +02:00
parent f2b12c36af
commit b6e0ec539c
6 changed files with 40 additions and 15 deletions
+2 -3
View File
@@ -17,7 +17,7 @@ class CreateNewUser implements CreatesNewUsers
use PasswordValidationRules, ProfileValidationRules; use PasswordValidationRules, ProfileValidationRules;
public function __construct( public function __construct(
private AcceptTeamInvite $acceptTeamInvite, private readonly AcceptTeamInvite $acceptTeamInvite,
) {} ) {}
/** /**
@@ -59,8 +59,7 @@ class CreateNewUser implements CreatesNewUsers
]); ]);
if ($invite !== null) { if ($invite !== null) {
$invite->team->members()->attach($user); ($this->acceptTeamInvite)($invite, $user);
$invite->delete();
} }
return $user; return $user;
+9 -3
View File
@@ -5,15 +5,21 @@ namespace App\Actions\Teams;
use App\Models\TeamInvite; use App\Models\TeamInvite;
use App\Models\User; use App\Models\User;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;
readonly class AcceptTeamInvite readonly class AcceptTeamInvite
{ {
public function __invoke(TeamInvite $invite): void public function __invoke(TeamInvite $invite, User $newUser): void
{ {
abort_unless(auth()->user()->email === $invite->invited_email, 403); abort_unless($newUser->email === $invite->invited_email, 403);
$team = $invite->team; $team = $invite->team;
$newUser = User::whereEmail($invite->invited_email)->firstOrFail();
if ($invite->team->require_2fa && ! $newUser->hasEnabledTwoFactorAuthentication()) {
throw ValidationException::withMessages([
'require_2fa' => 'Du musst 2FA einrichten, damit du dem Team beitreten kannst',
]);
}
try { try {
DB::transaction(function () use ($team, $newUser, $invite) { DB::transaction(function () use ($team, $newUser, $invite) {
+21 -3
View File
@@ -15,6 +15,7 @@ use Illuminate\Http\Request;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Inertia\Inertia; use Inertia\Inertia;
use Inertia\Response; use Inertia\Response;
@@ -50,10 +51,18 @@ class TeamController extends Controller
*/ */
public function store(StoreTeamRequest $request): RedirectResponse public function store(StoreTeamRequest $request): RedirectResponse
{ {
$validated = $request->validated();
$user = $request->user();
if (Arr::get($validated, 'require_2fa', false) && ! $user->hasEnabledTwoFactorAuthentication()) {
throw ValidationException::withMessages([
'require_2fa' => 'Du musst 2FA einrichten, damit du 2FA aktivieren kannst!',
]);
}
try { try {
DB::transaction(function () use ($request): void { DB::transaction(function () use ($validated, $user): void {
$team = Team::create($request->validated()); $team = Team::create($validated);
$team->members()->attach($request->user(), ['role' => TeamMemberRole::Owner]); $team->members()->attach($user, ['role' => TeamMemberRole::Owner]);
}); });
} catch (\Exception $exception) { } catch (\Exception $exception) {
report($exception); report($exception);
@@ -87,6 +96,15 @@ class TeamController extends Controller
*/ */
public function update(UpdateTeamRequest $request, Team $team): RedirectResponse public function update(UpdateTeamRequest $request, Team $team): RedirectResponse
{ {
$validated = $request->validated();
$user = $request->user();
if (Arr::get($validated, 'require_2fa', false) && ! $user->hasEnabledTwoFactorAuthentication()) {
throw ValidationException::withMessages([
'require_2fa' => 'Du musst 2FA einrichten, damit du 2FA aktivieren kannst!',
]);
}
try { try {
$team->update($request->validated()); $team->update($request->validated());
} catch (\Exception $exception) { } catch (\Exception $exception) {
@@ -17,7 +17,7 @@ class TeamInviteAcceptController extends Controller
$invite = TeamInvite::findByPlainToken($inviteToken)->first(); $invite = TeamInvite::findByPlainToken($inviteToken)->first();
if ($invite) { if ($invite) {
$accept($invite); $accept($invite, $request->user());
return to_route('teams.index'); return to_route('teams.index');
} }
@@ -32,7 +32,7 @@ class TeamInviteAcceptController extends Controller
{ {
$request->validated(); $request->validated();
$accept($request->teamInvite()); $accept($request->teamInvite(), $request->user());
return to_route('teams.index'); return to_route('teams.index');
} }
+1
View File
@@ -102,6 +102,7 @@ defineOptions({
/> />
<InputError :message="errors.invite_token" /> <InputError :message="errors.invite_token" />
</div> </div>
<InputError :message="errors.require_2fa" />
<Button <Button
:disabled="processing" :disabled="processing"
+5 -4
View File
@@ -1,10 +1,10 @@
<script lang="ts" setup> <script lang="ts" setup>
import teamRoutes from '@/routes/teams'; import teamRoutes from '@/routes/teams';
import { Form, Head, useForm } from '@inertiajs/vue3'; import {Form, Head, useForm} from '@inertiajs/vue3';
import { Card, CardContent } from '@/components/ui/card'; import {Card, CardContent} from '@/components/ui/card';
import { Input } from '@/components/ui/input'; import {Input} from '@/components/ui/input';
import InputError from '@/components/InputError.vue'; import InputError from '@/components/InputError.vue';
import { Button } from '@/components/ui/button'; import {Button} from '@/components/ui/button';
defineOptions({ defineOptions({
layout: { layout: {
@@ -49,6 +49,7 @@ const submit = () => form.post(teamRoutes.invite.store().url);
/> />
<InputError :message="form.errors.inviteToken" /> <InputError :message="form.errors.inviteToken" />
</div> </div>
<InputError :message="(form.errors as any).require_2fa" />
<div class="flex w-full justify-end"> <div class="flex w-full justify-end">
<Button :disabled="form.processing" type="submit" <Button :disabled="form.processing" type="submit"
>Team Beitreten</Button >Team Beitreten</Button