1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codelibs.fess.app.web.api.admin.searchlist;
17
18 import static org.codelibs.fess.app.web.admin.searchlist.AdminSearchlistAction.getDoc;
19 import static org.codelibs.fess.app.web.admin.searchlist.AdminSearchlistAction.validateFields;
20
21 import java.util.Map;
22
23 import org.apache.logging.log4j.LogManager;
24 import org.apache.logging.log4j.Logger;
25 import org.codelibs.core.lang.StringUtil;
26 import org.codelibs.fess.Constants;
27 import org.codelibs.fess.app.web.CrudMode;
28 import org.codelibs.fess.app.web.api.ApiResult;
29 import org.codelibs.fess.app.web.api.ApiResult.ApiDeleteResponse;
30 import org.codelibs.fess.app.web.api.ApiResult.ApiDocResponse;
31 import org.codelibs.fess.app.web.api.ApiResult.ApiDocsResponse;
32 import org.codelibs.fess.app.web.api.ApiResult.ApiResponse;
33 import org.codelibs.fess.app.web.api.ApiResult.ApiUpdateResponse;
34 import org.codelibs.fess.app.web.api.ApiResult.Status;
35 import org.codelibs.fess.app.web.api.admin.FessApiAdminAction;
36 import org.codelibs.fess.entity.SearchRenderData;
37 import org.codelibs.fess.exception.InvalidQueryException;
38 import org.codelibs.fess.exception.ResultOffsetExceededException;
39 import org.codelibs.fess.helper.SearchHelper;
40 import org.codelibs.fess.opensearch.client.SearchEngineClient;
41 import org.codelibs.fess.util.ComponentUtil;
42 import org.lastaflute.web.Execute;
43 import org.lastaflute.web.response.JsonResponse;
44 import org.opensearch.index.query.QueryBuilder;
45 import org.opensearch.index.query.QueryBuilders;
46
47 import jakarta.annotation.Resource;
48
49
50
51
52
53 public class ApiAdminSearchlistAction extends FessApiAdminAction {
54
55
56
57
58
59 private static final Logger logger = LogManager.getLogger(ApiAdminSearchlistAction.class);
60
61
62
63
64
65
66
67 public ApiAdminSearchlistAction() {
68 super();
69 }
70
71
72
73
74
75
76
77
78
79 @Resource
80 protected SearchHelper searchHelper;
81
82
83 @Resource
84 protected SearchEngineClient searchEngineClient;
85
86
87
88
89
90
91
92
93
94
95
96
97
98 @Execute
99 public JsonResponse<ApiResult> docs(final SearchBody body) {
100 validateApi(body, messages -> {});
101
102 if (StringUtil.isBlank(body.q)) {
103
104 body.q = Constants.MATCHES_ALL_QUERY;
105 }
106
107 final SearchRenderData renderData = new SearchRenderData();
108 body.initialize();
109 try {
110 searchHelper.search(body, renderData, getUserBean());
111 return asJson(new ApiDocsResponse().renderData(renderData).status(Status.OK).result());
112 } catch (final InvalidQueryException e) {
113 if (logger.isDebugEnabled()) {
114 logger.debug("Invalid query: {}", body.q, e);
115 }
116 throwValidationErrorApi(e.getMessageCode());
117 } catch (final ResultOffsetExceededException e) {
118 if (logger.isDebugEnabled()) {
119 logger.debug("Invalid offset: {}", body.offset, e);
120 }
121 throwValidationErrorApi(messages -> messages.addErrorsResultSizeExceeded(GLOBAL));
122 }
123
124 throwValidationErrorApi(messages -> messages.addErrorsInvalidQueryUnknown(GLOBAL));
125 return null;
126 }
127
128
129
130
131
132
133
134
135 @Execute
136 public JsonResponse<ApiResult> get$doc(final String id) {
137 return asJson(new ApiDocResponse().doc(searchEngineClient.getDocument(fessConfig.getIndexDocumentUpdateIndex(), builder -> {
138 builder.setQuery(QueryBuilders.termQuery(fessConfig.getIndexFieldDocId(), id));
139 return true;
140 }).orElseGet(() -> {
141 throwValidationErrorApi(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, id));
142 return null;
143 })).status(Status.OK).result());
144 }
145
146
147
148
149
150
151
152
153 @Execute
154 public JsonResponse<ApiResult> post$doc(final CreateBody body) {
155 validateApi(body, messages -> {});
156 if (body.doc == null) {
157 throwValidationErrorApi(messages -> messages.addErrorsCrudFailedToCreateCrudTable(GLOBAL, "doc is required"));
158 }
159 validateFields(body.doc, this::throwValidationErrorApi);
160 body.crudMode = CrudMode.CREATE;
161 final Map<String, Object> doc = getDoc(body).map(entity -> {
162 try {
163 entity.putAll(fessConfig.convertToStorableDoc(body.doc));
164
165 final String newId = ComponentUtil.getCrawlingInfoHelper().generateId(entity);
166 entity.put(fessConfig.getIndexFieldId(), newId);
167
168 final String index = fessConfig.getIndexDocumentUpdateIndex();
169 searchEngineClient.store(index, entity);
170 saveInfo(messages -> messages.addSuccessCrudCreateCrudTable(GLOBAL));
171 } catch (final Exception e) {
172 logger.warn("Failed to add {}", entity, e);
173 throwValidationErrorApi(messages -> messages.addErrorsCrudFailedToCreateCrudTable(GLOBAL, buildThrowableMessage(e)));
174 }
175 return entity;
176 }).orElseGet(() -> {
177 throwValidationErrorApi(messages -> messages.addErrorsCrudFailedToCreateInstance(GLOBAL));
178 return null;
179 });
180 return asJson(
181 new ApiUpdateResponse().id(doc.get(fessConfig.getIndexFieldDocId()).toString()).created(true).status(Status.OK).result());
182 }
183
184
185
186
187
188
189
190
191 @Execute
192 public JsonResponse<ApiResult> put$doc(final EditBody body) {
193 validateApi(body, messages -> {});
194 if (body.doc == null) {
195 throwValidationErrorApi(messages -> messages.addErrorsCrudFailedToCreateCrudTable(GLOBAL, "doc is required"));
196 }
197 validateFields(body.doc, this::throwValidationErrorApi);
198 body.crudMode = CrudMode.EDIT;
199 final Map<String, Object> doc = getDoc(body).map(entity -> {
200 final String index = fessConfig.getIndexDocumentUpdateIndex();
201 try {
202 entity.putAll(fessConfig.convertToStorableDoc(body.doc));
203
204 final String newId = ComponentUtil.getCrawlingInfoHelper().generateId(entity);
205 final String oldId = (String) entity.get(fessConfig.getIndexFieldId());
206 if (!newId.equals(oldId)) {
207 entity.put(fessConfig.getIndexFieldId(), newId);
208 entity.remove(fessConfig.getIndexFieldVersion());
209 final Number seqNo = (Number) entity.remove(fessConfig.getIndexFieldSeqNo());
210 final Number primaryTerm = (Number) entity.remove(fessConfig.getIndexFieldPrimaryTerm());
211 if (seqNo != null && primaryTerm != null && oldId != null) {
212 searchEngineClient.delete(index, oldId, seqNo, primaryTerm);
213 }
214 }
215
216 searchEngineClient.store(index, entity);
217 saveInfo(messages -> messages.addSuccessCrudUpdateCrudTable(GLOBAL));
218 } catch (final Exception e) {
219 logger.warn("Failed to update {}", entity, e);
220 throwValidationErrorApi(messages -> messages.addErrorsCrudFailedToUpdateCrudTable(GLOBAL, buildThrowableMessage(e)));
221 }
222 return entity;
223 }).orElseGet(() -> {
224 throwValidationErrorApi(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, body.doc.toString()));
225 return null;
226 });
227 return asJson(
228 new ApiUpdateResponse().id(doc.get(fessConfig.getIndexFieldDocId()).toString()).created(false).status(Status.OK).result());
229 }
230
231
232
233
234
235
236
237
238 @Execute
239 public JsonResponse<ApiResult> delete$doc(final String id) {
240 try {
241 final QueryBuilder query = QueryBuilders.termQuery(fessConfig.getIndexFieldDocId(), id);
242 searchEngineClient.deleteByQuery(fessConfig.getIndexDocumentUpdateIndex(), query);
243 saveInfo(messages -> messages.addSuccessDeleteDocFromIndex(GLOBAL));
244 } catch (final Exception e) {
245 logger.warn("Failed to process a request.", e);
246 throwValidationErrorApi(messages -> messages.addErrorsFailedToDeleteDocInAdmin(GLOBAL));
247 }
248 return asJson(new ApiResponse().status(Status.OK).result());
249 }
250
251
252
253
254
255
256
257
258 @Execute
259 public JsonResponse<ApiResult> delete$query(final SearchBody body) {
260 validateApi(body, messages -> {});
261
262 if (StringUtil.isBlank(body.q)) {
263 throwValidationErrorApi(messages -> messages.addErrorsInvalidQueryUnknown(GLOBAL));
264 }
265 try {
266 final long count = searchHelper.deleteByQuery(request, body);
267 return asJson(new ApiDeleteResponse().count(count).status(Status.OK).result());
268 } catch (final InvalidQueryException e) {
269 if (logger.isDebugEnabled()) {
270 logger.debug(e.getMessage(), e);
271 }
272 throwValidationErrorApi(e.getMessageCode());
273 } catch (final ResultOffsetExceededException e) {
274 if (logger.isDebugEnabled()) {
275 logger.debug(e.getMessage(), e);
276 }
277 throwValidationErrorApi(messages -> messages.addErrorsResultSizeExceeded(GLOBAL));
278 }
279
280 throwValidationErrorApi(messages -> messages.addErrorsInvalidQueryUnknown(GLOBAL));
281 return null;
282 }
283 }