View Javadoc
1   /*
2    * Copyright 2012-2025 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.boostdoc;
17  
18  import org.apache.logging.log4j.LogManager;
19  import org.apache.logging.log4j.Logger;
20  import org.codelibs.core.beans.util.BeanUtil;
21  import org.codelibs.fess.Constants;
22  import org.codelibs.fess.annotation.Secured;
23  import org.codelibs.fess.app.pager.BoostDocPager;
24  import org.codelibs.fess.app.service.BoostDocumentRuleService;
25  import org.codelibs.fess.app.web.CrudMode;
26  import org.codelibs.fess.app.web.base.FessAdminAction;
27  import org.codelibs.fess.helper.SystemHelper;
28  import org.codelibs.fess.opensearch.config.exentity.BoostDocumentRule;
29  import org.codelibs.fess.util.ComponentUtil;
30  import org.codelibs.fess.util.RenderDataUtil;
31  import org.dbflute.optional.OptionalEntity;
32  import org.dbflute.optional.OptionalThing;
33  import org.lastaflute.web.Execute;
34  import org.lastaflute.web.response.HtmlResponse;
35  import org.lastaflute.web.response.render.RenderData;
36  import org.lastaflute.web.ruts.process.ActionRuntime;
37  
38  import jakarta.annotation.Resource;
39  
40  /**
41   * Admin action for Boost Document management.
42   *
43   */
44  public class AdminBoostdocAction extends FessAdminAction {
45  
46      /**
47       * Default constructor.
48       */
49      public AdminBoostdocAction() {
50          super();
51      }
52  
53      /** The role for this action. */
54      public static final String ROLE = "admin-boostdoc";
55  
56      private static final Logger logger = LogManager.getLogger(AdminBoostdocAction.class);
57  
58      // ===================================================================================
59      //                                                                           Attribute
60      //                                                                           =========
61      @Resource
62      private BoostDocumentRuleService boostDocumentRuleService;
63      @Resource
64      private BoostDocPager boostDocPager;
65  
66      // ===================================================================================
67      //                                                                               Hook
68      //                                                                              ======
69      @Override
70      protected void setupHtmlData(final ActionRuntime runtime) {
71          super.setupHtmlData(runtime);
72          runtime.registerData("helpLink", systemHelper.getHelpLink(fessConfig.getOnlineHelpNameBoostdoc()));
73      }
74  
75      @Override
76      protected String getActionRole() {
77          return ROLE;
78      }
79  
80      // ===================================================================================
81      //                                                                      Search Execute
82      //                                                                      ==============
83      /**
84       * Show the index page.
85       * @return The HTML response.
86       */
87      @Execute
88      @Secured({ ROLE, ROLE + VIEW })
89      public HtmlResponse index() {
90          return asListHtml();
91      }
92  
93      /**
94       * Show the list page.
95       * @param pageNumber The page number.
96       * @param form The search form.
97       * @return The HTML response.
98       */
99      @Execute
100     @Secured({ ROLE, ROLE + VIEW })
101     public HtmlResponse list(final OptionalThing<Integer> pageNumber, final SearchForm form) {
102         pageNumber.ifPresent(num -> {
103             boostDocPager.setCurrentPageNumber(pageNumber.get());
104         }).orElse(() -> {
105             boostDocPager.setCurrentPageNumber(0);
106         });
107         return asHtml(path_AdminBoostdoc_AdminBoostdocJsp).renderWith(data -> {
108             searchPaging(data, form);
109         });
110     }
111 
112     /**
113      * Search for boost document rules.
114      * @param form The search form.
115      * @return The HTML response.
116      */
117     @Execute
118     @Secured({ ROLE, ROLE + VIEW })
119     public HtmlResponse search(final SearchForm form) {
120         copyBeanToBean(form, boostDocPager, op -> op.exclude(Constants.PAGER_CONVERSION_RULE));
121         return asHtml(path_AdminBoostdoc_AdminBoostdocJsp).renderWith(data -> {
122             searchPaging(data, form);
123         });
124     }
125 
126     /**
127      * Reset the search form.
128      * @param form The search form.
129      * @return The HTML response.
130      */
131     @Execute
132     @Secured({ ROLE, ROLE + VIEW })
133     public HtmlResponse reset(final SearchForm form) {
134         boostDocPager.clear();
135         return asHtml(path_AdminBoostdoc_AdminBoostdocJsp).renderWith(data -> {
136             searchPaging(data, form);
137         });
138     }
139 
140     /**
141      * Search with paging.
142      * @param data The render data.
143      * @param form The search form.
144      */
145     protected void searchPaging(final RenderData data, final SearchForm form) {
146         RenderDataUtil.register(data, "boostDocumentRuleItems", boostDocumentRuleService.getBoostDocumentRuleList(boostDocPager)); // page navi
147 
148         // restore from pager
149         copyBeanToBean(boostDocPager, form, op -> op.include("urlExpr", "boostExpr"));
150     }
151 
152     // ===================================================================================
153     //                                                                        Edit Execute
154     //                                                                        ============
155     // ----------------------------------------------------
156     //                                            Entry Page
157     //                                            ----------
158     /**
159      * Show the create new page.
160      * @return The HTML response.
161      */
162     @Execute
163     @Secured({ ROLE })
164     public HtmlResponse createnew() {
165         saveToken();
166         return asEditHtml().useForm(CreateForm.class, op -> {
167             op.setup(form -> {
168                 form.initialize();
169                 form.crudMode = CrudMode.CREATE;
170             });
171         });
172     }
173 
174     /**
175      * Show the edit page.
176      * @param form The edit form.
177      * @return The HTML response.
178      */
179     @Execute
180     @Secured({ ROLE })
181     public HtmlResponse edit(final EditForm form) {
182         validate(form, messages -> {}, this::asListHtml);
183         final String id = form.id;
184         boostDocumentRuleService.getBoostDocumentRule(id).ifPresent(entity -> {
185             copyBeanToBean(entity, form, op -> {});
186         }).orElse(() -> {
187             throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asListHtml);
188         });
189         saveToken();
190         if (form.crudMode.intValue() == CrudMode.EDIT) {
191             // back
192             form.crudMode = CrudMode.DETAILS;
193             return asDetailsHtml();
194         }
195         form.crudMode = CrudMode.EDIT;
196         return asEditHtml();
197     }
198 
199     // ----------------------------------------------------
200     //                                               Details
201     //                                               -------
202     /**
203      * Show the details page.
204      * @param crudMode The CRUD mode.
205      * @param id The ID of the boost document rule.
206      * @return The HTML response.
207      */
208     @Execute
209     @Secured({ ROLE, ROLE + VIEW })
210     public HtmlResponse details(final int crudMode, final String id) {
211         verifyCrudMode(crudMode, CrudMode.DETAILS, this::asListHtml);
212         saveToken();
213         return asDetailsHtml().useForm(EditForm.class, op -> {
214             op.setup(form -> {
215                 boostDocumentRuleService.getBoostDocumentRule(id).ifPresent(entity -> {
216                     copyBeanToBean(entity, form, copyOp -> {
217                         copyOp.excludeNull();
218                     });
219                     form.crudMode = crudMode;
220                 }).orElse(() -> {
221                     throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asListHtml);
222                 });
223             });
224         });
225     }
226 
227     // ----------------------------------------------------
228     //                                         Actually Crud
229     //                                         -------------
230     /**
231      * Create a new boost document rule.
232      * @param form The create form.
233      * @return The HTML response.
234      */
235     @Execute
236     @Secured({ ROLE })
237     public HtmlResponse create(final CreateForm form) {
238         verifyCrudMode(form.crudMode, CrudMode.CREATE, this::asListHtml);
239         validate(form, messages -> {}, this::asEditHtml);
240         verifyToken(this::asEditHtml);
241         getBoostDocumentRule(form).ifPresent(entity -> {
242             try {
243                 boostDocumentRuleService.store(entity);
244                 saveInfo(messages -> messages.addSuccessCrudCreateCrudTable(GLOBAL));
245             } catch (final Exception e) {
246                 logger.warn("Failed to process a request.", e);
247                 throwValidationError(messages -> messages.addErrorsCrudFailedToCreateCrudTable(GLOBAL, buildThrowableMessage(e)),
248                         this::asEditHtml);
249             }
250         }).orElse(() -> {
251             throwValidationError(messages -> messages.addErrorsCrudFailedToCreateInstance(GLOBAL), this::asEditHtml);
252         });
253         return redirect(getClass());
254     }
255 
256     /**
257      * Update a boost document rule.
258      * @param form The edit form.
259      * @return The HTML response.
260      */
261     @Execute
262     @Secured({ ROLE })
263     public HtmlResponse update(final EditForm form) {
264         verifyCrudMode(form.crudMode, CrudMode.EDIT, this::asListHtml);
265         validate(form, messages -> {}, this::asEditHtml);
266         verifyToken(this::asEditHtml);
267         getBoostDocumentRule(form).ifPresent(entity -> {
268             try {
269                 boostDocumentRuleService.store(entity);
270                 saveInfo(messages -> messages.addSuccessCrudUpdateCrudTable(GLOBAL));
271             } catch (final Exception e) {
272                 logger.warn("Failed to process a request.", e);
273                 throwValidationError(messages -> messages.addErrorsCrudFailedToUpdateCrudTable(GLOBAL, buildThrowableMessage(e)),
274                         this::asEditHtml);
275             }
276         }).orElse(() -> {
277             throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.id), this::asEditHtml);
278         });
279         return redirect(getClass());
280     }
281 
282     /**
283      * Delete a boost document rule.
284      * @param form The edit form.
285      * @return The HTML response.
286      */
287     @Execute
288     @Secured({ ROLE })
289     public HtmlResponse delete(final EditForm form) {
290         verifyCrudMode(form.crudMode, CrudMode.DETAILS, this::asListHtml);
291         validate(form, messages -> {}, this::asDetailsHtml);
292         verifyToken(this::asDetailsHtml);
293         final String id = form.id;
294         boostDocumentRuleService.getBoostDocumentRule(id).ifPresent(entity -> {
295             try {
296                 boostDocumentRuleService.delete(entity);
297                 saveInfo(messages -> messages.addSuccessCrudDeleteCrudTable(GLOBAL));
298             } catch (final Exception e) {
299                 logger.warn("Failed to process a request.", e);
300                 throwValidationError(messages -> messages.addErrorsCrudFailedToDeleteCrudTable(GLOBAL, buildThrowableMessage(e)),
301                         this::asEditHtml);
302             }
303         }).orElse(() -> {
304             throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asDetailsHtml);
305         });
306         return redirect(getClass());
307     }
308 
309     // ===================================================================================
310     //                                                                        Assist Logic
311     //                                                                        ============
312 
313     private static OptionalEntity<BoostDocumentRule> getEntity(final CreateForm form, final String username, final long currentTime) {
314         switch (form.crudMode) {
315         case CrudMode.CREATE:
316             return OptionalEntity.of(new BoostDocumentRule()).map(entity -> {
317                 entity.setCreatedBy(username);
318                 entity.setCreatedTime(currentTime);
319                 return entity;
320             });
321         case CrudMode.EDIT:
322             if (form instanceof EditForm) {
323                 return ComponentUtil.getComponent(BoostDocumentRuleService.class).getBoostDocumentRule(((EditForm) form).id);
324             }
325             break;
326         default:
327             break;
328         }
329         return OptionalEntity.empty();
330     }
331 
332     /**
333      * Get a boost document rule from a form.
334      * @param form The create form.
335      * @return An optional entity of a boost document rule.
336      */
337     public static OptionalEntity<BoostDocumentRule> getBoostDocumentRule(final CreateForm form) {
338         final SystemHelper systemHelper = ComponentUtil.getSystemHelper();
339         final String username = systemHelper.getUsername();
340         final long currentTime = systemHelper.getCurrentTimeAsLong();
341         return getEntity(form, username, currentTime).map(entity -> {
342             entity.setUpdatedBy(username);
343             entity.setUpdatedTime(currentTime);
344             BeanUtil.copyBeanToBean(form, entity, op -> op.exclude(Constants.COMMON_CONVERSION_RULE));
345             return entity;
346         });
347     }
348 
349     // ===================================================================================
350     //                                                                              JSP
351     //                                                                           =========
352 
353     private HtmlResponse asListHtml() {
354         return asHtml(path_AdminBoostdoc_AdminBoostdocJsp).renderWith(data -> {
355             RenderDataUtil.register(data, "boostDocumentRuleItems", boostDocumentRuleService.getBoostDocumentRuleList(boostDocPager));
356         }).useForm(SearchForm.class, setup -> {
357             setup.setup(form -> {
358                 copyBeanToBean(boostDocPager, form, op -> op.include("urlExpr", "boostExpr"));
359             });
360         });
361     }
362 
363     private HtmlResponse asEditHtml() {
364         return asHtml(path_AdminBoostdoc_AdminBoostdocEditJsp);
365     }
366 
367     private HtmlResponse asDetailsHtml() {
368         return asHtml(path_AdminBoostdoc_AdminBoostdocDetailsJsp);
369     }
370 
371 }