1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codelibs.fess.app.web.admin.badword;
17
18 import java.io.BufferedReader;
19 import java.io.BufferedWriter;
20 import java.io.InputStream;
21 import java.io.InputStreamReader;
22 import java.io.OutputStreamWriter;
23 import java.io.Reader;
24 import java.io.Writer;
25 import java.nio.file.Files;
26 import java.nio.file.Path;
27
28 import org.apache.logging.log4j.LogManager;
29 import org.apache.logging.log4j.Logger;
30 import org.codelibs.core.beans.util.BeanUtil;
31 import org.codelibs.core.concurrent.CommonPoolUtil;
32 import org.codelibs.fess.Constants;
33 import org.codelibs.fess.annotation.Secured;
34 import org.codelibs.fess.app.pager.BadWordPager;
35 import org.codelibs.fess.app.service.BadWordService;
36 import org.codelibs.fess.app.web.CrudMode;
37 import org.codelibs.fess.app.web.base.FessAdminAction;
38 import org.codelibs.fess.exception.FessSystemException;
39 import org.codelibs.fess.helper.SuggestHelper;
40 import org.codelibs.fess.helper.SystemHelper;
41 import org.codelibs.fess.opensearch.config.exentity.BadWord;
42 import org.codelibs.fess.util.ComponentUtil;
43 import org.codelibs.fess.util.RenderDataUtil;
44 import org.dbflute.optional.OptionalEntity;
45 import org.dbflute.optional.OptionalThing;
46 import org.lastaflute.web.Execute;
47 import org.lastaflute.web.response.ActionResponse;
48 import org.lastaflute.web.response.HtmlResponse;
49 import org.lastaflute.web.response.render.RenderData;
50 import org.lastaflute.web.ruts.process.ActionRuntime;
51
52 import jakarta.annotation.Resource;
53
54
55
56
57
58 public class AdminBadwordAction extends FessAdminAction {
59
60
61
62
63 public AdminBadwordAction() {
64 super();
65 }
66
67
68
69
70 public static final String ROLE = "admin-badword";
71
72 private static final Logger logger = LogManager.getLogger(AdminBadwordAction.class);
73
74
75
76
77 @Resource
78 private BadWordService badWordService;
79 @Resource
80 private BadWordPager badWordPager;
81
82
83
84
85 @Resource
86 protected SuggestHelper suggestHelper;
87
88
89
90
91 @Override
92 protected void setupHtmlData(final ActionRuntime runtime) {
93 super.setupHtmlData(runtime);
94 runtime.registerData("helpLink", systemHelper.getHelpLink(fessConfig.getOnlineHelpNameBadword()));
95 }
96
97 @Override
98 protected String getActionRole() {
99 return ROLE;
100 }
101
102
103
104
105
106
107
108
109 @Execute
110 @Secured({ ROLE, ROLE + VIEW })
111 public HtmlResponse index() {
112 return asListHtml();
113 }
114
115
116
117
118
119
120
121 @Execute
122 @Secured({ ROLE, ROLE + VIEW })
123 public HtmlResponse list(final OptionalThing<Integer> pageNumber, final SearchForm form) {
124 pageNumber.ifPresent(num -> {
125 badWordPager.setCurrentPageNumber(pageNumber.get());
126 }).orElse(() -> {
127 badWordPager.setCurrentPageNumber(0);
128 });
129 return asHtml(path_AdminBadword_AdminBadwordJsp).renderWith(data -> {
130 searchPaging(data, form);
131 });
132 }
133
134
135
136
137
138
139 @Execute
140 @Secured({ ROLE, ROLE + VIEW })
141 public HtmlResponse search(final SearchForm form) {
142 copyBeanToBean(form, badWordPager, op -> op.exclude(Constants.PAGER_CONVERSION_RULE));
143 return asHtml(path_AdminBadword_AdminBadwordJsp).renderWith(data -> {
144 searchPaging(data, form);
145 });
146 }
147
148
149
150
151
152
153 @Execute
154 @Secured({ ROLE, ROLE + VIEW })
155 public HtmlResponse reset(final SearchForm form) {
156 badWordPager.clear();
157 return asHtml(path_AdminBadword_AdminBadwordJsp).renderWith(data -> {
158 searchPaging(data, form);
159 });
160 }
161
162
163
164
165
166
167 protected void searchPaging(final RenderData data, final SearchForm form) {
168 RenderDataUtil.register(data, "badWordItems", badWordService.getBadWordList(badWordPager));
169
170
171 copyBeanToBean(badWordPager, form, op -> op.include("id"));
172 }
173
174
175
176
177
178
179
180
181
182
183
184 @Execute
185 @Secured({ ROLE })
186 public HtmlResponse createnew() {
187 saveToken();
188 return asEditHtml().useForm(CreateForm.class, op -> {
189 op.setup(form -> {
190 form.initialize();
191 form.crudMode = CrudMode.CREATE;
192 });
193 });
194 }
195
196
197
198
199
200
201 @Execute
202 @Secured({ ROLE })
203 public HtmlResponse edit(final EditForm form) {
204 validate(form, messages -> {}, this::asListHtml);
205 final String id = form.id;
206 badWordService.getBadWord(id).ifPresent(entity -> {
207 copyBeanToBean(entity, form, op -> {});
208 }).orElse(() -> {
209 throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asListHtml);
210 });
211 saveToken();
212 if (form.crudMode.intValue() == CrudMode.EDIT) {
213
214 form.crudMode = CrudMode.DETAILS;
215 return asDetailsHtml();
216 }
217 form.crudMode = CrudMode.EDIT;
218 return asEditHtml();
219 }
220
221
222
223
224
225
226
227
228
229
230 @Execute
231 @Secured({ ROLE, ROLE + VIEW })
232 public HtmlResponse details(final int crudMode, final String id) {
233 verifyCrudMode(crudMode, CrudMode.DETAILS, this::asListHtml);
234 saveToken();
235 return asDetailsHtml().useForm(EditForm.class, op -> {
236 op.setup(form -> {
237 badWordService.getBadWord(id).ifPresent(entity -> {
238 copyBeanToBean(entity, form, copyOp -> {
239 copyOp.excludeNull();
240 });
241 form.crudMode = crudMode;
242 }).orElse(() -> {
243 throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asListHtml);
244 });
245 });
246 });
247 }
248
249
250
251
252
253
254
255
256 @Execute
257 @Secured({ ROLE, ROLE + VIEW })
258 public HtmlResponse downloadpage() {
259 saveToken();
260 return asDownloadHtml();
261 }
262
263
264
265
266
267
268 @Execute
269 @Secured({ ROLE, ROLE + VIEW })
270 public ActionResponse download(final DownloadForm form) {
271 verifyToken(this::asDownloadHtml);
272
273 return asStream("badword.csv").contentTypeOctetStream().stream(out -> {
274 final Path tempFile = ComponentUtil.getSystemHelper().createTempFile("fess-badword-", ".csv").toPath();
275 try {
276 try (Writer writer = new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(tempFile), getCsvEncoding()))) {
277 badWordService.exportCsv(writer);
278 } catch (final Exception e) {
279 logger.warn("Failed to process a request.", e);
280 throwValidationError(messages -> messages.addErrorsFailedToDownloadBadwordFile(GLOBAL), this::asDownloadHtml);
281 }
282 try (InputStream in = Files.newInputStream(tempFile)) {
283 out.write(in);
284 }
285 } finally {
286 Files.delete(tempFile);
287 }
288 });
289 }
290
291
292
293
294
295
296
297
298 @Execute
299 @Secured({ ROLE })
300 public HtmlResponse uploadpage() {
301 saveToken();
302 return asUploadHtml();
303 }
304
305
306
307
308
309
310
311
312
313 @Execute
314 @Secured({ ROLE })
315 public HtmlResponse create(final CreateForm form) {
316 verifyCrudMode(form.crudMode, CrudMode.CREATE, this::asListHtml);
317 validate(form, messages -> {}, this::asEditHtml);
318 verifyToken(this::asEditHtml);
319 getBadWord(form).ifPresent(entity -> {
320 try {
321 badWordService.store(entity);
322 suggestHelper.addBadWord(entity.getSuggestWord(), false);
323 saveInfo(messages -> messages.addSuccessCrudCreateCrudTable(GLOBAL));
324 } catch (final Exception e) {
325 logger.warn("Failed to process a request.", e);
326 throwValidationError(messages -> messages.addErrorsCrudFailedToCreateCrudTable(GLOBAL, buildThrowableMessage(e)),
327 this::asEditHtml);
328 }
329 }).orElse(() -> {
330 throwValidationError(messages -> messages.addErrorsCrudFailedToCreateInstance(GLOBAL), this::asEditHtml);
331 });
332 return redirect(getClass());
333 }
334
335
336
337
338
339
340 @Execute
341 @Secured({ ROLE })
342 public HtmlResponse update(final EditForm form) {
343 verifyCrudMode(form.crudMode, CrudMode.EDIT, this::asListHtml);
344 validate(form, messages -> {}, this::asEditHtml);
345 verifyToken(this::asEditHtml);
346 getBadWord(form).ifPresent(entity -> {
347 try {
348 badWordService.store(entity);
349 suggestHelper.storeAllBadWords(false);
350 saveInfo(messages -> messages.addSuccessCrudUpdateCrudTable(GLOBAL));
351 } catch (final Exception e) {
352 logger.warn("Failed to process a request.", e);
353 throwValidationError(messages -> messages.addErrorsCrudFailedToUpdateCrudTable(GLOBAL, buildThrowableMessage(e)),
354 this::asEditHtml);
355 }
356 }).orElse(() -> {
357 throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.id), this::asEditHtml);
358 });
359 return redirect(getClass());
360 }
361
362
363
364
365
366
367 @Execute
368 @Secured({ ROLE })
369 public HtmlResponse delete(final EditForm form) {
370 verifyCrudMode(form.crudMode, CrudMode.DETAILS, this::asListHtml);
371 validate(form, messages -> {}, this::asDetailsHtml);
372 verifyToken(this::asDetailsHtml);
373 final String id = form.id;
374 badWordService.getBadWord(id).ifPresent(entity -> {
375 try {
376 badWordService.delete(entity);
377 suggestHelper.deleteBadWord(entity.getSuggestWord());
378 saveInfo(messages -> messages.addSuccessCrudDeleteCrudTable(GLOBAL));
379 } catch (final Exception e) {
380 logger.warn("Failed to process a request.", e);
381 throwValidationError(messages -> messages.addErrorsCrudFailedToDeleteCrudTable(GLOBAL, buildThrowableMessage(e)),
382 this::asDetailsHtml);
383 }
384 }).orElse(() -> {
385 throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asDetailsHtml);
386 });
387 return redirect(getClass());
388 }
389
390
391
392
393
394
395 @Execute
396 @Secured({ ROLE })
397 public HtmlResponse upload(final UploadForm form) {
398 validate(form, messages -> {}, this::asUploadHtml);
399 verifyToken(this::asUploadHtml);
400 CommonPoolUtil.execute(() -> {
401 try (Reader reader = new BufferedReader(new InputStreamReader(form.badWordFile.getInputStream(), getCsvEncoding()))) {
402 badWordService.importCsv(reader);
403 suggestHelper.storeAllBadWords(false);
404 } catch (final Exception e) {
405 throw new FessSystemException("Failed to import bad word data: fileName=" + form.badWordFile.getFileName(), e);
406 }
407 });
408 saveInfo(messages -> messages.addSuccessUploadBadWord(GLOBAL));
409 return redirect(getClass());
410 }
411
412
413
414
415 private static OptionalEntity<BadWord> getEntity(final CreateForm form, final String username, final long currentTime) {
416 switch (form.crudMode) {
417 case CrudMode.CREATE:
418 return OptionalEntity.of(new BadWord()).map(entity -> {
419 entity.setCreatedBy(username);
420 entity.setCreatedTime(currentTime);
421 return entity;
422 });
423 case CrudMode.EDIT:
424 if (form instanceof EditForm) {
425 return ComponentUtil.getComponent(BadWordService.class).getBadWord(((EditForm) form).id);
426 }
427 break;
428 default:
429 break;
430 }
431 return OptionalEntity.empty();
432 }
433
434
435
436
437
438
439 public static OptionalEntity<BadWord> getBadWord(final CreateForm form) {
440 final SystemHelper systemHelper = ComponentUtil.getSystemHelper();
441 final String username = systemHelper.getUsername();
442 final long currentTime = systemHelper.getCurrentTimeAsLong();
443 return getEntity(form, username, currentTime).map(entity -> {
444 entity.setUpdatedBy(username);
445 entity.setUpdatedTime(currentTime);
446 BeanUtil.copyBeanToBean(form, entity, op -> op.exclude(Constants.COMMON_CONVERSION_RULE));
447 return entity;
448 });
449 }
450
451
452
453
454 private String getCsvEncoding() {
455 return fessConfig.getCsvFileEncoding();
456 }
457
458
459
460
461 private HtmlResponse asListHtml() {
462 return asHtml(path_AdminBadword_AdminBadwordJsp).renderWith(data -> {
463 RenderDataUtil.register(data, "badWordItems", badWordService.getBadWordList(badWordPager));
464 }).useForm(SearchForm.class, setup -> {
465 setup.setup(form -> {
466 copyBeanToBean(badWordPager, form, op -> op.include("id"));
467 });
468 });
469 }
470
471 private HtmlResponse asEditHtml() {
472 return asHtml(path_AdminBadword_AdminBadwordEditJsp);
473 }
474
475 private HtmlResponse asDetailsHtml() {
476 return asHtml(path_AdminBadword_AdminBadwordDetailsJsp);
477 }
478
479 private HtmlResponse asUploadHtml() {
480 return asHtml(path_AdminBadword_AdminBadwordUploadJsp).useForm(UploadForm.class);
481 }
482
483 private HtmlResponse asDownloadHtml() {
484 return asHtml(path_AdminBadword_AdminBadwordDownloadJsp).useForm(DownloadForm.class);
485 }
486
487 }