View Javadoc
1   /*
2    * Copyright 2012-2021 CodeLibs Project and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.codelibs.fess.app.web.admin.elevateword;
17  
18  import static org.codelibs.core.stream.StreamUtil.split;
19  import static org.codelibs.core.stream.StreamUtil.stream;
20  
21  import java.io.BufferedReader;
22  import java.io.BufferedWriter;
23  import java.io.InputStream;
24  import java.io.InputStreamReader;
25  import java.io.OutputStreamWriter;
26  import java.io.Reader;
27  import java.io.Writer;
28  import java.nio.file.Files;
29  import java.nio.file.Path;
30  import java.util.stream.Collectors;
31  import java.util.stream.Stream;
32  
33  import javax.annotation.Resource;
34  
35  import org.codelibs.core.beans.util.BeanUtil;
36  import org.codelibs.core.concurrent.CommonPoolUtil;
37  import org.codelibs.core.lang.StringUtil;
38  import org.codelibs.fess.Constants;
39  import org.codelibs.fess.annotation.Secured;
40  import org.codelibs.fess.app.pager.ElevateWordPager;
41  import org.codelibs.fess.app.service.ElevateWordService;
42  import org.codelibs.fess.app.service.LabelTypeService;
43  import org.codelibs.fess.app.web.CrudMode;
44  import org.codelibs.fess.app.web.base.FessAdminAction;
45  import org.codelibs.fess.es.config.exentity.ElevateWord;
46  import org.codelibs.fess.exception.FessSystemException;
47  import org.codelibs.fess.helper.PermissionHelper;
48  import org.codelibs.fess.helper.SuggestHelper;
49  import org.codelibs.fess.helper.SystemHelper;
50  import org.codelibs.fess.util.ComponentUtil;
51  import org.codelibs.fess.util.RenderDataUtil;
52  import org.dbflute.optional.OptionalEntity;
53  import org.dbflute.optional.OptionalThing;
54  import org.lastaflute.web.Execute;
55  import org.lastaflute.web.response.ActionResponse;
56  import org.lastaflute.web.response.HtmlResponse;
57  import org.lastaflute.web.response.render.RenderData;
58  import org.lastaflute.web.ruts.process.ActionRuntime;
59  
60  /**
61   * @author Keiichi Watanabe
62   */
63  public class AdminElevatewordAction extends FessAdminAction {
64  
65      public static final String ROLE = "admin-elevateword";
66  
67      // ===================================================================================
68      //                                                                           Attribute
69      //                                                                           =========
70      @Resource
71      private ElevateWordService elevateWordService;
72      @Resource
73      private ElevateWordPager elevateWordPager;
74      @Resource
75      protected SuggestHelper suggestHelper;
76      @Resource
77      private LabelTypeService labelTypeService;
78  
79      // ===================================================================================
80      //                                                                               Hook
81      //                                                                              ======
82      @Override
83      protected void setupHtmlData(final ActionRuntime runtime) {
84          super.setupHtmlData(runtime);
85          runtime.registerData("helpLink", systemHelper.getHelpLink(fessConfig.getOnlineHelpNameElevateword()));
86      }
87  
88      @Override
89      protected String getActionRole() {
90          return ROLE;
91      }
92  
93      // ===================================================================================
94      //                                                                      Search Execute
95      //                                                                      ==============
96      @Execute
97      @Secured({ ROLE, ROLE + VIEW })
98      public HtmlResponse index() {
99          return asListHtml();
100     }
101 
102     @Execute
103     @Secured({ ROLE, ROLE + VIEW })
104     public HtmlResponse list(final OptionalThing<Integer> pageNumber, final SearchForm form) {
105         pageNumber.ifPresent(num -> {
106             elevateWordPager.setCurrentPageNumber(pageNumber.get());
107         }).orElse(() -> {
108             elevateWordPager.setCurrentPageNumber(0);
109         });
110         return asHtml(path_AdminElevateword_AdminElevatewordJsp).renderWith(data -> {
111             searchPaging(data, form);
112         });
113     }
114 
115     @Execute
116     @Secured({ ROLE, ROLE + VIEW })
117     public HtmlResponse search(final SearchForm form) {
118         copyBeanToBean(form, elevateWordPager, op -> op.exclude(Constants.PAGER_CONVERSION_RULE));
119         return asHtml(path_AdminElevateword_AdminElevatewordJsp).renderWith(data -> {
120             searchPaging(data, form);
121         });
122     }
123 
124     @Execute
125     @Secured({ ROLE, ROLE + VIEW })
126     public HtmlResponse reset(final SearchForm form) {
127         elevateWordPager.clear();
128         return asHtml(path_AdminElevateword_AdminElevatewordJsp).renderWith(data -> {
129             searchPaging(data, form);
130         });
131     }
132 
133     protected void searchPaging(final RenderData data, final SearchForm form) {
134         RenderDataUtil.register(data, "elevateWordItems", elevateWordService.getElevateWordList(elevateWordPager)); // page navi
135 
136         // restore from pager
137         copyBeanToBean(elevateWordPager, form, op -> op.include("id"));
138     }
139 
140     // ===================================================================================
141     //                                                                        Edit Execute
142     //                                                                        ============
143     // -----------------------------------------------------
144     //                                            Entry Page
145     //                                            ----------
146     @Execute
147     @Secured({ ROLE })
148     public HtmlResponse createnew() {
149         saveToken();
150         return asHtml(path_AdminElevateword_AdminElevatewordEditJsp).useForm(CreateForm.class, op -> {
151             op.setup(form -> {
152                 form.initialize();
153                 form.crudMode = CrudMode.CREATE;
154             });
155         }).renderWith(data -> {
156             registerLabels(data);
157         });
158     }
159 
160     @Execute
161     @Secured({ ROLE })
162     public HtmlResponse edit(final EditForm form) {
163         validate(form, messages -> {}, this::asListHtml);
164         final String id = form.id;
165         elevateWordService.getElevateWord(id).ifPresent(entity -> {
166             copyBeanToBean(entity, form, copyOp -> {
167                 copyOp.excludeNull();
168                 copyOp.exclude(Constants.PERMISSIONS);
169             });
170             final PermissionHelper permissionHelper = ComponentUtil.getPermissionHelper();
171             form.permissions = stream(entity.getPermissions()).get(stream -> stream.map(s -> permissionHelper.decode(s))
172                     .filter(StringUtil::isNotBlank).distinct().collect(Collectors.joining("\n")));
173         }).orElse(() -> {
174             throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asListHtml);
175         });
176         saveToken();
177         if (form.crudMode.intValue() == CrudMode.EDIT) {
178             // back
179             form.crudMode = CrudMode.DETAILS;
180             return asDetailsHtml();
181         }
182         form.crudMode = CrudMode.EDIT;
183         return asEditHtml();
184     }
185 
186     // -----------------------------------------------------
187     //                                               Details
188     //                                               -------
189     @Execute
190     @Secured({ ROLE, ROLE + VIEW })
191     public HtmlResponse details(final int crudMode, final String id) {
192         verifyCrudMode(crudMode, CrudMode.DETAILS);
193         saveToken();
194         final PermissionHelper permissionHelper = ComponentUtil.getPermissionHelper();
195         return asHtml(path_AdminElevateword_AdminElevatewordDetailsJsp).useForm(EditForm.class, op -> op.setup(form -> {
196             elevateWordService.getElevateWord(id).ifPresent(entity -> {
197                 copyBeanToBean(entity, form, copyOp -> {
198                     copyOp.excludeNull();
199                     copyOp.exclude(Constants.PERMISSIONS);
200                 });
201                 form.permissions = stream(entity.getPermissions()).get(stream -> stream.map(permissionHelper::decode)
202                         .filter(StringUtil::isNotBlank).distinct().collect(Collectors.joining("\n")));
203                 form.crudMode = crudMode;
204             }).orElse(() -> throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asListHtml));
205         })).renderWith(this::registerLabels);
206     }
207 
208     // -----------------------------------------------------
209     //                                              Download
210     //                                               -------
211     @Execute
212     @Secured({ ROLE, ROLE + VIEW })
213     public HtmlResponse downloadpage() {
214         saveToken();
215         return asDownloadHtml();
216     }
217 
218     @Execute
219     @Secured({ ROLE, ROLE + VIEW })
220     public ActionResponse download(final DownloadForm form) {
221         verifyToken(this::asDownloadHtml);
222 
223         return asStream("elevate.csv").contentTypeOctetStream().stream(out -> {
224             final Path tempFile = ComponentUtil.getSystemHelper().createTempFile("fess-elevate-", ".csv").toPath();
225             try {
226                 try (Writer writer = new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(tempFile), getCsvEncoding()))) {
227                     elevateWordService.exportCsv(writer);
228                 } catch (final Exception e) {
229                     throwValidationError(messages -> messages.addErrorsFailedToDownloadElevateFile(GLOBAL), this::asDownloadHtml);
230                 }
231                 try (InputStream in = Files.newInputStream(tempFile)) {
232                     out.write(in);
233                 }
234             } finally {
235                 Files.delete(tempFile);
236             }
237         });
238     }
239 
240     // -----------------------------------------------------
241     //                                                Upload
242     //                                               -------
243     @Execute
244     @Secured({ ROLE })
245     public HtmlResponse uploadpage() {
246         saveToken();
247         return asUploadHtml();
248     }
249 
250     // -----------------------------------------------------
251     //                                         Actually Crud
252     //                                         -------------
253     @Execute
254     @Secured({ ROLE })
255     public HtmlResponse create(final CreateForm form) {
256         verifyCrudMode(form.crudMode, CrudMode.CREATE);
257         validate(form, messages -> {}, this::asEditHtml);
258         verifyToken(this::asEditHtml);
259         getElevateWord(form).ifPresent(entity -> {
260             try {
261                 elevateWordService.store(entity);
262                 suggestHelper.addElevateWord(entity.getSuggestWord(), entity.getReading(), entity.getLabelTypeValues(),
263                         entity.getPermissions(), entity.getBoost(), false);
264                 saveInfo(messages -> messages.addSuccessCrudCreateCrudTable(GLOBAL));
265             } catch (final Exception e) {
266                 throwValidationError(messages -> messages.addErrorsCrudFailedToCreateCrudTable(GLOBAL, buildThrowableMessage(e)),
267                         this::asEditHtml);
268             }
269         }).orElse(() -> {
270             throwValidationError(messages -> messages.addErrorsCrudFailedToCreateInstance(GLOBAL), this::asEditHtml);
271         });
272         return redirect(getClass());
273     }
274 
275     @Execute
276     @Secured({ ROLE })
277     public HtmlResponse update(final EditForm form) {
278         verifyCrudMode(form.crudMode, CrudMode.EDIT);
279         validate(form, messages -> {}, this::asEditHtml);
280         verifyToken(this::asEditHtml);
281         getElevateWord(form).ifPresent(entity -> {
282             try {
283                 elevateWordService.store(entity);
284                 suggestHelper.deleteAllElevateWord(false);
285                 suggestHelper.storeAllElevateWords(false);
286                 saveInfo(messages -> messages.addSuccessCrudUpdateCrudTable(GLOBAL));
287             } catch (final Exception e) {
288                 throwValidationError(messages -> messages.addErrorsCrudFailedToUpdateCrudTable(GLOBAL, buildThrowableMessage(e)),
289                         this::asEditHtml);
290             }
291         }).orElse(() -> {
292             throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.id), this::asEditHtml);
293         });
294         return redirect(getClass());
295     }
296 
297     @Execute
298     @Secured({ ROLE })
299     public HtmlResponse delete(final EditForm form) {
300         verifyCrudMode(form.crudMode, CrudMode.DETAILS);
301         validate(form, messages -> {}, this::asDetailsHtml);
302         verifyToken(this::asDetailsHtml);
303         final String id = form.id;
304         elevateWordService.getElevateWord(id).ifPresent(entity -> {
305             try {
306                 elevateWordService.delete(entity);
307                 suggestHelper.deleteElevateWord(entity.getSuggestWord(), false);
308                 saveInfo(messages -> messages.addSuccessCrudDeleteCrudTable(GLOBAL));
309             } catch (final Exception e) {
310                 throwValidationError(messages -> messages.addErrorsCrudFailedToDeleteCrudTable(GLOBAL, buildThrowableMessage(e)),
311                         this::asEditHtml);
312             }
313         }).orElse(() -> throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asDetailsHtml));
314         return redirect(getClass());
315     }
316 
317     @Execute
318     @Secured({ ROLE })
319     public HtmlResponse upload(final UploadForm form) {
320         validate(form, messages -> {}, this::asUploadHtml);
321         verifyToken(this::asUploadHtml);
322         CommonPoolUtil.execute(() -> {
323             try (Reader reader = new BufferedReader(new InputStreamReader(form.elevateWordFile.getInputStream(), getCsvEncoding()))) {
324                 elevateWordService.importCsv(reader);
325                 suggestHelper.deleteAllElevateWord(false);
326                 suggestHelper.storeAllElevateWords(false);
327             } catch (final Exception e) {
328                 throw new FessSystemException("Failed to import data.", e);
329             }
330         });
331         saveInfo(messages -> messages.addSuccessUploadElevateWord(GLOBAL));
332         return redirect(getClass());
333     }
334 
335     // ===================================================================================
336     //                                                                        Assist Logic
337     //                                                                        ============
338     public static OptionalEntity<ElevateWord> getEntity(final CreateForm form, final String username, final long currentTime) {
339         switch (form.crudMode) {
340         case CrudMode.CREATE:
341             return OptionalEntity.of(new ElevateWord()).map(entity -> {
342                 entity.setCreatedBy(username);
343                 entity.setCreatedTime(currentTime);
344                 return entity;
345             });
346         case CrudMode.EDIT:
347             if (form instanceof EditForm) {
348                 return ComponentUtil.getComponent(ElevateWordService.class).getElevateWord(((EditForm) form).id);
349             }
350             break;
351         default:
352             break;
353         }
354         return OptionalEntity.empty();
355     }
356 
357     public static OptionalEntity<ElevateWord> getElevateWord(final CreateForm form) {
358         final SystemHelper systemHelper = ComponentUtil.getSystemHelper();
359         final String username = systemHelper.getUsername();
360         final long currentTime = systemHelper.getCurrentTimeAsLong();
361 
362         return getEntity(form, username, currentTime).map(entity -> {
363             entity.setUpdatedBy(username);
364             entity.setUpdatedTime(currentTime);
365             BeanUtil.copyBeanToBean(form, entity, op -> op.exclude(Stream
366                     .concat(Stream.of(Constants.COMMON_CONVERSION_RULE), Stream.of(Constants.PERMISSIONS)).toArray(n -> new String[n])));
367             final PermissionHelper permissionHelper = ComponentUtil.getPermissionHelper();
368             entity.setPermissions(split(form.permissions, "\n").get(
369                     stream -> stream.map(permissionHelper::encode).filter(StringUtil::isNotBlank).distinct().toArray(n -> new String[n])));
370             return entity;
371         });
372     }
373 
374     protected void registerLabels(final RenderData data) {
375         RenderDataUtil.register(data, "labelTypeItems", labelTypeService.getLabelTypeList());
376     }
377 
378     // ===================================================================================
379     //                                                                        Small Helper
380     //                                                                        ============
381     protected void verifyCrudMode(final int crudMode, final int expectedMode) {
382         if (crudMode != expectedMode) {
383             throwValidationError(messages -> {
384                 messages.addErrorsCrudInvalidMode(GLOBAL, String.valueOf(expectedMode), String.valueOf(crudMode));
385             }, this::asListHtml);
386         }
387     }
388 
389     private String getCsvEncoding() {
390         return fessConfig.getCsvFileEncoding();
391     }
392 
393     // ===================================================================================
394     //                                                                              JSP
395     //                                                                           =========
396     private HtmlResponse asListHtml() {
397         return asHtml(path_AdminElevateword_AdminElevatewordJsp).renderWith(data -> {
398             RenderDataUtil.register(data, "elevateWordItems", elevateWordService.getElevateWordList(elevateWordPager)); // page navi
399         }).useForm(SearchForm.class, setup -> {
400             setup.setup(form -> {
401                 copyBeanToBean(elevateWordPager, form, op -> op.include("id"));
402             });
403         });
404     }
405 
406     private HtmlResponse asEditHtml() {
407         return asHtml(path_AdminElevateword_AdminElevatewordEditJsp).renderWith(data -> {
408             registerLabels(data);
409         });
410     }
411 
412     private HtmlResponse asDetailsHtml() {
413         return asHtml(path_AdminElevateword_AdminElevatewordDetailsJsp).renderWith(data -> {
414             registerLabels(data);
415         });
416     }
417 
418     private HtmlResponse asUploadHtml() {
419         return asHtml(path_AdminElevateword_AdminElevatewordUploadJsp).useForm(UploadForm.class);
420     }
421 
422     private HtmlResponse asDownloadHtml() {
423         return asHtml(path_AdminElevateword_AdminElevatewordDownloadJsp).useForm(DownloadForm.class);
424     }
425 }