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.labeltype;
17  
18  import static org.codelibs.core.stream.StreamUtil.stream;
19  
20  import java.util.stream.Collectors;
21  import java.util.stream.Stream;
22  
23  import org.apache.logging.log4j.LogManager;
24  import org.apache.logging.log4j.Logger;
25  import org.codelibs.core.lang.StringUtil;
26  import org.codelibs.fess.Constants;
27  import org.codelibs.fess.annotation.Secured;
28  import org.codelibs.fess.app.pager.LabelTypePager;
29  import org.codelibs.fess.app.service.LabelTypeService;
30  import org.codelibs.fess.app.service.RoleTypeService;
31  import org.codelibs.fess.app.web.CrudMode;
32  import org.codelibs.fess.app.web.base.FessAdminAction;
33  import org.codelibs.fess.helper.PermissionHelper;
34  import org.codelibs.fess.helper.SystemHelper;
35  import org.codelibs.fess.opensearch.config.exentity.LabelType;
36  import org.codelibs.fess.util.ComponentUtil;
37  import org.codelibs.fess.util.RenderDataUtil;
38  import org.dbflute.optional.OptionalEntity;
39  import org.dbflute.optional.OptionalThing;
40  import org.lastaflute.web.Execute;
41  import org.lastaflute.web.response.HtmlResponse;
42  import org.lastaflute.web.response.render.RenderData;
43  import org.lastaflute.web.ruts.process.ActionRuntime;
44  
45  import jakarta.annotation.Resource;
46  
47  /**
48   * Admin action for Label Type management.
49   *
50   */
51  public class AdminLabeltypeAction extends FessAdminAction {
52  
53      /**
54       * Default constructor.
55       */
56      public AdminLabeltypeAction() {
57          super();
58      }
59  
60      /** The role name for label type administration. */
61      public static final String ROLE = "admin-labeltype";
62  
63      /** Logger for this class. */
64      private static final Logger logger = LogManager.getLogger(AdminLabeltypeAction.class);
65  
66      // ===================================================================================
67      //                                                                           Attribute
68      //                                                                           =========
69      /** Service for label type operations. */
70      @Resource
71      private LabelTypeService labelTypeService;
72  
73      /** Pager for label type list pagination. */
74      @Resource
75      private LabelTypePager labelTypePager;
76  
77      /** Service for role type operations. */
78      @Resource
79      private RoleTypeService roleTypeService;
80  
81      // ===================================================================================
82      //                                                                               Hook
83      //                                                                              ======
84      /**
85       * Sets up HTML data for rendering, including help link.
86       *
87       * @param runtime the action runtime
88       */
89      @Override
90      protected void setupHtmlData(final ActionRuntime runtime) {
91          super.setupHtmlData(runtime);
92          runtime.registerData("helpLink", systemHelper.getHelpLink(fessConfig.getOnlineHelpNameLabeltype()));
93      }
94  
95      /**
96       * Returns the action role for this admin action.
97       *
98       * @return the role name
99       */
100     @Override
101     protected String getActionRole() {
102         return ROLE;
103     }
104 
105     // ===================================================================================
106     //                                                                      Search Execute
107     //                                                                      ==============
108     /**
109      * Displays the label type list page.
110      *
111      * @param form the search form
112      * @return HTML response for the list page
113      */
114     @Execute
115     @Secured({ ROLE, ROLE + VIEW })
116     public HtmlResponse index(final SearchForm form) {
117         return asListHtml();
118     }
119 
120     /**
121      * Displays the label type list with pagination.
122      *
123      * @param pageNumber the page number
124      * @param form the search form
125      * @return HTML response for the list page
126      */
127     @Execute
128     @Secured({ ROLE, ROLE + VIEW })
129     public HtmlResponse list(final OptionalThing<Integer> pageNumber, final SearchForm form) {
130         pageNumber.ifPresent(num -> {
131             labelTypePager.setCurrentPageNumber(pageNumber.get());
132         }).orElse(() -> {
133             labelTypePager.setCurrentPageNumber(0);
134         });
135         return asHtml(path_AdminLabeltype_AdminLabeltypeJsp).renderWith(data -> {
136             searchPaging(data, form);
137         });
138     }
139 
140     /**
141      * Searches label types based on the form criteria.
142      *
143      * @param form the search form
144      * @return HTML response for the search results
145      */
146     @Execute
147     @Secured({ ROLE, ROLE + VIEW })
148     public HtmlResponse search(final SearchForm form) {
149         copyBeanToBean(form, labelTypePager, op -> op.exclude(Constants.PAGER_CONVERSION_RULE));
150         return asHtml(path_AdminLabeltype_AdminLabeltypeJsp).renderWith(data -> {
151             searchPaging(data, form);
152         });
153     }
154 
155     /**
156      * Resets the search criteria and displays the default list.
157      *
158      * @param form the search form
159      * @return HTML response for the reset list
160      */
161     @Execute
162     @Secured({ ROLE, ROLE + VIEW })
163     public HtmlResponse reset(final SearchForm form) {
164         labelTypePager.clear();
165         return asHtml(path_AdminLabeltype_AdminLabeltypeJsp).renderWith(data -> {
166             searchPaging(data, form);
167         });
168     }
169 
170     /**
171      * Sets up data for search result pagination.
172      *
173      * @param data the render data
174      * @param form the search form
175      */
176     protected void searchPaging(final RenderData data, final SearchForm form) {
177         RenderDataUtil.register(data, "labelTypeItems", labelTypeService.getLabelTypeList(labelTypePager)); // page navi
178 
179         // restore from pager
180         copyBeanToBean(labelTypePager, form, op -> op.include("name", "value"));
181     }
182 
183     // ===================================================================================
184     //                                                                        Edit Execute
185     //                                                                        ============
186     // -----------------------------------------------------
187     //                                            Entry Page
188     //                                            ----------
189     /**
190      * Displays the create new label type page.
191      *
192      * @return HTML response for the create page
193      */
194     @Execute
195     @Secured({ ROLE })
196     public HtmlResponse createnew() {
197         saveToken();
198         return asHtml(path_AdminLabeltype_AdminLabeltypeEditJsp).useForm(CreateForm.class, op -> {
199             op.setup(form -> {
200                 form.initialize();
201                 form.crudMode = CrudMode.CREATE;
202             });
203         }).renderWith(data -> {
204             registerRoleTypeItems(data);
205         });
206     }
207 
208     /**
209      * Displays the edit label type page.
210      *
211      * @param form the edit form
212      * @return HTML response for the edit page
213      */
214     @Execute
215     @Secured({ ROLE })
216     public HtmlResponse edit(final EditForm form) {
217         validate(form, messages -> {}, this::asListHtml);
218         final String id = form.id;
219         labelTypeService.getLabelType(id).ifPresent(entity -> {
220             copyBeanToBean(entity, form, copyOp -> {
221                 copyOp.excludeNull();
222                 copyOp.exclude(Constants.PERMISSIONS);
223             });
224             final PermissionHelper permissionHelper = ComponentUtil.getPermissionHelper();
225             form.permissions = stream(entity.getPermissions()).get(stream -> stream.map(s -> permissionHelper.decode(s))
226                     .filter(StringUtil::isNotBlank)
227                     .distinct()
228                     .collect(Collectors.joining("\n")));
229         }).orElse(() -> {
230             throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asListHtml);
231         });
232         saveToken();
233         if (form.crudMode.intValue() == CrudMode.EDIT) {
234             // back
235             form.crudMode = CrudMode.DETAILS;
236             return asDetailsHtml();
237         }
238         form.crudMode = CrudMode.EDIT;
239         return asEditHtml();
240     }
241 
242     // -----------------------------------------------------
243     //                                               Details
244     //                                               -------
245     /**
246      * Displays the label type details page.
247      *
248      * @param crudMode the CRUD mode
249      * @param id the label type ID
250      * @return HTML response for the details page
251      */
252     @Execute
253     @Secured({ ROLE, ROLE + VIEW })
254     public HtmlResponse details(final int crudMode, final String id) {
255         verifyCrudMode(crudMode, CrudMode.DETAILS, this::asListHtml);
256         saveToken();
257         return asHtml(path_AdminLabeltype_AdminLabeltypeDetailsJsp).useForm(EditForm.class, op -> {
258             op.setup(form -> {
259                 labelTypeService.getLabelType(id).ifPresent(entity -> {
260                     copyBeanToBean(entity, form, copyOp -> {
261                         copyOp.excludeNull();
262                         copyOp.exclude(Constants.PERMISSIONS);
263                     });
264                     final PermissionHelper permissionHelper = ComponentUtil.getPermissionHelper();
265                     form.permissions = stream(entity.getPermissions()).get(stream -> stream.map(s -> permissionHelper.decode(s))
266                             .filter(StringUtil::isNotBlank)
267                             .distinct()
268                             .collect(Collectors.joining("\n")));
269                     form.crudMode = crudMode;
270                 }).orElse(() -> {
271                     throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asListHtml);
272                 });
273             });
274         }).renderWith(data -> {
275             registerRoleTypeItems(data);
276         });
277     }
278 
279     // -----------------------------------------------------
280     //                                         Actually Crud
281     //                                         -------------
282     /**
283      * Creates a new label type.
284      *
285      * @param form the create form
286      * @return HTML response after creation
287      */
288     @Execute
289     @Secured({ ROLE })
290     public HtmlResponse create(final CreateForm form) {
291         verifyCrudMode(form.crudMode, CrudMode.CREATE, this::asListHtml);
292         validate(form, messages -> {}, this::asEditHtml);
293         verifyToken(this::asEditHtml);
294         getLabelType(form).ifPresent(entity -> {
295             try {
296                 labelTypeService.store(entity);
297                 saveInfo(messages -> messages.addSuccessCrudCreateCrudTable(GLOBAL));
298             } catch (final Exception e) {
299                 logger.warn("Failed to process a request.", e);
300                 throwValidationError(messages -> messages.addErrorsCrudFailedToCreateCrudTable(GLOBAL, buildThrowableMessage(e)),
301                         this::asEditHtml);
302             }
303         }).orElse(() -> {
304             throwValidationError(messages -> messages.addErrorsCrudFailedToCreateInstance(GLOBAL), this::asEditHtml);
305         });
306         return redirect(getClass());
307     }
308 
309     /**
310      * Updates an existing label type.
311      *
312      * @param form the edit form
313      * @return HTML response after update
314      */
315     @Execute
316     @Secured({ ROLE })
317     public HtmlResponse update(final EditForm form) {
318         verifyCrudMode(form.crudMode, CrudMode.EDIT, this::asListHtml);
319         validate(form, messages -> {}, this::asEditHtml);
320         verifyToken(this::asEditHtml);
321         getLabelType(form).ifPresent(entity -> {
322             try {
323                 labelTypeService.store(entity);
324                 saveInfo(messages -> messages.addSuccessCrudUpdateCrudTable(GLOBAL));
325             } catch (final Exception e) {
326                 logger.warn("Failed to process a request.", e);
327                 throwValidationError(messages -> messages.addErrorsCrudFailedToUpdateCrudTable(GLOBAL, buildThrowableMessage(e)),
328                         this::asEditHtml);
329             }
330         }).orElse(() -> {
331             throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.id), this::asEditHtml);
332         });
333         return redirect(getClass());
334     }
335 
336     /**
337      * Deletes a label type.
338      *
339      * @param form the edit form
340      * @return HTML response after deletion
341      */
342     @Execute
343     @Secured({ ROLE })
344     public HtmlResponse delete(final EditForm form) {
345         verifyCrudMode(form.crudMode, CrudMode.DETAILS, this::asListHtml);
346         validate(form, messages -> {}, this::asDetailsHtml);
347         verifyToken(this::asDetailsHtml);
348         final String id = form.id;
349         labelTypeService.getLabelType(id).ifPresent(entity -> {
350             try {
351                 labelTypeService.delete(entity);
352                 saveInfo(messages -> messages.addSuccessCrudDeleteCrudTable(GLOBAL));
353             } catch (final Exception e) {
354                 logger.warn("Failed to process a request.", e);
355                 throwValidationError(messages -> messages.addErrorsCrudFailedToDeleteCrudTable(GLOBAL, buildThrowableMessage(e)),
356                         this::asEditHtml);
357             }
358         }).orElse(() -> {
359             throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asDetailsHtml);
360         });
361         return redirect(getClass());
362     }
363 
364     // ===================================================================================
365     //                                                                        Assist Logic
366     //                                                                        ============
367 
368     /**
369      * Gets a label type entity based on the form and current user info.
370      *
371      * @param form the create form
372      * @param username the current username
373      * @param currentTime the current time
374      * @return optional label type entity
375      */
376     public static OptionalEntity<LabelType> getEntity(final CreateForm form, final String username, final long currentTime) {
377         switch (form.crudMode) {
378         case CrudMode.CREATE:
379             return OptionalEntity.of(new LabelType()).map(entity -> {
380                 entity.setCreatedBy(username);
381                 entity.setCreatedTime(currentTime);
382                 return entity;
383             });
384         case CrudMode.EDIT:
385             if (form instanceof EditForm) {
386                 return ComponentUtil.getComponent(LabelTypeService.class).getLabelType(((EditForm) form).id);
387             }
388             break;
389         default:
390             break;
391         }
392         return OptionalEntity.empty();
393     }
394 
395     /**
396      * Gets a label type entity from the form with system info.
397      *
398      * @param form the create form
399      * @return optional label type entity
400      */
401     public static OptionalEntity<LabelType> getLabelType(final CreateForm form) {
402         final SystemHelper systemHelper = ComponentUtil.getSystemHelper();
403         final String username = systemHelper.getUsername();
404         final long currentTime = systemHelper.getCurrentTimeAsLong();
405         return getEntity(form, username, currentTime).map(entity -> {
406             entity.setUpdatedBy(username);
407             entity.setUpdatedTime(currentTime);
408             copyBeanToBean(form, entity,
409                     op -> op.exclude(Stream.concat(Stream.of(Constants.COMMON_CONVERSION_RULE), Stream.of(Constants.PERMISSIONS))
410                             .toArray(n -> new String[n])));
411             entity.setPermissions(encodePermissions(form.permissions));
412             return entity;
413         });
414     }
415 
416     /**
417      * Registers role type items for the dropdown list.
418      *
419      * @param data the render data
420      */
421     protected void registerRoleTypeItems(final RenderData data) {
422         RenderDataUtil.register(data, "roleTypeItems", roleTypeService.getRoleTypeList());
423     }
424 
425     // ===================================================================================
426     //                                                                        Small Helper
427     //                                                                        ============
428     //                                                                              JSP
429     //                                                                           =========
430 
431     /**
432      * Returns HTML response for the list page.
433      *
434      * @return HTML response for the list page
435      */
436     private HtmlResponse asListHtml() {
437         return asHtml(path_AdminLabeltype_AdminLabeltypeJsp).renderWith(data -> {
438             RenderDataUtil.register(data, "labelTypeItems", labelTypeService.getLabelTypeList(labelTypePager)); // page navi
439         }).useForm(SearchForm.class, setup -> {
440             setup.setup(form -> {
441                 copyBeanToBean(labelTypePager, form, op -> op.include("name", "value"));
442             });
443         });
444     }
445 
446     /**
447      * Returns HTML response for the edit page.
448      *
449      * @return HTML response for the edit page
450      */
451     private HtmlResponse asEditHtml() {
452         return asHtml(path_AdminLabeltype_AdminLabeltypeEditJsp).renderWith(data -> {
453             registerRoleTypeItems(data);
454         });
455     }
456 
457     /**
458      * Returns HTML response for the details page.
459      *
460      * @return HTML response for the details page
461      */
462     private HtmlResponse asDetailsHtml() {
463         return asHtml(path_AdminLabeltype_AdminLabeltypeDetailsJsp).renderWith(data -> {
464             registerRoleTypeItems(data);
465         });
466     }
467 }