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.api.admin.group;
17  
18  import static org.codelibs.fess.app.web.admin.group.AdminGroupAction.getGroup;
19  import static org.codelibs.fess.app.web.admin.group.AdminGroupAction.validateAttributes;
20  
21  import java.util.List;
22  import java.util.stream.Collectors;
23  
24  import org.apache.logging.log4j.LogManager;
25  import org.apache.logging.log4j.Logger;
26  import org.codelibs.fess.app.pager.GroupPager;
27  import org.codelibs.fess.app.service.GroupService;
28  import org.codelibs.fess.app.web.CrudMode;
29  import org.codelibs.fess.app.web.api.ApiResult;
30  import org.codelibs.fess.app.web.api.admin.FessApiAdminAction;
31  import org.codelibs.fess.opensearch.user.exentity.Group;
32  import org.codelibs.fess.opensearch.user.exentity.User;
33  import org.lastaflute.web.Execute;
34  import org.lastaflute.web.response.JsonResponse;
35  
36  import jakarta.annotation.Resource;
37  
38  /**
39   * API action for admin group management.
40   * Provides RESTful API endpoints for managing user group settings in the Fess search engine.
41   * Groups define user permissions and access controls for search and administrative functions.
42   */
43  public class ApiAdminGroupAction extends FessApiAdminAction {
44  
45      private static final Logger logger = LogManager.getLogger(ApiAdminGroupAction.class);
46  
47      // ===================================================================================
48      //                                                                         Constructor
49      //                                                                         ===========
50      /**
51       * Default constructor.
52       */
53      public ApiAdminGroupAction() {
54          super();
55      }
56  
57      // ===================================================================================
58      //                                                                           Attribute
59      //                                                                           =========
60  
61      /** Service for managing group configurations */
62      @Resource
63      private GroupService groupService;
64  
65      // GET /api/admin/group
66      // PUT /api/admin/group
67      /**
68       * Returns list of group settings.
69       * Supports both GET and PUT requests for retrieving paginated group configurations.
70       *
71       * @param body search parameters for filtering and pagination
72       * @return JSON response containing group settings list with pagination info
73       */
74      @Execute
75      public JsonResponse<ApiResult> settings(final SearchBody body) {
76          validateApi(body, messages -> {});
77          final GroupPager pager = copyBeanToNewBean(body, GroupPager.class);
78          final List<Group> list = groupService.getGroupList(pager);
79          return asJson(
80                  new ApiResult.ApiConfigsResponse<EditBody>().settings(list.stream().map(this::createEditBody).collect(Collectors.toList()))
81                          .total(pager.getAllRecordCount())
82                          .status(ApiResult.Status.OK)
83                          .result());
84      }
85  
86      // GET /api/admin/group/setting/{id}
87      /**
88       * Returns specific group setting by ID.
89       *
90       * @param id the group setting ID
91       * @return JSON response containing the group setting details
92       */
93      @Execute
94      public JsonResponse<ApiResult> get$setting(final String id) {
95          return asJson(new ApiResult.ApiConfigResponse().setting(groupService.getGroup(id).map(this::createEditBody).orElseGet(() -> {
96              throwValidationErrorApi(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id));
97              return null;
98          })).status(ApiResult.Status.OK).result());
99      }
100 
101     // POST /api/admin/group/setting
102     /**
103      * Creates a new group setting.
104      *
105      * @param body group setting data to create
106      * @return JSON response with created setting ID and status
107      */
108     @Execute
109     public JsonResponse<ApiResult> post$setting(final CreateBody body) {
110         validateApi(body, messages -> {});
111         validateAttributes(body.attributes, this::throwValidationErrorApi);
112         body.crudMode = CrudMode.CREATE;
113         final Group entity = getGroup(body).orElseGet(() -> {
114             throwValidationErrorApi(messages -> {
115                 messages.addErrorsCrudFailedToCreateInstance(GLOBAL);
116             });
117             return null;
118         });
119         try {
120             groupService.store(entity);
121             saveInfo(messages -> messages.addSuccessCrudCreateCrudTable(GLOBAL));
122         } catch (final Exception e) {
123             logger.warn("Failed to process a request.", e);
124             throwValidationErrorApi(messages -> messages.addErrorsCrudFailedToCreateCrudTable(GLOBAL, buildThrowableMessage(e)));
125         }
126         return asJson(new ApiResult.ApiUpdateResponse().id(entity.getId()).created(true).status(ApiResult.Status.OK).result());
127     }
128 
129     // PUT /api/admin/group/setting
130     /**
131      * Updates an existing group setting.
132      *
133      * @param body group setting data to update
134      * @return JSON response with updated setting ID and status
135      */
136     @Execute
137     public JsonResponse<ApiResult> put$setting(final EditBody body) {
138         validateApi(body, messages -> {});
139         validateAttributes(body.attributes, this::throwValidationErrorApi);
140         body.crudMode = CrudMode.EDIT;
141         final Group entity = getGroup(body).orElseGet(() -> {
142             throwValidationErrorApi(messages -> {
143                 messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, body.id);
144             });
145             return null;
146         });
147         try {
148             groupService.store(entity);
149         } catch (final Exception e) {
150             throwValidationErrorApi(messages -> messages.addErrorsCrudFailedToUpdateCrudTable(GLOBAL, buildThrowableMessage(e)));
151         }
152         return asJson(new ApiResult.ApiUpdateResponse().id(entity.getId()).created(false).status(ApiResult.Status.OK).result());
153     }
154 
155     // DELETE /api/admin/group/setting/{id}
156     /**
157      * Deletes a specific group setting.
158      * Prevents deletion of the currently logged-in user's group for security.
159      *
160      * @param id the group setting ID to delete
161      * @return JSON response with deletion status
162      */
163     @Execute
164     public JsonResponse<ApiResult> delete$setting(final String id) {
165         final Group entity = groupService.getGroup(id).orElseGet(() -> {
166             throwValidationErrorApi(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id));
167             return null;
168         });
169         getUserBean().ifPresent(u -> {
170             if (u.getFessUser() instanceof User && entity.getName().equals(u.getUserId())) {
171                 throwValidationErrorApi(messages -> messages.addErrorsCouldNotDeleteLoggedInUser(GLOBAL));
172             }
173         });
174         try {
175             groupService.delete(entity);
176             saveInfo(messages -> messages.addSuccessCrudDeleteCrudTable(GLOBAL));
177         } catch (final Exception e) {
178             logger.warn("Failed to process a request.", e);
179             throwValidationErrorApi(messages -> messages.addErrorsCrudFailedToDeleteCrudTable(GLOBAL, buildThrowableMessage(e)));
180         }
181         return asJson(new ApiResult.ApiUpdateResponse().id(id).created(false).status(ApiResult.Status.OK).result());
182     }
183 
184     /**
185      * Creates an edit body from a group entity for API responses.
186      *
187      * @param entity the group entity to convert
188      * @return edit body containing the entity data
189      */
190     protected EditBody createEditBody(final Group entity) {
191         final EditBody body = new EditBody();
192         copyBeanToBean(entity, body, copyOp -> {
193             copyOp.excludeNull();
194         });
195         return body;
196     }
197 }