diff --git a/src/main/java/org/codelibs/fess/app/web/admin/searchlist/AdminSearchlistAction.java b/src/main/java/org/codelibs/fess/app/web/admin/searchlist/AdminSearchlistAction.java index 3257213d0..fbd6027b1 100644 --- a/src/main/java/org/codelibs/fess/app/web/admin/searchlist/AdminSearchlistAction.java +++ b/src/main/java/org/codelibs/fess/app/web/admin/searchlist/AdminSearchlistAction.java @@ -15,6 +15,7 @@ */ package org.codelibs.fess.app.web.admin.searchlist; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -22,7 +23,6 @@ import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import org.codelibs.core.lang.StringUtil; -import org.codelibs.core.misc.Pair; import org.codelibs.fess.Constants; import org.codelibs.fess.app.service.SearchService; import org.codelibs.fess.app.web.CrudMode; @@ -216,14 +216,14 @@ public class AdminSearchlistAction extends FessAdminAction { } @Execute - public HtmlResponse createnew() { + public HtmlResponse createnew(final CreateForm form) { saveToken(); - return asHtml(path_AdminSearchlist_AdminSearchlistEditJsp).useForm(CreateForm.class, op -> { - op.setup(form -> { - form.initialize(); - form.crudMode = CrudMode.CREATE; - }); + form.initialize(); + form.crudMode = CrudMode.CREATE; + getDoc(form).ifPresent(entity -> { + form.doc = fessConfig.convertToEditableDoc(entity); }); + return asEditHtml(); } @Execute @@ -231,7 +231,7 @@ public class AdminSearchlistAction extends FessAdminAction { validate(form, messages -> {}, () -> asListHtml()); final String docId = form.docId; getDoc(form).ifPresent(entity -> { - form.doc = entity; + form.doc = fessConfig.convertToEditableDoc(entity); form.id = (String) entity.remove(fessConfig.getIndexFieldId()); form.version = (Long) entity.remove(fessConfig.getIndexFieldVersion()); }).orElse(() -> { @@ -245,18 +245,28 @@ public class AdminSearchlistAction extends FessAdminAction { public HtmlResponse create(final CreateForm form) { verifyCrudMode(form.crudMode, CrudMode.CREATE); validate(form, messages -> {}, () -> asEditHtml()); - // TODO verify + if (!fessConfig.hasIndexRequiredFields(form.doc)) { + throwValidationError(messages -> messages.addErrorsCrudFailedToCreateInstance(GLOBAL), () -> asEditHtml()); + } verifyToken(() -> asEditHtml()); - getDoc(form).ifPresent(entity -> { - try { - // TODO save - saveInfo(messages -> messages.addSuccessCrudCreateCrudTable(GLOBAL)); - } catch (final Exception e) { - logger.error("Failed to add " + entity, e); - throwValidationError(messages -> messages.addErrorsCrudFailedToCreateCrudTable(GLOBAL, buildThrowableMessage(e)), - () -> asEditHtml()); - } - }).orElse(() -> { + getDoc(form).ifPresent( + entity -> { + try { + entity.putAll(fessConfig.convertToStorableDoc(form.doc)); + + final String newId = ComponentUtil.getCrawlingInfoHelper().generateId(entity); + entity.put(fessConfig.getIndexFieldId(), newId); + + final String index = fessConfig.getIndexDocumentUpdateIndex(); + final String type = fessConfig.getIndexDocumentType(); + fessEsClient.store(index, type, entity); + saveInfo(messages -> messages.addSuccessCrudCreateCrudTable(GLOBAL)); + } catch (final Exception e) { + logger.error("Failed to add " + entity, e); + throwValidationError(messages -> messages.addErrorsCrudFailedToCreateCrudTable(GLOBAL, buildThrowableMessage(e)), + () -> asEditHtml()); + } + }).orElse(() -> { throwValidationError(messages -> messages.addErrorsCrudFailedToCreateInstance(GLOBAL), () -> asEditHtml()); }); return redirect(getClass()); @@ -266,25 +276,25 @@ public class AdminSearchlistAction extends FessAdminAction { public HtmlResponse update(final EditForm form) { verifyCrudMode(form.crudMode, CrudMode.EDIT); validate(form, messages -> {}, () -> asEditHtml()); - // TODO verify + if (!fessConfig.hasIndexRequiredFields(form.doc)) { + throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.docId), () -> asEditHtml()); + } verifyToken(() -> asEditHtml()); getDoc(form).ifPresent( entity -> { try { - form.doc.entrySet().stream().map(e -> { - // TODO converter - return new Pair<>(e.getKey(), e.getValue()); - }).forEach(p -> entity.put(p.getFirst(), p.getSecond())); + entity.putAll(fessConfig.convertToStorableDoc(form.doc)); final String newId = ComponentUtil.getCrawlingInfoHelper().generateId(entity); String oldId = null; if (newId.equals(form.id)) { entity.put(fessConfig.getIndexFieldId(), form.id); + entity.put(fessConfig.getIndexFieldVersion(), form.version); } else { oldId = form.id; entity.put(fessConfig.getIndexFieldId(), newId); + entity.remove(fessConfig.getIndexFieldVersion()); } - entity.put(fessConfig.getIndexFieldVersion(), form.version); final String index = fessConfig.getIndexDocumentUpdateIndex(); final String type = fessConfig.getIndexDocumentType(); @@ -318,8 +328,9 @@ public class AdminSearchlistAction extends FessAdminAction { protected OptionalEntity> getDoc(final CreateForm form) { switch (form.crudMode) { case CrudMode.CREATE: - // TODO - return OptionalEntity.empty(); + Map entity = new HashMap<>(); + entity.put(fessConfig.getIndexFieldDocId(), systemHelper.generateDocId(entity)); + return OptionalEntity.of(entity); case CrudMode.EDIT: if (form instanceof EditForm) { final String docId = ((EditForm) form).docId; diff --git a/src/main/java/org/codelibs/fess/es/client/FessEsClient.java b/src/main/java/org/codelibs/fess/es/client/FessEsClient.java index ce0ea3d5d..13001d2d8 100644 --- a/src/main/java/org/codelibs/fess/es/client/FessEsClient.java +++ b/src/main/java/org/codelibs/fess/es/client/FessEsClient.java @@ -966,9 +966,12 @@ public class FessEsClient implements Client { .actionGet(fessConfig.getIndexIndexTimeout()); } else { // create or update - response = - client.prepareIndex(index, type, id).setSource(source).setRefresh(true).setOpType(OpType.INDEX).setVersion(version) - .execute().actionGet(fessConfig.getIndexIndexTimeout()); + IndexRequestBuilder builder = + client.prepareIndex(index, type, id).setSource(source).setRefresh(true).setOpType(OpType.INDEX); + if (version != null && version.longValue() > 0) { + builder.setVersion(version); + } + response = builder.execute().actionGet(fessConfig.getIndexIndexTimeout()); } return response.isCreated(); } catch (final ElasticsearchException e) { diff --git a/src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java b/src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java index 662ed2259..bd895213e 100644 --- a/src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java +++ b/src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java @@ -352,6 +352,27 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction /** The key of the configuration. e.g. doc */ String INDEX_DOCUMENT_TYPE = "index.document.type"; + /** The key of the configuration. e.g. lang,role,label,anchor */ + String INDEX_ADMIN_ARRAY_FIELDS = "index.admin.array.fields"; + + /** The key of the configuration. e.g. expires,created,timestamp,last_modified */ + String INDEX_ADMIN_DATE_FIELDS = "index.admin.date.fields"; + + /** The key of the configuration. e.g. */ + String INDEX_ADMIN_INTEGER_FIELDS = "index.admin.integer.fields"; + + /** The key of the configuration. e.g. favorite_count,click_count */ + String INDEX_ADMIN_LONG_FIELDS = "index.admin.long.fields"; + + /** The key of the configuration. e.g. boost */ + String INDEX_ADMIN_FLOAT_FIELDS = "index.admin.float.fields"; + + /** The key of the configuration. e.g. */ + String INDEX_ADMIN_DOUBLE_FIELDS = "index.admin.double.fields"; + + /** The key of the configuration. e.g. doc_id,url,title,role */ + String INDEX_ADMIN_REQUIRED_FIELDS = "index.admin.required.fields"; + /** The key of the configuration. e.g. 3m */ String INDEX_SEARCH_TIMEOUT = "index.search.timeout"; @@ -1988,6 +2009,72 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction */ String getIndexDocumentType(); + /** + * Get the value for the key 'index.admin.array.fields'.
+ * The value is, e.g. lang,role,label,anchor
+ * comment: doc management + * @return The value of found property. (NotNull: if not found, exception but basically no way) + */ + String getIndexAdminArrayFields(); + + /** + * Get the value for the key 'index.admin.date.fields'.
+ * The value is, e.g. expires,created,timestamp,last_modified
+ * @return The value of found property. (NotNull: if not found, exception but basically no way) + */ + String getIndexAdminDateFields(); + + /** + * Get the value for the key 'index.admin.integer.fields'.
+ * The value is, e.g.
+ * @return The value of found property. (NotNull: if not found, exception but basically no way) + */ + String getIndexAdminIntegerFields(); + + /** + * Get the value for the key 'index.admin.integer.fields' as {@link Integer}.
+ * The value is, e.g.
+ * @return The value of found property. (NotNull: if not found, exception but basically no way) + * @throws NumberFormatException When the property is not integer. + */ + Integer getIndexAdminIntegerFieldsAsInteger(); + + /** + * Get the value for the key 'index.admin.long.fields'.
+ * The value is, e.g. favorite_count,click_count
+ * @return The value of found property. (NotNull: if not found, exception but basically no way) + */ + String getIndexAdminLongFields(); + + /** + * Get the value for the key 'index.admin.float.fields'.
+ * The value is, e.g. boost
+ * @return The value of found property. (NotNull: if not found, exception but basically no way) + */ + String getIndexAdminFloatFields(); + + /** + * Get the value for the key 'index.admin.double.fields'.
+ * The value is, e.g.
+ * @return The value of found property. (NotNull: if not found, exception but basically no way) + */ + String getIndexAdminDoubleFields(); + + /** + * Get the value for the key 'index.admin.double.fields' as {@link Integer}.
+ * The value is, e.g.
+ * @return The value of found property. (NotNull: if not found, exception but basically no way) + * @throws NumberFormatException When the property is not integer. + */ + Integer getIndexAdminDoubleFieldsAsInteger(); + + /** + * Get the value for the key 'index.admin.required.fields'.
+ * The value is, e.g. doc_id,url,title,role
+ * @return The value of found property. (NotNull: if not found, exception but basically no way) + */ + String getIndexAdminRequiredFields(); + /** * Get the value for the key 'index.search.timeout'.
* The value is, e.g. 3m
@@ -4540,6 +4627,42 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction return get(FessConfig.INDEX_DOCUMENT_TYPE); } + public String getIndexAdminArrayFields() { + return get(FessConfig.INDEX_ADMIN_ARRAY_FIELDS); + } + + public String getIndexAdminDateFields() { + return get(FessConfig.INDEX_ADMIN_DATE_FIELDS); + } + + public String getIndexAdminIntegerFields() { + return get(FessConfig.INDEX_ADMIN_INTEGER_FIELDS); + } + + public Integer getIndexAdminIntegerFieldsAsInteger() { + return getAsInteger(FessConfig.INDEX_ADMIN_INTEGER_FIELDS); + } + + public String getIndexAdminLongFields() { + return get(FessConfig.INDEX_ADMIN_LONG_FIELDS); + } + + public String getIndexAdminFloatFields() { + return get(FessConfig.INDEX_ADMIN_FLOAT_FIELDS); + } + + public String getIndexAdminDoubleFields() { + return get(FessConfig.INDEX_ADMIN_DOUBLE_FIELDS); + } + + public Integer getIndexAdminDoubleFieldsAsInteger() { + return getAsInteger(FessConfig.INDEX_ADMIN_DOUBLE_FIELDS); + } + + public String getIndexAdminRequiredFields() { + return get(FessConfig.INDEX_ADMIN_REQUIRED_FIELDS); + } + public String getIndexSearchTimeout() { return get(FessConfig.INDEX_SEARCH_TIMEOUT); } diff --git a/src/main/java/org/codelibs/fess/mylasta/direction/FessProp.java b/src/main/java/org/codelibs/fess/mylasta/direction/FessProp.java index e0f9c8e17..ea638b9eb 100644 --- a/src/main/java/org/codelibs/fess/mylasta/direction/FessProp.java +++ b/src/main/java/org/codelibs/fess/mylasta/direction/FessProp.java @@ -18,6 +18,7 @@ package org.codelibs.fess.mylasta.direction; import static org.codelibs.core.stream.StreamUtil.stream; import java.util.Collections; +import java.util.Date; import java.util.Enumeration; import java.util.HashSet; import java.util.List; @@ -39,6 +40,7 @@ import org.codelibs.core.misc.Tuple3; import org.codelibs.fess.Constants; import org.codelibs.fess.helper.PermissionHelper; import org.codelibs.fess.mylasta.action.FessUserBean; +import org.codelibs.fess.taglib.FessFunctions; import org.codelibs.fess.util.ComponentUtil; import org.dbflute.optional.OptionalThing; import org.elasticsearch.action.search.SearchRequestBuilder; @@ -48,6 +50,18 @@ import org.lastaflute.web.util.LaRequestUtil; public interface FessProp { + public static final String INDEX_ADMIN_ARRAY_FIELD_SET = "indexAdminArrayFieldSet"; + + public static final String INDEX_ADMIN_DATE_FIELD_SET = "indexAdminDateFieldSet"; + + public static final String INDEX_ADMIN_INTEGER_FIELD_SET = "indexAdminIntegerFieldSet"; + + public static final String INDEX_ADMIN_LONG_FIELD_SET = "indexAdminLongFieldSet"; + + public static final String INDEX_ADMIN_FLOAT_FIELD_SET = "indexAdminFloatFieldSet"; + + public static final String INDEX_ADMIN_DOUBLE_FIELD_SET = "indexAdminDoubleFieldSet"; + public static final String OIC_DEFAULT_ROLES = "oicDefaultRoles"; public static final String OIC_DEFAULT_GROUPS = "oicDefaultGroups"; @@ -1034,4 +1048,172 @@ public interface FessProp { } return array; } + + String getIndexAdminArrayFields(); + + public default Set getIndexAdminArrayFieldSet() { + @SuppressWarnings("unchecked") + Set fieldSet = (Set) propMap.get(INDEX_ADMIN_ARRAY_FIELD_SET); + if (fieldSet == null) { + fieldSet = + stream(getIndexAdminArrayFields().split(",")).get( + stream -> stream.filter(StringUtil::isNotBlank).map(s -> s.trim()).collect(Collectors.toSet())); + propMap.put(INDEX_ADMIN_ARRAY_FIELD_SET, fieldSet); + } + return fieldSet; + } + + String getIndexAdminDateFields(); + + public default Set getIndexAdminDateFieldSet() { + @SuppressWarnings("unchecked") + Set fieldSet = (Set) propMap.get(INDEX_ADMIN_DATE_FIELD_SET); + if (fieldSet == null) { + fieldSet = + stream(getIndexAdminDateFields().split(",")).get( + stream -> stream.filter(StringUtil::isNotBlank).map(s -> s.trim()).collect(Collectors.toSet())); + propMap.put(INDEX_ADMIN_DATE_FIELD_SET, fieldSet); + } + return fieldSet; + } + + String getIndexAdminIntegerFields(); + + public default Set getIndexAdminIntegerFieldSet() { + @SuppressWarnings("unchecked") + Set fieldSet = (Set) propMap.get(INDEX_ADMIN_INTEGER_FIELD_SET); + if (fieldSet == null) { + fieldSet = + stream(getIndexAdminIntegerFields().split(",")).get( + stream -> stream.filter(StringUtil::isNotBlank).map(s -> s.trim()).collect(Collectors.toSet())); + propMap.put(INDEX_ADMIN_INTEGER_FIELD_SET, fieldSet); + } + return fieldSet; + } + + String getIndexAdminLongFields(); + + public default Set getIndexAdminLongFieldSet() { + @SuppressWarnings("unchecked") + Set fieldSet = (Set) propMap.get(INDEX_ADMIN_LONG_FIELD_SET); + if (fieldSet == null) { + fieldSet = + stream(getIndexAdminLongFields().split(",")).get( + stream -> stream.filter(StringUtil::isNotBlank).map(s -> s.trim()).collect(Collectors.toSet())); + propMap.put(INDEX_ADMIN_LONG_FIELD_SET, fieldSet); + } + return fieldSet; + } + + String getIndexAdminFloatFields(); + + public default Set getIndexAdminFloatFieldSet() { + @SuppressWarnings("unchecked") + Set fieldSet = (Set) propMap.get(INDEX_ADMIN_FLOAT_FIELD_SET); + if (fieldSet == null) { + fieldSet = + stream(getIndexAdminFloatFields().split(",")).get( + stream -> stream.filter(StringUtil::isNotBlank).map(s -> s.trim()).collect(Collectors.toSet())); + propMap.put(INDEX_ADMIN_FLOAT_FIELD_SET, fieldSet); + } + return fieldSet; + } + + String getIndexAdminDoubleFields(); + + public default Set getIndexAdminDoubleFieldSet() { + @SuppressWarnings("unchecked") + Set fieldSet = (Set) propMap.get(INDEX_ADMIN_DOUBLE_FIELD_SET); + if (fieldSet == null) { + fieldSet = + stream(getIndexAdminDoubleFields().split(",")).get( + stream -> stream.filter(StringUtil::isNotBlank).map(s -> s.trim()).collect(Collectors.toSet())); + propMap.put(INDEX_ADMIN_DOUBLE_FIELD_SET, fieldSet); + } + return fieldSet; + } + + public default Map convertToEditableDoc(final Map source) { + + final Set arrayFieldSet = getIndexAdminArrayFieldSet(); + final Set dateFieldSet = getIndexAdminDateFieldSet(); + final Set integerFieldSet = getIndexAdminIntegerFieldSet(); + final Set longFieldSet = getIndexAdminLongFieldSet(); + final Set floatFieldSet = getIndexAdminFloatFieldSet(); + final Set doubleFieldSet = getIndexAdminDoubleFieldSet(); + + return source.entrySet().stream().map(e -> { + final String key = e.getKey(); + Object value = e.getValue(); + if (value instanceof String || value == null) { + return new Pair(key, value); + } + if (arrayFieldSet.contains(key)) { + if (value instanceof String[]) { + value = stream((String[]) value).get(stream -> stream.collect(Collectors.joining("\n"))); + } else if (value instanceof List) { + @SuppressWarnings("unchecked") + final List list = (List) value; + value = list.stream().collect(Collectors.joining("\n")); + } + } else if (dateFieldSet.contains(key)) { + value = FessFunctions.formatDate((Date) value); + } else if (integerFieldSet.contains(key)) { + value = value.toString(); + } else if (longFieldSet.contains(key)) { + value = value.toString(); + } else if (floatFieldSet.contains(key)) { + value = value.toString(); + } else if (doubleFieldSet.contains(key)) { + value = value.toString(); + } + return new Pair(key, value); + }).collect(Collectors.toMap(Pair::getFirst, Pair::getSecond)); + } + + public default Map convertToStorableDoc(final Map source) { + + final Set arrayFieldSet = getIndexAdminArrayFieldSet(); + final Set dateFieldSet = getIndexAdminDateFieldSet(); + final Set integerFieldSet = getIndexAdminIntegerFieldSet(); + final Set longFieldSet = getIndexAdminLongFieldSet(); + final Set floatFieldSet = getIndexAdminFloatFieldSet(); + final Set doubleFieldSet = getIndexAdminDoubleFieldSet(); + + return source + .entrySet() + .stream() + .map(e -> { + final String key = e.getKey(); + Object value = e.getValue(); + if (value == null) { + return new Pair(key, value); + } + if (arrayFieldSet.contains(key)) { + value = + stream(value.toString().split("\n")).get( + stream -> stream.filter(StringUtil::isNotBlank).map(s -> s.trim()).collect(Collectors.toList())); + } else if (dateFieldSet.contains(key)) { + // TODO time zone + value = FessFunctions.parseDate(value.toString()); + } else if (integerFieldSet.contains(key)) { + value = Integer.parseInt(value.toString()); + } else if (longFieldSet.contains(key)) { + value = Long.parseLong(value.toString()); + } else if (floatFieldSet.contains(key)) { + value = Float.parseFloat(value.toString()); + } else if (doubleFieldSet.contains(key)) { + value = Double.parseDouble(value.toString()); + } + return new Pair(key, value); + }).collect(Collectors.toMap(Pair::getFirst, Pair::getSecond)); + } + + String getIndexAdminRequiredFields(); + + public default boolean hasIndexRequiredFields(final Map source) { + return stream(getIndexAdminRequiredFields().split(",")).get( + stream -> stream.filter(StringUtil::isNotBlank).map(s -> s.trim()).allMatch(s -> source.containsKey(s))); + } + } diff --git a/src/main/resources/fess_config.properties b/src/main/resources/fess_config.properties index 9668ccfa0..482b47cc8 100644 --- a/src/main/resources/fess_config.properties +++ b/src/main/resources/fess_config.properties @@ -171,6 +171,15 @@ index.document.search.index=fess index.document.update.index=fess index.document.type=doc +# doc management +index.admin.array.fields=lang,role,label,anchor +index.admin.date.fields=expires,created,timestamp,last_modified +index.admin.integer.fields= +index.admin.long.fields=favorite_count,click_count +index.admin.float.fields=boost +index.admin.double.fields= +index.admin.required.fields=doc_id,url,title,role + # timeout index.search.timeout=3m index.scroll.search.timeout.timeout=3m diff --git a/src/main/webapp/WEB-INF/view/admin/searchlist/admin_searchlist.jsp b/src/main/webapp/WEB-INF/view/admin/searchlist/admin_searchlist.jsp index f1be5978b..8f43ac917 100644 --- a/src/main/webapp/WEB-INF/view/admin/searchlist/admin_searchlist.jsp +++ b/src/main/webapp/WEB-INF/view/admin/searchlist/admin_searchlist.jsp @@ -33,6 +33,12 @@

+
+ + + + +
<%-- Box Body --%>
diff --git a/src/main/webapp/WEB-INF/view/admin/searchlist/admin_searchlist_edit.jsp b/src/main/webapp/WEB-INF/view/admin/searchlist/admin_searchlist_edit.jsp index 8b751735a..11a5ffe30 100644 --- a/src/main/webapp/WEB-INF/view/admin/searchlist/admin_searchlist_edit.jsp +++ b/src/main/webapp/WEB-INF/view/admin/searchlist/admin_searchlist_edit.jsp @@ -78,6 +78,20 @@
+
+ +
+ + +
+
+
+ +
+ + +
+
@@ -85,6 +99,13 @@
+
+ +
+ + +
+