CitationController.java
/*
* Copyright 2024 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.genesys.server.api.v2;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.ArrayUtils;
import org.genesys.server.api.ApiBaseController;
import org.genesys.server.api.FilteredPage;
import org.genesys.server.api.Pagination;
import org.genesys.server.api.v2.facade.CitationApiService;
import org.genesys.server.api.v2.model.bib.CitationDTO;
import org.genesys.server.exception.InvalidApiUsageException;
import org.genesys.server.exception.SearchException;
import org.genesys.server.model.bib.Citation;
import org.genesys.server.model.bib.QCitation;
import org.genesys.server.model.filters.CitationFilter;
import org.genesys.server.service.PartnerService;
import org.genesys.server.service.worker.bib.CitationRisConverter;
import org.genesys.server.service.worker.bib.CitationStyle;
import org.genesys.server.service.worker.dupe.DuplicateFinder;
import org.springdoc.api.annotations.ParameterObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.querydsl.core.types.OrderSpecifier;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import javax.validation.Valid;
@RestController("citationApi2")
@PreAuthorize("isAuthenticated()")
@RequestMapping(CitationController.CONTROLLER_URL)
@Tag(name = "Citation")
public class CitationController extends FilteredCRUDController<CitationDTO, Citation, CitationApiService, CitationFilter> {
/** The Constant CONTROLLER_URL. */
public static final String CONTROLLER_URL = ApiBaseController.APIv2_BASE + "/citation";
@Autowired
CitationStyle citationStyle;
@Autowired
private CitationRisConverter risConverter;
@Autowired
private PartnerService partnerService;
@Override
protected OrderSpecifier<?>[] defaultSort() {
return new OrderSpecifier[] { QCitation.citation.lastModifiedDate.desc() };
}
@Override
@Operation(hidden = true)
public CitationDTO get(long id) {
throw new InvalidApiUsageException("Not applicable");
}
@Operation(description = "Get record by UUID", summary = "Get")
@GetMapping("/{uuid:\\w{8}\\-\\w{4}\\-.{22}}")
public CitationDTO get(@PathVariable(value = "uuid") UUID uuid) {
return serviceFacade.get(uuid);
}
@Override
@Operation(hidden = true)
public CitationDTO remove(@PathVariable("id") final long id) {
throw new InvalidApiUsageException("Not applicable");
}
@Operation(description = "Delete record by UUID", summary = "Delete citation")
@DeleteMapping("/{uuid:\\w{8}\\-\\w{4}\\-.{22}}")
public CitationDTO remove(@PathVariable(value = "uuid") UUID uuid) {
return serviceFacade.remove(serviceFacade.get(uuid));
}
@Operation(description = "List records I can access", summary = "List only my records")
@PostMapping(value = "/list-mine", produces = MediaType.APPLICATION_JSON_VALUE)
public FilteredPage<CitationDTO, CitationFilter> listMyCitations(@RequestParam(name = "f", required = false) String filterCode, @ParameterObject final Pagination page,
@RequestBody(required = false) CitationFilter filter) throws IOException, SearchException {
var filterInfo = processFilter(filterCode, filter, filterType);
Pageable pageable = ArrayUtils.isEmpty(page.getS()) ? page.toPageRequest(MAX_PAGE_SIZE, DEFAULT_PAGE_SIZE, defaultSort()) : page.toPageRequest(MAX_PAGE_SIZE, DEFAULT_PAGE_SIZE);
return new FilteredPage<>(filterInfo.filterCode, filterInfo.filter, serviceFacade.listMyCitations(filterInfo.filter, pageable));
}
@Operation(description = "Find similar citations", summary = "Get similar")
@PostMapping(value = "/similar", produces = MediaType.APPLICATION_JSON_VALUE)
public List<DuplicateFinder.Hit<CitationDTO>> findSimilar(@RequestBody CitationDTO citation) {
return serviceFacade.findSimilar(citation, null);
}
/**
* Generate citation texts in different styles
*
* @param citation thing to cite
* @return Map of citations by style
*/
@Operation(description = "Generate citations in all available styles", summary = "Generate citation")
@PostMapping(value = "/cite", produces = MediaType.APPLICATION_JSON_VALUE)
public Map<String, String> cite(@RequestBody CitationDTO citation) {
return Map.of("apa", citationStyle.toAPA(citation));
}
@Operation(description = "Read citation data from RIS format", summary = "Parse RIS")
@PostMapping(value = "/parse", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.TEXT_PLAIN_VALUE)
public List<CitationDTO> parseCitations(@RequestBody String input) throws IOException {
return risConverter.readCitations(new StringReader(input)).collect(Collectors.toList());
}
@Operation(description = "Export citation data inf RIS format", summary = "Export as RIS")
@PostMapping(value = "/export", produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
public String exportCitations(@RequestBody CitationFilter filter) throws IOException, SearchException {
var citations = serviceFacade.listMyCitations(filter, Pageable.unpaged()).getContent();
var writer = new StringWriter();
for (CitationDTO citation : citations) {
risConverter.writeCitation(citation, writer);
}
return writer.toString();
}
@PostMapping(value = "/approve", produces = MediaType.APPLICATION_JSON_VALUE)
public CitationDTO approveCitation(@RequestBody @Valid EntityUuidAndVersion ref) {
return serviceFacade.get(serviceFacade.approveCitation(ref));
}
@PostMapping(value = "/reject", produces = MediaType.APPLICATION_JSON_VALUE)
public CitationDTO rejectCitation(@RequestBody @Valid EntityUuidAndVersion ref) {
return serviceFacade.get(serviceFacade.rejectCitation(ref));
}
@PostMapping(value = "/for-review", produces = MediaType.APPLICATION_JSON_VALUE)
public CitationDTO reviewCitation(@RequestBody @Valid EntityUuidAndVersion ref) {
return serviceFacade.get(serviceFacade.reviewCitation(ref));
}
@Operation(description = "Get all collections by owner", summary = "Get collections by owner")
@GetMapping("/owner/{uuid:\\w{8}\\-\\w{4}\\-.{22}}/collections")
public List<String> getCollections(@PathVariable(value = "uuid") UUID owner) {
return serviceFacade.getCollections(partnerService.get(owner));
}
@Operation(description = "Get all published collections by filter", summary = "Get published collections by filter")
@PostMapping("/collections")
public List<String> getCollections(@RequestBody(required = false) CitationFilter filter) {
return serviceFacade.getCollections(filter);
}
}