vcard4reseller/backend/src/Controller/EmployeeContactLinksController.php
Thomas Peterson 862385dbe0 Mitarbeiter: erweitertes Datenmodell + Tab-Formular
- Neue Felder: Anrede, akad. Titel, Privat-E-Mail, Fax, Zentrale, Website,
  Geschäfts-/Privatadresse (JSON), Über mich
- Foto-Upload (S3) + öffentliche Auslieferung /p/photo/{id}.jpg, Avatar in Liste
- Social-/Kontakt-Links: GET/PUT /api/employees/{id}/contact-links (Replace)
- Formular in Tabs: Allgemein / Kontakt / Adresse / Social / Zugang & NFC
- Telefonfelder mit Länder-Vorwahl + Emoji-Flagge (PhoneInput), Adress-Land
  per Flaggen-Auswahl (CountrySelect), countries.ts (Vorwahlen)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 18:56:22 +02:00

95 lines
3.5 KiB
PHP

<?php
namespace App\Controller;
use App\Entity\ContactLink;
use App\Entity\Employee;
use App\Security\TenantContext;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Component\Uid\Uuid;
/**
* Ersetzt die Social-/Kontakt-Links eines Mitarbeiters in einem Rutsch
* (das Mitarbeiter-Formular bearbeitet immer das ganze Set).
*/
#[IsGranted('ROLE_COMPANY_ADMIN')]
final class EmployeeContactLinksController
{
public function __construct(
private readonly EntityManagerInterface $em,
private readonly TenantContext $tenant,
) {
}
#[Route('/api/employees/{id}/contact-links', name: 'employee_links_get', methods: ['GET'])]
public function listLinks(string $id): JsonResponse
{
$employee = $this->scoped($id);
$out = [];
foreach ($employee->getContactLinks() as $link) {
$out[] = ['type' => $link->getType(), 'url' => $link->getUrl(), 'label' => $link->getLabel()];
}
return new JsonResponse(['links' => $out]);
}
#[Route('/api/employees/{id}/contact-links', name: 'employee_links_put', methods: ['PUT'])]
public function replace(string $id, Request $request): JsonResponse
{
$employee = $this->scoped($id);
foreach ($employee->getContactLinks()->toArray() as $link) {
$employee->removeContactLink($link);
}
$data = json_decode($request->getContent(), true) ?? [];
$links = \is_array($data['links'] ?? null) ? $data['links'] : [];
$pos = 0;
$out = [];
foreach ($links as $l) {
$url = trim((string) ($l['url'] ?? ''));
if ('' === $url) {
continue;
}
$type = substr(trim((string) ($l['type'] ?? 'custom')), 0, 40) ?: 'custom';
$label = trim((string) ($l['label'] ?? ''));
$link = (new ContactLink())
->setType($type)
->setUrl(substr($url, 0, 500))
->setLabel('' !== $label ? substr($label, 0, 120) : null)
->setPosition($pos++);
$employee->addContactLink($link);
$out[] = ['type' => $type, 'url' => $url, 'label' => '' !== $label ? $label : null];
}
$this->em->flush();
return new JsonResponse(['links' => $out]);
}
private function scoped(string $id): Employee
{
$employee = $this->em->getRepository(Employee::class)->find(Uuid::fromString($id));
if (!$employee instanceof Employee) {
throw new NotFoundHttpException('Mitarbeiter nicht gefunden.');
}
if ($this->tenant->isPlatformAdmin()) {
return $employee;
}
$reseller = $this->tenant->getReseller();
if (null === $reseller || true !== $employee->getReseller()?->getId()->equals($reseller->getId())) {
throw new AccessDeniedHttpException('Mitarbeiter gehört nicht zum eigenen Mandanten.');
}
$own = $this->tenant->getCompany();
if (null !== $own && !$employee->getCompany()->getId()->equals($own->getId())) {
throw new AccessDeniedHttpException('Nur die eigene Firma.');
}
return $employee;
}
}