diff --git a/Webshop.Api/Controllers/Admin/FileUploadController.cs b/Webshop.Api/Controllers/Admin/FileUploadController.cs new file mode 100644 index 0000000..85b2695 --- /dev/null +++ b/Webshop.Api/Controllers/Admin/FileUploadController.cs @@ -0,0 +1,47 @@ +// src/Webshop.Api/Controllers/Admin/FileUploadController.cs +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System.IO; +using System.Threading.Tasks; +using Webshop.Application.DTOs; +using Webshop.Domain.Interfaces; + +namespace Webshop.Api.Controllers.Admin +{ + [ApiController] + [Route("api/v1/admin/files")] + [Authorize(Roles = "Admin")] + public class FileUploadController : ControllerBase + { + private readonly IFileStorageService _fileStorageService; + + public FileUploadController(IFileStorageService fileStorageService) + { + _fileStorageService = fileStorageService; + } + + [HttpPost("upload")] + public async Task> UploadImage(IFormFile file) + { + if (file == null || file.Length == 0) + { + return BadRequest(new { Message = "Es wurde keine Datei hochgeladen." }); + } + + // Optional: Validierung des Dateityps + if (!file.ContentType.StartsWith("image/")) + { + return BadRequest(new { Message = "Nur Bilddateien sind erlaubt." }); + } + + // Öffne einen Stream aus der hochgeladenen Datei + await using var stream = file.OpenReadStream(); + + // Speichere die Datei mit dem Service und erhalte die URL + var fileUrl = await _fileStorageService.SaveFileAsync(stream, file.FileName, file.ContentType); + + return Ok(new FileUploadResultDto { Url = fileUrl }); + } + } +} \ No newline at end of file diff --git a/Webshop.Api/Program.cs b/Webshop.Api/Program.cs index 804a813..8158db2 100644 --- a/Webshop.Api/Program.cs +++ b/Webshop.Api/Program.cs @@ -289,7 +289,6 @@ var forwardedHeadersOptions = new ForwardedHeadersOptions ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto }; - // << Statische Dateien aus wwwroot bereitstellen (z.B. /uploads/xyz.jpg) >> app.UseStaticFiles(); diff --git a/Webshop.Application/DTOs/Images/FileUploadResultDto.cs b/Webshop.Application/DTOs/Images/FileUploadResultDto.cs new file mode 100644 index 0000000..85f737f --- /dev/null +++ b/Webshop.Application/DTOs/Images/FileUploadResultDto.cs @@ -0,0 +1,8 @@ +// src/Webshop.Application/DTOs/Images/FileUploadResultDto.cs +namespace Webshop.Application.DTOs +{ + public class FileUploadResultDto + { + public string Url { get; set; } = string.Empty; + } +} \ No newline at end of file diff --git a/Webshop.Application/Webshop.Application.csproj b/Webshop.Application/Webshop.Application.csproj index 96e600f..649d1f2 100644 --- a/Webshop.Application/Webshop.Application.csproj +++ b/Webshop.Application/Webshop.Application.csproj @@ -23,8 +23,4 @@ - - - - \ No newline at end of file diff --git a/Webshop.Domain/Interfaces/IFileStorageService.cs b/Webshop.Domain/Interfaces/IFileStorageService.cs new file mode 100644 index 0000000..16af061 --- /dev/null +++ b/Webshop.Domain/Interfaces/IFileStorageService.cs @@ -0,0 +1,18 @@ +// src/Webshop.Domain/Interfaces/IFileStorageService.cs +using System.IO; +using System.Threading.Tasks; + +namespace Webshop.Domain.Interfaces +{ + public interface IFileStorageService + { + /// + /// Speichert eine Datei und gibt die öffentlich zugängliche URL zurück. + /// + /// Der Stream der Datei. + /// Der ursprüngliche Dateiname (zur Ermittlung der Erweiterung). + /// Der MIME-Typ der Datei. + /// Die öffentliche URL der gespeicherten Datei. + Task SaveFileAsync(Stream fileStream, string fileName, string contentType); + } +} \ No newline at end of file diff --git a/Webshop.Infrastructure/Services/LocalFileStorageService.cs b/Webshop.Infrastructure/Services/LocalFileStorageService.cs new file mode 100644 index 0000000..4e1bdce --- /dev/null +++ b/Webshop.Infrastructure/Services/LocalFileStorageService.cs @@ -0,0 +1,51 @@ +// src/Webshop.Infrastructure/Services/LocalFileStorageService.cs +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using System; +using System.IO; +using System.Threading.Tasks; +using Webshop.Domain.Interfaces; + +namespace Webshop.Infrastructure.Services +{ + public class LocalFileStorageService : IFileStorageService + { + private readonly IWebHostEnvironment _env; + private readonly IHttpContextAccessor _httpContextAccessor; + + public LocalFileStorageService(IWebHostEnvironment env, IHttpContextAccessor httpContextAccessor) + { + _env = env; + _httpContextAccessor = httpContextAccessor; + } + + public async Task SaveFileAsync(Stream fileStream, string fileName, string contentType) + { + // Erstelle einen eindeutigen Dateinamen, um Kollisionen zu vermeiden + var fileExtension = Path.GetExtension(fileName); + var uniqueFileName = $"{Guid.NewGuid()}{fileExtension}"; + + // Definiere den Speicherort im wwwroot-Ordner + var uploadsFolderPath = Path.Combine(_env.WebRootPath, "uploads"); + if (!Directory.Exists(uploadsFolderPath)) + { + Directory.CreateDirectory(uploadsFolderPath); + } + + var filePath = Path.Combine(uploadsFolderPath, uniqueFileName); + + // Speichere den Stream in die Datei + await using (var outputStream = new FileStream(filePath, FileMode.Create)) + { + await fileStream.CopyToAsync(outputStream); + } + + // Erstelle die öffentliche URL + var request = _httpContextAccessor.HttpContext.Request; + var baseUrl = $"{request.Scheme}://{request.Host}"; + var fileUrl = $"{baseUrl}/uploads/{uniqueFileName}"; + + return fileUrl; + } + } +} \ No newline at end of file diff --git a/Webshop.Infrastructure/Webshop.Infrastructure.csproj b/Webshop.Infrastructure/Webshop.Infrastructure.csproj index 540032e..567e0e4 100644 --- a/Webshop.Infrastructure/Webshop.Infrastructure.csproj +++ b/Webshop.Infrastructure/Webshop.Infrastructure.csproj @@ -24,8 +24,4 @@ - - - -