company($id); $file = $this->file($request); if ('pdf' !== strtolower((string) $file->getClientOriginalExtension())) { throw new BadRequestHttpException('Nur PDF erlaubt.'); } $template = $this->getOrCreate($company); $key = $this->store($file, $company->getId(), 'background', 'pdf'); $template->setBackgroundPath($key); $this->em->persist($template); $this->em->flush(); return new JsonResponse(['backgroundKey' => $key, 'fileName' => $file->getClientOriginalName()], 201); } #[Route('/api/companies/{id}/card-template/background', name: 'card_bg_get', methods: ['GET'])] public function getBackground(string $id): Response { $company = $this->company($id); $key = $this->templates->findCardForCompany($company)?->getBackgroundPath(); if (!$key || !$this->cardAssets->fileExists($key)) { throw new NotFoundHttpException('Kein Hintergrund-PDF.'); } return new StreamedResponse(function () use ($key) { fpassthru($this->cardAssets->readStream($key)); }, 200, ['Content-Type' => 'application/pdf']); } #[Route('/api/companies/{id}/card-template/background', name: 'card_bg_delete', methods: ['DELETE'])] public function deleteBackground(string $id): JsonResponse { $company = $this->company($id); $template = $this->templates->findCardForCompany($company); if ($template && $template->getBackgroundPath()) { if ($this->cardAssets->fileExists($template->getBackgroundPath())) { $this->cardAssets->delete($template->getBackgroundPath()); } $template->setBackgroundPath(null); $this->em->flush(); } return new JsonResponse(['backgroundKey' => null]); } #[Route('/api/companies/{id}/card-template/font', name: 'card_font_upload', methods: ['POST'])] public function uploadFont(string $id, Request $request): JsonResponse { $company = $this->company($id); $file = $this->file($request); $ext = strtolower((string) $file->getClientOriginalExtension()); if (!in_array($ext, ['ttf', 'otf'], true)) { throw new BadRequestHttpException('Nur TTF/OTF erlaubt.'); } $family = trim((string) $request->request->get('family')) ?: pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME); $template = $this->getOrCreate($company); $key = $this->store($file, $company->getId(), 'font', $ext); $template->addFont($family, $key); $this->em->flush(); return new JsonResponse(['fonts' => $template->getFonts()], 201); } private function file(Request $request): UploadedFile { $file = $request->files->get('file'); if (!$file instanceof UploadedFile) { throw new BadRequestHttpException('Keine Datei (Feld "file") übermittelt.'); } return $file; } /** Lädt die Datei in den Object-Storage und liefert den Key zurück. */ private function store(UploadedFile $file, Uuid $companyId, string $prefix, string $ext): string { $key = sprintf('%s/%s-%s.%s', $companyId->toRfc4122(), $prefix, bin2hex(random_bytes(4)), $ext); $this->cardAssets->write($key, (string) file_get_contents($file->getPathname())); return $key; } private function getOrCreate(Company $company): CardTemplate { return $this->templates->findCardForCompany($company) ?? (new CardTemplate())->setCompany($company); } private function company(string $id): Company { $company = $this->em->getRepository(Company::class)->find(Uuid::fromString($id)); if (!$company instanceof Company) { throw new NotFoundHttpException('Firma nicht gefunden.'); } if ($this->tenant->isPlatformAdmin()) { return $company; } $reseller = $this->tenant->getReseller(); if (null === $reseller || $company->getReseller()?->getId()->equals($reseller->getId()) !== true) { throw new AccessDeniedHttpException('Firma gehört nicht zum eigenen Mandanten.'); } $own = $this->tenant->getCompany(); if (null !== $own && !$company->getId()->equals($own->getId())) { throw new AccessDeniedHttpException('Nur die eigene Firma.'); } return $company; } }