View Javadoc
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 }