add team delte
CI/CD / test_and_check_app (push) Failing after 55s
CI/CD / Publish immutable image (push) Skipped

This commit is contained in:
2026-09-29 21:39:26 +02:00
parent f6831a02a2
commit 0ea78a621a
7 changed files with 57 additions and 20 deletions
+1
View File
@@ -4,6 +4,7 @@ namespace App\Enums;
enum TeamMemberRole: string enum TeamMemberRole: string
{ {
case Owner = 'owner';
case Admin = 'admin'; case Admin = 'admin';
case Member = 'member'; case Member = 'member';
+12 -1
View File
@@ -53,7 +53,7 @@ class TeamController extends Controller
try { try {
DB::transaction(function () use ($request): void { DB::transaction(function () use ($request): void {
$team = Team::create($request->validated()); $team = Team::create($request->validated());
$team->members()->attach($request->user(), ['role' => TeamMemberRole::Admin]); $team->members()->attach($request->user(), ['role' => TeamMemberRole::Owner]);
}); });
} catch (\Exception $exception) { } catch (\Exception $exception) {
report($exception); report($exception);
@@ -100,6 +100,17 @@ class TeamController extends Controller
return to_route('teams.show', $team); return to_route('teams.show', $team);
} }
public function destroy(Request $request, Team $team)
{
try {
$team->delete();
} catch (\Exception $exception) {
report($exception);
Inertia::flash('error', 'Team could not be deleted.');
}
Inertia::flash('success', 'Team successfully deleted.');
}
public function nameToSlug(Request $request): JsonResponse public function nameToSlug(Request $request): JsonResponse
{ {
+11 -1
View File
@@ -28,6 +28,16 @@ class TeamPolicy
return false; return false;
} }
return $membership->pivot->role === TeamMemberRole::Admin; return ($membership->pivot->role === TeamMemberRole::Admin) || ($membership->pivot->role === TeamMemberRole::Owner);
}
public function delete(User $user, Team $team): bool
{
$membership = $team->members()->whereKey($user->id)->first();
if (! $membership) {
return false;
}
return $membership->pivot->role === TeamMemberRole::Owner;
} }
} }
+26 -15
View File
@@ -1,20 +1,12 @@
<script lang="ts" setup> <script lang="ts" setup>
import teamRoutes from '@/routes/teams'; import teamRoutes from '@/routes/teams';
import { Head, Link, router, usePage } from '@inertiajs/vue3'; import {Head, Link, router, usePage} from '@inertiajs/vue3';
import type { Team } from '@/types/models'; import type {Team} from '@/types/models';
import TextLink from '@/components/TextLink.vue'; import TextLink from '@/components/TextLink.vue';
import { Card, CardContent } from '@/components/ui/card'; import {Card, CardContent} from '@/components/ui/card';
import { import {Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow,} from '@/components/ui/table';
Table, import {Button} from '@/components/ui/button';
TableBody, import {Eye, Pencil, Plus, Trash} from '@lucide/vue';
TableCaption,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table';
import { Button } from '@/components/ui/button';
import { Eye, Pencil, Plus } from '@lucide/vue';
defineOptions({ defineOptions({
layout: { layout: {
@@ -38,6 +30,9 @@ const openTeam = (team: Team) =>
const canManageTeam = (team: Team) => const canManageTeam = (team: Team) =>
team.members.find((member) => member.email === user.email)?.role === 'admin'; team.members.find((member) => member.email === user.email)?.role === 'admin';
const canDeleteTeam = (team: Team) =>
team.members.find((member) => member.email === user.email)?.role === 'owner';
</script> </script>
<template> <template>
@@ -61,6 +56,7 @@ const canManageTeam = (team: Team) =>
<TableHead>Slug</TableHead> <TableHead>Slug</TableHead>
<TableHead>Mitglieder</TableHead> <TableHead>Mitglieder</TableHead>
<TableHead>2FA</TableHead> <TableHead>2FA</TableHead>
<TableHead/>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
@@ -78,7 +74,7 @@ const canManageTeam = (team: Team) =>
<TableCell>{{ <TableCell>{{
team.multi_factor_required ? 'Ja' : 'Nein' team.multi_factor_required ? 'Ja' : 'Nein'
}}</TableCell> }}</TableCell>
<TableCell> <TableCell class="flex gap-4 justify-end">
<Link <Link
:href=" :href="
(canManageTeam(team) ? teamRoutes.edit : teamRoutes.show)({ (canManageTeam(team) ? teamRoutes.edit : teamRoutes.show)({
@@ -93,6 +89,21 @@ const canManageTeam = (team: Team) =>
size="18" size="18"
/> />
</Link> </Link>
<Link
v-if="canDeleteTeam(team)"
:href="
teamRoutes.destroy({
team: team.slug,
})
"
class="cursor-pointer text-red-500"
@click.stop
>
<component
:is="Trash"
size="18"
/>
</Link>
</TableCell> </TableCell>
</TableRow> </TableRow>
</TableBody> </TableBody>
+4 -1
View File
@@ -6,7 +6,10 @@ export interface Team {
created_at: string; created_at: string;
} }
export type TeamMemberRole = 'admin' | 'member'; export type TeamMemberRole =
|'owner'
| 'admin'
| 'member';
export interface User { export interface User {
name: string; name: string;
+1
View File
@@ -25,6 +25,7 @@ Route::middleware(['auth'])->group(function () {
Route::patch('/{team:slug}', 'update')->name('update')->can('manage', 'team'); Route::patch('/{team:slug}', 'update')->name('update')->can('manage', 'team');
Route::post('/name-to-slug', 'nameToSlug')->name('nameToSlug'); Route::post('/name-to-slug', 'nameToSlug')->name('nameToSlug');
Route::get('/{team:slug}', 'show')->name('show')->can('view', 'team'); Route::get('/{team:slug}', 'show')->name('show')->can('view', 'team');
Route::delete('/{team:slug}', 'destroy')->name('destroy')->can('delete', 'team');
}); });
}); });
+2 -2
View File
@@ -65,7 +65,7 @@ test('unverified users cannot create teams', function (string $method, string $r
$this->assertDatabaseCount('teams', 0); $this->assertDatabaseCount('teams', 0);
})->with([['get', 'teams.create'], ['post', 'teams.store']]); })->with([['get', 'teams.create'], ['post', 'teams.store']]);
test('team creation derives the slug and adds its creator as admin', function () { test('team creation derives the slug and adds its creator as owner', function () {
$user = User::factory()->create(); $user = User::factory()->create();
$this->actingAs($user)->post(route('teams.store'), [ $this->actingAs($user)->post(route('teams.store'), [
@@ -73,7 +73,7 @@ test('team creation derives the slug and adds its creator as admin', function ()
])->assertSessionHasNoErrors()->assertRedirect(route('teams.index')); ])->assertSessionHasNoErrors()->assertRedirect(route('teams.index'));
$this->assertDatabaseHas('teams', ['name' => 'Test Team', 'slug' => 'test-team', 'require_2fa' => true]); $this->assertDatabaseHas('teams', ['name' => 'Test Team', 'slug' => 'test-team', 'require_2fa' => true]);
$this->assertDatabaseHas('team_members', ['user_id' => $user->id, 'role' => 'admin']); $this->assertDatabaseHas('team_members', ['user_id' => $user->id, 'role' => 'owner']);
$this->assertDatabaseMissing('teams', ['id' => 999]); $this->assertDatabaseMissing('teams', ['id' => 999]);
}); });