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.fileconfig;
17  
18  import static org.codelibs.core.stream.StreamUtil.split;
19  import static org.codelibs.core.stream.StreamUtil.stream;
20  
21  import java.util.stream.Collectors;
22  import java.util.stream.Stream;
23  
24  import javax.annotation.Resource;
25  
26  import org.codelibs.core.lang.StringUtil;
27  import org.codelibs.fess.Constants;
28  import org.codelibs.fess.annotation.Secured;
29  import org.codelibs.fess.app.pager.FileConfigPager;
30  import org.codelibs.fess.app.service.FileConfigService;
31  import org.codelibs.fess.app.service.LabelTypeService;
32  import org.codelibs.fess.app.service.RoleTypeService;
33  import org.codelibs.fess.app.web.CrudMode;
34  import org.codelibs.fess.app.web.base.FessAdminAction;
35  import org.codelibs.fess.es.config.exentity.CrawlingConfig.ConfigType;
36  import org.codelibs.fess.es.config.exentity.FileConfig;
37  import org.codelibs.fess.helper.PermissionHelper;
38  import org.codelibs.fess.helper.SystemHelper;
39  import org.codelibs.fess.util.ComponentUtil;
40  import org.codelibs.fess.util.RenderDataUtil;
41  import org.dbflute.optional.OptionalEntity;
42  import org.dbflute.optional.OptionalThing;
43  import org.lastaflute.web.Execute;
44  import org.lastaflute.web.response.HtmlResponse;
45  import org.lastaflute.web.response.render.RenderData;
46  import org.lastaflute.web.ruts.process.ActionRuntime;
47  
48  /**
49   * @author shinsuke
50   * @author Keiichi Watanabe
51   */
52  public class AdminFileconfigAction extends FessAdminAction {
53  
54      public static final String ROLE = "admin-fileconfig";
55  
56      // ===================================================================================
57      //                                                                           Attribute
58      //                                                                           =========
59      @Resource
60      private FileConfigService fileConfigService;
61      @Resource
62      private FileConfigPager fileConfigPager;
63      @Resource
64      private RoleTypeService roleTypeService;
65      @Resource
66      private LabelTypeService labelTypeService;
67  
68      // ===================================================================================
69      //                                                                               Hook
70      //                                                                              ======
71      @Override
72      protected void setupHtmlData(final ActionRuntime runtime) {
73          super.setupHtmlData(runtime);
74          runtime.registerData("helpLink", systemHelper.getHelpLink(fessConfig.getOnlineHelpNameFileconfig()));
75      }
76  
77      @Override
78      protected String getActionRole() {
79          return ROLE;
80      }
81  
82      // ===================================================================================
83      //                                                                      Search Execute
84      //                                                                      ==============
85      @Execute
86      @Secured({ ROLE, ROLE + VIEW })
87      public HtmlResponse index() {
88          return asListHtml();
89      }
90  
91      @Execute
92      @Secured({ ROLE, ROLE + VIEW })
93      public HtmlResponse list(final OptionalThing<Integer> pageNumber, final SearchForm form) {
94          pageNumber.ifPresent(num -> {
95              fileConfigPager.setCurrentPageNumber(pageNumber.get());
96          }).orElse(() -> {
97              fileConfigPager.setCurrentPageNumber(0);
98          });
99          return asHtml(path_AdminFileconfig_AdminFileconfigJsp).renderWith(data -> {
100             searchPaging(data, form);
101         });
102     }
103 
104     @Execute
105     @Secured({ ROLE, ROLE + VIEW })
106     public HtmlResponse search(final SearchForm form) {
107         copyBeanToBean(form, fileConfigPager, op -> op.exclude(Constants.PAGER_CONVERSION_RULE));
108         return asHtml(path_AdminFileconfig_AdminFileconfigJsp).renderWith(data -> {
109             searchPaging(data, form);
110         });
111     }
112 
113     @Execute
114     @Secured({ ROLE, ROLE + VIEW })
115     public HtmlResponse reset(final SearchForm form) {
116         fileConfigPager.clear();
117         return asHtml(path_AdminFileconfig_AdminFileconfigJsp).renderWith(data -> {
118             searchPaging(data, form);
119         });
120     }
121 
122     protected void searchPaging(final RenderData data, final SearchForm form) {
123         RenderDataUtil.register(data, "fileConfigItems", fileConfigService.getFileConfigList(fileConfigPager)); // page navi
124 
125         // restore from pager
126         copyBeanToBean(fileConfigPager, form, op -> op.include("name", "paths", "description"));
127     }
128 
129     // ===================================================================================
130     //                                                                        Edit Execute
131     //                                                                        ============
132     // -----------------------------------------------------
133     //                                            Entry Page
134     //                                            ----------
135     @Execute
136     @Secured({ ROLE })
137     public HtmlResponse createnew() {
138         saveToken();
139         return asHtml(path_AdminFileconfig_AdminFileconfigEditJsp).useForm(CreateForm.class, op -> {
140             op.setup(form -> {
141                 form.initialize();
142                 ComponentUtil.getCrawlingConfigHelper().getDefaultConfig(ConfigType.FILE).ifPresent(entity -> {
143                     copyBeanToBean(entity, form, copyOp -> {
144                         copyOp.excludeNull();
145                         copyOp.exclude(Stream.concat(Stream.of(Constants.COMMON_CONVERSION_RULE),
146                                 Stream.of(Constants.PERMISSIONS, Constants.VIRTUAL_HOSTS)).toArray(n -> new String[n]));
147                     });
148                     final PermissionHelper permissionHelper = ComponentUtil.getPermissionHelper();
149                     form.permissions = stream(entity.getPermissions()).get(stream -> stream.map(s -> permissionHelper.decode(s))
150                             .filter(StringUtil::isNotBlank).distinct().collect(Collectors.joining("\n")));
151                     form.virtualHosts = stream(entity.getVirtualHosts())
152                             .get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).collect(Collectors.joining("\n")));
153                     form.name = null;
154                 });
155                 form.crudMode = CrudMode.CREATE;
156             });
157         }).renderWith(data -> {
158             registerRolesAndLabels(data);
159         });
160     }
161 
162     @Execute
163     @Secured({ ROLE })
164     public HtmlResponse edit(final EditForm form) {
165         validate(form, messages -> {}, this::asListHtml);
166         final PermissionHelper permissionHelper = ComponentUtil.getPermissionHelper();
167         final String id = form.id;
168         fileConfigService.getFileConfig(id).ifPresent(entity -> {
169             copyBeanToBean(entity, form, copyOp -> {
170                 copyOp.excludeNull();
171                 copyOp.exclude(Constants.PERMISSIONS, Constants.VIRTUAL_HOSTS);
172             });
173             form.permissions = stream(entity.getPermissions()).get(stream -> stream.map(permissionHelper::decode)
174                     .filter(StringUtil::isNotBlank).distinct().collect(Collectors.joining("\n")));
175             form.virtualHosts = stream(entity.getVirtualHosts())
176                     .get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).collect(Collectors.joining("\n")));
177         }).orElse(() -> throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asListHtml));
178         saveToken();
179         if (form.crudMode.intValue() == CrudMode.EDIT) {
180             // back
181             form.crudMode = CrudMode.DETAILS;
182             return asDetailsHtml();
183         }
184         form.crudMode = CrudMode.EDIT;
185         return asEditHtml();
186     }
187 
188     // -----------------------------------------------------
189     //                                               Details
190     //                                               -------
191     @Execute
192     @Secured({ ROLE, ROLE + VIEW })
193     public HtmlResponse details(final int crudMode, final String id) {
194         verifyCrudMode(crudMode, CrudMode.DETAILS);
195         saveToken();
196         return asHtml(path_AdminFileconfig_AdminFileconfigDetailsJsp).useForm(EditForm.class, op -> op.setup(form -> {
197             fileConfigService.getFileConfig(id).ifPresent(entity -> {
198                 copyBeanToBean(entity, form, copyOp -> {
199                     copyOp.excludeNull();
200                     copyOp.exclude(Constants.PERMISSIONS, Constants.VIRTUAL_HOSTS);
201                 });
202                 final PermissionHelper permissionHelper = ComponentUtil.getPermissionHelper();
203                 form.permissions = stream(entity.getPermissions()).get(stream -> stream.map(s -> permissionHelper.decode(s))
204                         .filter(StringUtil::isNotBlank).distinct().collect(Collectors.joining("\n")));
205                 form.virtualHosts = stream(entity.getVirtualHosts())
206                         .get(stream -> stream.filter(StringUtil::isNotBlank).map(String::trim).collect(Collectors.joining("\n")));
207                 form.crudMode = crudMode;
208             }).orElse(() -> throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asListHtml));
209         })).renderWith(this::registerRolesAndLabels);
210     }
211 
212     // -----------------------------------------------------
213     //                                         Actually Crud
214     //                                         -------------
215     @Execute
216     @Secured({ ROLE })
217     public HtmlResponse create(final CreateForm form) {
218         verifyCrudMode(form.crudMode, CrudMode.CREATE);
219         validate(form, messages -> {}, this::asEditHtml);
220         verifyToken(this::asEditHtml);
221         getFileConfig(form).ifPresent(entity -> {
222             try {
223                 fileConfigService.store(entity);
224                 saveInfo(messages -> messages.addSuccessCrudCreateCrudTable(GLOBAL));
225             } catch (final Exception e) {
226                 throwValidationError(messages -> messages.addErrorsCrudFailedToCreateCrudTable(GLOBAL, buildThrowableMessage(e)),
227                         this::asEditHtml);
228             }
229         }).orElse(() -> {
230             throwValidationError(messages -> messages.addErrorsCrudFailedToCreateInstance(GLOBAL), this::asEditHtml);
231         });
232         return redirect(getClass());
233     }
234 
235     @Execute
236     @Secured({ ROLE })
237     public HtmlResponse update(final EditForm form) {
238         verifyCrudMode(form.crudMode, CrudMode.EDIT);
239         validate(form, messages -> {}, this::asEditHtml);
240         verifyToken(this::asEditHtml);
241         getFileConfig(form).ifPresent(entity -> {
242             try {
243                 fileConfigService.store(entity);
244                 saveInfo(messages -> messages.addSuccessCrudUpdateCrudTable(GLOBAL));
245             } catch (final Exception e) {
246                 throwValidationError(messages -> messages.addErrorsCrudFailedToUpdateCrudTable(GLOBAL, buildThrowableMessage(e)),
247                         this::asEditHtml);
248             }
249         }).orElse(() -> {
250             throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.id), this::asEditHtml);
251         });
252         return redirect(getClass());
253     }
254 
255     @Execute
256     @Secured({ ROLE })
257     public HtmlResponse delete(final EditForm form) {
258         verifyCrudMode(form.crudMode, CrudMode.DETAILS);
259         validate(form, messages -> {}, this::asDetailsHtml);
260         verifyToken(this::asDetailsHtml);
261         final String id = form.id;
262         fileConfigService.getFileConfig(id).ifPresent(entity -> {
263             try {
264                 fileConfigService.delete(entity);
265                 saveInfo(messages -> messages.addSuccessCrudDeleteCrudTable(GLOBAL));
266             } catch (final Exception e) {
267                 throwValidationError(messages -> messages.addErrorsCrudFailedToDeleteCrudTable(GLOBAL, buildThrowableMessage(e)),
268                         this::asEditHtml);
269             }
270         }).orElse(() -> {
271             throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asDetailsHtml);
272         });
273         return redirect(getClass());
274     }
275 
276     // ===================================================================================
277     //                                                                        Assist Logic
278     //                                                                        ============
279     public static OptionalEntity<FileConfig> getEntity(final CreateForm form, final String username, final long currentTime) {
280         switch (form.crudMode) {
281         case CrudMode.CREATE:
282             return OptionalEntity.of(new FileConfig()).map(entity -> {
283                 entity.setCreatedBy(username);
284                 entity.setCreatedTime(currentTime);
285                 return entity;
286             });
287         case CrudMode.EDIT:
288             if (form instanceof EditForm) {
289                 return ComponentUtil.getComponent(FileConfigService.class).getFileConfig(((EditForm) form).id);
290             }
291             break;
292         default:
293             break;
294         }
295         return OptionalEntity.empty();
296     }
297 
298     public static OptionalEntity<FileConfig> getFileConfig(final CreateForm form) {
299         final SystemHelper systemHelper = ComponentUtil.getSystemHelper();
300         final String username = systemHelper.getUsername();
301         final long currentTime = systemHelper.getCurrentTimeAsLong();
302         return getEntity(form, username, currentTime).map(entity -> {
303             entity.setUpdatedBy(username);
304             entity.setUpdatedTime(currentTime);
305             copyBeanToBean(form, entity,
306                     op -> op.exclude(Stream
307                             .concat(Stream.of(Constants.COMMON_CONVERSION_RULE), Stream.of(Constants.PERMISSIONS, Constants.VIRTUAL_HOSTS))
308                             .toArray(n -> new String[n])));
309             final PermissionHelper permissionHelper = ComponentUtil.getPermissionHelper();
310             entity.setPermissions(split(form.permissions, "\n").get(stream -> stream.map(s -> permissionHelper.encode(s))
311                     .filter(StringUtil::isNotBlank).distinct().toArray(n -> new String[n])));
312             entity.setVirtualHosts(split(form.virtualHosts, "\n")
313                     .get(stream -> stream.filter(StringUtil::isNotBlank).distinct().map(String::trim).toArray(n -> new String[n])));
314             return entity;
315         });
316     }
317 
318     protected void registerRolesAndLabels(final RenderData data) {
319         RenderDataUtil.register(data, "labelSettingEnabled", fessConfig.isFormAdminLabelInConfigEnabled());
320         RenderDataUtil.register(data, "roleTypeItems", roleTypeService.getRoleTypeList());
321         RenderDataUtil.register(data, "labelTypeItems", labelTypeService.getLabelTypeList());
322     }
323 
324     // ===================================================================================
325     //                                                                        Small Helper
326     //                                                                        ============
327     protected void verifyCrudMode(final int crudMode, final int expectedMode) {
328         if (crudMode != expectedMode) {
329             throwValidationError(messages -> {
330                 messages.addErrorsCrudInvalidMode(GLOBAL, String.valueOf(expectedMode), String.valueOf(crudMode));
331             }, this::asListHtml);
332         }
333     }
334 
335     // ===================================================================================
336     //                                                                              JSP
337     //                                                                           =========
338 
339     private HtmlResponse asListHtml() {
340         return asHtml(path_AdminFileconfig_AdminFileconfigJsp).renderWith(data -> {
341             RenderDataUtil.register(data, "fileConfigItems", fileConfigService.getFileConfigList(fileConfigPager)); // page navi
342         }).useForm(SearchForm.class, setup -> {
343             setup.setup(form -> {
344                 copyBeanToBean(fileConfigPager, form, op -> op.include("name", "paths", "description"));
345             });
346         });
347     }
348 
349     private HtmlResponse asEditHtml() {
350         return asHtml(path_AdminFileconfig_AdminFileconfigEditJsp).renderWith(data -> {
351             registerRolesAndLabels(data);
352         });
353     }
354 
355     private HtmlResponse asDetailsHtml() {
356         return asHtml(path_AdminFileconfig_AdminFileconfigDetailsJsp).renderWith(data -> {
357             registerRolesAndLabels(data);
358         });
359     }
360 }