Commit 5c014406 authored by Matija Obreza's avatar Matija Obreza
Browse files

Merge branch 'master' into acledit

parents 963dd6fb f69e4e49
......@@ -94,7 +94,7 @@ public interface AccessionRepository extends JpaRepository<Accession, Long> {
Accession findByInstituteCodeAndAccessionNameAndGenus(String holdingInstitute, String accessionName, String genus);
@Query("select count(a.id) from Accession a where a.id in ( ?1 ) and a.availability = 'Y'")
@Query("select count(a.id) from Accession a where a.id in ( ?1 ) and a.availability = true")
long countAvailable(Set<Long> accessionIds);
}
......@@ -19,6 +19,7 @@ package org.genesys2.server.service.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
......@@ -36,6 +37,7 @@ import org.genesys2.server.service.InstituteService;
import org.genesys2.server.service.OrganizationService;
import org.genesys2.server.service.TaxonomyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
......@@ -65,6 +67,7 @@ public class BatchRESTServiceImpl implements BatchRESTService {
@Override
@Transactional
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#institute, 'WRITE') or hasPermission(#institute, 'CREATE')")
public boolean upsertAccessionData(FaoInstitute institute, Map<BatchRESTService.DataJson, ObjectNode> batch) {
LOG.info("Batch processing " + batch.size() + " entries for " + institute);
List<Accession> toSave = new ArrayList<Accession>();
......@@ -107,6 +110,20 @@ public class BatchRESTServiceImpl implements BatchRESTService {
updated = true;
}
}
value = accnJson.get("uuid");
if (value != null) {
String uuid = value.isNull() ? null : value.textValue();
if (!StringUtils.equals(uuid, accession.getUuid())) {
if (uuid != null) {
// Throws a runtime exception if format is invalid
UUID.fromString(uuid);
}
accession.setUuid(uuid);
updated = true;
}
}
value = accnJson.get("acqDate");
if (value != null) {
String acqDate = value.isNull() ? null : value.textValue();
......
......@@ -2,16 +2,22 @@ package org.genesys2.server.service.impl;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
......@@ -22,10 +28,8 @@ import com.fasterxml.jackson.databind.ObjectMapper;
public class EasySMTAConnector {
private static final Log LOG = LogFactory.getLog(EasySMTAConnector.class);
// FIXME Use the safe URL
// private static final String ITPGRFA_PID_URL =
// "https://www.itworks.it/itt/index.php?r=extsys/getUserDetails2";
private static final String ITPGRFA_PID_URL = "https://www.itworks.it/itt/index.php?r=extsys/getUserDetails2&esUsername=XXX&esPassword=YYY&usEmail=ZZZ";
@Value("${itpgrfa.easysmta.url}")
private String serverUrl;
@Value("${itpgrfa.easysmta.username}")
private String serverUsername;
......@@ -36,28 +40,27 @@ public class EasySMTAConnector {
public EasySMTAUserData getUserData(String emailAddress) {
final HttpClient httpclient = new DefaultHttpClient();
// FIXME Url contains username+password, see below
String url = ITPGRFA_PID_URL.replace("XXX", serverUsername);
url = url.replace("YYY", serverPassword);
url = url.replace("ZZZ", emailAddress);
LOG.info("Checking EasySMTA at " + serverUrl + " for email: " + emailAddress);
final HttpPost httpPost = new HttpPost(serverUrl);
LOG.warn("Using unsafe fetch URL: " + url);
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(new BasicNameValuePair("esUsername", serverUsername));
nvps.add(new BasicNameValuePair("esPassword", serverPassword));
nvps.add(new BasicNameValuePair("usEmail", emailAddress));
try {
httpPost.setEntity(new UrlEncodedFormEntity(nvps));
} catch (UnsupportedEncodingException e1) {
LOG.error(e1, e1);
return null;
}
final HttpGet httpget = new HttpGet(url);
HttpResponse response = null;
BufferedReader br = null;
try {
LOG.info("Using " + serverUsername + " as Easy-SMTA username.");
// FIXME Use these when Easy-SMTA is fixed
// httpclient.getParams().setParameter("esUsername",
// serverUsername);
// httpclient.getParams().setParameter("esPassword",
// serverPassword);
// httpclient.getParams().setParameter("usEmail", emailAddress);
response = httpclient.execute(httpget);
response = httpclient.execute(httpPost);
// Get hold of the response entity
final HttpEntity entity = response.getEntity();
......@@ -68,7 +71,7 @@ public class EasySMTAConnector {
if (entity != null) {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode tree = objectMapper.readTree(entity.getContent());
LOG.debug(tree);
LOG.info("EasySMTA: " + tree);
if (tree.has("errorCode")) {
// Check failed
......@@ -78,10 +81,6 @@ public class EasySMTAConnector {
} else {
if (LOG.isDebugEnabled()) {
LOG.debug(tree);
}
return new EasySMTAUserData(tree.get("pid").asText(), tree.get("name").asText(), tree.get("surname").asText(), tree.get("email").asText(),
tree.get("orgName").asText(), tree.get("country").asText());
}
......@@ -93,7 +92,7 @@ public class EasySMTAConnector {
LOG.error(e);
} finally {
IOUtils.closeQuietly(br);
httpget.releaseConnection();
httpPost.releaseConnection();
LOG.debug("EasySMTA streams closed.");
}
......@@ -124,7 +123,7 @@ public class EasySMTAConnector {
@Override
public String toString() {
return "PID " + firstName + " " + lastName + ", " + organization + ", country=" + countryIsoCode3;
return "ITPGRFA.PID email=" + email + " first=" + firstName + " last=" + lastName + ", org=" + organization + ", country=" + countryIsoCode3;
}
}
}
......@@ -16,22 +16,18 @@
package org.genesys2.server.servlet.controller;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import net.tanesha.recaptcha.ReCaptchaImpl;
import net.tanesha.recaptcha.ReCaptchaResponse;
import org.genesys2.server.model.Permissions;
import org.genesys2.server.model.UserRole;
import org.genesys2.server.model.impl.User;
import org.genesys2.server.service.ContentService;
import org.genesys2.server.service.CropService;
import org.genesys2.server.service.UserService;
import org.genesys2.util.ReCaptchaUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
......@@ -105,28 +101,10 @@ public class HtmlController extends BaseController {
validator.validate(user, bindingResult);
// Validate the reCAPTCHA
String remoteAddr = req.getRemoteAddr();
boolean isLocalRequest = false;
try {
InetAddress remoteInetAddr = InetAddress.getByName(remoteAddr);
isLocalRequest = remoteInetAddr.isLinkLocalAddress() || remoteInetAddr.isAnyLocalAddress() || remoteInetAddr.isLoopbackAddress();
_logger.warn("Remote addr: " + remoteAddr + " " + remoteInetAddr + " isLocal=" + isLocalRequest);
} catch (UnknownHostException e1) {
_logger.warn(e1.getMessage());
}
if (!isLocalRequest) {
ReCaptchaImpl reCaptcha = new ReCaptchaImpl();
reCaptcha.setPrivateKey(captchaPrivateKey);
ReCaptchaResponse reCaptchaResponse = reCaptcha.checkAnswer(remoteAddr, challenge, response);
if (!reCaptchaResponse.isValid()) {
_logger.warn("Invalid captcha.");
FieldError fieldError = new FieldError("comment", "captcha", response, false, new String[] { "errors.badCaptcha" }, null, "Please try again.");
bindingResult.addError(fieldError);
}
if (!ReCaptchaUtil.isValid(captchaPrivateKey, req.getRemoteAddr(), challenge, response)) {
_logger.warn("Invalid captcha.");
FieldError fieldError = new FieldError("comment", "captcha", response, false, new String[] { "errors.badCaptcha" }, null, "Please try again.");
bindingResult.addError(fieldError);
}
try {
......
......@@ -16,12 +16,16 @@
package org.genesys2.server.servlet.controller;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils;
import org.genesys2.server.service.ContentService;
import org.genesys2.server.service.GenesysService;
import org.genesys2.server.service.impl.EasySMTAConnector;
import org.genesys2.server.service.impl.EasySMTAConnector.EasySMTAUserData;
import org.genesys2.util.ReCaptchaUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
......@@ -53,6 +57,12 @@ public class RequestController extends BaseController {
@Autowired
private EasySMTAConnector pidChecker;
@Value("${captcha.privateKey}")
private String captchaPrivateKey;
@Value("${captcha.publicKey}")
private String captchaPublicKey;
/**
* Give information about the request process
*
......@@ -73,18 +83,26 @@ public class RequestController extends BaseController {
@RequestMapping(method = RequestMethod.POST, value = "/start")
public String start(ModelMap model) {
model.addAttribute("blurp", contentService.getGlobalArticle("request-personal", getLocale()));
model.addAttribute("captchaPublicKey", captchaPublicKey);
return "/request/personal";
}
@RequestMapping(method = RequestMethod.POST, value = "/submit")
public String submit(ModelMap model, @RequestParam(value = "email", defaultValue = "", required = true) String emailAddress) {
public String submit(ModelMap model, HttpServletRequest req, @RequestParam(value = "email", defaultValue = "", required = true) String emailAddress, @RequestParam(value = "recaptcha_challenge_field", required = false) String challenge,
@RequestParam(value = "recaptcha_response_field", required = false) String response) {
emailAddress = emailAddress.trim();
if (StringUtils.isBlank(emailAddress)) {
_logger.warn("No email address was specified for request. Stopping here.");
return "/request/personal";
}
// Validate the reCAPTCHA
if (!ReCaptchaUtil.isValid(captchaPrivateKey, req.getRemoteAddr(), challenge, response)) {
_logger.warn("Recaptcha not valid. Stopping here.");
return "/request/personal";
}
_logger.info("Checking for ITPGRFA PID account for " + emailAddress);
EasySMTAUserData pid = pidChecker.getUserData(emailAddress);
......@@ -93,7 +111,7 @@ public class RequestController extends BaseController {
} else {
// TODO send email to registered email address, wait for response
_logger.info("TODO TODO TODO : Send email to : " + pid);
_logger.info("Send email to: " + pid);
}
......
......@@ -17,9 +17,7 @@
package org.genesys2.server.servlet.controller.rest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.genesys2.server.model.genesys.Accession;
......@@ -56,7 +54,7 @@ public class AccessionController extends RestController {
@Autowired
GenesysService genesysService;
@Autowired
BatchRESTService batchRESTService;
......@@ -133,7 +131,13 @@ public class AccessionController extends RestController {
Accession accession = genesysService.getAccession(dataJson.instCode, dataJson.genus, dataJson.acceNumb);
ret.put("id", accession != null ? accession.getId() : null);
if (accession != null) {
ret.put("id", accession.getId());
// Give them back the UUID
if (accession.getUuid() != null) {
ret.put("uuid", accession.getUuid());
}
}
rets.add(ret);
}
......@@ -141,94 +145,6 @@ public class AccessionController extends RestController {
return rets;
}
/**
* Update accessions in the system
*
* @return
* @throws IOException
* @throws JsonProcessingException
*/
@RequestMapping(value = "/{instCode}/update", method = { RequestMethod.POST, RequestMethod.PUT }, produces = { MediaType.APPLICATION_JSON_VALUE })
public @ResponseBody
boolean updateInstituteAccession(@PathVariable("instCode") String instCode, @RequestBody String content) throws JsonProcessingException, IOException {
// TODO Check user's permissions to update this WIEWS institute.
FaoInstitute institute = instituteService.getInstitute(instCode);
if (institute == null) {
throw new ResourceNotFoundException();
}
JsonNode json = mapper.readTree(content);
Map<BatchRESTService.DataJson, ObjectNode> batch = new HashMap<BatchRESTService.DataJson, ObjectNode>();
if (json.isArray()) {
for (JsonNode j : json) {
BatchRESTService.DataJson dataJson = readAid3(j);
if (!instCode.equals(dataJson.instCode)) {
throw new RuntimeException("Accession does not belong to instCode=" + instCode + " acn=" + dataJson);
}
batch.put(dataJson, (ObjectNode) j);
}
} else {
BatchRESTService.DataJson dataJson = readAid3(json);
if (!instCode.equals(dataJson.instCode)) {
throw new RuntimeException("Accession does not belong to instCode=" + instCode + " acn=" + dataJson);
}
batch.put(dataJson, (ObjectNode) json);
}
LOG.info("Batch processing " + batch.size() + " entries for " + institute);
List<Accession> toSave = new ArrayList<Accession>();
for (BatchRESTService.DataJson dataJson : batch.keySet()) {
if (LOG.isDebugEnabled())
LOG.debug("Loading accession " + dataJson);
Accession accession = genesysService.getAccession(dataJson.instCode, dataJson.genus, dataJson.acceNumb);
if (accession == null) {
// LOG.warn("No accession " + dataJson);
continue;
}
ObjectNode accnJson = batch.get(dataJson);
boolean updated = false;
JsonNode value = accnJson.get("mlsStat");
if (value != null) {
Boolean inMls = value.isNull() ? null : value.asBoolean();
if (inMls != accession.getMlsStatus()) {
if (LOG.isDebugEnabled())
LOG.debug("Setting MLSSTAT to " + inMls);
accession.setMlsStatus(inMls);
updated = true;
}
}
value = accnJson.get("availability");
if (value != null) {
Boolean availability = value.isNull() ? null : value.asBoolean();
if (availability != accession.getAvailability()) {
if (LOG.isDebugEnabled())
LOG.debug("Setting Availability to " + availability);
accession.setAvailability(availability);
updated = true;
}
}
if (updated) {
toSave.add(accession);
}
}
if (toSave.size() > 0) {
LOG.info("Storing " + toSave.size() + " accessions.");
genesysService.saveAccessions(toSave);
}
return toSave.size() > 0;
}
/**
* Update accessions in the system
......@@ -240,7 +156,7 @@ public class AccessionController extends RestController {
@RequestMapping(value = "/{instCode}/upsert", method = { RequestMethod.POST, RequestMethod.PUT }, produces = { MediaType.APPLICATION_JSON_VALUE })
public @ResponseBody
boolean upsertInstituteAccession(@PathVariable("instCode") String instCode, @RequestBody String content) throws JsonProcessingException, IOException {
// TODO Check user's permissions to update this WIEWS institute.
// User's permission to WRITE to this WIEWS institute are checked in BatchRESTService.
FaoInstitute institute = instituteService.getInstitute(instCode);
if (institute == null) {
throw new ResourceNotFoundException();
......
/**
* Copyright 2013 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.util;
import java.net.InetAddress;
import java.net.UnknownHostException;
import net.tanesha.recaptcha.ReCaptcha;
import net.tanesha.recaptcha.ReCaptchaImpl;
import net.tanesha.recaptcha.ReCaptchaResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* {@link ReCaptcha} wrapper
*
* @author matijaobreza
*
*/
public class ReCaptchaUtil {
private final static Logger _logger = LoggerFactory.getLogger(ReCaptchaUtil.class);
// Validate the reCAPTCHA
public static boolean isValid(String captchaPrivateKey, String remoteAddr, String challenge, String response) {
boolean isLocalRequest = false;
try {
InetAddress remoteInetAddr = InetAddress.getByName(remoteAddr);
isLocalRequest = remoteInetAddr.isLinkLocalAddress() || remoteInetAddr.isAnyLocalAddress() || remoteInetAddr.isLoopbackAddress();
_logger.warn("Remote addr: " + remoteAddr + " " + remoteInetAddr + " isLocal=" + isLocalRequest);
} catch (UnknownHostException e1) {
_logger.warn(e1.getMessage());
}
if (isLocalRequest) {
_logger.info("Ignoring localhost re-captcha.");
return true;
}
ReCaptchaImpl reCaptcha = new ReCaptchaImpl();
reCaptcha.setPrivateKey(captchaPrivateKey);
ReCaptchaResponse reCaptchaResponse = reCaptcha.checkAnswer(remoteAddr, challenge, response);
return reCaptchaResponse.isValid();
}
}
......@@ -150,6 +150,7 @@ ce.methods=Methods
ce.method=Method
method.fieldName=DB Field
accession.uuid=UUID
accession.accessionName=Accession
accession.origin=Country of origin
accession.holdingInstitute=Holding institute
......
......@@ -53,6 +53,7 @@
<prop key="hibernate.connection.autocommit">false</prop>
<prop key="hibernate.hbm2ddl.auto">${db.hbm2ddl}</prop>
<prop key="hibernate.search.default.indexBase">${lucene.indexDir}</prop>
<prop key="hibernate.search.default.exclusive_index_use">false</prop>
</props>
</property>
<property name="packagesToScan">
......
......@@ -20,7 +20,7 @@
#db.username = sa
#db.password =
db.url=jdbc:mysql://127.0.0.1/genesys2?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false&autoCommit=false
db.url=jdbc:mysql://127.0.0.1/genesys2?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false
db.driverClassName = com.mysql.jdbc.Driver
db.username = root
db.password =
......@@ -42,6 +42,7 @@ captcha.publicKey=6Lf7oucSAAAAAGaS7ObroY2bNgCqMTmpyFVu7wMW
download.files.dir=./data/
# ITPGRFA Easy-SMTA account (if you have one)
itpgrfa.easysmta.url=
itpgrfa.easysmta.username=
itpgrfa.easysmta.password=
......
......@@ -66,6 +66,12 @@
<td><spring:message code="accession.accessionName" /></td>
<td><c:out value="${accession.accessionName}" /></td>
</tr>
<c:if test="${accession.uuid ne null}">
<tr>
<td><spring:message code="accession.uuid" /></td>
<td><b><c:out value="${accession.uuid}" /></b></td>
</tr>
</c:if>
<c:if test="${crops ne null}">
<tr>
......
......@@ -20,7 +20,20 @@
<input type="text" name="email" class="span3 required email form-control" />
</div>
</div>
<div class="form-group">
<label class="col-lg-2 control-label"><spring:message code="captcha.text" /></label>
<div class="col-lg-3">
<script type="text/javascript" src="http://api.recaptcha.net/challenge?k=${captchaPublicKey}">
</script>
<noscript>
<iframe src="http://api.recaptcha.net/noscript?k=${captchaPublicKey}" height="300" width="500" frameborder="0"></iframe>
<br>
<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
<input type="hidden" name="recaptcha_response_field" value="manual_challenge">
</noscript>
</div>
</div>
<div class="form-actions">
<input class="btn btn-primary" type="submit" value="<spring:message code="request.start-request" />" />
</div>
......
......@@ -41,7 +41,7 @@
<a href="<c:url value="/org/${searchResult.slug}" />"><c:out value="${searchResult.slug}" /></a> <c:out value="${searchResult.title}" />
</c:when>
<c:when test="${clazz eq 'Accession'}">
<a href="<c:url value="/acn/id/${searchResult.id}" />">${searchResult.accessionName}</a>
<a href="<c:url value="/acn/id/${searchResult.id}" />">${searchResult.accessionName}</a> ${searchResult.taxonomy.taxonName} ${searchResult.instituteCode}
</c:when>
<c:when test="${clazz eq 'Crop'}">
<a href="<c:url value="/c/${searchResult.shortName}/data" />">${searchResult.name}</a>
......
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