package eu.semberal.reminders.service;
import eu.semberal.reminders.entity.Attachment;
import eu.semberal.reminders.entity.Note;
import eu.semberal.reminders.entity.User;
import org.hibernate.exception.ConstraintViolationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.FileCopyUtils;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.Query;
import java.io.*;
import java.util.Date;
import java.util.List;
@Transactional
public class FilesServiceImpl implements FilesService {
@PersistenceContext private EntityManager entityManager;
private String storagePath;
public void setStoragePath(String storagePath) {
this.storagePath = storagePath;
}
private Logger log = LoggerFactory.getLogger(FilesServiceImpl.class);
@Override
public void addAttachment(InputStream stream, String filename, Long userId) throws Exception {
if (stream == null || filename == null || userId == null)
throw new IllegalArgumentException("Argument is null"); //if sth is null, throw exception
User u = entityManager.find(User.class, userId);
if (u == null)
throw new IllegalArgumentException("User with specified ID was not found."); //if user not found, throw error
Attachment a = new Attachment();
a.setDateAdded(new Date());
a.setUser(u);
a.setFilename(filename);
a.setSize(0L);
entityManager.persist(a);
entityManager.flush(); //if the file was successfully put into the database, continue with saving the file on the disc
File f = new File(computePath(a));
f.getParentFile().mkdirs();
long bytes = FileCopyUtils.copy(new BufferedInputStream(stream), new BufferedOutputStream(new FileOutputStream(f)));
a.setSize(bytes);
}
@Override
@SuppressWarnings("unchecked")
public List<Attachment> getAttachmentsForUser(Long id) {
Query q = entityManager.createQuery("select a from Attachment a where a.user.id = :userId order by a.dateAdded");
q.setParameter("userId", id);
return q.getResultList();
}
@Override
public Attachment getAttachment(Long id) {
return entityManager.find(Attachment.class, id);
}
@Override
public File getAttachmentFile(Long id) {
Attachment a = entityManager.find(Attachment.class, id);
if (a == null) return null;
File f = new File(computePath(a));
if (!f.exists() || !f.canRead() || !f.isFile()) {
log.error("File {} was found in database as attachment, but is not readable on filesystem", f.getAbsolutePath());
return null;
}
return f;
}
@Override
@SuppressWarnings("unchecked")
public void deleteAttachment(Long id) {
Attachment a = entityManager.find(Attachment.class, id);
if (a == null) return;
File f = new File(computePath(a));
Query q = entityManager.createQuery("select n from Note n where :a member of n.attachments");
q.setParameter("a", a);
List<Note> notesContainingAttachment = q.getResultList();
for(Note n : notesContainingAttachment) {
n.getAttachments().remove(a);
entityManager.merge(n);
}
entityManager.remove(a);
f.delete();
}
private String computePath(Attachment a) {
return new StringBuilder(storagePath).append("/").append(a.getUser().getEmail()).append("/").append(a.getId()).append("_").append(a.getFilename()).toString();
}
}