|
@@ -17,24 +17,32 @@ package org.codelibs.fess.app.web.admin.backup;
|
|
|
|
|
|
import static org.codelibs.core.stream.StreamUtil.stream;
|
|
|
|
|
|
+import java.io.BufferedWriter;
|
|
|
import java.io.ByteArrayInputStream;
|
|
|
import java.io.ByteArrayOutputStream;
|
|
|
import java.io.IOException;
|
|
|
import java.io.InputStream;
|
|
|
import java.io.OutputStream;
|
|
|
+import java.io.OutputStreamWriter;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.util.ArrayList;
|
|
|
import java.util.HashMap;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
+import javax.servlet.http.HttpServletResponse;
|
|
|
|
|
|
+import org.codelibs.core.CoreLibConstants;
|
|
|
import org.codelibs.core.exception.IORuntimeException;
|
|
|
import org.codelibs.core.io.CopyUtil;
|
|
|
import org.codelibs.core.lang.StringUtil;
|
|
|
import org.codelibs.elasticsearch.runner.net.Curl;
|
|
|
import org.codelibs.elasticsearch.runner.net.CurlResponse;
|
|
|
import org.codelibs.fess.app.web.base.FessAdminAction;
|
|
|
+import org.codelibs.fess.es.log.exbhv.SearchLogBhv;
|
|
|
import org.codelibs.fess.util.ComponentUtil;
|
|
|
import org.codelibs.fess.util.RenderDataUtil;
|
|
|
import org.codelibs.fess.util.ResourceUtil;
|
|
@@ -46,6 +54,10 @@ import org.lastaflute.web.ruts.process.ActionRuntime;
|
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
+import com.healthmarketscience.jackcess.RuntimeIOException;
|
|
|
+import com.orangesignal.csv.CsvConfig;
|
|
|
+import com.orangesignal.csv.CsvWriter;
|
|
|
+
|
|
|
/**
|
|
|
* @author shinsuke
|
|
|
*/
|
|
@@ -53,9 +65,16 @@ public class AdminBackupAction extends FessAdminAction {
|
|
|
|
|
|
private static final Logger logger = LoggerFactory.getLogger(AdminBackupAction.class);
|
|
|
|
|
|
+ private static final String CSV_EXTENTION = ".csv";
|
|
|
+
|
|
|
+ private static final DateTimeFormatter ISO_8601_FORMATTER = DateTimeFormatter.ofPattern(CoreLibConstants.DATE_FORMAT_ISO_8601_EXTEND);
|
|
|
+
|
|
|
@Resource
|
|
|
private AsyncManager asyncManager;
|
|
|
|
|
|
+ @Resource
|
|
|
+ private HttpServletResponse response;
|
|
|
+
|
|
|
@Override
|
|
|
protected void setupHtmlData(final ActionRuntime runtime) {
|
|
|
super.setupHtmlData(runtime);
|
|
@@ -104,7 +123,7 @@ public class AdminBackupAction extends FessAdminAction {
|
|
|
|
|
|
@Execute
|
|
|
public ActionResponse download(final String id) {
|
|
|
- if (stream(fessConfig.getIndexBackupTargetsAsArray()).get(stream -> stream.anyMatch(s -> s.equals(id)))) {
|
|
|
+ if (stream(fessConfig.getIndexBackupAllTargets()).get(stream -> stream.anyMatch(s -> s.equals(id)))) {
|
|
|
if (id.equals("system.properties")) {
|
|
|
return asStream(id).contentTypeOctetStream().stream(out -> {
|
|
|
try (final ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
|
@@ -114,6 +133,17 @@ public class AdminBackupAction extends FessAdminAction {
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
+ } else if (id.endsWith(CSV_EXTENTION)) {
|
|
|
+ String name = id.substring(0, id.length() - CSV_EXTENTION.length());
|
|
|
+ if ("search_log".equals(name)) {
|
|
|
+ writeSearchLogCsvResponse(id);
|
|
|
+ return redirect(getClass()); // no-op
|
|
|
+ } else if ("user_info".equals(id)) {
|
|
|
+ // TODO user_info=createdAt,updatedAt
|
|
|
+ }
|
|
|
+ // TODO search_field_log=name,searchLogId,value
|
|
|
+ // TODO favorite_log=queryId,userInfoId,docId,url,createdAt
|
|
|
+ // TODO click_log=queryId,userSessionId,docId,url,order,queryRequestedAt,requestedAt
|
|
|
} else {
|
|
|
final String index;
|
|
|
final String filename;
|
|
@@ -140,8 +170,70 @@ public class AdminBackupAction extends FessAdminAction {
|
|
|
return redirect(getClass()); // no-op
|
|
|
}
|
|
|
|
|
|
+ private void writeSearchLogCsvResponse(final String id) {
|
|
|
+ writeCsvResponseHeader(id);
|
|
|
+ final CsvConfig cfg = new CsvConfig(',', '"', '"');
|
|
|
+ cfg.setEscapeDisabled(false);
|
|
|
+ cfg.setQuoteDisabled(false);
|
|
|
+ try (final CsvWriter writer =
|
|
|
+ new CsvWriter(new BufferedWriter(new OutputStreamWriter(response.getOutputStream(), fessConfig.getCsvFileEncoding())), cfg)) {
|
|
|
+ SearchLogBhv searchLogBhv = ComponentUtil.getComponent(SearchLogBhv.class);
|
|
|
+ searchLogBhv.selectCursor(cb -> {
|
|
|
+ cb.query().matchAll();
|
|
|
+ cb.query().addOrderBy_RequestedAt_Asc();
|
|
|
+ }, entity -> {
|
|
|
+ List<String> list = new ArrayList<>();
|
|
|
+ addToList(entity.getQueryId(), list);
|
|
|
+ addToList(entity.getUserInfoId(), list);
|
|
|
+ addToList(entity.getUserSessionId(), list);
|
|
|
+ addToList(entity.getUser(), list);
|
|
|
+ addToList(entity.getSearchWord(), list);
|
|
|
+ addToList(entity.getHitCount(), list);
|
|
|
+ addToList(entity.getQueryPageSize(), list);
|
|
|
+ addToList(entity.getQueryOffset(), list);
|
|
|
+ addToList(entity.getReferer(), list);
|
|
|
+ addToList(entity.getLanguages(), list);
|
|
|
+ addToList(entity.getRoles(), list);
|
|
|
+ addToList(entity.getUserAgent(), list);
|
|
|
+ addToList(entity.getClientIp(), list);
|
|
|
+ addToList(entity.getAccessType(), list);
|
|
|
+ addToList(entity.getQueryTime(), list);
|
|
|
+ addToList(entity.getResponseTime(), list);
|
|
|
+ addToList(entity.getRequestedAt(), list);
|
|
|
+ try {
|
|
|
+ writer.writeValues(list);
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw new RuntimeIOException(e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ writer.flush();
|
|
|
+ } catch (final Exception e) {
|
|
|
+ logger.warn("Failed to write " + id + " to response.", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void addToList(final Object value, final List<String> list) {
|
|
|
+ if (value == null) {
|
|
|
+ list.add(StringUtil.EMPTY);
|
|
|
+ } else if (value instanceof LocalDateTime) {
|
|
|
+ list.add(((LocalDateTime) value).format(ISO_8601_FORMATTER));
|
|
|
+ } else if (value instanceof String[]) {
|
|
|
+ String.join(",", (String[]) value);
|
|
|
+ } else {
|
|
|
+ list.add(value.toString());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void writeCsvResponseHeader(final String id) {
|
|
|
+ response.setContentType("application/octet-stream");
|
|
|
+ response.addHeader("Content-Disposition", "attachment; filename=\"" + id + "\"");
|
|
|
+ response.addHeader("Pragma", "no-cache");
|
|
|
+ response.addHeader("Cache-Control", "no-cache");
|
|
|
+ response.addHeader("Expires", "Thu, 01 Dec 1994 16:00:00 GMT");
|
|
|
+ }
|
|
|
+
|
|
|
private List<Map<String, String>> getBackupItems() {
|
|
|
- return stream(fessConfig.getIndexBackupTargetsAsArray()).get(stream -> stream.filter(StringUtil::isNotBlank).map(name -> {
|
|
|
+ return stream(fessConfig.getIndexBackupAllTargets()).get(stream -> stream.map(name -> {
|
|
|
final Map<String, String> map = new HashMap<>();
|
|
|
map.put("id", name);
|
|
|
map.put("name", name);
|