- Created Document entity with properties for file management, including filename, originalFilename, mimeType, size, uploadedAt, uploadedBy, relatedEntity, relatedEntityId, and description. - Implemented DocumentRepository for querying documents by related entity and user. - Added GitRepository entity with properties for managing Git repositories, including URL, localPath, branch, provider, accessToken, project, lastSync, name, description, createdAt, and updatedAt. - Implemented GitRepositoryRepository for querying repositories by project. - Developed GitHubService for interacting with GitHub API, including methods for fetching commits, contributions, branches, and repository info. - Developed GitService for local Git repository interactions, including methods for fetching commits, contributions, branches, and repository info. - Developed GiteaService for interacting with Gitea API, including methods for fetching commits, contributions, branches, repository info, and testing connection.
160 lines
5.8 KiB
PHP
160 lines
5.8 KiB
PHP
<?php
|
|
|
|
namespace App\Controller;
|
|
|
|
use App\Entity\Document;
|
|
use App\Entity\User;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
use Symfony\Component\HttpFoundation\File\Exception\FileException;
|
|
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
|
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
|
|
use Symfony\Component\Routing\Annotation\Route;
|
|
use Symfony\Component\String\Slugger\SluggerInterface;
|
|
|
|
#[Route('/api/documents')]
|
|
class DocumentController extends AbstractController
|
|
{
|
|
private string $uploadsDirectory;
|
|
|
|
public function __construct(
|
|
private EntityManagerInterface $entityManager,
|
|
private SluggerInterface $slugger
|
|
) {
|
|
// Get project directory from kernel parameter
|
|
$this->uploadsDirectory = '%kernel.project_dir%/var/uploads/documents';
|
|
}
|
|
|
|
#[Route('/upload', name: 'api_document_upload', methods: ['POST'])]
|
|
public function upload(Request $request): JsonResponse
|
|
{
|
|
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
|
|
|
|
// Resolve the actual path
|
|
$uploadsDirectory = str_replace('%kernel.project_dir%', $this->getParameter('kernel.project_dir'), $this->uploadsDirectory);
|
|
|
|
// Erstelle Upload-Verzeichnis falls nicht vorhanden
|
|
if (!is_dir($uploadsDirectory)) {
|
|
mkdir($uploadsDirectory, 0755, true);
|
|
}
|
|
|
|
/** @var UploadedFile $file */
|
|
$file = $request->files->get('file');
|
|
if (!$file) {
|
|
return $this->json(['error' => 'Keine Datei hochgeladen'], 400);
|
|
}
|
|
|
|
// Validierung
|
|
$maxSize = 10 * 1024 * 1024; // 10MB
|
|
if ($file->getSize() > $maxSize) {
|
|
return $this->json(['error' => 'Datei ist zu groß (max. 10MB)'], 400);
|
|
}
|
|
|
|
// Erlaubte Dateitypen
|
|
$allowedMimeTypes = [
|
|
// Bilder
|
|
'image/jpeg',
|
|
'image/jpg',
|
|
'image/png',
|
|
'image/gif',
|
|
'image/webp',
|
|
'image/svg+xml',
|
|
// PDF
|
|
'application/pdf',
|
|
// Excel
|
|
'application/vnd.ms-excel',
|
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
// CSV
|
|
'text/csv',
|
|
'text/plain',
|
|
// Word
|
|
'application/msword',
|
|
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
];
|
|
|
|
$mimeType = $file->getClientMimeType();
|
|
if (!in_array($mimeType, $allowedMimeTypes)) {
|
|
return $this->json([
|
|
'error' => 'Dateityp nicht erlaubt. Erlaubt sind: Bilder (JPG, PNG, GIF, WebP, SVG), PDF, Excel (XLS, XLSX), CSV und Word (DOC, DOCX)'
|
|
], 400);
|
|
}
|
|
|
|
$relatedEntity = $request->request->get('relatedEntity');
|
|
$relatedEntityId = $request->request->get('relatedEntityId');
|
|
|
|
if (!$relatedEntity || !$relatedEntityId) {
|
|
return $this->json(['error' => 'relatedEntity und relatedEntityId sind erforderlich'], 400);
|
|
}
|
|
|
|
// Datei-Informationen VOR dem Move speichern
|
|
$originalFilename = $file->getClientOriginalName();
|
|
$mimeType = $file->getClientMimeType();
|
|
$fileSize = $file->getSize();
|
|
|
|
// Sichere Dateinamen generieren
|
|
$safeFilename = $this->slugger->slug(pathinfo($originalFilename, PATHINFO_FILENAME));
|
|
$newFilename = $safeFilename . '-' . uniqid() . '.' . $file->guessExtension();
|
|
|
|
try {
|
|
$file->move($uploadsDirectory, $newFilename);
|
|
} catch (FileException $e) {
|
|
return $this->json(['error' => 'Datei konnte nicht gespeichert werden'], 500);
|
|
}
|
|
|
|
// Document Entity erstellen
|
|
$document = new Document();
|
|
$document->setFilename($newFilename);
|
|
$document->setOriginalFilename($originalFilename);
|
|
$document->setMimeType($mimeType);
|
|
$document->setSize($fileSize);
|
|
$document->setRelatedEntity($relatedEntity);
|
|
$document->setRelatedEntityId((int) $relatedEntityId);
|
|
$document->setDescription($request->request->get('description'));
|
|
|
|
/** @var User $user */
|
|
$user = $this->getUser();
|
|
$document->setUploadedBy($user);
|
|
|
|
$this->entityManager->persist($document);
|
|
$this->entityManager->flush();
|
|
|
|
return $this->json($document, 201, [], ['groups' => 'document:read']);
|
|
}
|
|
|
|
#[Route('/{id}/download', name: 'api_document_download', methods: ['GET'])]
|
|
public function download(Document $document): BinaryFileResponse
|
|
{
|
|
$this->denyAccessUnlessGranted('VIEW', $document);
|
|
|
|
$uploadsDirectory = str_replace('%kernel.project_dir%', $this->getParameter('kernel.project_dir'), $this->uploadsDirectory);
|
|
$filePath = $uploadsDirectory . '/' . $document->getFilename();
|
|
|
|
if (!file_exists($filePath)) {
|
|
throw $this->createNotFoundException('Datei nicht gefunden');
|
|
}
|
|
|
|
$response = new BinaryFileResponse($filePath);
|
|
|
|
// Inline anzeigen statt Download für gängige Dateitypen
|
|
$mimeType = $document->getMimeType();
|
|
$inlineTypes = ['application/pdf', 'image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp'];
|
|
|
|
if (in_array($mimeType, $inlineTypes)) {
|
|
$response->setContentDisposition(
|
|
ResponseHeaderBag::DISPOSITION_INLINE,
|
|
$document->getOriginalFilename()
|
|
);
|
|
} else {
|
|
$response->setContentDisposition(
|
|
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
|
|
$document->getOriginalFilename()
|
|
);
|
|
}
|
|
|
|
return $response;
|
|
}
|
|
}
|