@@ -1,15 +1,15 @@
|
||||
package info.bukova.isspst.data;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.hibernate.search.annotations.Analyze;
|
||||
import org.hibernate.search.annotations.Field;
|
||||
import org.hibernate.search.annotations.Index;
|
||||
import org.hibernate.search.annotations.Indexed;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "FILE_METAINFO")
|
||||
@Indexed
|
||||
@@ -27,6 +27,12 @@ public class FileMetainfo extends BaseData {
|
||||
@Type(type = "text")
|
||||
@Field(index = Index.YES, analyze = Analyze.YES)
|
||||
private String content;
|
||||
@Column(name = "MD5")
|
||||
private String md5;
|
||||
@Column(name = "DESCRIPTION")
|
||||
private String description;
|
||||
@Column(name = "CONTENT_TYPE")
|
||||
private String contentType;
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
@@ -68,4 +74,61 @@ public class FileMetainfo extends BaseData {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public String getMd5() {
|
||||
return md5;
|
||||
}
|
||||
|
||||
public void setMd5(String md5) {
|
||||
this.md5 = md5;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
public void setContentType(String contentType) {
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof FileMetainfo)) return false;
|
||||
|
||||
FileMetainfo that = (FileMetainfo) o;
|
||||
|
||||
if (getId() != 0 && getId() != that.getId()) return false;
|
||||
if (recordId != that.recordId) return false;
|
||||
if (content != null ? !content.equals(that.content) : that.content != null) return false;
|
||||
if (contentType != null ? !contentType.equals(that.contentType) : that.contentType != null) return false;
|
||||
if (description != null ? !description.equals(that.description) : that.description != null) return false;
|
||||
if (fileName != null ? !fileName.equals(that.fileName) : that.fileName != null) return false;
|
||||
if (md5 != null ? !md5.equals(that.md5) : that.md5 != null) return false;
|
||||
if (moduleId != null ? !moduleId.equals(that.moduleId) : that.moduleId != null) return false;
|
||||
if (pathInFilesystem != null ? !pathInFilesystem.equals(that.pathInFilesystem) : that.pathInFilesystem != null)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = fileName != null ? fileName.hashCode() : 0;
|
||||
result = 31 * result + (pathInFilesystem != null ? pathInFilesystem.hashCode() : 0);
|
||||
result = 31 * result + (moduleId != null ? moduleId.hashCode() : 0);
|
||||
result = 31 * result + recordId;
|
||||
result = 31 * result + (content != null ? content.hashCode() : 0);
|
||||
result = 31 * result + (md5 != null ? md5.hashCode() : 0);
|
||||
result = 31 * result + (description != null ? description.hashCode() : 0);
|
||||
result = 31 * result + (contentType != null ? contentType.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +1,20 @@
|
||||
package info.bukova.isspst.data;
|
||||
|
||||
import info.bukova.isspst.storage.EntityWithAttachment;
|
||||
import org.hibernate.annotations.LazyCollection;
|
||||
import org.hibernate.annotations.LazyCollectionOption;
|
||||
import org.hibernate.search.annotations.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.LazyCollection;
|
||||
import org.hibernate.annotations.LazyCollectionOption;
|
||||
import org.hibernate.search.annotations.Analyze;
|
||||
import org.hibernate.search.annotations.Field;
|
||||
import org.hibernate.search.annotations.Index;
|
||||
import org.hibernate.search.annotations.Indexed;
|
||||
import org.hibernate.search.annotations.IndexedEmbedded;
|
||||
|
||||
@Entity
|
||||
@Table(name = "TRIPREQUIREMENT")
|
||||
@Indexed
|
||||
public class TripRequirement extends RequirementBase {
|
||||
public class TripRequirement extends RequirementBase implements EntityWithAttachment {
|
||||
|
||||
@Column(name = "TRIP_FROM")
|
||||
@Field(index = Index.YES, analyze = Analyze.YES)
|
||||
@@ -49,7 +38,7 @@ public class TripRequirement extends RequirementBase {
|
||||
private Boolean requireDownPayment;
|
||||
@Column(name = "DOWN_PAYMENT", precision = 15, scale = 4)
|
||||
private BigDecimal downPayment;
|
||||
@OneToMany
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
@LazyCollection(LazyCollectionOption.TRUE)
|
||||
@IndexedEmbedded
|
||||
private List<FileMetainfo> attachedFiles;
|
||||
@@ -57,6 +46,7 @@ public class TripRequirement extends RequirementBase {
|
||||
public TripRequirement() {
|
||||
this.setOwnedBy(new User());
|
||||
passengers = new ArrayList<User>();
|
||||
attachedFiles = new ArrayList<FileMetainfo>();
|
||||
}
|
||||
|
||||
public String getFrom() {
|
||||
@@ -131,6 +121,7 @@ public class TripRequirement extends RequirementBase {
|
||||
this.downPayment = downPayment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileMetainfo> getAttachedFiles() {
|
||||
return attachedFiles;
|
||||
}
|
||||
@@ -139,4 +130,14 @@ public class TripRequirement extends RequirementBase {
|
||||
this.attachedFiles = attachedFiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAttachment(FileMetainfo metaInfo) {
|
||||
attachedFiles.add(metaInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttachment(FileMetainfo metainfo) {
|
||||
attachedFiles.remove(metainfo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+12
-8
@@ -1,21 +1,17 @@
|
||||
package info.bukova.isspst.services.requirement;
|
||||
|
||||
import info.bukova.isspst.Constants;
|
||||
import info.bukova.isspst.data.NumberSeries;
|
||||
import info.bukova.isspst.data.RequirementState;
|
||||
import info.bukova.isspst.data.TripBill;
|
||||
import info.bukova.isspst.data.TripRequirement;
|
||||
import info.bukova.isspst.data.User;
|
||||
import info.bukova.isspst.data.*;
|
||||
import info.bukova.isspst.services.LazyLoader;
|
||||
import info.bukova.isspst.services.tripbill.TripBillService;
|
||||
import info.bukova.isspst.services.workgroups.WorkgroupService;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.LazyInitializationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class TripRequirementServiceImpl extends RequirementBaseServiceImpl<TripRequirement>
|
||||
implements TripRequirementService, RequirementBaseService<TripRequirement> {
|
||||
|
||||
@@ -53,6 +49,14 @@ public class TripRequirementServiceImpl extends RequirementBaseServiceImpl<TripR
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@LazyLoader("form")
|
||||
public void loadAttachments(TripRequirement entity) {
|
||||
TripRequirement e = dao.getById(entity.getId());
|
||||
Hibernate.initialize(e.getAttachedFiles());
|
||||
entity.setAttachedFiles(e.getAttachedFiles());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postApprove(TripRequirement entity) {
|
||||
if (entity.getState() == RequirementState.APPROVED) {
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
package info.bukova.isspst.storage;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Abstraktni třída pro práci se soubory.
|
||||
*
|
||||
* @author Pepa Rokos
|
||||
*/
|
||||
public abstract class AbstractFileStorage<T> implements FileStorage<T> {
|
||||
|
||||
protected void saveFileDataToPath(byte[] data, String path) {
|
||||
|
||||
File file = new File(path);
|
||||
FileOutputStream os = null;
|
||||
try {
|
||||
os = new FileOutputStream(file);
|
||||
os.write(data);
|
||||
os.flush();
|
||||
os.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (os != null) {
|
||||
os.flush();
|
||||
os.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new StorageException("Cannot close stream", e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void saveFileToPtah(File file, String path) {
|
||||
File dest = new File(path + File.pathSeparator + file.getName());
|
||||
FileOutputStream fos = null;
|
||||
|
||||
try {
|
||||
fos = new FileOutputStream(dest);
|
||||
fos.write(readFile(file));
|
||||
fos.flush();
|
||||
fos.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new StorageException("Cannot move file: " + file.getName(), e.getCause());
|
||||
} catch (IOException e) {
|
||||
throw new StorageException("Cannot move file: " + file.getName(), e.getCause());
|
||||
} finally {
|
||||
if (fos != null) {
|
||||
try {
|
||||
fos.flush();
|
||||
fos.close();
|
||||
} catch (IOException e) {
|
||||
throw new StorageException("Cannot close stream", e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void removeFileByPath(String path) {
|
||||
File f = new File(path);
|
||||
if (!f.delete()) {
|
||||
throw new StorageException("Cannot delete file: " + path);
|
||||
}
|
||||
}
|
||||
|
||||
protected byte[] fileDataFromPath(String path) {
|
||||
File f = new File(path);
|
||||
return readFile(f);
|
||||
}
|
||||
|
||||
protected byte[] readFile(File file) {
|
||||
byte[] out = new byte[(int) file.length()];
|
||||
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(file);
|
||||
fis.read(out);
|
||||
fis.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new StorageException("File cannot be found: " + file.getName(), e.getCause());
|
||||
} catch (IOException e) {
|
||||
throw new StorageException("Cannot read file: " + file.getName(), e.getCause());
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (IOException e) {
|
||||
throw new StorageException("Cannot close stream", e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
protected File fileFromPath(String path) {
|
||||
return new File(path);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package info.bukova.isspst.storage;
|
||||
|
||||
import info.bukova.isspst.data.FileMetainfo;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Rozhraní servisního objektu pro práci s přílohami u záznamů. Přílohy jsou reprezentovány objektem FileMetainfo,
|
||||
* kde je zobrazované jméno souboru, vygenerovaný GUID, pod kterým je soubor fyzicky uložen a MD5 součet používaný
|
||||
* pro deduplikaci.
|
||||
*
|
||||
* @see info.bukova.isspst.data.FileMetainfo
|
||||
*
|
||||
* @author Pepa Rokos
|
||||
*/
|
||||
public interface DocumentFileStorage extends FileStorage<FileMetainfo> {
|
||||
|
||||
/**
|
||||
* Uloží data předaná jako byte[] do uložiště příloh a vrátí metainformace.
|
||||
* Metoda řeší deduplikaci souborů, takže v uložišti je fyzicky vždy jen jedna kopie.
|
||||
*
|
||||
* @see info.bukova.isspst.data.FileMetainfo
|
||||
*
|
||||
* @param data Data souboru
|
||||
* @param name Zobrazovaný název souboru
|
||||
* @return Metainformace o souboru
|
||||
*/
|
||||
public FileMetainfo saveAndCreateInfo(byte[] data, String name);
|
||||
|
||||
/**
|
||||
* Uloží data předaná jako File do uložiště příloh a vrátí metainformace.
|
||||
* Metoda řeší deduplikaci souborů, takže v uložišti je fyzicky vždy jen jedna kopie.
|
||||
*
|
||||
* @see info.bukova.isspst.data.FileMetainfo
|
||||
*
|
||||
* @param file Objekt reprezentující soubor
|
||||
* @param name Zobrazovaný název souboru
|
||||
* @return Metainformace o souboru
|
||||
*/
|
||||
public FileMetainfo saveAndCreateInfo(File file, String name);
|
||||
|
||||
/**
|
||||
* Vrátí metainformace podle fyzické cesty v uložišti.
|
||||
*
|
||||
* @param path Cesta k souboru v uložišti
|
||||
* @return Metainformace o souboru
|
||||
*/
|
||||
public FileMetainfo getMetainfoForPath(String path);
|
||||
|
||||
/**
|
||||
* Bezpečně odstraní přílohu ze záznamu. Záznam o příloze odstraní z kolekce příloh a následně zavolá metodu
|
||||
* removeFile(FileMetainfo info), která soubor fyzicky smaže, pokud už není nikam linkovaný.
|
||||
*
|
||||
* @param entity Entita s přílohami
|
||||
* @param metaInfo Příloha k odstranění
|
||||
*/
|
||||
public void removeAttachment(EntityWithAttachment entity, FileMetainfo metaInfo);
|
||||
|
||||
/**
|
||||
* Bezpečně odstraní všechny přílohy ze záznamu.
|
||||
*
|
||||
* @param entity Entita s přílohami
|
||||
*/
|
||||
public void removaAllAttachments(EntityWithAttachment entity);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
package info.bukova.isspst.storage;
|
||||
|
||||
import info.bukova.isspst.dao.QueryDao;
|
||||
import info.bukova.isspst.data.FileMetainfo;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.hibernate.Query;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.*;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Pepa Rokos
|
||||
*
|
||||
* Třída pro práci s uložištěm příloh u záznamů. Na soubory příloh se odkazuje pomocí objektů FileMetainfo.
|
||||
*
|
||||
* @see info.bukova.isspst.data.FileMetainfo
|
||||
*/
|
||||
public class DocumentFileStorageImpl extends AbstractFileStorage<FileMetainfo> implements DocumentFileStorage {
|
||||
|
||||
private String rootPath;
|
||||
@Autowired
|
||||
private QueryDao queryDao;
|
||||
|
||||
/**
|
||||
* Nastavuje kořenová adresář pro ukládání příloh. Nastavuje se absolutní cesta na filesystému serveru.
|
||||
*
|
||||
* @param rootPath kořenový adresář pro přílohy
|
||||
*/
|
||||
public void setRootPath(String rootPath) {
|
||||
this.rootPath = rootPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveFile(byte[] data, FileMetainfo fileID) {
|
||||
String fileName = generateFileName(fileID.getFileName());
|
||||
|
||||
saveFileDataToPath(data, rootPath + File.separator + fileName);
|
||||
fileID.setPathInFilesystem(fileName);
|
||||
fileID.setContentType(MimeTypes.getContentType(data, fileName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveFile(File file, FileMetainfo fileID) {
|
||||
String fileName = generateFileName(fileID.getFileName());
|
||||
|
||||
saveFileToPtah(file, rootPath + File.separator + fileName);
|
||||
fileID.setPathInFilesystem(fileName);
|
||||
fileID.setContentType(MimeTypes.getContentType(readFile(file), fileName));
|
||||
}
|
||||
|
||||
private String generateFileName(String originalName) {
|
||||
String extension = null;
|
||||
String fileName = UUID.randomUUID().toString();
|
||||
|
||||
if (originalName != null && !originalName.isEmpty()) {
|
||||
extension = MimeTypes.fileExtension(originalName);
|
||||
}
|
||||
|
||||
if (extension != null) {
|
||||
fileName = fileName + "." + extension;
|
||||
}
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void removeFile(FileMetainfo fileID) {
|
||||
if (fileID.getPathInFilesystem() == null || fileID.getPathInFilesystem().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (infosForPath(fileID.getPathInFilesystem()).size() <= 1) {
|
||||
removeFileByPath(rootPath + File.separator + fileID.getPathInFilesystem());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveFile(String source, String destination) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createDirectory(String dir) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] fileData(FileMetainfo fileID) {
|
||||
if (fileID.getPathInFilesystem() != null && !fileID.getPathInFilesystem().isEmpty()) {
|
||||
return fileDataFromPath(rootPath + File.separator + fileID.getPathInFilesystem());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File file(FileMetainfo fileID) {
|
||||
if (fileID.getPathInFilesystem() != null && !fileID.getPathInFilesystem().isEmpty()) {
|
||||
return fileFromPath(rootPath + File.separator + fileID.getPathInFilesystem());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dirExists(String path) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serverPath(FileMetainfo fileID) {
|
||||
return "/api/dl/" + fileID.getPathInFilesystem() + "/" + fileID.getFileName();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public FileMetainfo saveAndCreateInfo(byte[] data, String name) {
|
||||
FileMetainfo metaInfo = new FileMetainfo();
|
||||
metaInfo.setFileName(name);
|
||||
|
||||
if (!checkForDuplicate(new ByteArrayInputStream(data), metaInfo)) {
|
||||
saveFile(data, metaInfo);
|
||||
}
|
||||
|
||||
return metaInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public FileMetainfo saveAndCreateInfo(File file, String name) {
|
||||
FileMetainfo metaInfo = new FileMetainfo();
|
||||
metaInfo.setFileName(name);
|
||||
|
||||
try {
|
||||
if (!checkForDuplicate(new FileInputStream(file), metaInfo)) {
|
||||
saveFile(file, metaInfo);
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
//TODO: ošetřit
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return metaInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public FileMetainfo getMetainfoForPath(String path) {
|
||||
if (infosForPath(path).isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return infosForPath(path).get(0);
|
||||
}
|
||||
|
||||
private List<FileMetainfo> infosForPath(String path) {
|
||||
Query q = queryDao.getQuery("from FileMetainfo info where info.pathInFilesystem = :path");
|
||||
q.setString("path", path);
|
||||
|
||||
return q.list();
|
||||
}
|
||||
|
||||
private boolean checkForDuplicate(InputStream is, FileMetainfo info) {
|
||||
String md5 = null;
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
byte[] dataBytes = new byte[1024];
|
||||
int nread = 0;
|
||||
|
||||
while ((nread = is.read(dataBytes)) != -1) {
|
||||
md.update(dataBytes, 0, nread);
|
||||
}
|
||||
|
||||
md5 = new String(Hex.encodeHex(md.digest()));
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
//TODO: ošetřit
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
Query q = queryDao.getQuery("select info from FileMetainfo info where info.md5 = :md5");
|
||||
q.setString("md5", md5);
|
||||
List<FileMetainfo> found = (List<FileMetainfo>) q.list();
|
||||
|
||||
if (!found.isEmpty()) {
|
||||
FileMetainfo foundInfo = found.get(0);
|
||||
info.setPathInFilesystem(foundInfo.getPathInFilesystem());
|
||||
info.setMd5(foundInfo.getMd5());
|
||||
info.setContentType(foundInfo.getContentType());
|
||||
|
||||
return true;
|
||||
} else {
|
||||
info.setMd5(md5);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void removeAttachment(EntityWithAttachment entity, FileMetainfo metaInfo) {
|
||||
entity.removeAttachment(metaInfo);
|
||||
removeFile(metaInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void removaAllAttachments(EntityWithAttachment entity) {
|
||||
for (FileMetainfo metaInfo : entity.getAttachedFiles()) {
|
||||
removeFile(metaInfo);
|
||||
}
|
||||
|
||||
entity.getAttachedFiles().clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package info.bukova.isspst.storage;
|
||||
|
||||
import info.bukova.isspst.data.FileMetainfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Rozhraní datových entit s přílohami.
|
||||
*
|
||||
* @author Pepa Rokos
|
||||
*/
|
||||
public interface EntityWithAttachment {
|
||||
|
||||
public List<FileMetainfo> getAttachedFiles();
|
||||
public void addAttachment(FileMetainfo metaInfo);
|
||||
public void removeAttachment(FileMetainfo metainfo);
|
||||
|
||||
}
|
||||
@@ -2,17 +2,22 @@ package info.bukova.isspst.storage;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public interface FileStorage {
|
||||
/**
|
||||
* Rozhraní pro uložiště souborů
|
||||
*
|
||||
* @param <T> typ objektu, kterým se odkazuje na soubory
|
||||
*/
|
||||
public interface FileStorage<T> {
|
||||
|
||||
// public String getRootPath();
|
||||
public void saveFile(byte[] data, String fileName);
|
||||
public void saveFile(File file, String path);
|
||||
public void removeFile(String fileName);
|
||||
public void saveFile(byte[] data, T fileID);
|
||||
public void saveFile(File file, T fileId);
|
||||
public void removeFile(T fileID);
|
||||
public void moveFile(String source, String destination);
|
||||
public void createDirectory(String dir);
|
||||
public byte[] fileData(String fileName);
|
||||
public File file(String fileName);
|
||||
public byte[] fileData(T fileID);
|
||||
public File file(T fileID);
|
||||
public boolean dirExists(String path);
|
||||
public String serverPath(String fileName);
|
||||
public String serverPath(T fileID);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
package info.bukova.isspst.storage;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import java.io.*;
|
||||
|
||||
public class LocalFileStorage implements FileStorage {
|
||||
public class LocalFileStorage extends AbstractFileStorage<String> {
|
||||
|
||||
private String rootPath;
|
||||
private ServletContext context;
|
||||
@@ -26,96 +21,27 @@ public class LocalFileStorage implements FileStorage {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveFile(byte[] data, String fileName) {
|
||||
public void saveFile(byte[] data, String fileID) {
|
||||
saveFileDataToPath(data, getFullPath() + fileID);
|
||||
}
|
||||
|
||||
File file = new File(getFullPath() + fileName);
|
||||
FileOutputStream os = null;
|
||||
try {
|
||||
os = new FileOutputStream(file);
|
||||
os.write(data);
|
||||
os.flush();
|
||||
os.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (os != null) {
|
||||
os.flush();
|
||||
os.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new StorageException("Cannot close stream", e.getCause());
|
||||
}
|
||||
}
|
||||
public void saveFile(File file, String fileID) {
|
||||
saveFileToPtah(file, getFullPath() + fileID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveFile(File file, String path) {
|
||||
File dest = new File(getFullPath() + path + File.pathSeparator + file.getName());
|
||||
FileOutputStream fos = null;
|
||||
|
||||
try {
|
||||
fos = new FileOutputStream(dest);
|
||||
fos.write(fileData(file.getName()));
|
||||
fos.flush();
|
||||
fos.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new StorageException("Cannot move file: " + file.getName(), e.getCause());
|
||||
} catch (IOException e) {
|
||||
throw new StorageException("Cannot move file: " + file.getName(), e.getCause());
|
||||
} finally {
|
||||
if (fos != null) {
|
||||
try {
|
||||
fos.flush();
|
||||
fos.close();
|
||||
} catch (IOException e) {
|
||||
throw new StorageException("Cannot close stream", e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
public void removeFile(String fileID) {
|
||||
removeFileByPath(getFullPath() + fileID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFile(String fileName) {
|
||||
File f = new File(getFullPath() + fileName);
|
||||
if (!f.delete()) {
|
||||
throw new StorageException("Cannot delete file: " + getFullPath()
|
||||
+ fileName);
|
||||
}
|
||||
public byte[] fileData(String fileID) {
|
||||
return fileDataFromPath(getFullPath() + fileID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] fileData(String fileName) {
|
||||
File f = new File(getFullPath() + fileName);
|
||||
byte[] out = new byte[(int) f.length()];
|
||||
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(f);
|
||||
fis.read(out);
|
||||
fis.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new StorageException("File cannot be found: " + fileName, e.getCause());
|
||||
} catch (IOException e) {
|
||||
throw new StorageException("Cannot read file: " + fileName, e.getCause());
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (IOException e) {
|
||||
throw new StorageException("Cannot close stream", e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File file(String fileName) {
|
||||
return new File(getFullPath() + fileName);
|
||||
public File file(String fileID) {
|
||||
return fileFromPath(getFullPath() + fileID);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -139,8 +65,8 @@ public class LocalFileStorage implements FileStorage {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serverPath(String fileName) {
|
||||
return context.getRealPath(rootPath + File.separator + fileName);
|
||||
public String serverPath(String fileID) {
|
||||
return context.getRealPath(rootPath + File.separator + fileID);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
package info.bukova.isspst.storage;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* Created by pepa on 30.1.15.
|
||||
*/
|
||||
public class MimeTypes {
|
||||
|
||||
public static String getContentType(byte[] data)
|
||||
{
|
||||
return getContentType(data, null);
|
||||
}
|
||||
|
||||
public static String getContentType(byte[] data, String name)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
byte[] header = new byte[11];
|
||||
System.arraycopy(data, 0, header, 0, Math.min(data.length, header.length));
|
||||
int c1 = header[0] & 0xff;
|
||||
int c2 = header[1] & 0xff;
|
||||
int c3 = header[2] & 0xff;
|
||||
int c4 = header[3] & 0xff;
|
||||
int c5 = header[4] & 0xff;
|
||||
int c6 = header[5] & 0xff;
|
||||
int c7 = header[6] & 0xff;
|
||||
int c8 = header[7] & 0xff;
|
||||
int c9 = header[8] & 0xff;
|
||||
int c10 = header[9] & 0xff;
|
||||
int c11 = header[10] & 0xff;
|
||||
|
||||
if (c1 == 0xCA && c2 == 0xFE && c3 == 0xBA && c4 == 0xBE)
|
||||
{
|
||||
return "application/java-vm";
|
||||
}
|
||||
|
||||
if (c1 == 0xD0 && c2 == 0xCF && c3 == 0x11 && c4 == 0xE0 && c5 == 0xA1 && c6 == 0xB1 && c7 == 0x1A && c8 == 0xE1)
|
||||
{
|
||||
// if the name is set then check if it can be validated by name, because it could be a xls or powerpoint
|
||||
String contentType = guessContentTypeFromName(name);
|
||||
if (contentType != null)
|
||||
{
|
||||
return contentType;
|
||||
}
|
||||
return "application/msword";
|
||||
}
|
||||
if (c1 == 0x25 && c2 == 0x50 && c3 == 0x44 && c4 == 0x46 && c5 == 0x2d && c6 == 0x31 && c7 == 0x2e)
|
||||
{
|
||||
return "application/pdf";
|
||||
}
|
||||
|
||||
if (c1 == 0x38 && c2 == 0x42 && c3 == 0x50 && c4 == 0x53 && c5 == 0x00 && c6 == 0x01)
|
||||
{
|
||||
return "image/photoshop";
|
||||
}
|
||||
|
||||
if (c1 == 0x25 && c2 == 0x21 && c3 == 0x50 && c4 == 0x53)
|
||||
{
|
||||
return "application/postscript";
|
||||
}
|
||||
|
||||
if (c1 == 0xff && c2 == 0xfb && c3 == 0x30)
|
||||
{
|
||||
return "audio/mp3";
|
||||
}
|
||||
|
||||
if (c1 == 0x49 && c2 == 0x44 && c3 == 0x33)
|
||||
{
|
||||
return "audio/mp3";
|
||||
}
|
||||
|
||||
if (c1 == 0xAC && c2 == 0xED)
|
||||
{
|
||||
// next two bytes are version number, currently 0x00 0x05
|
||||
return "application/x-java-serialized-object";
|
||||
}
|
||||
|
||||
if (c1 == '<')
|
||||
{
|
||||
if (c2 == '!' ||
|
||||
((c2 == 'h' && (c3 == 't' && c4 == 'm' && c5 == 'l' || c3 == 'e' && c4 == 'a' && c5 == 'd') || (c2 == 'b' && c3 == 'o' && c4 == 'd' && c5 == 'y'))) ||
|
||||
((c2 == 'H' && (c3 == 'T' && c4 == 'M' && c5 == 'L' || c3 == 'E' && c4 == 'A' && c5 == 'D') || (c2 == 'B' && c3 == 'O' && c4 == 'D' && c5 == 'Y'))))
|
||||
{
|
||||
return "text/html";
|
||||
}
|
||||
|
||||
if (c2 == '?' && c3 == 'x' && c4 == 'm' && c5 == 'l' && c6 == ' ')
|
||||
{
|
||||
return "application/xml";
|
||||
}
|
||||
}
|
||||
|
||||
// big and little endian UTF-16 encodings, with byte order mark
|
||||
if (c1 == 0xfe && c2 == 0xff)
|
||||
{
|
||||
if (c3 == 0 && c4 == '<' && c5 == 0 && c6 == '?' && c7 == 0 && c8 == 'x')
|
||||
{
|
||||
return "application/xml";
|
||||
}
|
||||
}
|
||||
|
||||
if (c1 == 0xff && c2 == 0xfe)
|
||||
{
|
||||
if (c3 == '<' && c4 == 0 && c5 == '?' && c6 == 0 && c7 == 'x' && c8 == 0)
|
||||
{
|
||||
return "application/xml";
|
||||
}
|
||||
}
|
||||
|
||||
if (c1 == 'B' && c2 == 'M')
|
||||
{
|
||||
return "image/bmp";
|
||||
}
|
||||
|
||||
if (c1 == 0x49 && c2 == 0x49 && c3 == 0x2a && c4 == 0x00)
|
||||
{
|
||||
return "image/tiff";
|
||||
}
|
||||
|
||||
if (c1 == 0x4D && c2 == 0x4D && c3 == 0x00 && c4 == 0x2a)
|
||||
{
|
||||
return "image/tiff";
|
||||
}
|
||||
|
||||
if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8')
|
||||
{
|
||||
return "image/gif";
|
||||
}
|
||||
|
||||
if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f')
|
||||
{
|
||||
return "image/x-bitmap";
|
||||
}
|
||||
|
||||
if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' && c5 == 'M' && c6 == '2')
|
||||
{
|
||||
return "image/x-pixmap";
|
||||
}
|
||||
|
||||
if (c1 == 137 && c2 == 80 && c3 == 78 && c4 == 71 && c5 == 13 && c6 == 10 && c7 == 26 && c8 == 10)
|
||||
{
|
||||
return "image/png";
|
||||
}
|
||||
|
||||
if (c1 == 0xFF && c2 == 0xD8 && c3 == 0xFF)
|
||||
{
|
||||
if (c4 == 0xE0)
|
||||
{
|
||||
return "image/jpeg";
|
||||
}
|
||||
|
||||
/**
|
||||
* File format used by digital cameras to store images. Exif Format can be read by any application supporting JPEG. Exif Spec can be found at:
|
||||
* http://www.pima.net/standards/it10/PIMA15740/Exif_2-1.PDF
|
||||
*/
|
||||
if ((c4 == 0xE1) && (c7 == 'E' && c8 == 'x' && c9 == 'i' && c10 == 'f' && c11 == 0))
|
||||
{
|
||||
return "image/jpeg";
|
||||
}
|
||||
|
||||
if (c4 == 0xEE)
|
||||
{
|
||||
return "image/jpg";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* According to http://www.opendesign.com/files/guestdownloads/OpenDesign_Specification_for_.dwg_files.pdf
|
||||
* first 6 bytes are of type "AC1018" (for example) and the next 5 bytes are 0x00.
|
||||
*/
|
||||
if ((c1 == 0x41 && c2 == 0x43) && (c7 == 0x00 && c8 == 0x00 && c9 == 0x00 && c10 == 0x00 && c11 == 0x00))
|
||||
{
|
||||
return "application/acad";
|
||||
}
|
||||
|
||||
if (c1 == 0x2E && c2 == 0x73 && c3 == 0x6E && c4 == 0x64)
|
||||
{
|
||||
return "audio/basic"; // .au
|
||||
// format,
|
||||
// big
|
||||
// endian
|
||||
}
|
||||
|
||||
if (c1 == 0x64 && c2 == 0x6E && c3 == 0x73 && c4 == 0x2E)
|
||||
{
|
||||
return "audio/basic"; // .au
|
||||
// format,
|
||||
// little
|
||||
// endian
|
||||
}
|
||||
|
||||
if (c1 == 'R' && c2 == 'I' && c3 == 'F' && c4 == 'F')
|
||||
{
|
||||
/*
|
||||
* I don't know if this is official but evidence suggests that .wav files start with "RIFF" - brown
|
||||
*/
|
||||
return "audio/x-wav";
|
||||
}
|
||||
|
||||
if (c1 == 'P' && c2 == 'K')
|
||||
{
|
||||
// its application/zip but this could be a open office thing if name is given
|
||||
String contentType = guessContentTypeFromName(name);
|
||||
if (contentType != null)
|
||||
{
|
||||
return contentType;
|
||||
}
|
||||
return "application/zip";
|
||||
}
|
||||
return guessContentTypeFromName(name);
|
||||
}
|
||||
|
||||
private static final Map<String, String> mimeTypes = new HashMap<String, String>();
|
||||
|
||||
public static String guessContentTypeFromName(String name)
|
||||
{
|
||||
if (name == null) return null;
|
||||
|
||||
int lastIndex = name.lastIndexOf('.');
|
||||
if (lastIndex != -1)
|
||||
{
|
||||
String extention = name.substring(lastIndex + 1).toLowerCase();
|
||||
if (mimeTypes.size() == 0)
|
||||
{
|
||||
HashMap<String, String> tempMap = new HashMap<String, String>();
|
||||
InputStream is = MimeTypes.class.getResourceAsStream("mime.types.properties");
|
||||
try
|
||||
{
|
||||
Properties properties = new Properties();
|
||||
properties.load(is);
|
||||
for (Object key : properties.keySet())
|
||||
{
|
||||
String property = properties.getProperty((String)key);
|
||||
StringTokenizer st = new StringTokenizer(property, " ");
|
||||
while (st.hasMoreTokens())
|
||||
{
|
||||
tempMap.put(st.nextToken(), (String)key);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
//Debug.error(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
is.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
//Debug.error(e);
|
||||
}
|
||||
}
|
||||
synchronized (mimeTypes)
|
||||
{
|
||||
mimeTypes.putAll(tempMap);
|
||||
}
|
||||
}
|
||||
return mimeTypes.get(extention);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String fileExtension(String fileName) {
|
||||
int index = fileName.lastIndexOf(".");
|
||||
|
||||
if (index > -1) {
|
||||
return fileName.substring(index + 1);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package info.bukova.isspst.storage;
|
||||
|
||||
import info.bukova.isspst.data.FileMetainfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by pepa on 2.2.15.
|
||||
*/
|
||||
|
||||
@Controller
|
||||
public class StorageController {
|
||||
|
||||
@Autowired
|
||||
private DocumentFileStorage documentStorage;
|
||||
private static final Logger logger = LoggerFactory.getLogger(StorageController.class);
|
||||
|
||||
@RequestMapping(value = "dl/{path}/{name}")
|
||||
public void viewFile(HttpServletResponse response, @PathVariable("path") String path,
|
||||
@PathVariable("name") String name) {
|
||||
ServletOutputStream os = null;
|
||||
|
||||
try {
|
||||
os = response.getOutputStream();
|
||||
FileMetainfo metainfo = new FileMetainfo();
|
||||
metainfo.setPathInFilesystem(path);
|
||||
byte[] data = null;
|
||||
|
||||
try {
|
||||
data = documentStorage.fileData(metainfo);
|
||||
metainfo.setContentType(MimeTypes.getContentType(data, path));
|
||||
} catch (StorageException e) {
|
||||
response.sendError(404);
|
||||
}
|
||||
|
||||
if (data != null) {
|
||||
response.setContentType(metainfo.getContentType());
|
||||
response.setContentLength(data.length);
|
||||
|
||||
os.write(data, 0, data.length);
|
||||
os.flush();
|
||||
os.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error("I/O error: " + e.getMessage());
|
||||
} finally {
|
||||
if (os != null) {
|
||||
try {
|
||||
os.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +1,21 @@
|
||||
package info.bukova.isspst.ui.requirement;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.zkoss.bind.annotation.BindingParam;
|
||||
import org.zkoss.bind.annotation.Command;
|
||||
import org.zkoss.bind.annotation.Init;
|
||||
import org.zkoss.bind.annotation.NotifyChange;
|
||||
import org.zkoss.zk.ui.select.annotation.WireVariable;
|
||||
|
||||
import info.bukova.isspst.data.SettingsData;
|
||||
import info.bukova.isspst.data.TripRequirement;
|
||||
import info.bukova.isspst.data.User;
|
||||
import info.bukova.isspst.data.Workgroup;
|
||||
import info.bukova.isspst.data.*;
|
||||
import info.bukova.isspst.services.requirement.RequirementTypeService;
|
||||
import info.bukova.isspst.services.requirement.TripRequirementService;
|
||||
import info.bukova.isspst.services.settings.GlobalSettingsService;
|
||||
import info.bukova.isspst.services.users.UserService;
|
||||
import info.bukova.isspst.services.workgroups.WorkgroupService;
|
||||
import info.bukova.isspst.storage.DocumentFileStorage;
|
||||
import info.bukova.isspst.ui.FormViewModel;
|
||||
import info.bukova.isspst.validators.TripRequirementFormValidator;
|
||||
import org.zkoss.bind.annotation.*;
|
||||
import org.zkoss.zk.ui.event.UploadEvent;
|
||||
import org.zkoss.zk.ui.select.annotation.WireVariable;
|
||||
import org.zkoss.zul.Filedownload;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TripRequirementForm extends FormViewModel<TripRequirement> {
|
||||
|
||||
@@ -32,9 +29,13 @@ public class TripRequirementForm extends FormViewModel<TripRequirement> {
|
||||
private RequirementTypeService reqTypeService;
|
||||
@WireVariable
|
||||
private TripRequirementService tripRequirementService;
|
||||
@WireVariable
|
||||
private DocumentFileStorage documentStorage;
|
||||
private List<Workgroup> centres;
|
||||
private List<User> users;
|
||||
private List<User> passengers;
|
||||
private List<FileMetainfo> attachments;
|
||||
private List<FileMetainfo> forDelete;
|
||||
private User selUser;
|
||||
private TripRequirementFormValidator validator;
|
||||
|
||||
@@ -44,6 +45,8 @@ public class TripRequirementForm extends FormViewModel<TripRequirement> {
|
||||
centres = reqTypeService.filterCentres(getDataBean().getType(), workgroupService.getUserCentres(userService.getCurrent()));
|
||||
users = userService.getUsersForCombo();
|
||||
passengers = getDataBean().getPassengers();
|
||||
attachments = getDataBean().getAttachedFiles();
|
||||
forDelete = new ArrayList<FileMetainfo>(); // kolekce příloh na smazání v případě uložení záznamu
|
||||
validator = new TripRequirementFormValidator();
|
||||
}
|
||||
|
||||
@@ -87,4 +90,37 @@ public class TripRequirementForm extends FormViewModel<TripRequirement> {
|
||||
return passengers;
|
||||
}
|
||||
|
||||
@Command
|
||||
@NotifyChange("attachments")
|
||||
public void uploadAttachment(@ContextParam(ContextType.TRIGGER_EVENT) UploadEvent upEvent) {
|
||||
FileMetainfo metaInfo = documentStorage.saveAndCreateInfo(upEvent.getMedia().getByteData(),
|
||||
upEvent.getMedia().getName());
|
||||
|
||||
getDataBean().addAttachment(metaInfo);
|
||||
}
|
||||
|
||||
@Command
|
||||
@NotifyChange("attachments")
|
||||
public void deleteAttachment(@BindingParam("attachment") FileMetainfo metaInfo) {
|
||||
getDataBean().removeAttachment(metaInfo);
|
||||
forDelete.add(metaInfo); // smazat až v případě uložení záznamu
|
||||
}
|
||||
|
||||
@Command
|
||||
public void downloadAttachment(@BindingParam("attachment") FileMetainfo metaInfo) {
|
||||
Filedownload.save(documentStorage.fileData(metaInfo), metaInfo.getContentType(), metaInfo.getFileName());
|
||||
}
|
||||
|
||||
public List<FileMetainfo> getAttachments() {
|
||||
return attachments;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doSave() {
|
||||
for (FileMetainfo info : forDelete) {
|
||||
documentStorage.removeFile(info);
|
||||
}
|
||||
|
||||
super.doSave();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,10 +7,6 @@ import info.bukova.isspst.services.requirement.TripRequirementService;
|
||||
import info.bukova.isspst.services.users.UserService;
|
||||
import info.bukova.isspst.services.workgroups.WorkgroupService;
|
||||
import info.bukova.isspst.ui.ListViewModel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.zkoss.bind.BindUtils;
|
||||
import org.zkoss.bind.annotation.GlobalCommand;
|
||||
@@ -18,6 +14,9 @@ import org.zkoss.bind.annotation.Init;
|
||||
import org.zkoss.bind.annotation.NotifyChange;
|
||||
import org.zkoss.zk.ui.select.annotation.WireVariable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TripRequirementList extends ListViewModel<TripRequirement> {
|
||||
|
||||
@WireVariable
|
||||
@@ -79,11 +78,6 @@ public class TripRequirementList extends ListViewModel<TripRequirement> {
|
||||
return myCentres;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadLazyDataForEdit(TripRequirement data) {
|
||||
tripRequirementService.loadPassangers(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<TripRequirement> getListFromService()
|
||||
{
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
<value>/WEB-INF/mail.properties</value>
|
||||
<value>/WEB-INF/gmail.properties</value>
|
||||
<value>/WEB-INF/ad.properties</value>
|
||||
<value>/WEB-INF/storage.properties</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
@@ -52,10 +53,10 @@
|
||||
<property name="hibernateProperties">
|
||||
<props>
|
||||
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
|
||||
<prop key="hibernate.show_sql">true</prop>
|
||||
<prop key="hibernate.show_sql">false</prop>
|
||||
<prop key="hibernate.hbm2ddl.auto">update</prop>
|
||||
<prop key="hibernate.search.default.directory_provider">filesystem</prop>
|
||||
<prop key="hibernate.search.default.indexBase">./</prop>
|
||||
<prop key="hibernate.search.default.indexBase">${storage.fulltextIndex}</prop>
|
||||
<prop key="hibernate.search.analyzer">org.apache.lucene.analysis.cz.CzechAnalyzer</prop>
|
||||
<!-- <prop key="hibernate.enable_lazy_load_no_trans">true</prop> -->
|
||||
</props>
|
||||
@@ -176,6 +177,10 @@
|
||||
<property name="context" ref="servletContext"/>
|
||||
<property name="rootPath" value="/WEB-INF/upload"/>
|
||||
</bean>
|
||||
|
||||
<bean id="documentStorage" class="info.bukova.isspst.storage.DocumentFileStorageImpl">
|
||||
<property name="rootPath" value="${storage.root}"/>
|
||||
</bean>
|
||||
|
||||
<!-- Session data -->
|
||||
<bean id="sessionData" class="info.bukova.isspst.SessionData" scope="session">
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
storage.root=/home/pepa/tmp/isspst
|
||||
storage.fulltextIndex=/home/pepa/tmp/isspst
|
||||
@@ -1,57 +1,62 @@
|
||||
<?page title="${labels.AgendaSearch}" contentType="text/html;charset=UTF-8"?>
|
||||
<zk>
|
||||
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
|
||||
<zk xmlns="http://www.zkoss.org/2005/zul"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.zkoss.org/2005/zul http://www.zkoss.org/2005/zul/zul.xsd">
|
||||
|
||||
<window border="normal" closable="false"
|
||||
apply="org.zkoss.bind.BindComposer"
|
||||
viewModel="@id('vm') @init('info.bukova.isspst.ui.search.SearchForm')"
|
||||
vflex="1">
|
||||
<caption src="/img/search-032.png" zclass="form-caption" label="${labels.AgendaSearch}" />
|
||||
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
|
||||
|
||||
<vbox width="100%"
|
||||
vflex="1">
|
||||
<hbox hflex="1" align="center">
|
||||
<div align="center" hflex="1">
|
||||
<vbox>
|
||||
<image src="/img/lucene_logo.png"/>
|
||||
<hbox>
|
||||
<textbox value="@bind(vm.keyWord)" instant="true" width="250px" onOK="@command('doSearch')"/>
|
||||
<button label="${labels.Search}" onClick="@command('doSearch')" sclass="nicebutton" image="/img/search.png" />
|
||||
</hbox>
|
||||
</vbox>
|
||||
</div>
|
||||
</hbox>
|
||||
<panel hflex="1" vflex="1">
|
||||
<panelchildren style="overflow:auto;">
|
||||
<vbox children="@load(vm.results)" width="100%">
|
||||
<template name="children">
|
||||
<vbox width="100%">
|
||||
<separator bar="true" width="100%"/>
|
||||
<label value="@load(each.recordName)" style="font-weight: bold; font-size:14px;"/>
|
||||
<label value="@load(each.description)"/>
|
||||
<hbox>
|
||||
<label value="${labels.created}: "/>
|
||||
<label value="@load(each.created)"/>
|
||||
</hbox>
|
||||
<hbox>
|
||||
<label value="${labels.ownedBy}: "/>
|
||||
<label value="@load(each.ownedBy)"/>
|
||||
</hbox>
|
||||
<hbox>
|
||||
<label value="${labels.modified}: "/>
|
||||
<label value="@load(each.modified)"/>
|
||||
</hbox>
|
||||
<hbox>
|
||||
<label value="${labels.modifiedBy}: "/>
|
||||
<label value="@load(each.modifiedBy)"/>
|
||||
</hbox>
|
||||
<a href="@load(each.url)" label="@load(each.url)"/>
|
||||
</vbox>
|
||||
</template>
|
||||
</vbox>
|
||||
</panelchildren>
|
||||
</panel>
|
||||
</vbox>
|
||||
<window border="normal" closable="false"
|
||||
apply="org.zkoss.bind.BindComposer"
|
||||
viewModel="@id('vm') @init('info.bukova.isspst.ui.search.SearchForm')"
|
||||
vflex="1">
|
||||
<caption src="/img/search-032.png" zclass="form-caption" label="${labels.AgendaSearch}"/>
|
||||
|
||||
</window>
|
||||
<vbox width="100%"
|
||||
vflex="1">
|
||||
<hbox hflex="1" align="center">
|
||||
<div align="center" hflex="1">
|
||||
<vbox>
|
||||
<image src="/img/lucene_logo.png"/>
|
||||
<hbox>
|
||||
<textbox value="@bind(vm.keyWord)" instant="true" width="250px"
|
||||
onOK="@command('doSearch')"/>
|
||||
<button label="${labels.Search}" onClick="@command('doSearch')" sclass="nicebutton"
|
||||
image="/img/search.png"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</div>
|
||||
</hbox>
|
||||
<panel hflex="1" vflex="1">
|
||||
<panelchildren style="overflow:auto;">
|
||||
<vbox children="@load(vm.results)" width="100%">
|
||||
<template name="children">
|
||||
<vbox width="100%">
|
||||
<separator bar="true" width="100%"/>
|
||||
<label value="@load(each.recordName)" style="font-weight: bold; font-size:14px;"/>
|
||||
<label value="@load(each.description)"/>
|
||||
<hbox>
|
||||
<label value="${labels.created}: "/>
|
||||
<label value="@load(each.created)"/>
|
||||
</hbox>
|
||||
<hbox>
|
||||
<label value="${labels.ownedBy}: "/>
|
||||
<label value="@load(each.ownedBy)"/>
|
||||
</hbox>
|
||||
<hbox>
|
||||
<label value="${labels.modified}: "/>
|
||||
<label value="@load(each.modified)"/>
|
||||
</hbox>
|
||||
<hbox>
|
||||
<label value="${labels.modifiedBy}: "/>
|
||||
<label value="@load(each.modifiedBy)"/>
|
||||
</hbox>
|
||||
<a href="@load(each.url)" label="@load(each.url)"/>
|
||||
</vbox>
|
||||
</template>
|
||||
</vbox>
|
||||
</panelchildren>
|
||||
</panel>
|
||||
</vbox>
|
||||
|
||||
</window>
|
||||
</zk>
|
||||
@@ -1,5 +1,8 @@
|
||||
<?page title="${labels.RequirementsFormTitle}" contentType="text/html;charset=UTF-8"?>
|
||||
<zk>
|
||||
<zk xmlns="http://www.zkoss.org/2005/zul"
|
||||
xmlns:h="http://www.w3.org/1999/xhtml"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.zkoss.org/2005/zul http://www.zkoss.org/2005/zul/zul.xsd">
|
||||
<window
|
||||
id="editWin"
|
||||
closable="true"
|
||||
@@ -12,118 +15,144 @@
|
||||
zclass="form-caption"
|
||||
label="${labels.RequirementsFormTitle}" />
|
||||
<vlayout form="@id('fx') @load(vm.dataBean) @save(vm.dataBean, before='save') @validator(vm.validator)">
|
||||
<grid hflex="min">
|
||||
<columns>
|
||||
<column
|
||||
align="right"
|
||||
hflex="min" />
|
||||
<column />
|
||||
</columns>
|
||||
<rows>
|
||||
<row>
|
||||
<cell sclass="row-title">${labels.RequirementsFormNumberSerie} :</cell>
|
||||
<cell>
|
||||
<textbox
|
||||
id="numser"
|
||||
width="200px"
|
||||
value="@bind(fx.numser)"
|
||||
maxlength="@load(vm.lengthText)"
|
||||
readonly="true" />
|
||||
</cell>
|
||||
</row>
|
||||
<row>
|
||||
<cell sclass="row-title">${labels.RequirementsFormReqDate} :</cell>
|
||||
<cell>
|
||||
<datebox
|
||||
id="reqDate"
|
||||
width="200px"
|
||||
value="@bind(fx.reqDate)"
|
||||
format="${labels.DateFormat}" />
|
||||
</cell>
|
||||
</row>
|
||||
<row>
|
||||
<cell sclass="row-title">${labels.RequirementsFormCenter} :</cell>
|
||||
<cell>
|
||||
<combobox
|
||||
model="@load(vm.centres)"
|
||||
readonly="true"
|
||||
selectedItem="@bind(fx.centre)">
|
||||
<template name="model">
|
||||
<comboitem label="@load(each.fullName)" />
|
||||
</template>
|
||||
</combobox>
|
||||
</cell>
|
||||
</row>
|
||||
<row>
|
||||
<cell sclass="row-title">${labels.RequirementsFormFrom} :</cell>
|
||||
<cell>
|
||||
<textbox
|
||||
id="from"
|
||||
width="300px"
|
||||
maxlength="@load(vm.lengthText)"
|
||||
value="@bind(fx.from)" />
|
||||
</cell>
|
||||
</row>
|
||||
<row>
|
||||
<cell sclass="row-title">${labels.RequirementsFormStartDateTime} :</cell>
|
||||
<cell>
|
||||
<hbox>
|
||||
<datebox
|
||||
id="tripDate"
|
||||
width="200px"
|
||||
format="medium"
|
||||
value="@bind(fx.tripDate)" />
|
||||
<timebox
|
||||
id="tripTime"
|
||||
width="90px"
|
||||
format="short"
|
||||
value="@bind(fx.tripDate)" />
|
||||
|
||||
</hbox>
|
||||
</cell>
|
||||
</row>
|
||||
<row>
|
||||
<cell sclass="row-title">${labels.RequirementsFormTo} :</cell>
|
||||
<cell>
|
||||
<textbox
|
||||
id="to"
|
||||
width="300px"
|
||||
maxlength="@load(vm.lengthText)"
|
||||
value="@bind(fx.to)" />
|
||||
</cell>
|
||||
</row>
|
||||
<row>
|
||||
<cell sclass="row-title">${labels.RequirementsFormPurpose} :</cell>
|
||||
<cell>
|
||||
<textbox
|
||||
id="description"
|
||||
width="300px"
|
||||
maxlength="@load(vm.lengthText)"
|
||||
value="@bind(fx.description)" />
|
||||
</cell>
|
||||
</row>
|
||||
<row>
|
||||
<cell sclass="row-title">${labels.RequirementsFormEndTravel} :</cell>
|
||||
<cell>
|
||||
<textbox
|
||||
id="end"
|
||||
width="200px"
|
||||
maxlength="@load(vm.lengthText)"
|
||||
value="@bind(fx.end)" />
|
||||
</cell>
|
||||
</row>
|
||||
<row>
|
||||
<cell sclass="row-title">${labels.RequirementsFormEndDate} :</cell>
|
||||
<cell>
|
||||
<datebox
|
||||
id="endDate"
|
||||
width="300px"
|
||||
format="medium"
|
||||
value="@bind(fx.endDate)" />
|
||||
</cell>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
<hbox>
|
||||
<grid hflex="min">
|
||||
<columns>
|
||||
<column
|
||||
align="right"
|
||||
hflex="min" />
|
||||
<column />
|
||||
</columns>
|
||||
<rows>
|
||||
<row>
|
||||
<cell sclass="row-title">${labels.RequirementsFormNumberSerie} :</cell>
|
||||
<cell>
|
||||
<textbox
|
||||
id="numser"
|
||||
width="200px"
|
||||
value="@bind(fx.numser)"
|
||||
maxlength="@load(vm.lengthText)"
|
||||
readonly="true" />
|
||||
</cell>
|
||||
</row>
|
||||
<row>
|
||||
<cell sclass="row-title">${labels.RequirementsFormReqDate} :</cell>
|
||||
<cell>
|
||||
<datebox
|
||||
id="reqDate"
|
||||
width="200px"
|
||||
value="@bind(fx.reqDate)"
|
||||
format="${labels.DateFormat}" />
|
||||
</cell>
|
||||
</row>
|
||||
<row>
|
||||
<cell sclass="row-title">${labels.RequirementsFormCenter} :</cell>
|
||||
<cell>
|
||||
<combobox
|
||||
model="@load(vm.centres)"
|
||||
readonly="true"
|
||||
selectedItem="@bind(fx.centre)">
|
||||
<template name="model">
|
||||
<comboitem label="@load(each.fullName)" />
|
||||
</template>
|
||||
</combobox>
|
||||
</cell>
|
||||
</row>
|
||||
<row>
|
||||
<cell sclass="row-title">${labels.RequirementsFormFrom} :</cell>
|
||||
<cell>
|
||||
<textbox
|
||||
id="from"
|
||||
width="300px"
|
||||
maxlength="@load(vm.lengthText)"
|
||||
value="@bind(fx.from)" />
|
||||
</cell>
|
||||
</row>
|
||||
<row>
|
||||
<cell sclass="row-title">${labels.RequirementsFormStartDateTime} :</cell>
|
||||
<cell>
|
||||
<hbox>
|
||||
<datebox
|
||||
id="tripDate"
|
||||
width="200px"
|
||||
format="medium"
|
||||
value="@bind(fx.tripDate)" />
|
||||
<timebox
|
||||
id="tripTime"
|
||||
width="90px"
|
||||
format="short"
|
||||
value="@bind(fx.tripDate)" />
|
||||
|
||||
</hbox>
|
||||
</cell>
|
||||
</row>
|
||||
<row>
|
||||
<cell sclass="row-title">${labels.RequirementsFormTo} :</cell>
|
||||
<cell>
|
||||
<textbox
|
||||
id="to"
|
||||
width="300px"
|
||||
maxlength="@load(vm.lengthText)"
|
||||
value="@bind(fx.to)" />
|
||||
</cell>
|
||||
</row>
|
||||
<row>
|
||||
<cell sclass="row-title">${labels.RequirementsFormPurpose} :</cell>
|
||||
<cell>
|
||||
<textbox
|
||||
id="description"
|
||||
width="300px"
|
||||
maxlength="@load(vm.lengthText)"
|
||||
value="@bind(fx.description)" />
|
||||
</cell>
|
||||
</row>
|
||||
<row>
|
||||
<cell sclass="row-title">${labels.RequirementsFormEndTravel} :</cell>
|
||||
<cell>
|
||||
<textbox
|
||||
id="end"
|
||||
width="200px"
|
||||
maxlength="@load(vm.lengthText)"
|
||||
value="@bind(fx.end)" />
|
||||
</cell>
|
||||
</row>
|
||||
<row>
|
||||
<cell sclass="row-title">${labels.RequirementsFormEndDate} :</cell>
|
||||
<cell>
|
||||
<datebox
|
||||
id="endDate"
|
||||
width="300px"
|
||||
format="medium"
|
||||
value="@bind(fx.endDate)" />
|
||||
</cell>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
<vbox>
|
||||
<button label="Připojit"
|
||||
upload="true"
|
||||
onUpload="@command('uploadAttachment')"
|
||||
sclass="nicebutton" />
|
||||
<grid model="@load(vm.attachments)">
|
||||
<columns>
|
||||
<column/>
|
||||
</columns>
|
||||
<rows>
|
||||
<template name="model">
|
||||
<row>
|
||||
<a href="@load('/api/dl/'.concat(each.pathInFilesystem).concat('/').concat(each.fileName))"
|
||||
label="@load(each.fileName)"
|
||||
target="blank"/>
|
||||
<hbox>
|
||||
<button label="Odebrat" onClick="@command('deleteAttachment', attachment=each)"/>
|
||||
<button label="Stáhnout" onClick="@command('downloadAttachment', attachment=each)"/>
|
||||
</hbox>
|
||||
</row>
|
||||
</template>
|
||||
</rows>
|
||||
</grid>
|
||||
</vbox>
|
||||
</hbox>
|
||||
<vbox>
|
||||
<label value="${labels.RequirementsFormPassengers}"/>
|
||||
<hbox>
|
||||
@@ -147,7 +176,7 @@
|
||||
<rows>
|
||||
<template name="model">
|
||||
<row>
|
||||
<label value="@load(each)"/>
|
||||
<label value="@load(each)" />
|
||||
<button label="${labels.RemoveItem}"
|
||||
onClick="@command('removePassanger', user=each)"
|
||||
sclass="nicebutton"/>
|
||||
|
||||
Reference in New Issue
Block a user