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.role;
17  
18  import java.util.Base64;
19  
20  import org.apache.logging.log4j.LogManager;
21  import org.apache.logging.log4j.Logger;
22  import org.codelibs.fess.Constants;
23  import org.codelibs.fess.annotation.Secured;
24  import org.codelibs.fess.app.pager.RolePager;
25  import org.codelibs.fess.app.service.RoleService;
26  import org.codelibs.fess.app.web.CrudMode;
27  import org.codelibs.fess.app.web.base.FessAdminAction;
28  import org.codelibs.fess.opensearch.user.exentity.Role;
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 Role management.
42   *
43   */
44  public class AdminRoleAction extends FessAdminAction {
45  
46      /**
47       * Default constructor.
48       */
49      public AdminRoleAction() {
50          super();
51      }
52  
53      /** Role name for admin role operations */
54      public static final String ROLE = "admin-role";
55  
56      private static final Logger logger = LogManager.getLogger(AdminRoleAction.class);
57  
58      // ===================================================================================
59      //                                                                           Attribute
60      //                                                                           =========
61      @Resource
62      private RoleService roleService;
63      @Resource
64      private RolePager rolePager;
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.getOnlineHelpNameRole()));
73      }
74  
75      @Override
76      protected String getActionRole() {
77          return ROLE;
78      }
79  
80      // ===================================================================================
81      //                                                                      Search Execute
82      //                                                                      ==============
83      /**
84       * Displays the role management index page.
85       *
86       * @param form the search form for filtering
87       * @return HTML response for the role list page
88       */
89      @Execute
90      @Secured({ ROLE, ROLE + VIEW })
91      public HtmlResponse index(final SearchForm form) {
92          return asListHtml();
93      }
94  
95      /**
96       * Displays a paginated list of role items.
97       *
98       * @param pageNumber the page number to display (optional)
99       * @param form the search form containing filter criteria
100      * @return HTML response with the role list
101      */
102     @Execute
103     @Secured({ ROLE, ROLE + VIEW })
104     public HtmlResponse list(final OptionalThing<Integer> pageNumber, final SearchForm form) {
105         pageNumber.ifPresent(num -> {
106             rolePager.setCurrentPageNumber(pageNumber.get());
107         }).orElse(() -> {
108             rolePager.setCurrentPageNumber(0);
109         });
110         return asHtml(path_AdminRole_AdminRoleJsp).renderWith(data -> {
111             searchPaging(data, form);
112         });
113     }
114 
115     /**
116      * Searches for role items based on the provided search criteria.
117      *
118      * @param form the search form containing search criteria
119      * @return HTML response with filtered role results
120      */
121     @Execute
122     @Secured({ ROLE, ROLE + VIEW })
123     public HtmlResponse search(final SearchForm form) {
124         copyBeanToBean(form, rolePager, op -> op.exclude(Constants.PAGER_CONVERSION_RULE));
125         return asHtml(path_AdminRole_AdminRoleJsp).renderWith(data -> {
126             searchPaging(data, form);
127         });
128     }
129 
130     /**
131      * Resets the search criteria and displays all role items.
132      *
133      * @param form the search form to reset
134      * @return HTML response with the reset role list
135      */
136     @Execute
137     @Secured({ ROLE, ROLE + VIEW })
138     public HtmlResponse reset(final SearchForm form) {
139         rolePager.clear();
140         return asHtml(path_AdminRole_AdminRoleJsp).renderWith(data -> {
141             searchPaging(data, form);
142         });
143     }
144 
145     /**
146      * Sets up search paging data for rendering the role list.
147      *
148      * @param data the render data to populate
149      * @param form the search form containing current search criteria
150      */
151     protected void searchPaging(final RenderData data, final SearchForm form) {
152         RenderDataUtil.register(data, "roleItems", roleService.getRoleList(rolePager)); // page navi
153 
154         // restore from pager
155         copyBeanToBean(rolePager, form, op -> op.include("id"));
156     }
157 
158     // ===================================================================================
159     //                                                                        Edit Execute
160     //                                                                        ============
161     // -----------------------------------------------------
162     //                                            Entry Page
163     //                                            ----------
164     /**
165      * Displays the form for creating a new role item.
166      *
167      * @return HTML response for the create form
168      */
169     @Execute
170     @Secured({ ROLE })
171     public HtmlResponse createnew() {
172         saveToken();
173         return asHtml(path_AdminRole_AdminRoleEditJsp).useForm(CreateForm.class, op -> {
174             op.setup(form -> {
175                 form.initialize();
176                 form.crudMode = CrudMode.CREATE;
177             });
178         });
179     }
180 
181     // -----------------------------------------------------
182     //                                               Details
183     //                                               -------
184     /**
185      * Displays the details of a role item.
186      *
187      * @param crudMode the CRUD mode for the operation
188      * @param id the ID of the role item to display
189      * @return HTML response for the details page
190      */
191     @Execute
192     @Secured({ ROLE, ROLE + VIEW })
193     public HtmlResponse details(final int crudMode, final String id) {
194         verifyCrudMode(crudMode, CrudMode.DETAILS, this::asListHtml);
195         saveToken();
196         return asHtml(path_AdminRole_AdminRoleDetailsJsp).useForm(EditForm.class, op -> {
197             op.setup(form -> {
198                 roleService.getRole(id).ifPresent(entity -> {
199                     copyBeanToBean(entity, form, copyOp -> {
200                         copyOp.excludeNull();
201                     });
202                     form.crudMode = crudMode;
203                 }).orElse(() -> {
204                     throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asListHtml);
205                 });
206             });
207         });
208     }
209 
210     // -----------------------------------------------------
211     //                                         Actually Crud
212     //                                         -------------
213     /**
214      * Creates a new role item.
215      *
216      * @param form the create form containing the new item data
217      * @return HTML response redirecting to the list page after creation
218      */
219     @Execute
220     @Secured({ ROLE })
221     public HtmlResponse create(final CreateForm form) {
222         verifyCrudMode(form.crudMode, CrudMode.CREATE, this::asListHtml);
223         validate(form, messages -> {}, this::asEditHtml);
224         verifyToken(this::asEditHtml);
225         getRole(form).ifPresent(entity -> {
226             try {
227                 roleService.store(entity);
228                 saveInfo(messages -> messages.addSuccessCrudCreateCrudTable(GLOBAL));
229                 logger.info("Created role: {}", entity.getName());
230             } catch (final Exception e) {
231                 logger.warn("Failed to create role: {}", form.name, e);
232                 throwValidationError(messages -> messages.addErrorsCrudFailedToCreateCrudTable(GLOBAL, buildThrowableMessage(e)),
233                         this::asEditHtml);
234             }
235         }).orElse(() -> {
236             throwValidationError(messages -> messages.addErrorsCrudFailedToCreateInstance(GLOBAL), this::asEditHtml);
237         });
238         return redirect(getClass());
239     }
240 
241     /**
242      * Deletes a role item.
243      *
244      * @param form the edit form containing the ID of the item to delete
245      * @return HTML response redirecting to the list page after deletion
246      */
247     @Execute
248     @Secured({ ROLE })
249     public HtmlResponse delete(final EditForm form) {
250         verifyCrudMode(form.crudMode, CrudMode.DETAILS, this::asListHtml);
251         validate(form, messages -> {}, this::asDetailsHtml);
252         verifyToken(this::asDetailsHtml);
253         final String id = form.id;
254         roleService.getRole(id).ifPresent(entity -> {
255             try {
256                 roleService.delete(entity);
257                 saveInfo(messages -> messages.addSuccessCrudDeleteCrudTable(GLOBAL));
258                 logger.info("Deleted role: {}", entity.getName());
259             } catch (final Exception e) {
260                 logger.warn("Failed to delete role: {}", form.name, e);
261                 throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asDetailsHtml);
262             }
263         }).orElse(() -> {
264             throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asDetailsHtml);
265         });
266         return redirect(getClass());
267     }
268 
269     // ===================================================================================
270     //                                                                        Assist Logic
271     //                                                                        ============
272     /**
273      * Creates a Role entity from form data.
274      *
275      * @param form the form containing the role data
276      * @return optional entity containing the role data, or empty if creation fails
277      */
278     private static OptionalEntity<Role> getEntity(final CreateForm form) {
279         switch (form.crudMode) {
280         case CrudMode.CREATE:
281             return OptionalEntity.of(new Role()).map(entity -> {
282                 entity.setId(Base64.getUrlEncoder().encodeToString(form.name.getBytes(Constants.CHARSET_UTF_8)));
283                 return entity;
284             });
285         case CrudMode.EDIT:
286             if (form instanceof EditForm) {
287                 return ComponentUtil.getComponent(RoleService.class).getRole(((EditForm) form).id);
288             }
289             break;
290         default:
291             break;
292         }
293         return OptionalEntity.empty();
294     }
295 
296     /**
297      * Creates a Role entity from the provided form data.
298      *
299      * @param form the form containing the role data
300      * @return optional entity containing the role data, or empty if creation fails
301      */
302     public static OptionalEntity<Role> getRole(final CreateForm form) {
303         return getEntity(form).map(entity -> {
304             copyMapToBean(form.attributes, entity, op -> op.exclude(Constants.COMMON_CONVERSION_RULE));
305             copyBeanToBean(form, entity, op -> op.exclude(Constants.COMMON_CONVERSION_RULE));
306             return entity;
307         });
308     }
309 
310     // ===================================================================================
311     //                                                                        Small Helper
312     //                                                                        ============
313     //                                                                              JSP
314     //                                                                           =========
315 
316     private HtmlResponse asListHtml() {
317         return asHtml(path_AdminRole_AdminRoleJsp).renderWith(data -> {
318             RenderDataUtil.register(data, "roleItems", roleService.getRoleList(rolePager)); // page navi
319         }).useForm(SearchForm.class, setup -> {
320             setup.setup(form -> {
321                 copyBeanToBean(rolePager, form, op -> op.include("id"));
322             });
323         });
324     }
325 
326     private HtmlResponse asEditHtml() {
327         return asHtml(path_AdminRole_AdminRoleEditJsp);
328     }
329 
330     private HtmlResponse asDetailsHtml() {
331         return asHtml(path_AdminRole_AdminRoleDetailsJsp);
332     }
333 }