using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using DysonNetwork.Drive.Interfaces; using DysonNetwork.Drive.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; namespace DysonNetwork.Drive.Controllers { [ApiController] [Route("api/files")] [Authorize] public class FileController : ControllerBase { private readonly IFileService _fileService; private readonly ILogger _logger; public FileController(IFileService fileService, ILogger logger) { _fileService = fileService ?? throw new ArgumentNullException(nameof(fileService)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } [HttpGet("{fileId}")] [ProducesResponseType(typeof(FileResult), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetFile(Guid fileId, CancellationToken cancellationToken = default) { try { var file = await _fileService.GetFileAsync(fileId, cancellationToken); var stream = await _fileService.DownloadFileAsync(fileId, cancellationToken); return File(stream, file.MimeType, file.OriginalName); } catch (FileNotFoundException ex) { _logger.LogWarning(ex, "File not found: {FileId}", fileId); return NotFound(new { message = $"File with ID {fileId} not found." }); } catch (Exception ex) { _logger.LogError(ex, "Error retrieving file: {FileId}", fileId); return StatusCode(StatusCodes.Status500InternalServerError, new { message = "An error occurred while retrieving the file." }); } } [HttpPost("upload")] [ProducesResponseType(typeof(CloudFile), StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status400BadRequest)] public async Task UploadFile(IFormFile file, CancellationToken cancellationToken = default) { if (file == null || file.Length == 0) { return BadRequest(new { message = "No file uploaded." }); } try { using var stream = file.OpenReadStream(); var uploadedFile = await _fileService.UploadFileAsync( stream, file.FileName, file.ContentType, null, cancellationToken); return CreatedAtAction( nameof(GetFile), new { fileId = uploadedFile.Id }, uploadedFile); } catch (Exception ex) { _logger.LogError(ex, "Error uploading file: {FileName}", file?.FileName); return StatusCode(StatusCodes.Status500InternalServerError, new { message = "An error occurred while uploading the file." }); } } [HttpDelete("{fileId}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task DeleteFile(Guid fileId, CancellationToken cancellationToken = default) { try { var deleted = await _fileService.DeleteFileAsync(fileId, cancellationToken); if (!deleted) { return NotFound(new { message = $"File with ID {fileId} not found." }); } return NoContent(); } catch (Exception ex) { _logger.LogError(ex, "Error deleting file: {FileId}", fileId); return StatusCode(StatusCodes.Status500InternalServerError, new { message = "An error occurred while deleting the file." }); } } [HttpGet("{fileId}/metadata")] [ProducesResponseType(typeof(CloudFile), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetFileMetadata(Guid fileId, CancellationToken cancellationToken = default) { try { var file = await _fileService.GetFileAsync(fileId, cancellationToken); return Ok(file); } catch (FileNotFoundException ex) { _logger.LogWarning(ex, "File not found: {FileId}", fileId); return NotFound(new { message = $"File with ID {fileId} not found." }); } catch (Exception ex) { _logger.LogError(ex, "Error retrieving file metadata: {FileId}", fileId); return StatusCode(StatusCodes.Status500InternalServerError, new { message = "An error occurred while retrieving file metadata." }); } } [HttpPut("{fileId}/metadata")] [ProducesResponseType(typeof(CloudFile), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task UpdateFileMetadata( Guid fileId, [FromBody] Dictionary metadata, CancellationToken cancellationToken = default) { if (metadata == null || metadata.Count == 0) { return BadRequest(new { message = "No metadata provided." }); } try { var updatedFile = await _fileService.UpdateFileMetadataAsync(fileId, metadata, cancellationToken); return Ok(updatedFile); } catch (FileNotFoundException ex) { _logger.LogWarning(ex, "File not found: {FileId}", fileId); return NotFound(new { message = $"File with ID {fileId} not found." }); } catch (Exception ex) { _logger.LogError(ex, "Error updating file metadata: {FileId}", fileId); return StatusCode(StatusCodes.Status500InternalServerError, new { message = "An error occurred while updating file metadata." }); } } [HttpGet("{fileId}/url")] [ProducesResponseType(typeof(string), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetFileUrl(Guid fileId, [FromQuery] int? expiresInSeconds = null, CancellationToken cancellationToken = default) { try { TimeSpan? expiry = expiresInSeconds.HasValue ? TimeSpan.FromSeconds(expiresInSeconds.Value) : null; var url = await _fileService.GetFileUrlAsync(fileId, expiry, cancellationToken); return Ok(new { url }); } catch (FileNotFoundException ex) { _logger.LogWarning(ex, "File not found: {FileId}", fileId); return NotFound(new { message = $"File with ID {fileId} not found." }); } catch (Exception ex) { _logger.LogError(ex, "Error generating file URL: {FileId}", fileId); return StatusCode(StatusCodes.Status500InternalServerError, new { message = "An error occurred while generating the file URL." }); } } [HttpGet("{fileId}/thumbnail")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetFileThumbnail( Guid fileId, [FromQuery] int? width = null, [FromQuery] int? height = null, [FromQuery] int? expiresInSeconds = null, CancellationToken cancellationToken = default) { try { TimeSpan? expiry = expiresInSeconds.HasValue ? TimeSpan.FromSeconds(expiresInSeconds.Value) : null; var url = await _fileService.GetFileThumbnailUrlAsync( fileId, width, height, expiry, cancellationToken); return Ok(new { url }); } catch (FileNotFoundException ex) { _logger.LogWarning(ex, "File not found: {FileId}", fileId); return NotFound(new { message = $"File with ID {fileId} not found." }); } catch (Exception ex) { _logger.LogError(ex, "Error generating thumbnail URL: {FileId}", fileId); return StatusCode(StatusCodes.Status500InternalServerError, new { message = "An error occurred while generating the thumbnail URL." }); } } } }