feat: allow duplicate resource names, show the room next to the name

This commit is contained in:
fromme committed 2026-09-17 18:40:53 +02:00
1 parent 84724879c7
commit d37d8bc786
8 files changed
+39 -21

No files matched your search

+26
View File
@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20260917130000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Drops the unique (type, label) guard on resources';
}
public function up(Schema $schema): void
{
$this->addSql('DROP INDEX uniq_resource_label ON resource');
}
public function down(Schema $schema): void
{
$this->addSql('CREATE UNIQUE INDEX uniq_resource_label ON resource (type, label)');
}
}
-3
View File
@@ -7,15 +7,12 @@ namespace App\Entity;
use App\Enum\ResourceType;
use App\Repository\ResourceRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Validator\Constraints as Assert;
/**
* A bookable thing: a desk, a parking spot or a portable device.
*/
#[ORM\Entity(repositoryClass: ResourceRepository::class)]
#[ORM\UniqueConstraint(name: 'uniq_resource_label', columns: ['type', 'label'])]
#[UniqueEntity(fields: ['type', 'label'], message: 'Diese Bezeichnung ist bereits vergeben.', errorPath: 'label')]
class Resource
{
#[ORM\Id]
@@ -4,7 +4,8 @@
{% block content %}
<p>
{{ resource.type.label }} <em>{{ resource.label }}</em> wird endgültig gelöscht.
{{ resource.type.label }} <em>{{ resource.label }}</em>
{%- if resource.group %} ({{ resource.group.label }}){% endif %} wird endgültig gelöscht.
</p>
{% if upcoming > 0 or past > 0 %}
<p class="pt-2" data-booking-count>
@@ -24,6 +24,7 @@
<p class="pb-4 text-sm text-gray-500">
{{ resource.type.label }} · {{ resource.label }}
{%- if resource.group %} · {{ resource.group.label }}{% endif %}
</p>
{% include 'booking/_fields.html.twig' %}
+1
View File
@@ -21,6 +21,7 @@
<p class="pb-4 text-sm text-gray-500">
{{ resource.type.label }} · {{ booking.date|format_datetime(pattern: 'EEEE, d. MMMM y') }}
{%- if resource.group %} · {{ resource.group.label }}{% endif %}
</p>
{% if booking.partOfSeries %}
@@ -4,7 +4,8 @@
{% block content %}
<p>
{{ series.resource.label }} · {{ series.describe }}
{{ series.resource.label }}
{%- if series.resource.group %} ({{ series.resource.group.label }}){% endif %} · {{ series.describe }}
{% if series.user.id != app.user.id %}
— Wiederkehrende Buchung von <em>{{ series.user.name }}</em>
{% endif %}
+2 -1
View File
@@ -33,7 +33,8 @@
{% endif %}
</span>
{% if tile.mine %}
<span class="badge bg-primary text-white">{{ tile.mine.resource.label }}</span>
<span class="badge bg-primary text-white">{{ tile.mine.resource.label }}
{%- if tile.mine.resource.group %} · {{ tile.mine.resource.group.label }}{% endif %}</span>
{% endif %}
</div>
</a>
@@ -82,28 +82,18 @@ class ResourceAdminControllerTest extends WebTestCase
self::assertTrue($created->isActive());
}
public function testADuplicateLabelIsRejectedInTheModal(): void
/**
* Labels are not unique: two desks may both be called "Schreibtisch 01", e.g. in different rooms.
*/
public function testADuplicateLabelIsAccepted(): void
{
$this->resource('Schreibtisch 01');
$this->client->loginUser($this->admin());
$response = $this->submit('/admin/resources/new/desk', 'resource_form', ['label' => 'Schreibtisch 01']);
self::assertSame(Response::HTTP_UNPROCESSABLE_ENTITY, $response->getStatusCode());
self::assertStringContainsString('bereits vergeben', (string) $response->getContent());
}
/**
* The same label is fine for another type -- uniqueness is per type, like the database's.
*/
public function testTheSameLabelMayExistForAnotherType(): void
{
$this->resource('A1');
$this->client->loginUser($this->admin());
$response = $this->submit('/admin/resources/new/parking', 'resource_form', ['label' => 'A1']);
self::assertSame('/admin/resources', $response->headers->get('HX-Redirect'));
self::assertCount(2, $this->em->getRepository(Resource::class)->findBy(['label' => 'Schreibtisch 01']));
}
/**