Commit 7169f253 authored by Matija Obreza's avatar Matija Obreza

MaterialRequest (+tests) addresses issue #11

parent 3cb046a3
/**
* Copyright 2014 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.genesys2.server.model.genesys;
import java.text.MessageFormat;
import java.util.UUID;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Lob;
import javax.persistence.PrePersist;
import javax.persistence.Table;
import org.apache.commons.lang.math.RandomUtils;
import org.genesys2.server.model.VersionedAuditedModel;
@Entity
@Table(name = "request")
public class MaterialRequest extends VersionedAuditedModel {
@Column(length = 36, unique=true)
private String uuid;
@Column(length = 200, nullable = false)
private String email;
@Column(length = 100000)
@Lob
private String body;
@Column(length = 32, nullable = false)
private String pid;
@PrePersist
void prepersist() {
if (this.uuid == null)
this.uuid = UUID.nameUUIDFromBytes(("genesys:request:" + email + ":" + System.currentTimeMillis() + ":" + RandomUtils.nextInt(100)).getBytes())
.toString();
}
public MaterialRequest() {
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
@Override
public String toString() {
return MessageFormat.format("Request uuid={0} email={1} body={2}", uuid, email, body);
}
/**
* @param pid EasySMTA PID
*/
public void setPid(String pid) {
this.pid = pid;
}
/**
* @return EasySMTA PID
*/
public String getPid() {
return pid;
}
}
......@@ -59,8 +59,8 @@ public class Article extends AuditedModel {
@Field(name = "title", store = Store.NO)
private String title;
@Column(nullable = false)
@Lob
@Column(length = 100000)
@Field(name = "body", store = Store.NO)
private String body;
......
/**
* Copyright 2014 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.genesys2.server.persistence.domain;
import java.util.List;
import org.genesys2.server.model.genesys.MaterialRequest;
import org.springframework.data.jpa.repository.JpaRepository;
public interface MaterialRequestRepository extends JpaRepository<MaterialRequest, Long> {
List<MaterialRequest> findByEmail(String email);
MaterialRequest findByUuid(String uuid);
}
......@@ -18,10 +18,15 @@ package org.genesys2.server.service;
import java.util.Set;
import org.genesys2.server.model.genesys.MaterialRequest;
import org.genesys2.server.service.impl.EasySMTAConnector.EasySMTAUserData;
public interface RequestService {
void sendRequest(EasySMTAUserData pid, Set<Long> accessionIds);
MaterialRequest sendRequest(EasySMTAUserData pid, Set<Long> accessionIds);
MaterialRequest createRequest(EasySMTAUserData pid, Set<Long> accessionIds);
MaterialRequest getRequest(String uuid);
}
......@@ -121,7 +121,7 @@ public class EasySMTAConnector {
*
* @author matijaobreza
*/
public class EasySMTAUserData {
public static class EasySMTAUserData {
private String pid;
private String firstName;
private String lastName;
......
......@@ -17,6 +17,7 @@
package org.genesys2.server.service.impl;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
......@@ -24,7 +25,9 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.genesys2.server.model.genesys.Accession;
import org.genesys2.server.model.genesys.MaterialRequest;
import org.genesys2.server.model.impl.Article;
import org.genesys2.server.persistence.domain.MaterialRequestRepository;
import org.genesys2.server.service.ContentService;
import org.genesys2.server.service.EMailService;
import org.genesys2.server.service.GenesysService;
......@@ -35,10 +38,15 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@Service
@Transactional(readOnly=true)
public class RequestServiceImpl implements RequestService {
private static final Log LOG = LogFactory.getLog(EMailVerificationServiceImpl.class);
private static final Log LOG = LogFactory.getLog(RequestServiceImpl.class);
@Autowired
private EMailService emailService;
......@@ -49,14 +57,22 @@ public class RequestServiceImpl implements RequestService {
@Autowired
private GenesysService genesysService;
@Autowired
private MaterialRequestRepository requestRepository;
@Value("${base.url}")
private String baseUrl;
@Value("${mail.requests.to}")
private String requestsEmail;
private ObjectMapper mapper = new ObjectMapper();
@Override
public void sendRequest(EasySMTAUserData pid, Set<Long> accessionIds) {
@Transactional
public MaterialRequest sendRequest(EasySMTAUserData pid, Set<Long> accessionIds) {
MaterialRequest request = createRequest(pid, accessionIds);
Article article = contentService.getGlobalArticle("smtp.material-request", Locale.ENGLISH);
String mailSubject = article.getTitle();
......@@ -73,6 +89,45 @@ public class RequestServiceImpl implements RequestService {
LOG.info(">>>" + mailBody);
emailService.sendMail(requestsEmail, null, mailSubject, mailBody);
return request;
}
@Override
@Transactional(readOnly = false)
public MaterialRequest createRequest(EasySMTAUserData pid, Set<Long> accessionIds) {
MaterialRequest request = new MaterialRequest();
request.setEmail(pid.getEmail());
request.setPid(pid.getPid());
RequestBody rb = new RequestBody(pid, accessionIds);
String x = null;
try {
x = mapper.writeValueAsString(rb);
System.err.println("JSON: " + x);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
request.setBody(x);
request = requestRepository.save(request);
LOG.info("Persisted new material request: " + request);
return request;
}
public static final class RequestBody {
public Set<Long> accessionIds;
public EasySMTAUserData pid;
public RequestBody(EasySMTAUserData pid, Set<Long> accessionIds2) {
this.pid=pid;
this.accessionIds = new HashSet<Long>(accessionIds2);
}
}
@Override
public MaterialRequest getRequest(String uuid) {
return requestRepository.findByUuid(uuid);
}
}
......@@ -19,11 +19,13 @@ package org.genesys2.server.servlet.controller;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils;
import org.genesys2.server.model.impl.User;
import org.genesys2.server.service.ContentService;
import org.genesys2.server.service.GenesysService;
import org.genesys2.server.service.RequestService;
import org.genesys2.server.service.impl.EasySMTAConnector;
import org.genesys2.server.service.impl.EasySMTAConnector.EasySMTAUserData;
import org.genesys2.spring.SecurityContextUtil;
import org.genesys2.util.ReCaptchaUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
......@@ -86,8 +88,11 @@ public class RequestController extends BaseController {
@RequestMapping(method = RequestMethod.POST, value = "/start")
public String start(ModelMap model) {
User currentUser = SecurityContextUtil.getCurrentUser();
model.addAttribute("blurp", contentService.getGlobalArticle("request-personal", getLocale()));
model.addAttribute("captchaPublicKey", captchaPublicKey);
if (currentUser != null)
model.addAttribute("requestEmail", currentUser.getEmail());
return "/request/personal";
}
......@@ -96,6 +101,7 @@ public class RequestController extends BaseController {
@RequestParam(value = "recaptcha_challenge_field", required = false) String challenge,
@RequestParam(value = "recaptcha_response_field", required = false) String response) {
emailAddress = emailAddress.trim();
User currentUser = SecurityContextUtil.getCurrentUser();
if (StringUtils.isBlank(emailAddress)) {
_logger.warn("No email address was specified for request. Stopping here.");
......@@ -103,7 +109,7 @@ public class RequestController extends BaseController {
}
// Validate the reCAPTCHA
if (!ReCaptchaUtil.isValid(captchaPrivateKey, req.getRemoteAddr(), challenge, response)) {
if (currentUser == null && !ReCaptchaUtil.isValid(captchaPrivateKey, req.getRemoteAddr(), challenge, response)) {
_logger.warn("Recaptcha not valid. Stopping here.");
return "/request/personal";
}
......
......@@ -17,15 +17,19 @@
<div class="form-group">
<label class="col-lg-2 control-label"><spring:message code="request.your-email" /></label>
<div class="col-lg-3">
<input type="text" name="email" class="span3 required email form-control" />
<input type="text" name="email" class="span3 required email form-control" value="${requestEmail}" />
</div>
</div>
<div class="form-group">
<label class="col-lg-2 control-label"><spring:message code="captcha.text" /></label>
<div class="col-lg-3">
<%@include file="/WEB-INF/jsp/recaptcha/here.jsp" %>
<security:authorize access="isAnonymous()">
<div class="form-group">
<label class="col-lg-2 control-label"><spring:message code="captcha.text" /></label>
<div class="col-lg-3">
<%@include file="/WEB-INF/jsp/recaptcha/here.jsp" %>
</div>
</div>
</div>
</security:authorize>
<div class="form-actions">
<input class="btn btn-primary" type="submit" value="<spring:message code="request.start-request" />" />
</div>
......
/**
* Copyright 2014 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.genesys2.server.service.worker;
import static org.junit.Assert.assertTrue;
......
/**
* Copyright 2014 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.genesys2.server.test;
import org.genesys2.server.aspect.AsAdminAspect;
import org.genesys2.server.service.AclService;
import org.genesys2.server.service.GenesysService;
import org.genesys2.server.service.GeoService;
import org.genesys2.server.service.TaxonomyService;
import org.genesys2.server.service.UserService;
import org.genesys2.server.service.audit.SpringSecurityAuditorAware;
import org.genesys2.server.service.impl.AclServiceImpl;
import org.genesys2.server.service.impl.GenesysServiceImpl;
import org.genesys2.server.service.impl.GeoServiceImpl;
import org.genesys2.server.service.impl.TaxonomyServiceImpl;
import org.genesys2.server.service.impl.UserServiceImpl;
import org.springframework.cache.CacheManager;
import org.springframework.cache.support.NoOpCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.domain.AuditorAware;
@ComponentScan(basePackages = { "org.genesys2.server.persistence.domain" })
public class GenesysBeansConfig extends JpaDataConfig {
@Bean
public AsAdminAspect asAdminAspect() {
return new AsAdminAspect();
}
@Bean
public AuditorAware<?> auditorAware() {
return new SpringSecurityAuditorAware();
}
@Bean
public GeoService geoService() {
return new GeoServiceImpl();
}
@Bean
public GenesysService genesysService() {
return new GenesysServiceImpl();
}
@Bean
public TaxonomyService taxonomyService() {
return new TaxonomyServiceImpl();
}
@Bean
public UserService userService() {
return new UserServiceImpl();
}
@Bean
public AclService aclService() {
return new AclServiceImpl();
}
@Bean
public CacheManager cacheManager() {
return new NoOpCacheManager();
}
}
/**
* Copyright 2014 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.genesys2.server.test;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import javax.mail.internet.MimeMessage;
import org.apache.commons.lang.math.RandomUtils;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.exception.VelocityException;
import org.genesys2.server.listener.sample.CreateContentListener;
import org.genesys2.server.model.genesys.MaterialRequest;
import org.genesys2.server.persistence.domain.MaterialRequestRepository;
import org.genesys2.server.security.AsAdminInvoker;
import org.genesys2.server.service.ContentService;
import org.genesys2.server.service.EMailService;
import org.genesys2.server.service.HtmlSanitizer;
import org.genesys2.server.service.RequestService;
import org.genesys2.server.service.impl.ContentServiceImpl;
import org.genesys2.server.service.impl.EMailServiceImpl;
import org.genesys2.server.service.impl.EasySMTAConnector.EasySMTAUserData;
import org.genesys2.server.service.impl.OWASPSanitizer;
import org.genesys2.server.service.impl.RequestServiceImpl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.mail.MailException;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.ui.velocity.VelocityEngineFactoryBean;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = MaterialRequestTest.Config.class, initializers = PropertyPlacholderInitializer.class)
public class MaterialRequestTest {
@Import(GenesysBeansConfig.class)
public static class Config {
@Bean
public RequestService requestService() {
return new RequestServiceImpl();
}
@Bean
public EMailService emailService() {
return new EMailServiceImpl();
}
@Bean
public ContentService contentService() {
return new ContentServiceImpl();
}
@Bean
public HtmlSanitizer htmlSanitizer() {
return new OWASPSanitizer();
}
@Bean
public VelocityEngine velocityEngine() throws VelocityException, IOException {
VelocityEngineFactoryBean vf = new VelocityEngineFactoryBean();
return vf.createVelocityEngine();
}
@Bean
public ThreadPoolTaskExecutor taskExecutor() {
return new ThreadPoolTaskExecutor();
}
@Bean
public JavaMailSender javaMailSender() {
JavaMailSender jms = new JavaMailSenderImpl() {
@Override
protected void doSend(MimeMessage[] mimeMessages, Object[] originalMessages) throws MailException {
System.err.println("Faking sending email...");
}
};
return jms;
}
@Bean
public AsAdminInvoker asAdminInvoker() {
return new AsAdminInvoker();
}
@Bean
public CreateContentListener createContentListener() {
return new CreateContentListener();
}
}
@Autowired
private RequestService requestService;
@Autowired
private MaterialRequestRepository requestRepository;
// Initialize bean to create default contents
@Autowired
private CreateContentListener createContentListener;
@Test
public void testCreateRequest() {
EasySMTAUserData pid = generatePid();
Set<Long> accessionIds = generateAccessionIds();
MaterialRequest request = requestService.createRequest(pid, accessionIds);
System.err.println(request);
assertTrue(request.getId() != null);
assertTrue(request.getUuid() != null);
assertTrue(request.getBody() != null);
assertTrue(request.getPid().equals("pid1"));
assertTrue(request.getEmail().equals("email@localhost"));
MaterialRequest loaded = requestService.getRequest(request.getUuid());
assertTrue("Could not load request", loaded != null);
assertTrue("Got something else back", loaded.getId().equals(request.getId()));
}
EasySMTAUserData generatePid() {
EasySMTAUserData pid = new EasySMTAUserData("pid1", "firstName", "lastName", "email@localhost", "organization", "DEU", "address", "shipAddress", "AFG");
return pid;
}
Set<Long> generateAccessionIds() {
Set<Long> accessionIds = new HashSet<Long>();
for (long i = 2 + RandomUtils.nextInt(20); i >= 0; i--) {
accessionIds.add(i);
}
return accessionIds;
}
@Test(expected = DataIntegrityViolationException.class)
public void expectDataIntegrityViolationOnDoubleUuid() {
MaterialRequest mr = new MaterialRequest();
mr.setPid("pid2");
mr.setEmail("email@localhost");
requestRepository.save(mr);
assertTrue(mr.getId() != null);
assertTrue(mr.getUuid() != null);
MaterialRequest mr2 = new MaterialRequest();
mr2.setUuid(mr.getUuid());
requestRepository.save(mr2);
}
@Test
public void testEmail() {
EasySMTAUserData pid = generatePid();