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