/*
* Copyright 2015-Present Entando Inc. (http://www.entando.com) All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package org.entando.entando.apsadmin.filebrowser;
import com.agiletec.aps.util.SelectItem;
import com.agiletec.apsadmin.system.ApsAdminSystemConstants;
import com.agiletec.apsadmin.system.BaseAction;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.entando.entando.aps.system.services.storage.BasicFileAttributeView;
import org.entando.entando.aps.system.services.storage.IStorageManager;
import org.entando.entando.aps.system.services.storage.StorageManagerUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author S.Loru - E.Santoboni
*/
public class FileBrowserAction extends BaseAction {
private static final Logger _logger = LoggerFactory.getLogger(FileBrowserAction.class);
public String list() {
return SUCCESS;
}
public String edit() {
try {
String result = this.validateTextFileExtension(this.getFilename());
if (null != result) return result;
String validatePath = this.validateFullPath();
if (null != validatePath) return validatePath;
String fullPath = this.getCurrentPath() + this.getFilename();
BasicFileAttributeView fileAttributeView = this.getStorageManager().getAttributes(fullPath, this.getProtectedFolderBoolean());
if (null == fileAttributeView || fileAttributeView.isDirectory()) {
return INPUT;
}
String text = this.getStorageManager().readFile(fullPath, this.getProtectedFolderBoolean());
this.setFileText(text);
this.setStrutsAction(ApsAdminSystemConstants.EDIT);
} catch (Throwable t) {
_logger.error("error editing file, fullPath: {}", this.getCurrentPath(), t);
return FAILURE;
}
return SUCCESS;
}
public String newFile() {
this.setStrutsAction(ADD_NEW_FILE);
return SUCCESS;
}
public String uploadNewFile() {
this.setStrutsAction(UPLOAD_NEW_FILE);
return SUCCESS;
}
public String newDirectory() {
this.setStrutsAction(ADD_NEW_DIRECTORY);
return SUCCESS;
}
public String upload() {
try {
if (!StorageManagerUtil.isValidDirName(this.getCurrentPath())) {
this.addActionError(this.getText("error.filebrowser.filepath.invalid"));
return INPUT;
}
String result = this.checkExistingFileExtension(this.getCurrentPath(), this.getUploadFileName(), false);
if (null != result) return result;
this.getStorageManager().saveFile(this.getCurrentPath() + this.getUploadFileName(), this.getProtectedFolderBoolean(), this.getInputStream());
} catch (Throwable t) {
_logger.error("error in upload", t);
return FAILURE;
}
return SUCCESS;
}
public String trash() {
try {
String validatePath = this.validateFullPath();
if (null != validatePath) return validatePath;
String fullPath = this.getCurrentPath() + this.getFilename();
BasicFileAttributeView fileAttributeView = this.getStorageManager().getAttributes(fullPath, this.getProtectedFolderBoolean());
if (null == fileAttributeView) {
this.addActionError(this.getText("error.filebrowser.filepath.null"));
return INPUT;
}
this.setStrutsAction(ApsAdminSystemConstants.DELETE);
} catch (Throwable t) {
_logger.error("error in trash", t);
return FAILURE;
}
return SUCCESS;
}
public String delete() {
try {
if (null == this.isDeleteFile()) {
this.addActionError(this.getText("error.filebrowser.delete.missingInformation"));
return INPUT;
}
String validatePath = this.validateFullPath();
if (null != validatePath) return validatePath;
String subPath = this.getCurrentPath() + this.getFilename();
if (this.isDeleteFile()) {
this.getStorageManager().deleteFile(subPath, this.getProtectedFolderBoolean());
} else {
this.getStorageManager().deleteDirectory(subPath, this.getProtectedFolderBoolean());
}
} catch (Throwable t) {
_logger.error("error in delete", t);
return FAILURE;
}
return SUCCESS;
}
public String save() {
try {
String validatePath = this.validateFullPath();
if (null != validatePath) return validatePath;
InputStream stream = new ByteArrayInputStream(this.getFileText().getBytes(StandardCharsets.UTF_8));
String filename = this.getFilename();
if (this.getStrutsAction() == ADD_NEW_FILE) {
filename += "." + this.getTextFileExtension();
}
String result = this.validateTextFileExtension(filename);
if (null != result) return result;
boolean expectedExist = (this.getStrutsAction() == ApsAdminSystemConstants.EDIT);
result = this.checkExistingFileExtension(this.getCurrentPath(), filename, expectedExist);
if (null != result) return result;
this.getStorageManager().editFile(this.getCurrentPath() + filename, this.getProtectedFolderBoolean(), stream);
} catch (Throwable t) {
_logger.error("error saving file, fullPath: {} text: {}", this.getCurrentPath(), this.getFileText(), t);
return FAILURE;
}
return SUCCESS;
}
public boolean isTextFile(String filename) {
int index = filename.lastIndexOf(".");
String extension = (index > 0) ? filename.substring(index+1) : null;
if (StringUtils.isBlank(extension)) {
return false;
}
String[] extensions = this.getTextFileTypes();
for (int i = 0; i < extensions.length; i++) {
String allowedExtension = extensions[i];
if (allowedExtension.equalsIgnoreCase(extension)) {
return true;
}
}
return false;
}
protected String validateTextFileExtension(String filename) {
if (!this.isTextFile(filename)) {
this.addFieldError("textFileExtension", this.getText("error.filebrowser.addTextFile.wrongExtension"));
return INPUT;
}
return null;
}
protected String checkExistingFileExtension(String path, String filename, boolean expected) throws Throwable {
boolean exist = this.getStorageManager().exists(path + filename, this.getProtectedFolderBoolean());
if (exist != expected) {
String[] args = new String[]{filename};
if (expected) {
this.addFieldError("filename", this.getText("error.filebrowser.file.doesNotExist", args));
} else {
this.addFieldError("filename", this.getText("error.filebrowser.file.exist", args));
}
return INPUT;
}
return null;
}
public String createDir() {
try {
if (!StorageManagerUtil.isValidDirName(this.getCurrentPath())) {
this.addActionError(this.getText("error.filebrowser.filepath.invalid"));
return INPUT;
}
if (!StorageManagerUtil.isValidDirName(this.getDirname()) || this.getDirname().trim().length() == 0) {
this.addActionError(this.getText("error.filebrowser.dirname.invalid"));
return INPUT;
}
this.getStorageManager().createDirectory(this.getCurrentPath() + this.getDirname(), this.getProtectedFolderBoolean());
} catch (Throwable t) {
_logger.error("error creating dir, fullPath: {} text: {}", this.getCurrentPath(), this.getDirname(), t);
return FAILURE;
}
return SUCCESS;
}
public String download() {
try {
String validatePath = this.validateFullPath();
if (null != validatePath) return validatePath;
String fullPath = this.getCurrentPath() + this.getFilename();
InputStream is = this.getStorageManager().getStream(fullPath, this.getProtectedFolderBoolean());
if (null == is) {
this.addActionError(this.getText("error.filebrowser.download.missingFile"));
return INPUT;
}
this.setDownloadInputStream(is);
String contentType = URLConnection.guessContentTypeFromName(this.getFilename());
this.setDownloadContentType(contentType);
} catch (Throwable t) {
_logger.error("error downloading file, fullPath: '{}' file: '{}'", this.getCurrentPath(), this.getFilename(), t);
return FAILURE;
}
return SUCCESS;
}
public RootFolderAttributeView getRootFolder(boolean protectedFolder) {
String folderName = (protectedFolder) ? "protected" : "public";
return new RootFolderAttributeView(folderName, protectedFolder);
}
public List<SelectItem> getBreadCrumbsTargets() {
if (null == this.getProtectedFolder()) {
return null;
}
List<SelectItem> items = new ArrayList<SelectItem>();
RootFolderAttributeView rootFolder = this.getRootFolder(this.getProtectedFolderBoolean());
items.add(new SelectItem(null, rootFolder.getName()));
String currentPath = this.getCurrentPath();
if (StringUtils.isEmpty(currentPath)) {
return items;
}
String[] folders = currentPath.split("/");
for (int i = 0; i < folders.length; i++) {
String folderName = folders[i];
String subpath = null;
if (i == 0) {
subpath = folderName + "/";
} else if (i == (folders.length-1)) {
subpath = currentPath;
} else {
int index = currentPath.indexOf(folderName) + folderName.length();
subpath = currentPath.substring(0, index) + "/";
}
items.add(new SelectItem(subpath, folderName));
}
return items;
}
public BasicFileAttributeView[] getFilesAttributes() {
try {
if (!StorageManagerUtil.isValidDirName(this.getCurrentPath())) {
_logger.info("invalid path specified: {}", this.getCurrentPath());
this.setCurrentPath("");
}
if (null == this.getProtectedFolder()) {
BasicFileAttributeView[] bfav = new BasicFileAttributeView[2];
bfav[0] = this.getRootFolder(false);
bfav[1] = this.getRootFolder(true);
return bfav;
} else {
return this.getStorageManager().listAttributes(this.getCurrentPath(), this.getProtectedFolderBoolean());
}
} catch (Throwable t) {
_logger.error("error extraction file attributes, fullPath: {} ", this.getCurrentPath(), t);
return null;
}
}
public String getCurrentPath() {
if (StringUtils.isBlank(_currentPath) || null == this.getProtectedFolder()) {
_currentPath = "";
} else if (!_currentPath.endsWith("/")) {
_currentPath = _currentPath + "/";
}
return _currentPath;
}
/**
* Check the provided filename and currentPath parameters and raises an error if one of these parameters are invalid
* @return INPUT one or more errors are found. Otherwise null.
*/
protected String validateFullPath() {
if (!StorageManagerUtil.isValidFilenameNoExtension(this.getFilename())) {
this.addActionError(this.getText("error.filebrowser.filename.invalid"));
return INPUT;
}
if (!StorageManagerUtil.isValidDirName(this.getCurrentPath())) {
this.addActionError(this.getText("error.filebrowser.filepath.invalid"));
return INPUT;
}
return null;
}
public void setCurrentPath(String currentPath) {
this._currentPath = currentPath;
}
protected boolean getProtectedFolderBoolean() {
if (null == this.getProtectedFolder()) {
return false;
}
return Boolean.parseBoolean(this.getProtectedFolder());
}
public String getProtectedFolder() {
return _protectedFolder;
}
public void setProtectedFolder(String protectedFolder) {
this._protectedFolder = protectedFolder;
}
public String getFileText() {
return _fileText;
}
public void setFileText(String fileText) {
fileText = (null != fileText) ? fileText : "";
this._fileText = fileText;
}
public String getTextFileExtension() {
return _textFileExtension;
}
public void setTextFileExtension(String textFileExtension) {
this._textFileExtension = textFileExtension;
}
public int getStrutsAction() {
return _strutsAction;
}
public void setStrutsAction(int strutsAction) {
this._strutsAction = strutsAction;
}
public void setUpload(File file) {
this._file = file;
}
public File getUpload() {
return this._file;
}
public int getFileSize() {
return (int) this._file.length() / 1000;
}
public File getFile() {
return _file;
}
public InputStream getInputStream() throws Throwable {
if (null == this.getFile()) {
return null;
}
return new FileInputStream(this.getFile());
}
public String getFilename() {
if (StringUtils.isBlank(_filename)) {
_filename = "";
}
return _filename;
}
public void setFilename(String filename) {
this._filename = filename;
}
public String getDirname() {
return _dirname;
}
public void setDirname(String dirname) {
this._dirname = dirname;
}
public Boolean isDeleteFile() {
return _deleteFile;
}
public void setDeleteFile(Boolean deleteFile) {
this._deleteFile = deleteFile;
}
public String getUploadFileName() {
return _uploadFileName;
}
public void setUploadFileName(String uploadFileName) {
this._uploadFileName = uploadFileName;
}
public InputStream getUploadInputStream() {
return _uploadInputStream;
}
public void setUploadInputStream(InputStream uploadInputStream) {
this._uploadInputStream = uploadInputStream;
}
public String[] getTextFileTypes() {
return this.getTextFileTypesCSV().split(",");
}
protected String getTextFileTypesCSV() {
return _textFileTypesCSV;
}
public void setTextFileTypesCSV(String textFileTypesCSV) {
this._textFileTypesCSV = textFileTypesCSV;
}
public InputStream getDownloadInputStream() {
return _downloadInputStream;
}
public void setDownloadInputStream(InputStream downloadInputStream) {
this._downloadInputStream = downloadInputStream;
}
public String getDownloadContentType() {
return _downloadContentType;
}
public void setDownloadContentType(String downloadContentType) {
this._downloadContentType = downloadContentType;
}
protected IStorageManager getStorageManager() {
return _storageManager;
}
public void setStorageManager(IStorageManager storageManager) {
this._storageManager = storageManager;
}
private String _currentPath;
private String _protectedFolder = null;
private String _fileText;
private String _textFileExtension;
private String _filename;
private String _dirname;
private Boolean _deleteFile;
private int _strutsAction;
//variables for file upload
private File _file;
private String _uploadFileName;
private InputStream _uploadInputStream;
private String _textFileTypesCSV;
private InputStream _downloadInputStream;
private String _downloadContentType;
private IStorageManager _storageManager;
public static final int ADD_NEW_FILE = 11;
public static final int ADD_NEW_DIRECTORY = 12;
public static final int UPLOAD_NEW_FILE = 13;
}