<commit_before>package com.imcode.imcms.domain.service.api;

import com.imcode.imcms.domain.dto.ImageFileDTO;
import com.imcode.imcms.domain.dto.ImageFileUsageDTO;
import com.imcode.imcms.domain.exception.FolderNotExistException;
import com.imcode.imcms.domain.service.CommonContentService;
import com.imcode.imcms.domain.service.ImageFileService;
import com.imcode.imcms.domain.service.ImageService;
import com.imcode.imcms.mapping.ImageCacheMapper;
import com.imcode.imcms.model.CommonContent;
import com.imcode.imcms.persistence.entity.Image;
import com.imcode.imcms.persistence.entity.ImageCacheDomainObject;
import imcode.util.Utility;
import imcode.util.io.FileUtility;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Transactional
class DefaultImageFileService implements ImageFileService {

    private final Function<File, ImageFileDTO> fileToImageFileDTO;
    private final ImageService imageService;
    private final CommonContentService commonContentService;
    private final ImageCacheMapper imageCacheMapper;
    @Value("${ImagePath}")
    private File imagesPath;

    DefaultImageFileService(Function<File, ImageFileDTO> fileToImageFileDTO, ImageService imageService, CommonContentService commonContentService, ImageCacheMapper imageCacheMapper) {
        this.fileToImageFileDTO = fileToImageFileDTO;
        this.imageService = imageService;
        this.commonContentService = commonContentService;
        this.imageCacheMapper = imageCacheMapper;
    }

    @Override
    public List<ImageFileDTO> saveNewImageFiles(String folder, List<MultipartFile> files) throws IOException {

        final File targetFolder = getTargetFolder(folder);
        final ArrayList<ImageFileDTO> imageFileDTOS = new ArrayList<>();
        final Function<File, Boolean> mapAndAddToList = fileToImageFileDTO.andThen(imageFileDTOS::add);

        // do not rewrite using Java Stream API, file transfer can be long operation. in cycle.
        for (MultipartFile file : files) {
            int copiesCount = 1;
            String originalFilename = Utility.normalizeString(file.getOriginalFilename());
            originalFilename = originalFilename.replace("(", "").replace(")", "");
            File destination = new File(targetFolder, originalFilename);

            while (destination.exists()) {
                final String baseName = FilenameUtils.getBaseName(originalFilename);
                final String newName = baseName + copiesCount + "." + FilenameUtils.getExtension(originalFilename);
                destination = new File(targetFolder, newName);
                copiesCount++;
            }

            file.transferTo(destination);
            mapAndAddToList.apply(destination);
        }

        return imageFileDTOS;
    }

    private File getTargetFolder(String folder) {
        final File targetFolder;

        if ((folder == null) || folder.isEmpty()) {
            targetFolder = imagesPath;

        } else {
            targetFolder = new File(imagesPath, folder);

            if (!targetFolder.exists()) {
                throw new FolderNotExistException("Folder " + folder + " not exist! Folder creation is another service job.");

            } else if (!targetFolder.isDirectory()) {
                throw new RuntimeException("Target directory is not a directory...");

            } else if (!targetFolder.canWrite()) {
                throw new RuntimeException("Can't write to specified directory!");
            }
        }
        return targetFolder;
    }

    @Override
    public List<ImageFileUsageDTO> deleteImage(ImageFileDTO imageFileDTO) throws IOException {
        final String imageFileDTOPath = imageFileDTO.getPath();

        List<ImageFileUsageDTO> usages = getImageFileUsages(imageFileDTOPath);

        if (usages.isEmpty()) {
            //No usages found. Can safely remove file
            final File imageFile = new File(imagesPath, imageFileDTOPath);
            FileUtility.forceDelete(imageFile);
        }
        return usages;
    }

    @Override
    public List<ImageFileUsageDTO> getImageFileUsages(String imageFileDTOPath) {
        List<Image> foundUsagesInDocumentContent =
                imageService.getUsedImagesInWorkingAndLatestVersions(imageFileDTOPath.replaceFirst(File.separator, ""));
        List<CommonContent> foundUsagesInCommonContent = commonContentService.findCommonContentWhichUsesImage(imageFileDTOPath);

        List<ImageCacheDomainObject> foundImageCache =
                imageCacheMapper.getAllImageResourcesByResourcePath(File.separator + imagesPath.getName() + imageFileDTOPath);

        List<ImageFileUsageDTO> usages = new ArrayList<>();
        if (!foundUsagesInDocumentContent.isEmpty() || !foundUsagesInCommonContent.isEmpty()) {
            usages.addAll(foundUsagesInDocumentContent.stream()
                    .map(item -> new ImageFileUsageDTO(item.getVersion().getDocId(), item.getVersion().getNo(), item.getIndex(), "content image"))
                    .collect(Collectors.toList())
            );
            usages.addAll(foundUsagesInCommonContent.stream()
                    .map(item -> new ImageFileUsageDTO(item.getDocId(), item.getVersionNo(), null, "menu image"))
                    .collect(Collectors.toList())
            );
            usages.addAll(foundImageCache.stream()
                    .map(item -> new ImageFileUsageDTO(null, null, null, "image cache content"))
                    .collect(Collectors.toList())
            );
        }
        return usages;
    }
}
<commit_msg>IMCMS-376 - Image list - erasing images: - Some  service code update<commit_after>package com.imcode.imcms.domain.service.api;

import com.imcode.imcms.domain.dto.ImageFileDTO;
import com.imcode.imcms.domain.dto.ImageFileUsageDTO;
import com.imcode.imcms.domain.exception.FolderNotExistException;
import com.imcode.imcms.domain.service.CommonContentService;
import com.imcode.imcms.domain.service.ImageFileService;
import com.imcode.imcms.domain.service.ImageService;
import com.imcode.imcms.mapping.ImageCacheMapper;
import com.imcode.imcms.model.CommonContent;
import com.imcode.imcms.persistence.entity.Image;
import com.imcode.imcms.persistence.entity.ImageCacheDomainObject;
import imcode.util.Utility;
import imcode.util.io.FileUtility;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Transactional
class DefaultImageFileService implements ImageFileService {

    private final Function<File, ImageFileDTO> fileToImageFileDTO;
    private final ImageService imageService;
    private final CommonContentService commonContentService;
    private final ImageCacheMapper imageCacheMapper;
    @Value("${ImagePath}")
    private File imagesPath;

    DefaultImageFileService(Function<File, ImageFileDTO> fileToImageFileDTO, ImageService imageService, CommonContentService commonContentService, ImageCacheMapper imageCacheMapper) {
        this.fileToImageFileDTO = fileToImageFileDTO;
        this.imageService = imageService;
        this.commonContentService = commonContentService;
        this.imageCacheMapper = imageCacheMapper;
    }

    @Override
    public List<ImageFileDTO> saveNewImageFiles(String folder, List<MultipartFile> files) throws IOException {

        final File targetFolder = getTargetFolder(folder);
        final ArrayList<ImageFileDTO> imageFileDTOS = new ArrayList<>();
        final Function<File, Boolean> mapAndAddToList = fileToImageFileDTO.andThen(imageFileDTOS::add);

        // do not rewrite using Java Stream API, file transfer can be long operation. in cycle.
        for (MultipartFile file : files) {
            int copiesCount = 1;
            String originalFilename = Utility.normalizeString(file.getOriginalFilename());
            originalFilename = originalFilename.replace("(", "").replace(")", "");
            File destination = new File(targetFolder, originalFilename);

            while (destination.exists()) {
                final String baseName = FilenameUtils.getBaseName(originalFilename);
                final String newName = baseName + copiesCount + "." + FilenameUtils.getExtension(originalFilename);
                destination = new File(targetFolder, newName);
                copiesCount++;
            }

            file.transferTo(destination);
            mapAndAddToList.apply(destination);
        }

        return imageFileDTOS;
    }

    private File getTargetFolder(String folder) {
        final File targetFolder;

        if ((folder == null) || folder.isEmpty()) {
            targetFolder = imagesPath;

        } else {
            targetFolder = new File(imagesPath, folder);

            if (!targetFolder.exists()) {
                throw new FolderNotExistException("Folder " + folder + " not exist! Folder creation is another service job.");

            } else if (!targetFolder.isDirectory()) {
                throw new RuntimeException("Target directory is not a directory...");

            } else if (!targetFolder.canWrite()) {
                throw new RuntimeException("Can't write to specified directory!");
            }
        }
        return targetFolder;
    }

    @Override
    public List<ImageFileUsageDTO> deleteImage(ImageFileDTO imageFileDTO) throws IOException {
        final String imageFileDTOPath = imageFileDTO.getPath();

        List<ImageFileUsageDTO> usages = getImageFileUsages(imageFileDTOPath);

        if (usages.isEmpty()) {
            //No usages found. Can safely remove file
            final File imageFile = new File(imagesPath, imageFileDTOPath);
            FileUtility.forceDelete(imageFile);
        }
        return usages;
    }

    @Override
    public List<ImageFileUsageDTO> getImageFileUsages(String imageFileDTOPath) {
        List<Image> foundUsagesInDocumentContent =
                imageService.getUsedImagesInWorkingAndLatestVersions(imageFileDTOPath.startsWith(File.separator) ? imageFileDTOPath.substring(1) : imageFileDTOPath);
        List<CommonContent> foundUsagesInCommonContent = commonContentService.findCommonContentWhichUsesImage(imageFileDTOPath);

        List<ImageCacheDomainObject> foundImageCache =
                imageCacheMapper.getAllImageResourcesByResourcePath(File.separator + imagesPath.getName() + imageFileDTOPath);

        List<ImageFileUsageDTO> usages = new ArrayList<>();
        if (!foundUsagesInDocumentContent.isEmpty() || !foundUsagesInCommonContent.isEmpty() || !foundImageCache.isEmpty()) {
            usages.addAll(foundUsagesInDocumentContent.stream()
                    .map(item -> new ImageFileUsageDTO(item.getVersion().getDocId(), item.getVersion().getNo(), item.getIndex(), "content image"))
                    .collect(Collectors.toList())
            );
            usages.addAll(foundUsagesInCommonContent.stream()
                    .map(item -> new ImageFileUsageDTO(item.getDocId(), item.getVersionNo(), null, "menu image"))
                    .collect(Collectors.toList())
            );
            usages.addAll(foundImageCache.stream()
                    .map(item -> new ImageFileUsageDTO(null, null, null, "image cache content"))
                    .collect(Collectors.toList())
            );
        }
        return usages;
    }
}

{'fraction_non_alphanumeric': 0.09340109981669721, 'fraction_numerical': 0.0004999166805532411, 'mean_word_length': 3.22938689217759, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3526135', 'n_tokens_mistral': 3133, 'n_tokens_neox': 3098, 'n_words': 629}