1 package de.dlr.shepard.common.search.endpoints;
2
3 import de.dlr.shepard.common.search.io.CollectionSearchBody;
4 import de.dlr.shepard.common.search.io.CollectionSearchResult;
5 import de.dlr.shepard.common.search.io.ContainerSearchBody;
6 import de.dlr.shepard.common.search.io.ContainerSearchResult;
7 import de.dlr.shepard.common.search.io.ResponseBody;
8 import de.dlr.shepard.common.search.io.SearchBody;
9 import de.dlr.shepard.common.search.io.UserGroupSearchBody;
10 import de.dlr.shepard.common.search.io.UserGroupSearchResult;
11 import de.dlr.shepard.common.search.io.UserSearchBody;
12 import de.dlr.shepard.common.search.io.UserSearchResult;
13 import de.dlr.shepard.common.search.services.CollectionSearchService;
14 import de.dlr.shepard.common.search.services.ContainerSearchService;
15 import de.dlr.shepard.common.search.services.PaginatedCollectionList;
16 import de.dlr.shepard.common.search.services.SearchService;
17 import de.dlr.shepard.common.search.services.UserGroupSearchService;
18 import de.dlr.shepard.common.search.services.UserSearchService;
19 import de.dlr.shepard.common.util.Constants;
20 import de.dlr.shepard.common.util.PaginationHelper;
21 import de.dlr.shepard.common.util.SortingHelper;
22 import de.dlr.shepard.context.collection.io.CollectionIO;
23 import jakarta.enterprise.context.RequestScoped;
24 import jakarta.inject.Inject;
25 import jakarta.validation.Valid;
26 import jakarta.validation.constraints.Positive;
27 import jakarta.validation.constraints.PositiveOrZero;
28 import jakarta.ws.rs.Consumes;
29 import jakarta.ws.rs.POST;
30 import jakarta.ws.rs.Path;
31 import jakarta.ws.rs.Produces;
32 import jakarta.ws.rs.QueryParam;
33 import jakarta.ws.rs.core.MediaType;
34 import jakarta.ws.rs.core.Response;
35 import java.util.Optional;
36 import org.eclipse.microprofile.openapi.annotations.Operation;
37 import org.eclipse.microprofile.openapi.annotations.media.Content;
38 import org.eclipse.microprofile.openapi.annotations.media.Schema;
39 import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
40 import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody;
41 import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
42 import org.eclipse.microprofile.openapi.annotations.tags.Tag;
43
44 @Path(Constants.SEARCH)
45 @Produces(MediaType.APPLICATION_JSON)
46 @Consumes(MediaType.APPLICATION_JSON)
47 @RequestScoped
48 public class SearchRest {
49
50 @Inject
51 SearchService searchService;
52
53 @Inject
54 UserSearchService userSearchService;
55
56 @Inject
57 UserGroupSearchService userGroupSearchService;
58
59 @Inject
60 ContainerSearchService containerSearchService;
61
62 @Inject
63 CollectionSearchService collectionSearchService;
64
65 @POST
66 @Tag(name = Constants.SEARCH)
67 @Operation(description = "search")
68 @APIResponse(
69 description = "ok",
70 responseCode = "200",
71 content = @Content(schema = @Schema(implementation = ResponseBody.class))
72 )
73 @APIResponse(responseCode = "400", description = "bad request")
74 @APIResponse(responseCode = "401", description = "not authorized")
75 public Response search(
76 @RequestBody(
77 required = true,
78 content = @Content(schema = @Schema(implementation = SearchBody.class))
79 ) @Valid SearchBody body
80 ) {
81 ResponseBody ret = searchService.search(body);
82 return Response.ok(ret).build();
83 }
84
85 @POST
86 @Path("/" + Constants.COLLECTIONS)
87 @Tag(name = Constants.SEARCH)
88 @Operation(description = "Search collections with paginated response")
89 @APIResponse(
90 description = "ok",
91 responseCode = "200",
92 content = @Content(schema = @Schema(implementation = CollectionSearchResult.class))
93 )
94 @APIResponse(responseCode = "400", description = "bad request")
95 @APIResponse(responseCode = "401", description = "not authorized")
96 @Parameter(name = Constants.QP_PAGE, description = "Pagination starts at 0")
97 @Parameter(name = Constants.QP_SIZE)
98 @Parameter(name = Constants.QP_ORDER_BY_ATTRIBUTE, description = "Defaults to 'createdAt'")
99 @Parameter(name = Constants.QP_ORDER_DESC, description = "Defaults to 'true'")
100 public Response searchCollections(
101 @RequestBody(
102 required = true,
103 content = @Content(schema = @Schema(implementation = CollectionSearchBody.class)),
104 description = "You can search by ID, name or createdBy. Connect search parameters like this: {\"OR\":[{\"property\":\"name\",\"value\":\"ABC\",\"operator\":\"contains\"},{\"property\":\"id\",\"value\":123,\"operator\":\"contains\"}]}\"" +
105 " "
106 ) @Valid CollectionSearchBody collectionSearchBody,
107 @QueryParam(Constants.QP_PAGE) @PositiveOrZero Integer page,
108 @QueryParam(Constants.QP_SIZE) @Positive Integer size,
109 @QueryParam(Constants.QP_ORDER_BY_ATTRIBUTE) BasicCollectionAttributes orderBy,
110 @QueryParam(Constants.QP_ORDER_DESC) Boolean orderDesc
111 ) {
112 PaginatedCollectionList paginatedCollectionList = collectionSearchService.search(
113 collectionSearchBody.getSearchParams().getQuery(),
114 Optional.ofNullable(page),
115 Optional.ofNullable(size),
116 Optional.ofNullable(orderBy).orElse(BasicCollectionAttributes.createdAt),
117 Optional.ofNullable(orderDesc).orElse(true)
118 );
119
120 CollectionSearchResult collectionSearchResult = new CollectionSearchResult(
121 paginatedCollectionList.getResults().stream().map(CollectionIO::new).toList(),
122 collectionSearchBody.getSearchParams(),
123 paginatedCollectionList.getTotalResults()
124 );
125
126 return Response.ok(collectionSearchResult).build();
127 }
128
129 @POST
130 @Path("/" + Constants.CONTAINERS)
131 @Tag(name = Constants.SEARCH)
132 @Operation(description = "Search containers")
133 @APIResponse(
134 description = "ok",
135 responseCode = "200",
136 content = @Content(schema = @Schema(implementation = ContainerSearchResult.class))
137 )
138 @APIResponse(responseCode = "400", description = "bad request")
139 @APIResponse(responseCode = "401", description = "not authorized")
140 @Parameter(name = Constants.QP_PAGE, description = "Pagination starts at 0")
141 @Parameter(name = Constants.QP_SIZE)
142 @Parameter(name = Constants.QP_ORDER_BY_ATTRIBUTE, description = "Defaults to 'createdAt'")
143 @Parameter(name = Constants.QP_ORDER_DESC, description = "Defaults to 'true'")
144 public Response searchContainers(
145 @RequestBody(
146 required = true,
147 content = @Content(schema = @Schema(implementation = ContainerSearchBody.class))
148 ) @Valid ContainerSearchBody containerSearchBody,
149 @QueryParam(Constants.QP_PAGE) @PositiveOrZero Integer page,
150 @QueryParam(Constants.QP_SIZE) @Positive Integer size,
151 @QueryParam(Constants.QP_ORDER_BY_ATTRIBUTE) BasicContainerAttributes orderBy,
152 @QueryParam(Constants.QP_ORDER_DESC) Boolean orderDesc
153 ) {
154 PaginationHelper pagination = null;
155 if (page != null && size != null) pagination = new PaginationHelper(page, size);
156 SortingHelper sortingHelper = new SortingHelper(
157 Optional.ofNullable(orderBy).orElse(BasicContainerAttributes.createdAt),
158 Optional.ofNullable(orderDesc).orElse(true)
159 );
160 ContainerSearchResult ret = containerSearchService.search(containerSearchBody, pagination, sortingHelper);
161 return Response.ok(ret).build();
162 }
163
164 @POST
165 @Path("/" + Constants.USERS)
166 @Tag(name = Constants.SEARCH)
167 @Operation(description = "Search users")
168 @APIResponse(
169 description = "ok",
170 responseCode = "200",
171 content = @Content(schema = @Schema(implementation = UserSearchResult.class))
172 )
173 @APIResponse(responseCode = "400", description = "bad request")
174 @APIResponse(responseCode = "401", description = "not authorized")
175 public Response searchUsers(
176 @RequestBody(
177 required = true,
178 content = @Content(schema = @Schema(implementation = UserSearchBody.class))
179 ) @Valid UserSearchBody userSearchBody
180 ) {
181 UserSearchResult ret = userSearchService.search(userSearchBody);
182 return Response.ok(ret).build();
183 }
184
185 @POST
186 @Path("/" + Constants.USERGROUPS)
187 @Tag(name = Constants.SEARCH)
188 @Operation(description = "Search user groups")
189 @APIResponse(
190 description = "ok",
191 responseCode = "200",
192 content = @Content(schema = @Schema(implementation = UserGroupSearchResult.class))
193 )
194 @APIResponse(responseCode = "400", description = "bad request")
195 @APIResponse(responseCode = "401", description = "not authorized")
196 public Response searchUserGroups(
197 @RequestBody(
198 required = true,
199 content = @Content(schema = @Schema(implementation = UserSearchBody.class))
200 ) @Valid UserGroupSearchBody userGroupSearchBody
201 ) {
202 UserGroupSearchResult ret = userGroupSearchService.search(userGroupSearchBody);
203 return Response.ok(ret).build();
204 }
205 }