#2731 add favorite api

This commit is contained in:
Shinsuke Sugaya 2023-03-29 22:07:51 +09:00
parent f0cfcaf149
commit 4d2b938e85
3 changed files with 158 additions and 27 deletions

View file

@ -335,6 +335,91 @@ paths:
'500':
$ref: '#/components/responses/InternalServerError'
/favorites:
get:
tags:
- favorite
summary: List favorites
description: Returns favorited document IDs
operationId: listFavorites
parameters:
- name: queryId
in: query
description: Query ID where the document is contained
required: true
schema:
type: string
example: queryid
responses:
'200':
description: Successful operation
content:
application/json:
schema:
type: object
properties:
record_count:
type: integer
example: 9
data:
type: array
items:
type: object
properties:
doc_id:
type: string
example: "e79fbfdfb09d4bffb58ec230c68f6f7e"
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
'500':
$ref: '#/components/responses/InternalServerError'
/documents/{docId}/favorite:
post:
tags:
- favorite
summary: Set a favorite mark
description: Set a favorite mark to the document
operationId: setFavorite
parameters:
- name: docId
in: path
description: Document ID to be favorited
required: true
schema:
type: string
example: documentid
- name: queryId
in: query
description: Query ID where the document is contained
required: true
schema:
type: string
example: queryid
responses:
'201':
description: Successful operation
content:
application/json:
schema:
type: object
properties:
result:
type: string
example: created
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
'500':
$ref: '#/components/responses/InternalServerError'
/popular-words:
get:
tags:

View file

@ -87,9 +87,15 @@ public class SearchApiManager extends BaseApiManager {
private static final Logger logger = LogManager.getLogger(SearchApiManager.class);
private static final String MESSAGE_FIELD = "message";
protected static final String MESSAGE_FIELD = "message";
private static final String RESULT_FIELD = "result";
protected static final String RESULT_FIELD = "result";
private static final String DOC_ID_FIELD = "doc_id";
protected static final String GET = "GET";
protected static final String POST = "POST";
protected String mimeType = "application/json";
@ -115,7 +121,10 @@ public class SearchApiManager extends BaseApiManager {
}
final String type = value.toLowerCase(Locale.ROOT);
if ("documents".equals(type)) {
// return FormatType.FAVORITE;
if (values.length > 5 && "favorite".equals(values[5])) {
request.setAttribute(DOC_ID_FIELD, values[4]);
return FormatType.FAVORITE;
}
// return FormatType.SCROLL;
return FormatType.SEARCH;
} else if ("labels".equals(type)) {
@ -128,6 +137,8 @@ public class SearchApiManager extends BaseApiManager {
return FormatType.PING;
} else if ("suggest-words".equals(type)) {
return FormatType.SUGGEST;
} else if ("scroll".equals(type)) {
return FormatType.SCROLL;
} else {
// default
return FormatType.OTHER;
@ -179,8 +190,22 @@ public class SearchApiManager extends BaseApiManager {
}
}
protected boolean acceptHttpMethod(final HttpServletRequest request, final String... methods) {
final String method = request.getMethod();
for (String m : methods) {
if (m.equals(method)) {
return true;
}
}
writeJsonResponse(HttpServletResponse.SC_METHOD_NOT_ALLOWED, escapeJsonKeyValue(MESSAGE_FIELD, method + " is not allowed."));
return false;
}
protected void processScrollSearchRequest(final HttpServletRequest request, final HttpServletResponse response,
final FilterChain chain) {
if (!acceptHttpMethod(request, GET)) {
return;
}
final SearchHelper searchHelper = ComponentUtil.getSearchHelper();
final FessConfig fessConfig = ComponentUtil.getFessConfig();
@ -231,12 +256,12 @@ public class SearchApiManager extends BaseApiManager {
}
} catch (final InvalidQueryException | ResultOffsetExceededException e) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to process a search request.", e);
logger.debug("Failed to process a scroll request.", e);
}
writeJsonResponse(HttpServletResponse.SC_BAD_REQUEST, e);
} catch (final Exception e) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to process a search request.", e);
logger.debug("Failed to process a scroll request.", e);
}
writeJsonResponse(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
}
@ -244,6 +269,10 @@ public class SearchApiManager extends BaseApiManager {
}
protected void processPingRequest(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain) {
if (!acceptHttpMethod(request, GET)) {
return;
}
final SearchEngineClient searchEngineClient = ComponentUtil.getSearchEngineClient();
try {
final PingResponse pingResponse = searchEngineClient.ping();
@ -258,6 +287,10 @@ public class SearchApiManager extends BaseApiManager {
}
protected void processSearchRequest(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain) {
if (!acceptHttpMethod(request, GET)) {
return;
}
final SearchHelper searchHelper = ComponentUtil.getSearchHelper();
final FessConfig fessConfig = ComponentUtil.getFessConfig();
final RelatedQueryHelper relatedQueryHelper = ComponentUtil.getRelatedQueryHelper();
@ -461,6 +494,10 @@ public class SearchApiManager extends BaseApiManager {
}
protected void processLabelRequest(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain) {
if (!acceptHttpMethod(request, GET)) {
return;
}
final LabelTypeHelper labelTypeHelper = ComponentUtil.getLabelTypeHelper();
final StringBuilder buf = new StringBuilder(255);
@ -499,6 +536,10 @@ public class SearchApiManager extends BaseApiManager {
protected void processPopularWordRequest(final HttpServletRequest request, final HttpServletResponse response,
final FilterChain chain) {
if (!acceptHttpMethod(request, GET)) {
return;
}
if (!ComponentUtil.getFessConfig().isWebApiPopularWord()) {
writeJsonResponse(HttpServletResponse.SC_BAD_REQUEST, escapeJsonKeyValue(MESSAGE_FIELD, "Unsupported operation."));
return;
@ -545,6 +586,10 @@ public class SearchApiManager extends BaseApiManager {
}
protected void processFavoriteRequest(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain) {
if (!acceptHttpMethod(request, POST)) {
return;
}
if (!ComponentUtil.getFessConfig().isUserFavorite()) {
writeJsonResponse(HttpServletResponse.SC_BAD_REQUEST, escapeJsonKeyValue(MESSAGE_FIELD, "Unsupported operation."));
return;
@ -557,7 +602,11 @@ public class SearchApiManager extends BaseApiManager {
final SystemHelper systemHelper = ComponentUtil.getSystemHelper();
try {
final String docId = request.getParameter("docId");
final Object docIdObj = request.getAttribute(DOC_ID_FIELD);
if (docIdObj == null) {
throw new WebApiException(HttpServletResponse.SC_BAD_REQUEST, "docId is empty.");
}
final String docId = docIdObj.toString();
final String queryId = request.getParameter("queryId");
final String[] docIds = userInfoHelper.getResultDocIds(URLDecoder.decode(queryId, Constants.UTF_8));
@ -630,6 +679,10 @@ public class SearchApiManager extends BaseApiManager {
}
protected void processFavoritesRequest(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain) {
if (!acceptHttpMethod(request, GET)) {
return;
}
if (!ComponentUtil.getFessConfig().isUserFavorite()) {
writeJsonResponse(HttpServletResponse.SC_BAD_REQUEST, escapeJsonKeyValue(MESSAGE_FIELD, "Unsupported operation."));
return;
@ -676,14 +729,14 @@ public class SearchApiManager extends BaseApiManager {
}
final StringBuilder buf = new StringBuilder(255);
buf.append("\"num\":").append(docIdList.size());
buf.append(", \"doc_ids\":[");
buf.append("\"record_count\":").append(docIdList.size());
buf.append(", \"data\":[");
if (!docIdList.isEmpty()) {
for (int i = 0; i < docIdList.size(); i++) {
if (i > 0) {
buf.append(',');
}
buf.append(escapeJson(docIdList.get(i)));
buf.append('{').append(escapeJsonKeyValue(DOC_ID_FIELD, docIdList.get(i))).append('}');
}
}
buf.append(']');
@ -704,6 +757,10 @@ public class SearchApiManager extends BaseApiManager {
protected void processSuggestRequest(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain)
throws IOException, ServletException {
if (!acceptHttpMethod(request, GET)) {
return;
}
final FessConfig fessConfig = ComponentUtil.getFessConfig();
if (!fessConfig.isAcceptedSearchReferer(request.getHeader("referer"))) {
writeJsonResponse(HttpServletResponse.SC_BAD_REQUEST, escapeJsonKeyValue(MESSAGE_FIELD, "Referer is invalid."));

View file

@ -93,8 +93,8 @@ $(function() {
actionUrl,
docId;
if (values.length === 2 && $queryId.length > 0) {
actionUrl = contextPath + "/json";
docId = values[1];
actionUrl = contextPath + "/api/v1/documents/" + docId + "/favorite";
$.ajax({
dataType: "json",
cache: false,
@ -102,19 +102,13 @@ $(function() {
timeoutNumber: 10000,
url: actionUrl,
data: {
type: "favorite",
docId: docId,
queryId: $queryId.val()
}
})
.done(function(data) {
var $favorited,
$favoritedCount;
if (
data.response.status === 0 &&
typeof data.response.result !== "undefined" &&
data.response.result === "ok"
) {
if (data.result === "created") {
$favorited = $favorite.siblings(".favorited");
$favoritedCount = $(".favorited-count", $favorited);
$favoritedCount.css("display", "none");
@ -136,25 +130,20 @@ $(function() {
$.ajax({
dataType: "json",
cache: false,
type: "post",
type: "get",
timeoutNumber: 10000,
url: contextPath + "/json",
url: contextPath + "/api/v1/favorites",
data: {
type: "favorites",
queryId: $queryId.val()
}
})
.done(function(data) {
var docIds,
i;
if (
data.response.status === 0 &&
typeof data.response.num !== "undefined" &&
data.response.num > 0
) {
docIds = data.response.doc_ids;
if (data.record_count > 0) {
docIds = data.data;
for (i = 0; i < docIds.length; i++) {
docIds[i] = "#" + docIds[i];
docIds[i] = "#" + docIds[i].doc_id;
}
$favorites.each(function(index) {
var $favorite = $(this),