LocalFileStorage.java

package com.wilzwert.myjobs.infrastructure.storage;


import com.wilzwert.myjobs.core.domain.model.attachment.AttachmentId;
import com.wilzwert.myjobs.core.domain.model.attachment.exception.AttachmentFileNotReadableException;
import com.wilzwert.myjobs.core.domain.model.DownloadableFile;
import com.wilzwert.myjobs.core.domain.model.job.JobId;
import com.wilzwert.myjobs.core.domain.shared.ports.driven.FileStorage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;


/**
 * @author Wilhelm Zwertvaegher
 */
@Profile("dev")
@Component
public class LocalFileStorage implements FileStorage {

    private final Path storageLocation; // Dossier local

    private final String backendUrl;

    @Autowired
    public LocalFileStorage(@Value("${application.backend.url}") final String backendUrl) {
        this(backendUrl, Paths.get("uploads"));
    }

    public LocalFileStorage(String backendUrl, Path storageLocation) {
        try {
            if (!Files.exists(storageLocation)) {
                Files.createDirectories(storageLocation); // Crée le répertoire s'il n'existe pas
            }
        } catch (IOException e) {
            throw new StorageException("Failed to initialize local storage", e);
        }
        this.storageLocation = storageLocation;
        this.backendUrl = backendUrl;
    }

    @Override
    public DownloadableFile store(File file, String targetFilename, String originalFilename) {
        try {
            Path targetLocation = storageLocation.resolve(targetFilename);
            Path directory = targetLocation.getParent();
            if (!Files.exists(directory)) {
                Files.createDirectories(directory);
            }
            Files.copy(file.toPath(), targetLocation);
            // we use the targetlocation as fileid
            return new DownloadableFile(targetLocation.toString(), targetLocation.toString(), getContentType(originalFilename, targetLocation.toString()), "");
        } catch (IOException e) {
            throw new StorageException("Failed to store file", e);
        }
    }

    @Override
    public void delete(String fileId) {
        try {
            Files.delete(Paths.get(fileId));
        } catch (IOException e) {
            throw new StorageException("Failed to delete file", e);
        }
    }

    @Override
    public DownloadableFile retrieve(String fileId, String originalFilename) {
        Path filePath = Paths.get(fileId);
        FileSystemResource resource = new FileSystemResource(filePath.toFile());
        if (!resource.exists() || !resource.isReadable()) {
            throw new AttachmentFileNotReadableException();
        }

        try {
            // for now, target path and fileId are the same
            return new DownloadableFile(filePath.toString(), filePath.toString(), getContentType(originalFilename, fileId), originalFilename);
        }
        catch (IOException e) {
            throw new AttachmentFileNotReadableException();
        }
    }

    @Override
    public String generateProtectedUrl(JobId jobId, AttachmentId attachmentId, String fileId) {
        return backendUrl+"/api/jobs/"+jobId.value().toString()+"/attachments/"+attachmentId.value().toString()+"/file";
    }

    private String getContentType(String originalFilename, String filePath) throws IOException {
        // get file MIME type
        String contentType = Files.probeContentType(Paths.get(filePath));
        if(contentType == null) {
            Optional<MediaType> mimeTypeOptional = MediaTypeFactory.getMediaType(originalFilename);
            if(mimeTypeOptional.isPresent()) {
                contentType = mimeTypeOptional.get().toString();
            }
        }
        if (contentType == null) {
            contentType = "application/octet-stream"; // default value
        }

        return contentType;
    }
}