AttachmentController.java
package com.wilzwert.myjobs.infrastructure.api.rest.controller;
import com.wilzwert.myjobs.core.domain.model.AttachmentFileInfo;
import com.wilzwert.myjobs.core.domain.model.attachment.command.CreateAttachmentCommand;
import com.wilzwert.myjobs.core.domain.model.attachment.command.DeleteAttachmentCommand;
import com.wilzwert.myjobs.core.domain.model.attachment.command.DownloadAttachmentCommand;
import com.wilzwert.myjobs.core.domain.model.attachment.Attachment;
import com.wilzwert.myjobs.core.domain.model.DownloadableFile;
import com.wilzwert.myjobs.core.domain.model.attachment.AttachmentId;
import com.wilzwert.myjobs.core.domain.model.attachment.ports.driving.GetAttachmentFileInfoUseCase;
import com.wilzwert.myjobs.core.domain.model.job.JobId;
import com.wilzwert.myjobs.core.domain.model.job.ports.driving.AddAttachmentToJobUseCase;
import com.wilzwert.myjobs.core.domain.model.job.ports.driving.DeleteAttachmentUseCase;
import com.wilzwert.myjobs.core.domain.model.attachment.ports.driving.DownloadAttachmentUseCase;
import com.wilzwert.myjobs.infrastructure.api.rest.dto.*;
import com.wilzwert.myjobs.infrastructure.mapper.AttachmentFileInfoMapper;
import com.wilzwert.myjobs.infrastructure.persistence.mongo.mapper.AttachmentMapper;
import com.wilzwert.myjobs.infrastructure.security.service.UserDetailsImpl;
import com.wilzwert.myjobs.infrastructure.storage.StorageException;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;
import java.io.*;
import java.nio.file.Files;
import java.util.Base64;
import java.util.UUID;
/**
* @author Wilhelm Zwertvaegher
*/
@RestController
@Slf4j
@RequestMapping("/api/jobs")
public class AttachmentController {
private final AttachmentMapper attachmentMapper;
private final AddAttachmentToJobUseCase addAttachmentToJobUseCase;
private final DownloadAttachmentUseCase downloadAttachmentUseCase;
private final DeleteAttachmentUseCase deleteAttachmentUseCase;
private final GetAttachmentFileInfoUseCase getAttachmentFileInfoUseCase;
private final AttachmentFileInfoMapper attachmentFileInfoMapper;
public AttachmentController(
AddAttachmentToJobUseCase addAttachmentToJobUseCase,
DownloadAttachmentUseCase downloadAttachmentUseCase,
DeleteAttachmentUseCase deleteAttachmentUseCase,
GetAttachmentFileInfoUseCase getAttachmentFileInfoUseCase,
AttachmentMapper attachmentMapper,
AttachmentFileInfoMapper attachmentFileInfoMapper
) {
this.addAttachmentToJobUseCase = addAttachmentToJobUseCase;
this.downloadAttachmentUseCase = downloadAttachmentUseCase;
this.deleteAttachmentUseCase = deleteAttachmentUseCase;
this.getAttachmentFileInfoUseCase = getAttachmentFileInfoUseCase;
this.attachmentMapper = attachmentMapper;
this.attachmentFileInfoMapper = attachmentFileInfoMapper;
}
@PostMapping("{jobId}/attachments")
@ResponseStatus(HttpStatus.CREATED)
public AttachmentResponse createAttachment(@PathVariable("jobId") String jobId, @RequestBody @Valid CreateAttachmentRequest createAttachmentRequest, Authentication authentication) {
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
// put file contents in temp file
try {
File tempFile = File.createTempFile("atta", "chment");
String[] parts = createAttachmentRequest.getContent().split(",");
if (parts.length != 2) {
throw new IllegalArgumentException("Invalid base64 content");
}
byte[] fileData = Base64.getDecoder().decode(parts[1]);
try (FileOutputStream fos = new FileOutputStream(tempFile)) {
fos.write(fileData);
}
CreateAttachmentCommand command = attachmentMapper.toCommand(createAttachmentRequest, userDetails.getId(), new JobId(UUID.fromString(jobId)), tempFile);
Attachment attachment = addAttachmentToJobUseCase.addAttachmentToJob(command);
Files.delete(tempFile.toPath());
return attachmentMapper.toResponse(attachment);
} catch (IOException e) {
throw new StorageException("an io exception occurred", e);
}
}
@DeleteMapping("{jobId}/attachments/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteAttachment(@PathVariable("jobId") String jobId, @PathVariable("id") String id, Authentication authentication) {
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
deleteAttachmentUseCase.deleteAttachment(new DeleteAttachmentCommand(new AttachmentId(UUID.fromString(id)), userDetails.getId(), new JobId(UUID.fromString(jobId))));
}
@GetMapping("{jobId}/attachments/{id}/file")
public ResponseEntity<Resource> downloadFile(@PathVariable("jobId") String jobId, @PathVariable("id") String id, Authentication authentication) {
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
DownloadableFile downloadableFile = downloadAttachmentUseCase.downloadAttachment(new DownloadAttachmentCommand(id, userDetails.getId(), new JobId(UUID.fromString(jobId))));
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(downloadableFile.contentType()))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + downloadableFile.filename() + "\"")
.body(new FileSystemResource(downloadableFile.path()));
}
@GetMapping("{jobId}/attachments/{id}/file/info")
public ProtectedFileResponse getProtectedFile(@PathVariable("jobId") String jobId, @PathVariable("id") String id, Authentication authentication) {
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
AttachmentFileInfo info = getAttachmentFileInfoUseCase.getAttachmentFileInfo(new DownloadAttachmentCommand(id, userDetails.getId(), new JobId(UUID.fromString(jobId))));
return attachmentFileInfoMapper.toResponse(info);
}
}