Add checkbox for destroying participant
continuous-integration/drone/push Build is failing Details

This commit is contained in:
philipp lang 2025-12-02 01:15:24 +01:00
parent 502ba20b6d
commit 5117360c03
4 changed files with 35 additions and 12 deletions

View File

@ -6,6 +6,7 @@ use App\Form\Models\Participant;
use App\Lib\JobMiddleware\JobChannels; use App\Lib\JobMiddleware\JobChannels;
use App\Lib\JobMiddleware\WithJobState; use App\Lib\JobMiddleware\WithJobState;
use App\Lib\Queue\TracksJob; use App\Lib\Queue\TracksJob;
use Lorisleiva\Actions\ActionRequest;
use Lorisleiva\Actions\Concerns\AsAction; use Lorisleiva\Actions\Concerns\AsAction;
class ParticipantDestroyAction class ParticipantDestroyAction
@ -13,14 +14,20 @@ class ParticipantDestroyAction
use AsAction; use AsAction;
use TracksJob; use TracksJob;
public function handle(int $participantId): void public function handle(int $participantId, bool $force): void
{ {
Participant::findOrFail($participantId)->update(['cancelled_at' => now()]); $participant = Participant::findOrFail($participantId);
if ($force) {
$participant->delete();
} else {
$participant->update(['cancelled_at' => now()]);
}
} }
public function asController(Participant $participant): void public function asController(ActionRequest $request, Participant $participant): void
{ {
$this->startJob($participant->id); $this->startJob($participant->id, $request->header('X-Force') === '1');
} }
/** /**

View File

@ -47,8 +47,10 @@ export function useApiIndex(firstUrl, siteName = null) {
single.value = null; single.value = null;
} }
async function remove(model) { async function remove(model, force = true) {
await axios.delete(model.links.destroy); await axios.delete(model.links.destroy, {
headers: { 'X-Force': force ? '1' : '0' }
});
await reload(); await reload();
} }

View File

@ -11,9 +11,10 @@
<ui-popup v-if="assigning !== null" heading="Mitglied zuweisen" closeable @close="assigning = null"> <ui-popup v-if="assigning !== null" heading="Mitglied zuweisen" closeable @close="assigning = null">
<member-assign @assign="assign" /> <member-assign @assign="assign" />
</ui-popup> </ui-popup>
<ui-popup v-if="deleting !== null" heading="Teilnehmer*in löschen?" @close="deleting = null"> <ui-popup v-if="deleting !== null" heading="Teilnehmer*in abmelden?" @close="deleting = null">
<div> <div>
<p class="mt-4">Den*Die Teilnehmer*in löschen?</p> <p class="mt-4">Den*Die Teilnehmer*in abmelden?</p>
<f-switch class="mt-2" v-model="deleting.force" name="force_delete" id="force_delete" label="löschen statt abmelden (permanent)" size="sm" />
<div class="grid grid-cols-2 gap-3 mt-6"> <div class="grid grid-cols-2 gap-3 mt-6">
<a href="#" class="text-center btn btn-danger" @click.prevent="handleDelete">Mitglied loschen</a> <a href="#" class="text-center btn btn-danger" @click.prevent="handleDelete">Mitglied loschen</a>
<a href="#" class="text-center btn btn-primary" @click.prevent="deleting = null">Abbrechen</a> <a href="#" class="text-center btn btn-primary" @click.prevent="deleting = null">Abbrechen</a>
@ -96,7 +97,7 @@
</td> </td>
<td> <td>
<a v-tooltip="`Bearbeiten`" href="#" class="ml-2 inline-flex btn btn-warning btn-sm" @click.prevent="editReal(participant)"><ui-sprite src="pencil" /></a> <a v-tooltip="`Bearbeiten`" href="#" class="ml-2 inline-flex btn btn-warning btn-sm" @click.prevent="editReal(participant)"><ui-sprite src="pencil" /></a>
<a v-tooltip="`Löschen`" href="#" class="ml-2 inline-flex btn btn-danger btn-sm" @click.prevent="deleting = participant"><ui-sprite src="trash" /></a> <a v-tooltip="`Abmelden`" href="#" class="ml-2 inline-flex btn btn-danger btn-sm" @click.prevent="deleting = {model: participant, force: false}"><ui-sprite src="trash" /></a>
</td> </td>
</tr> </tr>
<template v-for="child in childrenOf(participant.id)" :key="child.id"> <template v-for="child in childrenOf(participant.id)" :key="child.id">
@ -115,7 +116,7 @@
</td> </td>
<td> <td>
<a v-tooltip="`Bearbeiten`" href="#" class="ml-2 inline-flex btn btn-warning btn-sm" @click.prevent="editReal(child)"><ui-sprite src="pencil" /></a> <a v-tooltip="`Bearbeiten`" href="#" class="ml-2 inline-flex btn btn-warning btn-sm" @click.prevent="editReal(child)"><ui-sprite src="pencil" /></a>
<a v-tooltip="`Löschen`" href="#" class="ml-2 inline-flex btn btn-danger btn-sm" @click.prevent="deleting = child"><ui-sprite src="trash" /></a> <a v-tooltip="`Abmelden`" href="#" class="ml-2 inline-flex btn btn-danger btn-sm" @click.prevent="deleting = {model: child, force: false}"><ui-sprite src="trash" /></a>
</td> </td>
</tr> </tr>
</template> </template>
@ -210,7 +211,7 @@ const sortingConfig = computed({
}); });
async function handleDelete() { async function handleDelete() {
await remove(deleting.value); await remove(deleting.value.model, deleting.value.force);
deleting.value = null; deleting.value = null;
} }

View File

@ -14,7 +14,7 @@ beforeEach(function () {
test()->setUpForm(); test()->setUpForm();
}); });
it('testItCanDestroyAParticipant', function () { it('cancels a participant', function () {
$this->login()->loginNami()->withoutExceptionHandling(); $this->login()->loginNami()->withoutExceptionHandling();
$form = Form::factory() $form = Form::factory()
->has(Participant::factory()) ->has(Participant::factory())
@ -30,3 +30,16 @@ it('testItCanDestroyAParticipant', function () {
'id' => $form->participants->first()->id, 'id' => $form->participants->first()->id,
]); ]);
}); });
it('testItCanDestroyAParticipant', function () {
$this->login()->loginNami()->withoutExceptionHandling();
$form = Form::factory()
->has(Participant::factory())
->sections([])
->create();
$this->deleteJson(route('participant.destroy', ['participant' => $form->participants->first()]), [], ['X-Force' => '1'])
->assertOk();
$this->assertDatabaseCount('participants', 0);
});