<commit_before>/* $This file is distributed under the terms of the license in /doc/license.txt$ */

package edu.cornell.mannlib.vitro.webapp.controller.freemarker;

import static edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.MAXIMUM_FILE_SIZE;
import static edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.PARAMETER_UPLOADED_FILE;
import static edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.THUMBNAIL_HEIGHT;
import static edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.THUMBNAIL_WIDTH;
import static edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServletRequest.FILE_ITEM_MAP;
import static edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServletRequest.FILE_UPLOAD_EXCEPTION;

import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.CropRectangle;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.Dimensions;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.UserMistakeException;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
import edu.cornell.mannlib.vitro.webapp.filestorage.FileModelHelper;
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileAlreadyExistsException;
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorage;
import edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServletRequest;

/**
 * Handle the mechanics of validating, storing, and deleting file images.
 */
public class ImageUploadHelper {
	private static final Log log = LogFactory.getLog(ImageUploadHelper.class);

	/**
	 * If the main image is larger than this, it will be displayed at reduced
	 * scale.
	 */
	public static final int MAXIMUM_IMAGE_DISPLAY_WIDTH = 500;

	/** Recognized file extensions mapped to MIME-types. */
	private static final Map<String, String> RECOGNIZED_FILE_TYPES = createFileTypesMap();

	private static Map<String, String> createFileTypesMap() {
		Map<String, String> map = new HashMap<String, String>();
		map.put(".gif", "image/gif");
		map.put(".png", "image/png");
		map.put(".jpg", "image/jpeg");
		map.put(".jpeg", "image/jpeg");
		map.put(".jpe", "image/jpeg");
		return Collections.unmodifiableMap(map);
	}

	private final FileModelHelper fileModelHelper;
	private final FileStorage fileStorage;

	ImageUploadHelper(FileStorage fileStorage, WebappDaoFactory webAppDaoFactory) {
		this.fileModelHelper = new FileModelHelper(webAppDaoFactory);
		this.fileStorage = fileStorage;
	}

	/**
	 * The image must be present and non-empty, and must have a mime-type that
	 * represents an image we support.
	 * 
	 * We rely on the fact that a {@link FileUploadServletRequest} will always
	 * have a map of {@link FileItem}s, even if it is empty. However, that map
	 * may not contain the field that we want, or that field may contain an
	 * empty file.
	 * 
	 * @throws UserMistakeException
	 *             if there is no file, if it is empty, or if it is not an image
	 *             file.
	 */
	@SuppressWarnings("unchecked")
	FileItem validateImageFromRequest(HttpServletRequest request)
			throws UserMistakeException {
		Object exception = request.getAttribute(FILE_UPLOAD_EXCEPTION);
		if (exception != null) {
			int limit = MAXIMUM_FILE_SIZE / (1024 * 1024);
			throw new UserMistakeException(
					"Please upload an image smaller than " + limit
							+ " megabytes");
		}

		Map<String, List<FileItem>> map = (Map<String, List<FileItem>>) request
				.getAttribute(FILE_ITEM_MAP);
		if (map == null) {
			throw new IllegalStateException("Failed to parse the "
					+ "multi-part request for uploading an image.");
		}
		List<FileItem> list = map.get(PARAMETER_UPLOADED_FILE);
		if ((list == null) || list.isEmpty()) {
			throw new UserMistakeException("The form did not contain a '"
					+ PARAMETER_UPLOADED_FILE + "' field.");
		}

		FileItem file = list.get(0);
		if (file.getSize() == 0) {
			throw new UserMistakeException("No file was uploaded in '"
					+ PARAMETER_UPLOADED_FILE + "'");
		}

		String filename = getSimpleFilename(file);
		String mimeType = getMimeType(file);
		if (!RECOGNIZED_FILE_TYPES.containsValue(mimeType)) {
			throw new UserMistakeException("'" + filename
					+ "' is not a recognized image file type. "
					+ "These are the recognized types: "
					+ RECOGNIZED_FILE_TYPES);
		}

		return file;
	}

	/**
	 * If this entity already had a main image, remove the connection. If the
	 * image and the thumbnail are no longer used by anyone, remove them from
	 * the model, and from the file system.
	 */
	void removeExistingImage(Individual person) {
		Individual mainImage = fileModelHelper.removeMainImage(person);<commit_msg>NIHVIVO-577: Improved error message copy<commit_after>/* $This file is distributed under the terms of the license in /doc/license.txt$ */

package edu.cornell.mannlib.vitro.webapp.controller.freemarker;

import static edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.MAXIMUM_FILE_SIZE;
import static edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.PARAMETER_UPLOADED_FILE;
import static edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.THUMBNAIL_HEIGHT;
import static edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.THUMBNAIL_WIDTH;
import static edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServletRequest.FILE_ITEM_MAP;
import static edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServletRequest.FILE_UPLOAD_EXCEPTION;

import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.CropRectangle;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.Dimensions;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.UserMistakeException;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
import edu.cornell.mannlib.vitro.webapp.filestorage.FileModelHelper;
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileAlreadyExistsException;
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorage;
import edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServletRequest;

/**
 * Handle the mechanics of validating, storing, and deleting file images.
 */
public class ImageUploadHelper {
	private static final Log log = LogFactory.getLog(ImageUploadHelper.class);

	/**
	 * If the main image is larger than this, it will be displayed at reduced
	 * scale.
	 */
	public static final int MAXIMUM_IMAGE_DISPLAY_WIDTH = 500;

	/** Recognized file extensions mapped to MIME-types. */
	private static final Map<String, String> RECOGNIZED_FILE_TYPES = createFileTypesMap();

	private static Map<String, String> createFileTypesMap() {
		Map<String, String> map = new HashMap<String, String>();
		map.put(".gif", "image/gif");
		map.put(".png", "image/png");
		map.put(".jpg", "image/jpeg");
		map.put(".jpeg", "image/jpeg");
		map.put(".jpe", "image/jpeg");
		return Collections.unmodifiableMap(map);
	}

	private final FileModelHelper fileModelHelper;
	private final FileStorage fileStorage;

	ImageUploadHelper(FileStorage fileStorage, WebappDaoFactory webAppDaoFactory) {
		this.fileModelHelper = new FileModelHelper(webAppDaoFactory);
		this.fileStorage = fileStorage;
	}

	/**
	 * The image must be present and non-empty, and must have a mime-type that
	 * represents an image we support.
	 * 
	 * We rely on the fact that a {@link FileUploadServletRequest} will always
	 * have a map of {@link FileItem}s, even if it is empty. However, that map
	 * may not contain the field that we want, or that field may contain an
	 * empty file.
	 * 
	 * @throws UserMistakeException
	 *             if there is no file, if it is empty, or if it is not an image
	 *             file.
	 */
	@SuppressWarnings("unchecked")
	FileItem validateImageFromRequest(HttpServletRequest request)
			throws UserMistakeException {
		Object exception = request.getAttribute(FILE_UPLOAD_EXCEPTION);
		if (exception != null) {
			int limit = MAXIMUM_FILE_SIZE / (1024 * 1024);
			throw new UserMistakeException(
					"Please upload an image smaller than " + limit
							+ " megabytes");
		}

		Map<String, List<FileItem>> map = (Map<String, List<FileItem>>) request
				.getAttribute(FILE_ITEM_MAP);
		if (map == null) {
			throw new IllegalStateException("Failed to parse the "
					+ "multi-part request for uploading an image.");
		}
		List<FileItem> list = map.get(PARAMETER_UPLOADED_FILE);
		if ((list == null) || list.isEmpty()) {
			throw new UserMistakeException("The form did not contain a '"
					+ PARAMETER_UPLOADED_FILE + "' field.");
		}

		FileItem file = list.get(0);
		if (file.getSize() == 0) {
			throw new UserMistakeException("Please browse and select a photo.");
		}

		String filename = getSimpleFilename(file);
		String mimeType = getMimeType(file);
		if (!RECOGNIZED_FILE_TYPES.containsValue(mimeType)) {
			throw new UserMistakeException("'" + filename
					+ "' is not a recognized image file type. Please upload JPEG, GIF, or PNG files only.");
		}

		return file;
	}

	/**
	 * If this entity already had a main image, remove the connection. If the
	 * image and the thumbnail are no longer used by anyone, remove them from
	 * the model, and from the file system.
	 */
	void removeExistingImage(Individual person) {
		Individual mainImage = fileModelHelper.removeMainImage(person);
{'fraction_non_alphanumeric': 0.10126004382761139, 'fraction_numerical': 0.0028305332359386415, 'mean_word_length': 4.879227053140097, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 21, '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': '5048161', 'n_tokens_mistral': 3659, 'n_tokens_neox': 3384, 'n_words': 815}