1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codelibs.fess.app.web.admin.user;
17
18 import java.util.Base64;
19 import java.util.HashMap;
20 import java.util.Map;
21 import java.util.function.Consumer;
22
23 import javax.annotation.Resource;
24
25 import org.apache.commons.lang3.ArrayUtils;
26 import org.apache.logging.log4j.LogManager;
27 import org.apache.logging.log4j.Logger;
28 import org.codelibs.core.lang.StringUtil;
29 import org.codelibs.fess.Constants;
30 import org.codelibs.fess.annotation.Secured;
31 import org.codelibs.fess.app.pager.UserPager;
32 import org.codelibs.fess.app.service.GroupService;
33 import org.codelibs.fess.app.service.RoleService;
34 import org.codelibs.fess.app.service.UserService;
35 import org.codelibs.fess.app.web.CrudMode;
36 import org.codelibs.fess.app.web.base.FessAdminAction;
37 import org.codelibs.fess.app.web.base.login.FessLoginAssist;
38 import org.codelibs.fess.es.user.exentity.User;
39 import org.codelibs.fess.mylasta.action.FessMessages;
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 import org.lastaflute.web.validation.VaErrorHook;
49 import org.lastaflute.web.validation.VaMessenger;
50
51
52
53
54
55 public class AdminUserAction extends FessAdminAction {
56
57 public static final String ROLE = "admin-user";
58
59 private static final Logger logger = LogManager.getLogger(AdminUserAction.class);
60
61
62
63
64 @Resource
65 private UserService userService;
66 @Resource
67 private RoleService roleService;
68 @Resource
69 private GroupService groupService;
70 @Resource
71 private UserPager userPager;
72
73
74
75
76 @Override
77 protected void setupHtmlData(final ActionRuntime runtime) {
78 super.setupHtmlData(runtime);
79 runtime.registerData("helpLink", systemHelper.getHelpLink(fessConfig.getOnlineHelpNameUser()));
80 runtime.registerData("ldapAdminEnabled", fessConfig.isLdapAdminEnabled());
81 }
82
83 @Override
84 protected String getActionRole() {
85 return ROLE;
86 }
87
88
89
90
91 @Execute
92 @Secured({ ROLE, ROLE + VIEW })
93 public HtmlResponse index() {
94 return asListHtml();
95 }
96
97 @Execute
98 @Secured({ ROLE, ROLE + VIEW })
99 public HtmlResponse list(final OptionalThing<Integer> pageNumber, final SearchForm form) {
100 pageNumber.ifPresent(num -> {
101 userPager.setCurrentPageNumber(pageNumber.get());
102 }).orElse(() -> {
103 userPager.setCurrentPageNumber(0);
104 });
105 return asHtml(path_AdminUser_AdminUserJsp).renderWith(data -> {
106 searchPaging(data, form);
107 });
108 }
109
110 @Execute
111 @Secured({ ROLE, ROLE + VIEW })
112 public HtmlResponse search(final SearchForm form) {
113 copyBeanToBean(form, userPager, op -> op.exclude(Constants.PAGER_CONVERSION_RULE));
114 return asHtml(path_AdminUser_AdminUserJsp).renderWith(data -> {
115 searchPaging(data, form);
116 });
117 }
118
119 @Execute
120 @Secured({ ROLE, ROLE + VIEW })
121 public HtmlResponse reset(final SearchForm form) {
122 userPager.clear();
123 return asHtml(path_AdminUser_AdminUserJsp).renderWith(data -> {
124 searchPaging(data, form);
125 });
126 }
127
128 protected void searchPaging(final RenderData data, final SearchForm form) {
129 RenderDataUtil.register(data, "userItems", userService.getUserList(userPager));
130
131 copyBeanToBean(userPager, form, op -> op.include("id"));
132 }
133
134 private void registerForms(final RenderData data) {
135 RenderDataUtil.register(data, "roleItems", roleService.getAvailableRoleList());
136 RenderDataUtil.register(data, "groupItems", groupService.getAvailableGroupList());
137 }
138
139
140
141
142
143
144
145 @Execute
146 @Secured({ ROLE })
147 public HtmlResponse createnew() {
148 saveToken();
149 return asHtml(path_AdminUser_AdminUserEditJsp).useForm(CreateForm.class, op -> {
150 op.setup(form -> {
151 form.initialize();
152 form.crudMode = CrudMode.CREATE;
153 });
154 }).renderWith(data -> {
155 registerForms(data);
156 });
157 }
158
159 @Execute
160 @Secured({ ROLE })
161 public HtmlResponse edit(final EditForm form) {
162 validate(form, messages -> {}, this::asListHtml);
163 final String id = form.id;
164 userService.getUser(id).ifPresent(entity -> {
165 copyBeanToBean(entity, form, op -> {});
166 }).orElse(() -> {
167 throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asListHtml);
168 });
169 resetPassword(form);
170 saveToken();
171 if (form.crudMode.intValue() == CrudMode.EDIT) {
172
173 form.crudMode = CrudMode.DETAILS;
174 return asDetailsHtml();
175 }
176 form.crudMode = CrudMode.EDIT;
177 return asEditHtml();
178 }
179
180
181
182
183 @Execute
184 @Secured({ ROLE, ROLE + VIEW })
185 public HtmlResponse details(final int crudMode, final String id) {
186 verifyCrudMode(crudMode, CrudMode.DETAILS);
187 saveToken();
188 return asHtml(path_AdminUser_AdminUserDetailsJsp).useForm(EditForm.class, op -> {
189 op.setup(form -> {
190 userService.getUser(id).ifPresent(entity -> {
191 copyBeanToBean(entity, form, copyOp -> {
192 copyOp.excludeNull();
193 });
194 form.crudMode = crudMode;
195 }).orElse(() -> {
196 throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asListHtml);
197 });
198 resetPassword(form);
199 });
200 }).renderWith(data -> {
201 registerForms(data);
202 });
203 }
204
205
206
207
208 @Execute
209 @Secured({ ROLE })
210 public HtmlResponse create(final CreateForm form) {
211 verifyCrudMode(form.crudMode, CrudMode.CREATE);
212 validate(form, messages -> {}, this::asEditHtml);
213 validateAttributes(form.attributes, v -> throwValidationError(v, this::asEditHtml));
214 verifyPassword(form, this::asEditHtml);
215 verifyToken(this::asEditHtml);
216 getUser(form).ifPresent(entity -> {
217 try {
218 userService.store(entity);
219 saveInfo(messages -> messages.addSuccessCrudCreateCrudTable(GLOBAL));
220 } catch (final Exception e) {
221 logger.error("Failed to add {}", entity, e);
222 throwValidationError(messages -> messages.addErrorsCrudFailedToCreateCrudTable(GLOBAL, buildThrowableMessage(e)),
223 this::asEditHtml);
224 }
225 }).orElse(() -> {
226 throwValidationError(messages -> messages.addErrorsCrudFailedToCreateInstance(GLOBAL), this::asEditHtml);
227 });
228 return redirect(getClass());
229 }
230
231 @Execute
232 @Secured({ ROLE })
233 public HtmlResponse update(final EditForm form) {
234 verifyCrudMode(form.crudMode, CrudMode.EDIT);
235 validate(form, messages -> {}, this::asEditHtml);
236 validateAttributes(form.attributes, v -> throwValidationError(v, this::asEditHtml));
237 verifyPassword(form, this::asEditHtml);
238 verifyToken(this::asEditHtml);
239 getUser(form).ifPresent(entity -> {
240 try {
241 userService.store(entity);
242 saveInfo(messages -> messages.addSuccessCrudUpdateCrudTable(GLOBAL));
243 } catch (final Exception e) {
244 logger.error("Failed to update {}", entity, e);
245 throwValidationError(messages -> messages.addErrorsCrudFailedToUpdateCrudTable(GLOBAL, buildThrowableMessage(e)),
246 this::asEditHtml);
247 }
248 }).orElse(() -> {
249 throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.id), this::asEditHtml);
250 });
251 return redirect(getClass());
252 }
253
254 @Execute
255 @Secured({ ROLE })
256 public HtmlResponse delete(final EditForm form) {
257 verifyCrudMode(form.crudMode, CrudMode.DETAILS);
258 validate(form, messages -> {}, this::asDetailsHtml);
259 getUserBean().ifPresent(u -> {
260 if (u.getFessUser() instanceof User && form.name.equals(u.getUserId())) {
261 throwValidationError(messages -> messages.addErrorsCouldNotDeleteLoggedInUser(GLOBAL), this::asDetailsHtml);
262 }
263 });
264 verifyToken(this::asDetailsHtml);
265 final String id = form.id;
266 userService.getUser(id).ifPresent(entity -> {
267 try {
268 userService.delete(entity);
269 saveInfo(messages -> messages.addSuccessCrudDeleteCrudTable(GLOBAL));
270 } catch (final Exception e) {
271 logger.error("Failed to delete {}", entity, e);
272 throwValidationError(messages -> messages.addErrorsCrudFailedToDeleteCrudTable(GLOBAL, buildThrowableMessage(e)),
273 this::asDetailsHtml);
274 }
275 }).orElse(() -> {
276 throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id), this::asDetailsHtml);
277 });
278 return redirect(getClass());
279 }
280
281
282
283
284 private static OptionalEntity<User> getEntity(final CreateForm form) {
285 switch (form.crudMode) {
286 case CrudMode.CREATE:
287 return OptionalEntity.of(new User()).map(entity -> {
288 entity.setId(Base64.getUrlEncoder().encodeToString(form.name.getBytes(Constants.CHARSET_UTF_8)));
289 return entity;
290 });
291 case CrudMode.EDIT:
292 if (form instanceof EditForm) {
293 return ComponentUtil.getComponent(UserService.class).getUser(((EditForm) form).id);
294 }
295 break;
296 default:
297 break;
298 }
299 return OptionalEntity.empty();
300 }
301
302 public static OptionalEntity<User> getUser(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(ArrayUtils.addAll(Constants.COMMON_CONVERSION_RULE, "password")));
306 if (form.crudMode.intValue() == CrudMode.CREATE || StringUtil.isNotBlank(form.password)) {
307 final String encodedPassword = ComponentUtil.getComponent(FessLoginAssist.class).encryptPassword(form.password);
308 entity.setOriginalPassword(form.password);
309 entity.setPassword(encodedPassword);
310 }
311 return entity;
312 });
313 }
314
315 protected Map<String, String> createItem(final String label, final String value) {
316 final Map<String, String> map = new HashMap<>(2);
317 map.put(Constants.ITEM_LABEL, label);
318 map.put(Constants.ITEM_VALUE, value);
319 return map;
320 }
321
322
323
324
325
326 protected void verifyCrudMode(final int crudMode, final int expectedMode) {
327 if (crudMode != expectedMode) {
328 throwValidationError(messages -> {
329 messages.addErrorsCrudInvalidMode(GLOBAL, String.valueOf(expectedMode), String.valueOf(crudMode));
330 }, this::asListHtml);
331 }
332 }
333
334 protected void verifyPassword(final CreateForm form, final VaErrorHook validationErrorLambda) {
335 if (form.crudMode == CrudMode.CREATE && StringUtil.isBlank(form.password)) {
336 resetPassword(form);
337 throwValidationError(messages -> {
338 messages.addErrorsBlankPassword("password");
339 }, validationErrorLambda);
340 }
341 if (form.password != null && !form.password.equals(form.confirmPassword)) {
342 form.confirmPassword = null;
343 throwValidationError(messages -> {
344 messages.addErrorsInvalidConfirmPassword("confirmPassword");
345 }, validationErrorLambda);
346 }
347 }
348
349 public static void resetPassword(final CreateForm form) {
350 form.password = null;
351 form.confirmPassword = null;
352 }
353
354 public static void validateAttributes(final Map<String, String> attributes, final Consumer<VaMessenger<FessMessages>> throwError) {
355 ComponentUtil.getLdapManager().validateUserAttributes(Long.class, attributes,
356 s -> throwError.accept(messages -> messages.addErrorsPropertyTypeLong("attributes." + s, "attributes." + s)));
357 }
358
359
360
361
362
363 private HtmlResponse asListHtml() {
364 return asHtml(path_AdminUser_AdminUserJsp).renderWith(data -> {
365 RenderDataUtil.register(data, "userItems", userService.getUserList(userPager));
366 }).useForm(SearchForm.class, setup -> {
367 setup.setup(form -> {
368 copyBeanToBean(userPager, form, op -> op.include("id"));
369 });
370 });
371 }
372
373 private HtmlResponse asEditHtml() {
374 return asHtml(path_AdminUser_AdminUserEditJsp).renderWith(data -> {
375 registerForms(data);
376 });
377 }
378
379 private HtmlResponse asDetailsHtml() {
380 return asHtml(path_AdminUser_AdminUserDetailsJsp).renderWith(data -> {
381 registerForms(data);
382 });
383 }
384 }