Commit c0062a15 authored by Viacheslav Pavlov's avatar Viacheslav Pavlov Committed by Matija Obreza
Browse files

Requests API v1: creating requests for material



- moved filterAvailableForDistributionByUuid to Accession service
- removed @Preauth from some Request controller methods
- fixed tests
Signed-off-by: Matija Obreza's avatarMatija Obreza <matija.obreza@croptrust.org>
parent 340029f6
......@@ -17,9 +17,12 @@
package org.genesys2.server.api.v1;
import java.io.IOException;
import java.util.Set;
import java.util.UUID;
import org.genesys.blocks.model.JsonViews;
import org.genesys.catalog.api.FilteredPage;
import org.genesys.catalog.exceptions.InvalidApiUsageException;
import org.genesys.catalog.service.ShortFilterService;
import org.genesys2.server.api.ApiBaseController;
import org.genesys2.server.model.genesys.MaterialRequest;
......@@ -28,6 +31,7 @@ import org.genesys2.server.model.impl.FaoInstitute;
import org.genesys2.server.service.InstituteService;
import org.genesys2.server.service.RequestService;
import org.genesys2.server.service.RequestService.NoPidException;
import org.genesys2.server.service.TokenVerificationService;
import org.genesys2.server.service.filter.MaterialRequestFilter;
import org.genesys2.server.service.filter.MaterialSubRequestFilter;
import org.genesys2.server.service.impl.EasySMTAException;
......@@ -46,6 +50,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.annotations.Api;
......@@ -56,7 +61,14 @@ import io.swagger.annotations.Api;
public class RequestsController extends ApiBaseController {
// Rest controller base URL
protected static final String CONTROLLER_URL = ApiBaseController.APIv1_BASE + "/requests";
public static final String CONTROLLER_URL = ApiBaseController.APIv1_BASE + "/requests";
public static final String PARAM_KEY = "key";
public static final String PARAM_TOKENUUID = "tokenUuid";
private final ObjectMapper objectMapper = new ObjectMapper();
@Autowired
private RequestService requestService;
......@@ -124,6 +136,16 @@ public class RequestsController extends ApiBaseController {
return requestService.sendValidationEmail(materialRequest);
}
@PostMapping(value = "/r/initiate", produces = { MediaType.APPLICATION_JSON_VALUE }, consumes = { MediaType.APPLICATION_JSON_VALUE } )
public MaterialRequest initiateRequest(@RequestParam(name = "requestInfo") String requestInfo,
@RequestBody Set<UUID> accessionUuids) throws RequestService.RequestException, IOException {
LOG.info("Initiating request: info={} accessionUuids={}", requestInfo, accessionUuids);
RequestService.RequestInfo requestInfo1 = objectMapper.readValue(requestInfo, RequestService.RequestInfo.class);
return requestService.initiateRequestByUuids(requestInfo1, accessionUuids);
}
/**
* Validate request
*
......@@ -131,7 +153,6 @@ public class RequestsController extends ApiBaseController {
* @throws EasySMTAException
* @throws NoPidException
*/
@PreAuthorize("hasRole('ADMINISTRATOR')")
@PostMapping(value = "/r/{uuid:.{36}}/validate", produces = { MediaType.APPLICATION_JSON_VALUE })
public MaterialRequest validateRequest(@PathVariable("uuid") String uuid) throws NoPidException, EasySMTAException {
LOG.info("Loading request uuid={}", uuid);
......@@ -139,6 +160,24 @@ public class RequestsController extends ApiBaseController {
return requestService.validateRequest(materialRequest);
}
/**
* Validate request
*
* @return
* @throws EasySMTAException
* @throws NoPidException
*/
@PostMapping(value = "/r/validate", produces = { MediaType.APPLICATION_JSON_VALUE })
public MaterialRequest validateRequest(@RequestParam(PARAM_TOKENUUID) String tokenUuid, @RequestParam(PARAM_KEY) String key) {
LOG.info("Validating request tokenUuid={}, key={}", tokenUuid, key);
try {
return requestService.validateClientRequest(tokenUuid, key);
} catch (NoPidException | EasySMTAException pidE) {
throw new InvalidApiUsageException(pidE.getMessage(), pidE);
} catch (TokenVerificationService.NoSuchVerificationTokenException | TokenVerificationService.TokenExpiredException | RequestService.RequestException e) {
throw new InvalidApiUsageException(e.getMessage(), e);
}
}
/**
* Reload PID data
*
......
......@@ -17,6 +17,7 @@ package org.genesys2.server.service;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.genesys2.server.model.genesys.Accession;
......@@ -69,6 +70,15 @@ public interface AccessionService {
*/
Accession getByDoi(String doi);
/**
* Get only available for distribution accessions id-s.
*
* @param accessionUuids uuids of accessions
* @return id-s of available accessions
*/
Set<Long> filterAvailableForDistributionByUuid(Set<UUID> accessionUuids);
/**
* Converts AccessionIdentifiers to UUID
*
......
......@@ -17,6 +17,7 @@
package org.genesys2.server.service;
import java.util.Set;
import java.util.UUID;
import org.genesys2.server.model.genesys.MaterialRequest;
import org.genesys2.server.model.genesys.MaterialSubRequest;
......@@ -40,6 +41,16 @@ public interface RequestService {
*/
MaterialRequest initiateRequest(RequestInfo requestInfo, Set<Long> accessionIds) throws RequestException;
/**
* Creates a {@link MaterialRequest} and sends a validation email to user
*
* @param requestInfo
* @param accessionUuids
* @return
* @throws RequestException
*/
MaterialRequest initiateRequestByUuids(RequestInfo requestInfo, Set<UUID> accessionUuids) throws RequestException;
/**
* Validation request attempt by user
*
......
......@@ -15,12 +15,9 @@
*/
package org.genesys2.server.service.impl;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.*;
import com.querydsl.core.BooleanBuilder;
import org.genesys2.server.model.genesys.Accession;
import org.genesys2.server.model.genesys.AccessionData;
import org.genesys2.server.model.genesys.AccessionId;
......@@ -145,6 +142,27 @@ public class AccessionServiceImpl implements AccessionService {
return total;
}
@Override
public Set<Long> filterAvailableForDistributionByUuid(Set<UUID> accessionUuids) {
if (accessionUuids == null || accessionUuids.size() == 0) {
return Collections.emptySet();
}
QAccession accession = QAccession.accession;
BooleanBuilder predicate = new BooleanBuilder();
predicate.and(accession.accessionId.uuid.in(accessionUuids));
predicate.and(accession.historic.isFalse());
predicate.and(accession.available.isNull().or(accession.available.isTrue()));
predicate.and(accession.institute.allowMaterialRequests.isTrue());
JPAQuery<Long> query = jpaQueryFactory.select(accession.id)
.from(accession)
.where(predicate);
return new HashSet<>(query.fetch());
}
/*
* (non-Javadoc)
* @see
......
......@@ -29,31 +29,17 @@ import java.util.zip.ZipOutputStream;
import javax.persistence.EntityManager;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.apache.commons.collections4.CollectionUtils;
import org.genesys.blocks.security.SecurityContextUtil;
import org.genesys.blocks.security.model.AclSid;
import org.genesys.blocks.security.service.CustomAclService;
import org.genesys2.server.api.model.AccessionHeaderJson;
import org.genesys2.server.model.elastic.AccessionDetails;
import org.genesys2.server.model.genesys.Accession;
import org.genesys2.server.model.genesys.*;
import org.genesys2.server.model.genesys.AccessionAlias.AliasType;
import org.genesys2.server.model.genesys.AccessionData;
import org.genesys2.server.model.genesys.AccessionGeo;
import org.genesys2.server.model.genesys.AccessionHistoric;
import org.genesys2.server.model.genesys.AccessionId;
import org.genesys2.server.model.genesys.AccessionTrait;
import org.genesys2.server.model.genesys.AllAccnames;
import org.genesys2.server.model.genesys.ExperimentAccessionTrait;
import org.genesys2.server.model.genesys.ExperimentTrait;
import org.genesys2.server.model.genesys.Metadata;
import org.genesys2.server.model.genesys.Method;
import org.genesys2.server.model.genesys.PDCI;
import org.genesys2.server.model.genesys.PDCIStatistics;
import org.genesys2.server.model.genesys.PhenoStatistics;
import org.genesys2.server.model.genesys.SelfCopy;
import org.genesys2.server.model.genesys.SvalbardDeposit;
import org.genesys2.server.model.genesys.Taxonomy2;
import org.genesys2.server.model.genesys.TraitCode;
import org.genesys2.server.model.impl.AccessionIdentifier3;
import org.genesys2.server.model.impl.Country;
import org.genesys2.server.model.impl.Crop;
......@@ -116,6 +102,10 @@ public class GenesysServiceImpl implements GenesysService, DatasetService {
@Autowired
private EntityManager entityManager;
@Autowired
private JPAQueryFactory jpaQueryFactory;
// Services
@Autowired
private TaxonomyService taxonomyService;
......@@ -866,7 +856,7 @@ public class GenesysServiceImpl implements GenesysService, DatasetService {
return accessionRepository.filterAvailableForDistribution(accessionIds);
}
/**
/**
* Returns datasets to which current user has 'WRITE'
*/
@Override
......
......@@ -17,14 +17,7 @@
package org.genesys2.server.service.impl;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.*;
import org.apache.commons.lang3.StringUtils;
import org.genesys2.server.model.genesys.Accession;
......@@ -37,13 +30,7 @@ import org.genesys2.server.model.impl.FaoInstituteSetting;
import org.genesys2.server.model.impl.VerificationToken;
import org.genesys2.server.persistence.MaterialRequestRepository;
import org.genesys2.server.persistence.MaterialSubRequestRepository;
import org.genesys2.server.service.ContentService;
import org.genesys2.server.service.EMailService;
import org.genesys2.server.service.EasySMTA;
import org.genesys2.server.service.GenesysService;
import org.genesys2.server.service.InstituteService;
import org.genesys2.server.service.RequestService;
import org.genesys2.server.service.TokenVerificationService;
import org.genesys2.server.service.*;
import org.genesys2.server.service.TokenVerificationService.NoSuchVerificationTokenException;
import org.genesys2.server.service.TokenVerificationService.TokenExpiredException;
import org.genesys2.server.service.filter.MaterialRequestFilter;
......@@ -87,6 +74,9 @@ public class RequestServiceImpl implements RequestService {
@Autowired
private GenesysService genesysService;
@Autowired
private AccessionService accessionService;
@Autowired
private InstituteService instituteService;
......@@ -127,6 +117,30 @@ public class RequestServiceImpl implements RequestService {
return sendValidationEmail(request);
}
@Override
@Transactional
public MaterialRequest initiateRequestByUuids(RequestInfo requestInfo, Set<UUID> accessionUuids) throws RequestException {
final Set<Long> availableAccessionIds = accessionService.filterAvailableForDistributionByUuid(accessionUuids);
final Locale locale = LocaleContextHolder.getLocale();
System.err.println("Current locale: " + locale);
if (availableAccessionIds == null || availableAccessionIds.size() == 0) {
throw new RequestException("None of the selected accessions are available for distribution");
}
// Check Easy-SMTA for PID
EasySMTA.EasySMTAUserData pid;
try {
pid = pidChecker.getUserData(requestInfo.getEmail());
} catch (EasySMTAException e) {
throw new RequestException(e.getMessage(), e);
}
final MaterialRequest request = createRequest(requestInfo, pid, availableAccessionIds);
return sendValidationEmail(request);
}
// Send email to the user with verification
@Override
@Transactional
......@@ -197,7 +211,7 @@ public class RequestServiceImpl implements RequestService {
String x = null;
try {
x = mapper.writeValueAsString(rb);
System.err.println("JSON: " + x);
LOG.debug("Request JSON: {}" + x);
} catch (final JsonProcessingException e) {
e.printStackTrace();
}
......
......@@ -30,6 +30,7 @@ import org.genesys.catalog.service.DatasetService;
import org.genesys.catalog.service.ShortFilterService;
import org.genesys.test.config.ApplicationConfig;
import org.genesys2.server.model.PublishState;
import org.genesys2.server.persistence.FaoInstituteRepository;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
......@@ -43,6 +44,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.WebApplicationContext;
import com.fasterxml.jackson.databind.ObjectMapper;
......@@ -69,7 +71,9 @@ public abstract class AbstractApiTest extends AbstractTest {
protected DatasetService datasetService;
@Autowired
protected ShortFilterService shortFilterService;
@Autowired
private FaoInstituteRepository instituteRepository;
protected MockMvc mockMvc;
@Rule
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("target/generated-snippets");
......@@ -84,14 +88,16 @@ public abstract class AbstractApiTest extends AbstractTest {
super.beforeTest();
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).apply(documentationConfiguration(restDocumentation).uris().withScheme("https").withHost(
"api.catalog.genesys-pgr.org").withPort(443)).build();
"api.genesys-pgr.org").withPort(443)).build();
}
@After
@Override
@Transactional
public void cleanup() throws Exception {
datasetRepository.deleteAll();
partnerRepository.deleteAll();
instituteRepository.deleteAll();
super.cleanup();
}
......
package org.genesys.test.server.api.v1;
import static org.hamcrest.Matchers.*;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import java.util.Collections;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import java.util.UUID;
import org.genesys.test.base.AbstractApiTest;
import org.genesys2.server.api.v0.AccessionController;
import org.genesys2.server.api.v1.RequestsController;
import org.genesys2.server.model.genesys.Accession;
import org.genesys2.server.model.impl.FaoInstitute;
import org.genesys2.server.model.impl.VerificationToken;
import org.genesys2.server.persistence.*;
import org.genesys2.server.service.ContentService;
import org.genesys2.server.service.InstituteService;
import org.genesys2.server.service.RequestService;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.WebApplicationContext;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Lists;
/**
* @author Viacheslav Pavlov
*/
public class RequestControllerTest extends AbstractApiTest {
private static final String TEST_INSTCODE = "XXX001";
private static final ObjectMapper objectMapper;
private static FaoInstitute institute;
static {
objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
}
@Rule
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("target/generated-snippets");
MockMvc mockMvc;
@Autowired
private WebApplicationContext webApplicationContext;
@Autowired
private InstituteService instituteService;
@Autowired
private ContentService contentService;
@Autowired
private RequestService requestService;
@Autowired
private MaterialRequestRepository materialRequestRepository;
@Autowired
private MaterialSubRequestRepository materialSubRequestRepository;
@Autowired
private AccessionRepository accessionRepository;
@Autowired
private VerificationTokenRepository verificationTokenRepository;
@Autowired
private ArticleRepository articleRepository;
@Before
@Override
@Transactional
public void beforeTest() throws Exception {
super.beforeTest();
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).apply(documentationConfiguration(this.restDocumentation).uris().withScheme("https").withHost(
"sandbox.genesys-pgr.org").withPort(443)).build();
institute = new FaoInstitute();
institute.setCode(TEST_INSTCODE);
institute.setFullName("An institute");
institute.setAllowMaterialRequests(true);
instituteService.update(Lists.newArrayList(institute));
institute = instituteService.getInstitute(TEST_INSTCODE);
contentService.createGlobalArticle(ContentService.SMTP_MATERIAL_CONFIRM_NO_PID, contentService.getDefaultLocale(), "test confirm-no-pid", "test body", "test Summary", true);
contentService.createGlobalArticle(ContentService.SMTP_MATERIAL_CONFIRM, contentService.getDefaultLocale(), "test confirm", "test body", "test Summary", true);
contentService.createGlobalArticle(ContentService.SMTP_MATERIAL_REQUEST, contentService.getDefaultLocale(), "test relay", "test relay", "test relay", true);
try {
upsert(setUpAccession());
} catch (Exception e) {
e.printStackTrace();
}
}
@After
@Override
@Transactional
public void cleanup() throws Exception {
materialSubRequestRepository.deleteAll();
materialRequestRepository.deleteAll();
accessionRepository.deleteAll();
articleRepository.deleteAll();
verificationTokenRepository.deleteAll();
super.cleanup();
}
@Test
public void initiateRequestTest() throws Exception {
RequestService.RequestInfo requestInfo = new RequestService.RequestInfo();
requestInfo.setPreacceptSMTA(false);
requestInfo.setEmail("user@localhost");
requestInfo.setNotes("Notes " + System.currentTimeMillis());
Accession accession = accessionRepository.findAll().get(0);
Set<UUID> accUuids = new HashSet<>();
accUuids.add(accession.getUuid());
/*@formatter:off*/
mockMvc.perform(post(RequestsController.CONTROLLER_URL + "/r/initiate")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(accUuids))
.param("requestInfo", objectMapper.writeValueAsString(requestInfo)))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$", not(nullValue())))
.andExpect(jsonPath("$.uuid", notNullValue()))
.andExpect(jsonPath("$.email", is(requestInfo.getEmail())))
.andExpect(jsonPath("$.state", is(0)))
.andExpect(jsonPath("$.body.requestInfo.email", is(requestInfo.getEmail())))
.andExpect(jsonPath("$.body.requestInfo.purposeType", is(0)))
.andExpect(jsonPath("$.body.requestInfo.notes", is(requestInfo.getNotes())))
/// Sometimes this is ok, sometimes not
// .andExpect(jsonPath("$.body.pid", nullValue()));
.andExpect(jsonPath("$.body.accessionIds[0]", is(accession.getId().intValue())))
;
/*@formatter:on*/
}
@Test
public void validateRequestTest() throws Exception {
initRequest();
VerificationToken token = verificationTokenRepository.findAll().get(0);
/*@formatter:off*/
mockMvc.perform(post(RequestsController.CONTROLLER_URL + "/r/validate")
.param(RequestsController.PARAM_TOKENUUID, token.getUuid())
.param(RequestsController.PARAM_KEY, token.getKey()))
.andDo(MockMvcResultHandlers.print())
/// Sometimes this is 400, sometimes 200
// .andExpect(status().isOk());
// {"error":"Email not registered with PID server","localizedError":"Email not registered with PID server"};
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8));
/*@formatter:on*/
}
private ObjectNode setUpAccession() {
ObjectNode accession = objectMapper.createObjectNode();
accession.put("instCode", institute.getCode());
accession.put("accessionNumber", "A1");
accession.put("available", true);
ObjectNode taxa = accession.putObject("taxonomy");
taxa.put("genus", "Manihot");
return accession;
}
private void initRequest() throws Exception {
RequestService.RequestInfo requestInfo = new RequestService.RequestInfo();
requestInfo.setPreacceptSMTA(false);
requestInfo.setEmail("user@localhost");
UUID uuid = accessionRepository.findAll().get(0).getUuid();
requestService.initiateRequestByUuids(requestInfo, Collections.singleton(uuid));
}
private ResultActions upsert(ObjectNode accessionJson) throws Exception, JsonProcessingException {
LOG.debug("Upsering {}", verboseMapper.writerWithDefaultPrettyPrinter().writeValueAsString(accessionJson));
/*@formatter:off*/
return mockMvc.perform(post(AccessionController.API_BASE + "/" + institute.getCode() + "/upsert")
.contentType(MediaType.APPLICATION_JSON)
.content("[" + verboseMapper.writeValueAsString(accessionJson) + "]"))
.andExpect(status().isOk());
/*@formatter:on*/
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment