diff --git a/src/main/java/org/codelibs/fess/app/pager/ProtwordsPager.java b/src/main/java/org/codelibs/fess/app/pager/ProtwordsPager.java new file mode 100644 index 000000000..082bc4df9 --- /dev/null +++ b/src/main/java/org/codelibs/fess/app/pager/ProtwordsPager.java @@ -0,0 +1,123 @@ +/* + * Copyright 2012-2016 CodeLibs Project and the Others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.codelibs.fess.app.pager; + +import java.io.Serializable; +import java.util.List; + +import org.codelibs.fess.Constants; + +public class ProtwordsPager implements Serializable { + + private static final long serialVersionUID = 1L; + + private int allRecordCount; + + private int allPageCount; + + private boolean existPrePage; + + private boolean existNextPage; + + private List pageNumberList; + + private int pageSize; + + private int currentPageNumber; + + public String id; + + public void clear() { + allRecordCount = 0; + allPageCount = 0; + existPrePage = false; + existNextPage = false; + pageSize = getDefaultPageSize(); + currentPageNumber = getDefaultCurrentPageNumber(); + + id = null; + } + + protected int getDefaultPageSize() { + return Constants.DEFAULT_ADMIN_PAGE_SIZE; + } + + protected int getDefaultCurrentPageNumber() { + return 1; + } + + public int getAllRecordCount() { + return allRecordCount; + } + + public void setAllRecordCount(final int allRecordCount) { + this.allRecordCount = allRecordCount; + } + + public int getAllPageCount() { + return allPageCount; + } + + public void setAllPageCount(final int allPageCount) { + this.allPageCount = allPageCount; + } + + public boolean isExistPrePage() { + return existPrePage; + } + + public void setExistPrePage(final boolean existPrePage) { + this.existPrePage = existPrePage; + } + + public boolean isExistNextPage() { + return existNextPage; + } + + public void setExistNextPage(final boolean existNextPage) { + this.existNextPage = existNextPage; + } + + public int getPageSize() { + if (pageSize <= 0) { + pageSize = getDefaultPageSize(); + } + return pageSize; + } + + public void setPageSize(final int pageSize) { + this.pageSize = pageSize; + } + + public int getCurrentPageNumber() { + if (currentPageNumber <= 0) { + currentPageNumber = getDefaultCurrentPageNumber(); + } + return currentPageNumber; + } + + public void setCurrentPageNumber(final int currentPageNumber) { + this.currentPageNumber = currentPageNumber; + } + + public List getPageNumberList() { + return pageNumberList; + } + + public void setPageNumberList(final List pageNumberList) { + this.pageNumberList = pageNumberList; + } +} diff --git a/src/main/java/org/codelibs/fess/app/service/ProtwordsService.java b/src/main/java/org/codelibs/fess/app/service/ProtwordsService.java new file mode 100644 index 000000000..0466ffa6c --- /dev/null +++ b/src/main/java/org/codelibs/fess/app/service/ProtwordsService.java @@ -0,0 +1,76 @@ +/* + * Copyright 2012-2016 CodeLibs Project and the Others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.codelibs.fess.app.service; + +import java.util.Collections; +import java.util.List; + +import javax.annotation.Resource; + +import org.codelibs.core.beans.util.BeanUtil; +import org.codelibs.fess.Constants; +import org.codelibs.fess.app.pager.ProtwordsPager; +import org.codelibs.fess.dict.DictionaryFile.PagingList; +import org.codelibs.fess.dict.DictionaryManager; +import org.codelibs.fess.dict.protwords.ProtwordsFile; +import org.codelibs.fess.dict.protwords.ProtwordsItem; +import org.dbflute.optional.OptionalEntity; + +public class ProtwordsService { + @Resource + protected DictionaryManager dictionaryManager; + + public List getProtwordsList(final String dictId, final ProtwordsPager protwordsPager) { + return getProtwordsFile(dictId).map( + file -> { + final int pageSize = protwordsPager.getPageSize(); + final PagingList protwordsList = + file.selectList((protwordsPager.getCurrentPageNumber() - 1) * pageSize, pageSize); + + // update pager + BeanUtil.copyBeanToBean(protwordsList, protwordsPager, option -> option.include(Constants.PAGER_CONVERSION_RULE)); + protwordsList.setPageRangeSize(5); + protwordsPager.setPageNumberList(protwordsList.createPageNumberList()); + + return (List) protwordsList; + }).orElse(Collections.emptyList()); + } + + public OptionalEntity getProtwordsFile(final String dictId) { + return dictionaryManager.getDictionaryFile(dictId).filter(file -> file instanceof ProtwordsFile) + .map(file -> OptionalEntity.of((ProtwordsFile) file)).orElse(OptionalEntity.empty()); + } + + public OptionalEntity getProtwordsItem(final String dictId, final long id) { + return getProtwordsFile(dictId).map(file -> file.get(id).get()); + } + + public void store(final String dictId, final ProtwordsItem protwordsItem) { + getProtwordsFile(dictId).ifPresent(file -> { + if (protwordsItem.getId() == 0) { + file.insert(protwordsItem); + } else { + file.update(protwordsItem); + } + }); + } + + public void delete(final String dictId, final ProtwordsItem protwordsItem) { + getProtwordsFile(dictId).ifPresent(file -> { + file.delete(protwordsItem); + }); + } +} diff --git a/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/AdminDictProtwordsAction.java b/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/AdminDictProtwordsAction.java new file mode 100644 index 000000000..f5aef14af --- /dev/null +++ b/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/AdminDictProtwordsAction.java @@ -0,0 +1,391 @@ +/* + * Copyright 2012-2016 CodeLibs Project and the Others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.codelibs.fess.app.web.admin.dict.protwords; + +import static org.codelibs.core.stream.StreamUtil.stream; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import javax.annotation.Resource; + +import org.codelibs.core.beans.util.BeanUtil; +import org.codelibs.core.lang.StringUtil; +import org.codelibs.fess.Constants; +import org.codelibs.fess.app.pager.ProtwordsPager; +import org.codelibs.fess.app.service.ProtwordsService; +import org.codelibs.fess.app.web.CrudMode; +import org.codelibs.fess.app.web.admin.dict.AdminDictAction; +import org.codelibs.fess.app.web.base.FessAdminAction; +import org.codelibs.fess.dict.protwords.ProtwordsItem; +import org.codelibs.fess.util.RenderDataUtil; +import org.dbflute.optional.OptionalEntity; +import org.dbflute.optional.OptionalThing; +import org.lastaflute.web.Execute; +import org.lastaflute.web.response.ActionResponse; +import org.lastaflute.web.response.HtmlResponse; +import org.lastaflute.web.response.render.RenderData; +import org.lastaflute.web.ruts.process.ActionRuntime; +import org.lastaflute.web.validation.VaErrorHook; + +/** + * @author nocode + * @author shinsuke + */ +public class AdminDictProtwordsAction extends FessAdminAction { + + // =================================================================================== + // Attribute + // ========= + @Resource + private ProtwordsService protwordsService; + @Resource + private ProtwordsPager protwordsPager; + + // =================================================================================== + // Hook + // ====== + @Override + protected void setupHtmlData(final ActionRuntime runtime) { + super.setupHtmlData(runtime); + runtime.registerData("helpLink", systemHelper.getHelpLink(fessConfig.getOnlineHelpNameDictProtwords())); + } + + // =================================================================================== + // Search Execute + // ============== + @Execute + public HtmlResponse index(final SearchForm form) { + validate(form, messages -> {}, () -> asDictIndexHtml()); + return asHtml(path_AdminDictProtwords_AdminDictProtwordsJsp).renderWith(data -> { + searchPaging(data, form); + }); + } + + @Execute + public HtmlResponse list(final OptionalThing pageNumber, final SearchForm form) { + validate(form, messages -> {}, () -> asDictIndexHtml()); + pageNumber.ifPresent(num -> { + protwordsPager.setCurrentPageNumber(pageNumber.get()); + }).orElse(() -> { + protwordsPager.setCurrentPageNumber(0); + }); + return asHtml(path_AdminDictProtwords_AdminDictProtwordsJsp).renderWith(data -> { + searchPaging(data, form); + }); + } + + @Execute + public HtmlResponse search(final SearchForm form) { + validate(form, messages -> {}, () -> asDictIndexHtml()); + copyBeanToBean(form, protwordsPager, op -> op.exclude(Constants.PAGER_CONVERSION_RULE)); + return asHtml(path_AdminDictProtwords_AdminDictProtwordsJsp).renderWith(data -> { + searchPaging(data, form); + }); + } + + @Execute + public HtmlResponse reset(final SearchForm form) { + validate(form, messages -> {}, () -> asDictIndexHtml()); + protwordsPager.clear(); + return asHtml(path_AdminDictProtwords_AdminDictProtwordsJsp).renderWith(data -> { + searchPaging(data, form); + }); + } + + protected void searchPaging(final RenderData data, final SearchForm form) { + // page navi + RenderDataUtil.register(data, "protwordsItemItems", protwordsService.getProtwordsList(form.dictId, protwordsPager)); + + // restore from pager + BeanUtil.copyBeanToBean(protwordsPager, form, op -> { + op.exclude(Constants.PAGER_CONVERSION_RULE); + }); + } + + // =================================================================================== + // Edit Execute + // ============ + // ----------------------------------------------------- + // Entry Page + // ---------- + @Execute + public HtmlResponse createnew(final String dictId) { + saveToken(); + return asHtml(path_AdminDictProtwords_AdminDictProtwordsEditJsp).useForm(CreateForm.class, op -> { + op.setup(form -> { + form.initialize(); + form.crudMode = CrudMode.CREATE; + form.dictId = dictId; + }); + }); + } + + @Execute + public HtmlResponse edit(final EditForm form) { + validate(form, messages -> {}, () -> asListHtml(form.dictId)); + protwordsService + .getProtwordsItem(form.dictId, form.id) + .ifPresent(entity -> { + form.inputs = entity.getInputsValue(); + }) + .orElse(() -> { + throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.getDisplayId()), + () -> asListHtml(form.dictId)); + }); + saveToken(); + if (form.crudMode.intValue() == CrudMode.EDIT) { + // back + form.crudMode = CrudMode.DETAILS; + return asDetailsHtml(); + } else { + form.crudMode = CrudMode.EDIT; + return asEditHtml(); + } + } + + // ----------------------------------------------------- + // Details + // ------- + @Execute + public HtmlResponse details(final String dictId, final int crudMode, final long id) { + verifyCrudMode(crudMode, CrudMode.DETAILS, dictId); + saveToken(); + return asDetailsHtml().useForm( + EditForm.class, + op -> { + op.setup(form -> { + protwordsService + .getProtwordsItem(dictId, id) + .ifPresent(entity -> { + form.inputs = entity.getInputsValue(); + }) + .orElse(() -> { + throwValidationError( + messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, dictId + ":" + id), + () -> asListHtml(dictId)); + }); + form.id = id; + form.crudMode = crudMode; + form.dictId = dictId; + }); + }); + } + + // ----------------------------------------------------- + // Download + // ------- + @Execute + public HtmlResponse downloadpage(final String dictId) { + saveToken(); + return asHtml(path_AdminDictProtwords_AdminDictProtwordsDownloadJsp).useForm(DownloadForm.class, op -> { + op.setup(form -> { + form.dictId = dictId; + }); + }).renderWith(data -> { + protwordsService.getProtwordsFile(dictId).ifPresent(file -> { + RenderDataUtil.register(data, "path", file.getPath()); + }).orElse(() -> { + throwValidationError(messages -> messages.addErrorsFailedToDownloadProtwordsFile(GLOBAL), () -> asDictIndexHtml()); + }); + }); + } + + @Execute + public ActionResponse download(final DownloadForm form) { + validate(form, messages -> {}, () -> downloadpage(form.dictId)); + verifyTokenKeep(() -> downloadpage(form.dictId)); + return protwordsService.getProtwordsFile(form.dictId).map(file -> { + return asStream(new File(file.getPath()).getName()).contentTypeOctetStream().stream(out -> { + try (InputStream inputStream = file.getInputStream()) { + out.write(inputStream); + } + }); + }).orElseGet(() -> { + throwValidationError(messages -> messages.addErrorsFailedToDownloadProtwordsFile(GLOBAL), () -> downloadpage(form.dictId)); + return null; + }); + } + + // ----------------------------------------------------- + // Upload + // ------- + @Execute + public HtmlResponse uploadpage(final String dictId) { + saveToken(); + return asHtml(path_AdminDictProtwords_AdminDictProtwordsUploadJsp).useForm(UploadForm.class, op -> { + op.setup(form -> { + form.dictId = dictId; + }); + }).renderWith(data -> { + protwordsService.getProtwordsFile(dictId).ifPresent(file -> { + RenderDataUtil.register(data, "path", file.getPath()); + }).orElse(() -> { + throwValidationError(messages -> messages.addErrorsFailedToDownloadProtwordsFile(GLOBAL), () -> asDictIndexHtml()); + }); + }); + } + + @Execute + public HtmlResponse upload(final UploadForm form) { + validate(form, messages -> {}, () -> uploadpage(form.dictId)); + verifyToken(() -> uploadpage(form.dictId)); + return protwordsService.getProtwordsFile(form.dictId).map(file -> { + try (InputStream inputStream = form.protwordsFile.getInputStream()) { + file.update(inputStream); + } catch (final IOException e) { + throwValidationError(messages -> messages.addErrorsFailedToUploadProtwordsFile(GLOBAL), () -> { + return redirectWith(getClass(), moreUrl("uploadpage/" + form.dictId)); + }); + } + saveInfo(messages -> messages.addSuccessUploadSynonymFile(GLOBAL)); + return redirectWith(getClass(), moreUrl("uploadpage/" + form.dictId)); + }).orElseGet(() -> { + throwValidationError(messages -> messages.addErrorsFailedToUploadProtwordsFile(GLOBAL), () -> uploadpage(form.dictId)); + return null; + }); + + } + + // ----------------------------------------------------- + // Actually Crud + // ------------- + @Execute + public HtmlResponse create(final CreateForm form) { + verifyCrudMode(form.crudMode, CrudMode.CREATE, form.dictId); + validate(form, messages -> {}, () -> asEditHtml()); + verifyToken(() -> asEditHtml()); + createProtwordsItem(form, () -> asEditHtml()).ifPresent(entity -> { + protwordsService.store(form.dictId, entity); + saveInfo(messages -> messages.addSuccessCrudCreateCrudTable(GLOBAL)); + }).orElse(() -> throwValidationError(messages -> messages.addErrorsCrudFailedToCreateInstance(GLOBAL), () -> asEditHtml())); + return redirectWith(getClass(), moreUrl("list/1").params("dictId", form.dictId)); + } + + @Execute + public HtmlResponse update(final EditForm form) { + verifyCrudMode(form.crudMode, CrudMode.EDIT, form.dictId); + validate(form, messages -> {}, () -> asEditHtml()); + verifyToken(() -> asEditHtml()); + createProtwordsItem(form, () -> asEditHtml()).ifPresent(entity -> { + protwordsService.store(form.dictId, entity); + saveInfo(messages -> messages.addSuccessCrudUpdateCrudTable(GLOBAL)); + }).orElse( + () -> throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.getDisplayId()), + () -> asEditHtml())); + return redirectWith(getClass(), moreUrl("list/1").params("dictId", form.dictId)); + } + + @Execute + public HtmlResponse delete(final EditForm form) { + verifyCrudMode(form.crudMode, CrudMode.DETAILS, form.dictId); + verifyToken(() -> asDetailsHtml()); + validate(form, messages -> {}, () -> asDetailsHtml()); + protwordsService + .getProtwordsItem(form.dictId, form.id) + .ifPresent(entity -> { + protwordsService.delete(form.dictId, entity); + saveInfo(messages -> messages.addSuccessCrudDeleteCrudTable(GLOBAL)); + }) + .orElse(() -> { + throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.getDisplayId()), + () -> asDetailsHtml()); + }); + return redirectWith(getClass(), moreUrl("list/1").params("dictId", form.dictId)); + } + + //=================================================================================== + // Assist Logic + // ============ + + private OptionalEntity getEntity(final CreateForm form) { + switch (form.crudMode) { + case CrudMode.CREATE: + final ProtwordsItem entity = new ProtwordsItem(0, StringUtil.EMPTY_STRINGS); + return OptionalEntity.of(entity); + case CrudMode.EDIT: + if (form instanceof EditForm) { + return protwordsService.getProtwordsItem(form.dictId, ((EditForm) form).id); + } + break; + default: + break; + } + return OptionalEntity.empty(); + } + + protected OptionalEntity createProtwordsItem(final CreateForm form, final VaErrorHook hook) { + return getEntity(form).map(entity -> { + final String[] newInputs = splitLine(form.inputs); + validateProtwordsString(newInputs, "inputs", hook); + entity.setNewInputs(newInputs); + return entity; + }); + } + + // =================================================================================== + // Small Helper + // ============ + protected void verifyCrudMode(final int crudMode, final int expectedMode, final String dictId) { + if (crudMode != expectedMode) { + throwValidationError(messages -> { + messages.addErrorsCrudInvalidMode(GLOBAL, String.valueOf(expectedMode), String.valueOf(crudMode)); + }, () -> asListHtml(dictId)); + } + } + + private void validateProtwordsString(final String[] values, final String propertyName, final VaErrorHook hook) { + if (values.length == 0) { + return; + } + // TODO validation + } + + private String[] splitLine(final String value) { + if (StringUtil.isBlank(value)) { + return StringUtil.EMPTY_STRINGS; + } + return stream(value.split(",")).get(stream -> stream.filter(StringUtil::isNotBlank).map(s -> s.trim()).toArray(n -> new String[n])); + } + + // =================================================================================== + // JSP + // ========= + + protected HtmlResponse asDictIndexHtml() { + return redirect(AdminDictAction.class); + } + + private HtmlResponse asListHtml(final String dictId) { + return asHtml(path_AdminDictProtwords_AdminDictProtwordsJsp).renderWith(data -> { + RenderDataUtil.register(data, "protwordsItemItems", protwordsService.getProtwordsList(dictId, protwordsPager)); + }).useForm(SearchForm.class, setup -> { + setup.setup(form -> { + copyBeanToBean(protwordsPager, form, op -> op.include("id")); + }); + }); + } + + private HtmlResponse asEditHtml() { + return asHtml(path_AdminDictProtwords_AdminDictProtwordsEditJsp); + } + + private HtmlResponse asDetailsHtml() { + return asHtml(path_AdminDictProtwords_AdminDictProtwordsDetailsJsp); + } + +} diff --git a/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/CreateForm.java b/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/CreateForm.java new file mode 100644 index 000000000..9c6bdcbe4 --- /dev/null +++ b/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/CreateForm.java @@ -0,0 +1,42 @@ +/* + * Copyright 2012-2016 CodeLibs Project and the Others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.codelibs.fess.app.web.admin.dict.protwords; + +import javax.validation.constraints.Size; + +import org.codelibs.fess.app.web.CrudMode; +import org.lastaflute.web.validation.Required; +import org.lastaflute.web.validation.theme.conversion.ValidateTypeFailure; + +/** + * @author nocode + */ +public class CreateForm { + + @Required + public String dictId; + + @ValidateTypeFailure + public Integer crudMode; + + @Required + @Size(max = 1000) + public String inputs; + + public void initialize() { + crudMode = CrudMode.CREATE; + } +} diff --git a/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/DownloadForm.java b/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/DownloadForm.java new file mode 100644 index 000000000..e4b42a3ff --- /dev/null +++ b/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/DownloadForm.java @@ -0,0 +1,23 @@ +/* + * Copyright 2012-2016 CodeLibs Project and the Others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.codelibs.fess.app.web.admin.dict.protwords; + +import org.lastaflute.web.validation.Required; + +public class DownloadForm { + @Required + public String dictId; +} diff --git a/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/EditForm.java b/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/EditForm.java new file mode 100644 index 000000000..db4b6b9e7 --- /dev/null +++ b/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/EditForm.java @@ -0,0 +1,33 @@ +/* + * Copyright 2012-2016 CodeLibs Project and the Others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.codelibs.fess.app.web.admin.dict.protwords; + +import org.lastaflute.web.validation.Required; +import org.lastaflute.web.validation.theme.conversion.ValidateTypeFailure; + +/** + * @author nocode + */ +public class EditForm extends CreateForm { + + @Required + @ValidateTypeFailure + public Long id; + + public String getDisplayId() { + return dictId + ":" + id; + } +} diff --git a/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/SearchForm.java b/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/SearchForm.java new file mode 100644 index 000000000..9dcdb8851 --- /dev/null +++ b/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/SearchForm.java @@ -0,0 +1,27 @@ +/* + * Copyright 2012-2016 CodeLibs Project and the Others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.codelibs.fess.app.web.admin.dict.protwords; + +import org.lastaflute.web.validation.Required; + +/** + * @author nocode + */ +public class SearchForm { + + @Required + public String dictId; +} diff --git a/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/UploadForm.java b/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/UploadForm.java new file mode 100644 index 000000000..4fd87dd6b --- /dev/null +++ b/src/main/java/org/codelibs/fess/app/web/admin/dict/protwords/UploadForm.java @@ -0,0 +1,32 @@ +/* + * Copyright 2012-2016 CodeLibs Project and the Others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.codelibs.fess.app.web.admin.dict.protwords; + +import org.lastaflute.web.ruts.multipart.MultipartFormFile; +import org.lastaflute.web.validation.Required; + +/** + * @author nocode + */ +public class UploadForm { + + @Required + public String dictId; + + @Required + public MultipartFormFile protwordsFile; + +} \ No newline at end of file diff --git a/src/main/java/org/codelibs/fess/dict/DictionaryManager.java b/src/main/java/org/codelibs/fess/dict/DictionaryManager.java index 24da57d02..ec40fe444 100644 --- a/src/main/java/org/codelibs/fess/dict/DictionaryManager.java +++ b/src/main/java/org/codelibs/fess/dict/DictionaryManager.java @@ -30,6 +30,7 @@ import org.codelibs.core.io.FileUtil; import org.codelibs.elasticsearch.runner.net.Curl; import org.codelibs.elasticsearch.runner.net.CurlResponse; import org.codelibs.fess.Constants; +import org.codelibs.fess.util.ComponentUtil; import org.codelibs.fess.util.ResourceUtil; import org.dbflute.optional.OptionalEntity; import org.slf4j.Logger; @@ -49,7 +50,8 @@ public class DictionaryManager { public DictionaryFile[] getDictionaryFiles() { try (CurlResponse response = - Curl.get(ResourceUtil.getElasticsearchHttpUrl() + "/_configsync/file").param("fields", "path,@timestamp").execute()) { + Curl.get(ResourceUtil.getElasticsearchHttpUrl() + "/_configsync/file").param("fields", "path,@timestamp") + .param("size", ComponentUtil.getFessConfig().getPageDictionaryMaxFetchSize()).execute()) { final Map contentMap = response.getContentAsMap(); @SuppressWarnings("unchecked") final List> fileList = (List>) contentMap.get("file"); diff --git a/src/main/java/org/codelibs/fess/dict/protwords/ProtwordsCreator.java b/src/main/java/org/codelibs/fess/dict/protwords/ProtwordsCreator.java new file mode 100644 index 000000000..743b6deb0 --- /dev/null +++ b/src/main/java/org/codelibs/fess/dict/protwords/ProtwordsCreator.java @@ -0,0 +1,39 @@ +/* + * Copyright 2012-2016 CodeLibs Project and the Others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.codelibs.fess.dict.protwords; + +import java.util.Date; + +import org.codelibs.fess.dict.DictionaryCreator; +import org.codelibs.fess.dict.DictionaryFile; +import org.codelibs.fess.dict.DictionaryItem; + +public class ProtwordsCreator extends DictionaryCreator { + + public ProtwordsCreator() { + super("protwords.*\\.txt"); + } + + public ProtwordsCreator(final String pattern) { + super(pattern); + } + + @Override + protected DictionaryFile newDictionaryFile(final String id, final String path, final Date timestamp) { + return new ProtwordsFile(id, path, timestamp).manager(dictionaryManager); + } + +} diff --git a/src/main/java/org/codelibs/fess/dict/protwords/ProtwordsFile.java b/src/main/java/org/codelibs/fess/dict/protwords/ProtwordsFile.java new file mode 100644 index 000000000..c627e7d7d --- /dev/null +++ b/src/main/java/org/codelibs/fess/dict/protwords/ProtwordsFile.java @@ -0,0 +1,326 @@ +/* + * Copyright 2012-2016 CodeLibs Project and the Others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.codelibs.fess.dict.protwords; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.Closeable; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import org.apache.commons.io.IOUtils; +import org.codelibs.core.lang.StringUtil; +import org.codelibs.fess.Constants; +import org.codelibs.fess.dict.DictionaryException; +import org.codelibs.fess.dict.DictionaryFile; +import org.dbflute.optional.OptionalEntity; + +public class ProtwordsFile extends DictionaryFile { + private static final String PROTWORDS = "protwords"; + + List protwordsItemList; + + public ProtwordsFile(final String id, final String path, final Date timestamp) { + super(id, path, timestamp); + } + + @Override + public String getType() { + return PROTWORDS; + } + + @Override + public String getPath() { + return path; + } + + @Override + public synchronized OptionalEntity get(final long id) { + if (protwordsItemList == null) { + reload(null, null); + } + + for (final ProtwordsItem ProtwordsItem : protwordsItemList) { + if (id == ProtwordsItem.getId()) { + return OptionalEntity.of(ProtwordsItem); + } + } + return OptionalEntity.empty(); + } + + @Override + public synchronized PagingList selectList(final int offset, final int size) { + if (protwordsItemList == null) { + reload(null, null); + } + + if (offset >= protwordsItemList.size() || offset < 0) { + return new PagingList<>(Collections. emptyList(), offset, size, protwordsItemList.size()); + } + + int toIndex = offset + size; + if (toIndex > protwordsItemList.size()) { + toIndex = protwordsItemList.size(); + } + + return new PagingList<>(protwordsItemList.subList(offset, toIndex), offset, size, protwordsItemList.size()); + } + + @Override + public synchronized void insert(final ProtwordsItem item) { + try (SynonymUpdater updater = new SynonymUpdater(item)) { + reload(updater, null); + } + } + + @Override + public synchronized void update(final ProtwordsItem item) { + try (SynonymUpdater updater = new SynonymUpdater(item)) { + reload(updater, null); + } + } + + @Override + public synchronized void delete(final ProtwordsItem item) { + final ProtwordsItem ProtwordsItem = item; + ProtwordsItem.setNewInputs(StringUtil.EMPTY_STRINGS); + try (SynonymUpdater updater = new SynonymUpdater(item)) { + reload(updater, null); + } + } + + protected void reload(final SynonymUpdater updater, final InputStream in) { + final List itemList = new ArrayList<>(); + try (BufferedReader reader = + new BufferedReader(new InputStreamReader(in != null ? in : dictionaryManager.getContentInputStream(this), Constants.UTF_8))) { + long id = 0; + String line = null; + while ((line = reader.readLine()) != null) { + if (line.length() == 0 || line.charAt(0) == '#') { + if (updater != null) { + updater.write(line); + } + continue; // ignore empty lines and comments + } + + final List inputStrings = split(line, ","); + final String[] inputs = new String[inputStrings.size()]; + for (int i = 0; i < inputs.length; i++) { + inputs[i] = unescape(inputStrings.get(i)).trim(); + } + + if (inputs.length > 0) { + id++; + final ProtwordsItem item = new ProtwordsItem(id, inputs); + if (updater != null) { + final ProtwordsItem newItem = updater.write(item); + if (newItem != null) { + itemList.add(newItem); + } else { + id--; + } + } else { + itemList.add(item); + } + } + } + if (updater != null) { + final ProtwordsItem item = updater.commit(); + if (item != null) { + itemList.add(item); + } + } + protwordsItemList = itemList; + } catch (final IOException e) { + throw new DictionaryException("Failed to parse " + path, e); + } + } + + private static List split(final String s, final String separator) { + final List list = new ArrayList<>(2); + StringBuilder sb = new StringBuilder(); + int pos = 0; + final int end = s.length(); + while (pos < end) { + if (s.startsWith(separator, pos)) { + if (sb.length() > 0) { + list.add(sb.toString()); + sb = new StringBuilder(); + } + pos += separator.length(); + continue; + } + + char ch = s.charAt(pos++); + if (ch == '\\') { + sb.append(ch); + if (pos >= end) { + break; // ERROR, or let it go? + } + ch = s.charAt(pos++); + } + + sb.append(ch); + } + + if (sb.length() > 0) { + list.add(sb.toString()); + } + + return list; + } + + private String unescape(final String s) { + if (s.indexOf('\\') >= 0) { + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < s.length(); i++) { + final char ch = s.charAt(i); + if (ch == '\\' && i < s.length() - 1) { + sb.append(s.charAt(++i)); + } else { + sb.append(ch); + } + } + return sb.toString(); + } + return s; + } + + public String getSimpleName() { + return new File(path).getName(); + } + + public InputStream getInputStream() throws IOException { + return new BufferedInputStream(dictionaryManager.getContentInputStream(this)); + } + + public synchronized void update(final InputStream in) throws IOException { + try (SynonymUpdater updater = new SynonymUpdater(null)) { + reload(updater, in); + } + } + + @Override + public String toString() { + return "SynonymFile [path=" + path + ", srotwordsItemList=" + protwordsItemList + ", id=" + id + "]"; + } + + protected class SynonymUpdater implements Closeable { + + protected boolean isCommit = false; + + protected File newFile; + + protected Writer writer; + + protected ProtwordsItem item; + + protected SynonymUpdater(final ProtwordsItem newItem) { + try { + newFile = File.createTempFile(PROTWORDS, ".txt"); + writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(newFile), Constants.UTF_8)); + } catch (final IOException e) { + if (newFile != null) { + newFile.delete(); + } + throw new DictionaryException("Failed to write a userDict file.", e); + } + item = newItem; + } + + public ProtwordsItem write(final ProtwordsItem oldItem) { + try { + if (item != null && item.getId() == oldItem.getId() && item.isUpdated()) { + if (item.equals(oldItem)) { + try { + if (!item.isDeleted()) { + // update + writer.write(item.toLineString()); + writer.write(Constants.LINE_SEPARATOR); + return new ProtwordsItem(item.getId(), item.getNewInputs()); + } else { + return null; + } + } finally { + item.setNewInputs(null); + } + } else { + throw new DictionaryException("Protwords file was updated: old=" + oldItem + " : new=" + item); + } + } else { + writer.write(oldItem.toLineString()); + writer.write(Constants.LINE_SEPARATOR); + return oldItem; + } + } catch (final IOException e) { + throw new DictionaryException("Failed to write: " + oldItem + " -> " + item, e); + } + } + + public void write(final String line) { + try { + writer.write(line); + writer.write(Constants.LINE_SEPARATOR); + } catch (final IOException e) { + throw new DictionaryException("Failed to write: " + line, e); + } + } + + public ProtwordsItem commit() { + isCommit = true; + if (item != null && item.isUpdated()) { + try { + writer.write(item.toLineString()); + writer.write(Constants.LINE_SEPARATOR); + return item; + } catch (final IOException e) { + throw new DictionaryException("Failed to write: " + item, e); + } + } + return null; + } + + @Override + public void close() { + try { + writer.flush(); + } catch (final IOException e) { + // ignore + } + IOUtils.closeQuietly(writer); + + if (isCommit) { + try { + dictionaryManager.store(ProtwordsFile.this, newFile); + } finally { + newFile.delete(); + } + } else { + newFile.delete(); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/org/codelibs/fess/dict/protwords/ProtwordsItem.java b/src/main/java/org/codelibs/fess/dict/protwords/ProtwordsItem.java new file mode 100644 index 000000000..49f2fe991 --- /dev/null +++ b/src/main/java/org/codelibs/fess/dict/protwords/ProtwordsItem.java @@ -0,0 +1,105 @@ +/* + * Copyright 2012-2016 CodeLibs Project and the Others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.codelibs.fess.dict.protwords; + +import java.util.Arrays; + +import org.apache.commons.lang3.StringUtils; +import org.codelibs.core.lang.StringUtil; +import org.codelibs.fess.dict.DictionaryItem; + +public class ProtwordsItem extends DictionaryItem { + private final String[] inputs; + + private String[] newInputs; + + public ProtwordsItem(final long id, final String[] inputs) { + this.id = id; + this.inputs = inputs; + + if (id == 0) { + // create + newInputs = inputs; + } + } + + public String[] getNewInputs() { + return newInputs; + } + + public void setNewInputs(final String[] newInputs) { + this.newInputs = newInputs; + } + + public String[] getInputs() { + return inputs; + } + + public String getInputsValue() { + if (inputs == null) { + return StringUtil.EMPTY; + } + return String.join(",", inputs); + } + + public boolean isUpdated() { + return newInputs != null; + } + + public boolean isDeleted() { + return isUpdated() && newInputs.length == 0; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Arrays.hashCode(inputs); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final ProtwordsItem other = (ProtwordsItem) obj; + if (!Arrays.equals(inputs, other.inputs)) { + return false; + } + return true; + } + + @Override + public String toString() { + return "ProtwordsItem [id=" + id + ", inputs=" + Arrays.toString(inputs) + ", newInputs=" + Arrays.toString(newInputs) + "]"; + } + + public String toLineString() { + if (isUpdated()) { + return StringUtils.join(newInputs, ","); + } else { + return StringUtils.join(inputs, ","); + } + } + +} diff --git a/src/main/java/org/codelibs/fess/mylasta/action/FessHtmlPath.java b/src/main/java/org/codelibs/fess/mylasta/action/FessHtmlPath.java index c13274694..aa5a706e6 100644 --- a/src/main/java/org/codelibs/fess/mylasta/action/FessHtmlPath.java +++ b/src/main/java/org/codelibs/fess/mylasta/action/FessHtmlPath.java @@ -92,6 +92,22 @@ public interface FessHtmlPath { /** The path of the HTML: /admin/dict/kuromoji/admin_dict_kuromoji_upload.jsp */ HtmlNext path_AdminDictKuromoji_AdminDictKuromojiUploadJsp = new HtmlNext("/admin/dict/kuromoji/admin_dict_kuromoji_upload.jsp"); + /** The path of the HTML: /admin/dict/protwords/admin_dict_protwords.jsp */ + HtmlNext path_AdminDictProtwords_AdminDictProtwordsJsp = new HtmlNext("/admin/dict/protwords/admin_dict_protwords.jsp"); + + /** The path of the HTML: /admin/dict/protwords/admin_dict_protwords_details.jsp */ + HtmlNext path_AdminDictProtwords_AdminDictProtwordsDetailsJsp = new HtmlNext("/admin/dict/protwords/admin_dict_protwords_details.jsp"); + + /** The path of the HTML: /admin/dict/protwords/admin_dict_protwords_download.jsp */ + HtmlNext path_AdminDictProtwords_AdminDictProtwordsDownloadJsp = + new HtmlNext("/admin/dict/protwords/admin_dict_protwords_download.jsp"); + + /** The path of the HTML: /admin/dict/protwords/admin_dict_protwords_edit.jsp */ + HtmlNext path_AdminDictProtwords_AdminDictProtwordsEditJsp = new HtmlNext("/admin/dict/protwords/admin_dict_protwords_edit.jsp"); + + /** The path of the HTML: /admin/dict/protwords/admin_dict_protwords_upload.jsp */ + HtmlNext path_AdminDictProtwords_AdminDictProtwordsUploadJsp = new HtmlNext("/admin/dict/protwords/admin_dict_protwords_upload.jsp"); + /** The path of the HTML: /admin/dict/seunjeon/admin_dict_seunjeon.jsp */ HtmlNext path_AdminDictSeunjeon_AdminDictSeunjeonJsp = new HtmlNext("/admin/dict/seunjeon/admin_dict_seunjeon.jsp"); diff --git a/src/main/java/org/codelibs/fess/mylasta/action/FessLabels.java b/src/main/java/org/codelibs/fess/mylasta/action/FessLabels.java index 9adf7a3cd..d063a6398 100644 --- a/src/main/java/org/codelibs/fess/mylasta/action/FessLabels.java +++ b/src/main/java/org/codelibs/fess/mylasta/action/FessLabels.java @@ -1851,6 +1851,45 @@ public class FessLabels extends ActionMessages { /** The key of the message: Kuromoji File */ public static final String LABELS_dict_kuromoji_file = "{labels.dict_kuromoji_file}"; + /** The key of the message: Protwords List */ + public static final String LABELS_dict_protwords_configuration = "{labels.dict_protwords_configuration}"; + + /** The key of the message: Protwords List */ + public static final String LABELS_dict_protwords_title = "{labels.dict_protwords_title}"; + + /** The key of the message: List */ + public static final String LABELS_dict_protwords_list_link = "{labels.dict_protwords_list_link}"; + + /** The key of the message: Create New */ + public static final String LABELS_dict_protwords_link_create = "{labels.dict_protwords_link_create}"; + + /** The key of the message: Edit */ + public static final String LABELS_dict_protwords_link_edit = "{labels.dict_protwords_link_edit}"; + + /** The key of the message: Delete */ + public static final String LABELS_dict_protwords_link_delete = "{labels.dict_protwords_link_delete}"; + + /** The key of the message: Details */ + public static final String LABELS_dict_protwords_link_details = "{labels.dict_protwords_link_details}"; + + /** The key of the message: Download */ + public static final String LABELS_dict_protwords_link_download = "{labels.dict_protwords_link_download}"; + + /** The key of the message: Upload */ + public static final String LABELS_dict_protwords_link_upload = "{labels.dict_protwords_link_upload}"; + + /** The key of the message: Source */ + public static final String LABELS_dict_protwords_source = "{labels.dict_protwords_source}"; + + /** The key of the message: Download */ + public static final String LABELS_dict_protwords_button_download = "{labels.dict_protwords_button_download}"; + + /** The key of the message: Upload */ + public static final String LABELS_dict_protwords_button_upload = "{labels.dict_protwords_button_upload}"; + + /** The key of the message: Protwords File */ + public static final String LABELS_dict_protwords_file = "{labels.dict_protwords_file}"; + /** The key of the message: Doc Boost */ public static final String LABELS_boost_document_rule_configuration = "{labels.boost_document_rule_configuration}"; diff --git a/src/main/java/org/codelibs/fess/mylasta/action/FessMessages.java b/src/main/java/org/codelibs/fess/mylasta/action/FessMessages.java index 8c4bf916c..9251f73c8 100644 --- a/src/main/java/org/codelibs/fess/mylasta/action/FessMessages.java +++ b/src/main/java/org/codelibs/fess/mylasta/action/FessMessages.java @@ -242,6 +242,12 @@ public class FessMessages extends FessLabels { /** The key of the message: Failed to upload the Kuromoji file. */ public static final String ERRORS_failed_to_upload_kuromoji_file = "{errors.failed_to_upload_kuromoji_file}"; + /** The key of the message: Failed to download the Protwords file. */ + public static final String ERRORS_failed_to_download_protwords_file = "{errors.failed_to_download_protwords_file}"; + + /** The key of the message: Failed to upload the Protwords file. */ + public static final String ERRORS_failed_to_upload_protwords_file = "{errors.failed_to_upload_protwords_file}"; + /** The key of the message: Failed to download the Elevate file. */ public static final String ERRORS_failed_to_download_elevate_file = "{errors.failed_to_download_elevate_file}"; @@ -1469,6 +1475,34 @@ public class FessMessages extends FessLabels { return this; } + /** + * Add the created action message for the key 'errors.failed_to_download_protwords_file' with parameters. + *
+     * message: Failed to download the Protwords file.
+     * 
+ * @param property The property name for the message. (NotNull) + * @return this. (NotNull) + */ + public FessMessages addErrorsFailedToDownloadProtwordsFile(String property) { + assertPropertyNotNull(property); + add(property, new ActionMessage(ERRORS_failed_to_download_protwords_file)); + return this; + } + + /** + * Add the created action message for the key 'errors.failed_to_upload_protwords_file' with parameters. + *
+     * message: Failed to upload the Protwords file.
+     * 
+ * @param property The property name for the message. (NotNull) + * @return this. (NotNull) + */ + public FessMessages addErrorsFailedToUploadProtwordsFile(String property) { + assertPropertyNotNull(property); + add(property, new ActionMessage(ERRORS_failed_to_upload_protwords_file)); + return this; + } + /** * Add the created action message for the key 'errors.failed_to_download_elevate_file' with parameters. *
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 d0b55b9d7..d950bd20b 100644
--- a/src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java
+++ b/src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java
@@ -565,6 +565,9 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
     /** The key of the configuration. e.g. 1000 */
     String PAGE_BAD_WORD_MAX_FETCH_SIZE = "page.bad.word.max.fetch.size";
 
+    /** The key of the configuration. e.g. 1000 */
+    String PAGE_DICTIONARY_MAX_FETCH_SIZE = "page.dictionary.max.fetch.size";
+
     /** The key of the configuration. e.g. 0 */
     String PAGING_SEARCH_PAGE_START = "paging.search.page.start";
 
@@ -616,6 +619,9 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
     /** The key of the configuration. e.g. seunjeon */
     String ONLINE_HELP_NAME_DICT_SEUNJEON = "online.help.name.dict.seunjeon";
 
+    /** The key of the configuration. e.g. protwords */
+    String ONLINE_HELP_NAME_DICT_PROTWORDS = "online.help.name.dict.protwords";
+
     /** The key of the configuration. e.g. webconfig */
     String ONLINE_HELP_NAME_WEBCONFIG = "online.help.name.webconfig";
 
@@ -2676,6 +2682,21 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
      */
     Integer getPageBadWordMaxFetchSizeAsInteger();
 
+    /**
+     * Get the value for the key 'page.dictionary.max.fetch.size'. 
+ * The value is, e.g. 1000
+ * @return The value of found property. (NotNull: if not found, exception but basically no way) + */ + String getPageDictionaryMaxFetchSize(); + + /** + * Get the value for the key 'page.dictionary.max.fetch.size' as {@link Integer}.
+ * The value is, e.g. 1000
+ * @return The value of found property. (NotNull: if not found, exception but basically no way) + * @throws NumberFormatException When the property is not integer. + */ + Integer getPageDictionaryMaxFetchSizeAsInteger(); + /** * Get the value for the key 'paging.search.page.start'.
* The value is, e.g. 0
@@ -2841,6 +2862,13 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction */ String getOnlineHelpNameDictSeunjeon(); + /** + * Get the value for the key 'online.help.name.dict.protwords'.
+ * The value is, e.g. protwords
+ * @return The value of found property. (NotNull: if not found, exception but basically no way) + */ + String getOnlineHelpNameDictProtwords(); + /** * Get the value for the key 'online.help.name.webconfig'.
* The value is, e.g. webconfig
@@ -4589,6 +4617,14 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction return getAsInteger(FessConfig.PAGE_BAD_WORD_MAX_FETCH_SIZE); } + public String getPageDictionaryMaxFetchSize() { + return get(FessConfig.PAGE_DICTIONARY_MAX_FETCH_SIZE); + } + + public Integer getPageDictionaryMaxFetchSizeAsInteger() { + return getAsInteger(FessConfig.PAGE_DICTIONARY_MAX_FETCH_SIZE); + } + public String getPagingSearchPageStart() { return get(FessConfig.PAGING_SEARCH_PAGE_START); } @@ -4677,6 +4713,10 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction return get(FessConfig.ONLINE_HELP_NAME_DICT_SEUNJEON); } + public String getOnlineHelpNameDictProtwords() { + return get(FessConfig.ONLINE_HELP_NAME_DICT_PROTWORDS); + } + public String getOnlineHelpNameWebconfig() { return get(FessConfig.ONLINE_HELP_NAME_WEBCONFIG); } diff --git a/src/main/resources/fess_config.properties b/src/main/resources/fess_config.properties index 7515e5d19..2bc6b71f0 100644 --- a/src/main/resources/fess_config.properties +++ b/src/main/resources/fess_config.properties @@ -315,6 +315,7 @@ page.scheduled.job.max.fetch.size=100 page.search.field.log.max.fetch.size=100 page.elevate.word.max.fetch.size=1000 page.bad.word.max.fetch.size=1000 +page.dictionary.max.fetch.size=1000 # search page paging.search.page.start=0 @@ -347,6 +348,7 @@ online.help.name.dict.synonym=synonym online.help.name.dict=dict online.help.name.dict.kuromoji=kuromoji online.help.name.dict.seunjeon=seunjeon +online.help.name.dict.protwords=protwords online.help.name.webconfig=webconfig online.help.name.searchlist=searchlist online.help.name.log=log diff --git a/src/main/resources/fess_dict.xml b/src/main/resources/fess_dict.xml index f4ee4593f..5d18b9b08 100644 --- a/src/main/resources/fess_dict.xml +++ b/src/main/resources/fess_dict.xml @@ -14,6 +14,9 @@ synonymCreator + + protwordsCreator + + + diff --git a/src/main/resources/fess_label.properties b/src/main/resources/fess_label.properties index ba06e2768..dcb48d672 100644 --- a/src/main/resources/fess_label.properties +++ b/src/main/resources/fess_label.properties @@ -607,6 +607,19 @@ labels.dict_kuromoji_pos=POS labels.dict_kuromoji_button_download=Download labels.dict_kuromoji_button_upload=Upload labels.dict_kuromoji_file=Kuromoji File +labels.dict_protwords_configuration=Protwords List +labels.dict_protwords_title = Protwords List +labels.dict_protwords_list_link = List +labels.dict_protwords_link_create = Create New +labels.dict_protwords_link_edit = Edit +labels.dict_protwords_link_delete = Delete +labels.dict_protwords_link_details = Details +labels.dict_protwords_link_download = Download +labels.dict_protwords_link_upload = Upload +labels.dict_protwords_source = Source +labels.dict_protwords_button_download = Download +labels.dict_protwords_button_upload = Upload +labels.dict_protwords_file = Protwords File labels.boost_document_rule_configuration=Doc Boost labels.boost_document_rule_title_details=Doc Boost labels.boost_document_rule_list_url_expr=Condition diff --git a/src/main/resources/fess_label_en.properties b/src/main/resources/fess_label_en.properties index c29fb2ae7..433fa10a2 100644 --- a/src/main/resources/fess_label_en.properties +++ b/src/main/resources/fess_label_en.properties @@ -607,6 +607,19 @@ labels.dict_kuromoji_pos=POS labels.dict_kuromoji_button_download=Download labels.dict_kuromoji_button_upload=Upload labels.dict_kuromoji_file=Kuromoji File +labels.dict_protwords_configuration=Protwords List +labels.dict_protwords_title = Protwords List +labels.dict_protwords_list_link = List +labels.dict_protwords_link_create = Create New +labels.dict_protwords_link_edit = Edit +labels.dict_protwords_link_delete = Delete +labels.dict_protwords_link_details = Details +labels.dict_protwords_link_download = Download +labels.dict_protwords_link_upload = Upload +labels.dict_protwords_source = Source +labels.dict_protwords_button_download = Download +labels.dict_protwords_button_upload = Upload +labels.dict_protwords_file = Protwords File labels.boost_document_rule_configuration=Doc Boost labels.boost_document_rule_title_details=Doc Boost labels.boost_document_rule_list_url_expr=Condition diff --git a/src/main/resources/fess_label_ja.properties b/src/main/resources/fess_label_ja.properties index 720aa77b2..2b4482620 100644 --- a/src/main/resources/fess_label_ja.properties +++ b/src/main/resources/fess_label_ja.properties @@ -603,6 +603,19 @@ labels.dict_kuromoji_pos=\u54c1\u8a5e labels.dict_kuromoji_button_download=\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9 labels.dict_kuromoji_button_upload=\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9 labels.dict_kuromoji_file=Kuromoji\u30d5\u30a1\u30a4\u30eb +labels.dict_protwords_configuration=Protwords\u5358\u8a9e\u4e00\u89a7 +labels.dict_protwords_title = Protwords\u5358\u8a9e\u4e00\u89a7 +labels.dict_protwords_list_link = \u4e00\u89a7 +labels.dict_protwords_link_create = \u65b0\u898f\u4f5c\u6210 +labels.dict_protwords_link_edit = \u7de8\u96c6 +labels.dict_protwords_link_delete = \u524a\u9664 +labels.dict_protwords_link_details = \u8a73\u7d30 +labels.dict_protwords_link_download = \u30c0\u30a6\u30f3\u30ed\u30fc\u30c9 +labels.dict_protwords_link_upload = \u30a2\u30c3\u30d7\u30ed\u30fc\u30c9 +labels.dict_protwords_source = \u5358\u8a9e\u60c5\u5831 +labels.dict_protwords_button_download = \u30c0\u30a6\u30f3\u30ed\u30fc\u30c9 +labels.dict_protwords_button_upload = \u30a2\u30c3\u30d7\u30ed\u30fc\u30c9 +labels.dict_protwords_file = Protwords\u30d5\u30a1\u30a4\u30eb labels.boost_document_rule_configuration=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d6\u30fc\u30b9\u30c8 labels.boost_document_rule_title_details=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d6\u30fc\u30b9\u30c8 labels.boost_document_rule_list_url_expr=\u72b6\u614b diff --git a/src/main/resources/fess_label_ko.properties b/src/main/resources/fess_label_ko.properties index b927299f1..dbbb185a6 100644 --- a/src/main/resources/fess_label_ko.properties +++ b/src/main/resources/fess_label_ko.properties @@ -598,6 +598,19 @@ labels.dict_kuromoji_pos = \ud488\uc0ac labels.dict_kuromoji_button_download = \ub2e4\uc6b4\ub85c\ub4dc labels.dict_kuromoji_button_upload = \uc5c5\ub85c\ub4dc labels.dict_kuromoji_file = Kuromoji \ud30c\uc77c +labels.dict_protwords_configuration = Protwords \ubaa9\ub85d +labels.dict_protwords_title = Protwords \ubaa9\ub85d +labels.dict_protwords_list_link = \ubaa9\ub85d +labels.dict_protwords_link_create = \uc0c8\ub85c \ub9cc\ub4e4\uae30 +labels.dict_protwords_link_edit = \ud3b8\uc9d1 +labels.dict_protwords_link_delete = \uc0ad\uc81c +labels.dict_protwords_link_details = \uc0c1\uc138 +labels.dict_protwords_link_download = \ub2e4\uc6b4\ub85c\ub4dc +labels.dict_protwords_link_upload = \uc5c5\ub85c\ub4dc +labels.dict_protwords_source = \uc6d0\ubcf8 +labels.dict_protwords_button_download = \ub2e4\uc6b4\ub85c\ub4dc +labels.dict_protwords_button_upload = \uc5c5\ub85c\ub4dc +labels.dict_protwords_file = Protwords \ud30c\uc77c labels.boost_document_rule_configuration = \ubb38\uc11c \ubd80\uc2a4\ud2b8 labels.boost_document_rule_title_details = \ubb38\uc11c \ubd80\uc2a4\ud2b8 labels.boost_document_rule_list_url_expr = \uc0c1\ud0dc diff --git a/src/main/resources/fess_message.properties b/src/main/resources/fess_message.properties index 141b7a863..5adf521a9 100644 --- a/src/main/resources/fess_message.properties +++ b/src/main/resources/fess_message.properties @@ -102,6 +102,8 @@ errors.failed_to_download_synonym_file=Failed to download the Synonym file. errors.failed_to_upload_synonym_file=Failed to upload the Synonym file. errors.failed_to_download_kuromoji_file=Failed to download the Kuromoji file. errors.failed_to_upload_kuromoji_file=Failed to upload the Kuromoji file. +errors.failed_to_download_protwords_file=Failed to download the Protwords file. +errors.failed_to_upload_protwords_file=Failed to upload the Protwords file. errors.failed_to_download_elevate_file=Failed to download the Elevate file. errors.failed_to_upload_elevate_file=Failed to upload the Elevate file. errors.failed_to_download_badword_file=Failed to download the Badword file. diff --git a/src/main/resources/fess_message_en.properties b/src/main/resources/fess_message_en.properties index 176b540e5..fed189f0f 100644 --- a/src/main/resources/fess_message_en.properties +++ b/src/main/resources/fess_message_en.properties @@ -106,6 +106,8 @@ errors.failed_to_download_elevate_file=Failed to download the Elevate file. errors.failed_to_upload_elevate_file=Failed to upload the Elevate file. errors.failed_to_download_badword_file=Failed to download the Badword file. errors.failed_to_upload_badword_file=Failed to upload the Badword file. +errors.failed_to_download_protwords_file=Failed to download the Protwords file. +errors.failed_to_upload_protwords_file=Failed to upload the Protwords file. errors.invalid_str_is_included="{1}" in "{0}" is invalid. errors.blank_password=Password is required. errors.invalid_confirm_password=Confirm Password does not match. diff --git a/src/main/resources/fess_message_ja.properties b/src/main/resources/fess_message_ja.properties index bd0f3d063..1d0fb42e7 100644 --- a/src/main/resources/fess_message_ja.properties +++ b/src/main/resources/fess_message_ja.properties @@ -98,6 +98,8 @@ errors.failed_to_download_synonym_file = \u540c\u7fa9\u8a9e\u30d5\u30a1\u30a4\u3 errors.failed_to_upload_synonym_file = \u540c\u7fa9\u8a9e\u30d5\u30a1\u30a4\u30eb\u3092\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 errors.failed_to_download_kuromoji_file = Kuromoji\u30d5\u30a1\u30a4\u30eb\u306e\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 errors.failed_to_upload_kuromoji_file = Kuromoji\u30d5\u30a1\u30a4\u30eb\u3092\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 +errors.failed_to_download_protwords_file = Protwords\u30d5\u30a1\u30a4\u30eb\u306e\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 +errors.failed_to_upload_protwords_file = Protwords\u30d5\u30a1\u30a4\u30eb\u3092\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 errors.failed_to_download_elevate_file = \u8ffd\u52a0\u30ef\u30fc\u30c9\u30d5\u30a1\u30a4\u30eb\u306e\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 errors.failed_to_upload_elevate_file = \u8ffd\u52a0\u30ef\u30fc\u30c9\u30d5\u30a1\u30a4\u30eb\u3092\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 errors.failed_to_download_badword_file = \u9664\u5916\u30ef\u30fc\u30c9\u30d5\u30a1\u30a4\u30eb\u306e\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 diff --git a/src/main/resources/fess_message_ko.properties b/src/main/resources/fess_message_ko.properties index 846d5e891..3d86e9133 100644 --- a/src/main/resources/fess_message_ko.properties +++ b/src/main/resources/fess_message_ko.properties @@ -98,6 +98,8 @@ errors.failed_to_download_synonym_file = \ub3d9\uc758\uc5b4 \ud30c\uc77c \ub2e4\ errors.failed_to_upload_synonym_file = \ub3d9\uc758\uc5b4 \ud30c\uc77c\uc744 \uc5c5\ub85c\ub4dc\uc5d0 \uc2e4\ud328\ud588\uc2b5\ub2c8\ub2e4. errors.failed_to_download_k\u200b\u200buromoji_file = Kuromoji \ud30c\uc77c \ub2e4\uc6b4\ub85c\ub4dc\uc5d0 \uc2e4\ud328\ud588\uc2b5\ub2c8\ub2e4. errors.failed_to_upload_k\u200b\u200buromoji_file = Kuromoji \ud30c\uc77c \uc5c5\ub85c\ub4dc\uc5d0 \uc2e4\ud328\ud588\uc2b5\ub2c8\ub2e4. +errors.failed_to_download_protwords_file = Protwords \ud30c\uc77c \ub2e4\uc6b4\ub85c\ub4dc\uc5d0 \uc2e4\ud328\ud588\uc2b5\ub2c8\ub2e4. +errors.failed_to_upload_protwords_file = Protwords \ud30c\uc77c \uc5c5\ub85c\ub4dc\uc5d0 \uc2e4\ud328\ud588\uc2b5\ub2c8\ub2e4. errors.failed_to_download_elevate_file = \ucd94\uac00 \uc6cc\ub4dc \ud30c\uc77c \ub2e4\uc6b4\ub85c\ub4dc\uc5d0 \uc2e4\ud328\ud588\uc2b5\ub2c8\ub2e4. errors.failed_to_upload_elevate_file = \ucd94\uac00 \uc6cc\ub4dc \ud30c\uc77c \uc5c5\ub85c\ub4dc\uc5d0 \uc2e4\ud328\ud588\uc2b5\ub2c8\ub2e4. errors.failed_to_download_badword_file = \uc81c\uc678 \uc6cc\ub4dc \ud30c\uc77c \ub2e4\uc6b4\ub85c\ub4dc\uc5d0 \uc2e4\ud328\ud588\uc2b5\ub2c8\ub2e4. diff --git a/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords.jsp b/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords.jsp new file mode 100644 index 000000000..a993ceaee --- /dev/null +++ b/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords.jsp @@ -0,0 +1,154 @@ +<%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%> + + + +<la:message key="labels.admin_brand_title" /> | <la:message + key="labels.dict_protwords_configuration" /> + + + +
+ + + + + +
+
+

+ +

+ +
+
+
+
+
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + +
+
+ +
+ <%-- Message --%> +
+ +
${msg}
+
+ +
+ <%-- List --%> + +
+
+ + +
+
+
+ +
+
+ + + + + + + + + + + + + +
${f:h(data.inputsValue)}
+
+
+ +
+
+ +
+
+
    + + + + + + + +
  • class="active">${p}
  • +
    + + + + + + +
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + + diff --git a/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords_details.jsp b/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords_details.jsp new file mode 100644 index 000000000..06c941008 --- /dev/null +++ b/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords_details.jsp @@ -0,0 +1,123 @@ +<%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%> + + + +<la:message key="labels.admin_brand_title" /> | <la:message + key="labels.dict_protwords_configuration" /> + + + +
+ + + + + +
+
+

+ +

+ +
+
+ + + + + + +
+
+
box-successbox-warningbox-dangerbox-primary"> + <%-- Box Header --%> +
+

+ + + + + + + + + + + + +

+
+ + + + + + + + + + + + + + + + + + + + +
+
+ <%-- Box Body --%> +
+ <%-- Message --%> +
+ +
${msg}
+
+ +
+ <%-- Form Fields --%> + + + + + + + +
${f:h(inputs)}
+
+ + + +
+ +
+
+
+
+
+ +
+ + + diff --git a/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords_download.jsp b/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords_download.jsp new file mode 100644 index 000000000..471b82572 --- /dev/null +++ b/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords_download.jsp @@ -0,0 +1,103 @@ +<%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%> + + + +<la:message key="labels.admin_brand_title" /> | <la:message + key="labels.dict_protwords_configuration" /> + + + +
+ + + + + +
+
+

+ +

+ +
+
+ + +
+
+
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + +
+
+ +
+ <%-- Message --%> +
+ +
${msg}
+
+ +
+
+ +
+
+ + + +
+ +
+
+
+
+
+ +
+ + + diff --git a/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords_edit.jsp b/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords_edit.jsp new file mode 100644 index 000000000..643eab532 --- /dev/null +++ b/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords_edit.jsp @@ -0,0 +1,120 @@ +<%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%> + + + +<la:message key="labels.admin_brand_title" /> | <la:message + key="labels.dict_protwords_configuration" /> + + + +
+ + + + + +
+
+

+ +

+ +
+
+ + + + + + +
+
+
box-successbox-warning"> +
+

+ + + + + + +

+
+ + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
${msg}
+
+ +
+
+ +
+ + +
+
+
+ + + +
+ +
+
+
+
+
+ +
+ + + diff --git a/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords_upload.jsp b/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords_upload.jsp new file mode 100644 index 000000000..1060b698c --- /dev/null +++ b/src/main/webapp/WEB-INF/view/admin/dict/protwords/admin_dict_protwords_upload.jsp @@ -0,0 +1,107 @@ +<%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%> + + + +<la:message key="labels.admin_brand_title" /> | <la:message + key="labels.dict_protwords_configuration" /> + + + +
+ + + + + +
+
+

+ +

+ +
+
+ + +
+
+
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + +
+
+ +
+ <%-- Message --%> +
+ +
${msg}
+
+ +
+
+ +
+ +
+
+
+ + + +
+ +
+
+
+
+
+ +
+ + +