- 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>
95 lines
3.5 KiB
PHP
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;
|
|
}
|
|
}
|