package org.akaza.openclinica.controller.openrosa;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.akaza.openclinica.bean.core.Status;
import org.akaza.openclinica.bean.managestudy.StudySubjectBean;
import org.akaza.openclinica.bean.rule.FileProperties;
import org.akaza.openclinica.control.submit.UploadFileServlet;
import org.akaza.openclinica.dao.core.CoreResources;
import org.akaza.openclinica.dao.hibernate.StudyDao;
import org.akaza.openclinica.dao.hibernate.StudyParameterValueDao;
import org.akaza.openclinica.dao.hibernate.UserAccountDao;
import org.akaza.openclinica.domain.datamap.Study;
import org.akaza.openclinica.domain.datamap.StudyParameterValue;
import org.akaza.openclinica.domain.user.UserAccount;
import org.akaza.openclinica.exception.OpenClinicaSystemException;
import org.akaza.openclinica.i18n.core.LocaleResolver;
import org.akaza.openclinica.service.pmanage.ParticipantPortalRegistrar;
import org.akaza.openclinica.web.pform.PFormCache;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.validation.DataBinder;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
@RequestMapping(value = "/openrosa")
public class OpenRosaSubmissionController {
@Autowired
ServletContext context;
@Autowired
private OpenRosaSubmissionService openRosaSubmissionService;
@Autowired
private StudyDao studyDao;
@Autowired
private StudyParameterValueDao studyParameterValueDao;
@Autowired
private UserAccountDao userAccountDao;
@Autowired
PformSubmissionNotificationService notifier;
protected final Logger logger = LoggerFactory.getLogger(getClass().getName());
public static final String FORM_CONTEXT = "ecid";
/**
* @api {post} /pages/api/v1/editform/:studyOid/submission Submit form data
* @apiName doSubmission
* @apiPermission admin
* @apiVersion 3.8.0
* @apiParam {String} studyOid Study Oid.
* @apiParam {String} ecid Key that will be used to look up subject context information while processing submission.
* @apiGroup Form
* @apiDescription Submits the data from a completed form.
*/
@RequestMapping(value = "/{studyOID}/submission", method = RequestMethod.POST)
public ResponseEntity<String> doSubmission(HttpServletRequest request, HttpServletResponse response,
@PathVariable("studyOID") String studyOID, @RequestParam(FORM_CONTEXT) String ecid) {
logger.info("Processing xform submission.");
HashMap<String, String> subjectContext = null;
Locale locale = LocaleResolver.getLocale(request);
DataBinder dataBinder = new DataBinder(null);
Errors errors = dataBinder.getBindingResult();
Study study = studyDao.findByOcOID(studyOID);
String requestBody=null;
HashMap<String,String> map = new HashMap();
ArrayList <HashMap> listOfUploadFilePaths = new ArrayList();
try {
// Verify Study is allowed to submit
if (!mayProceed(studyOID)) {
logger.info("Submissions to the study not allowed. Aborting submission.");
return new ResponseEntity<String>(org.springframework.http.HttpStatus.NOT_ACCEPTABLE);
}
if (ServletFileUpload.isMultipartContent(request)) {
String dir = getAttachedFilePath(studyOID);
FileProperties fileProperties= new FileProperties();
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setFileSizeMax(fileProperties.getFileSizeMax());
List<FileItem> items = upload.parseRequest(request);
for (FileItem item : items) {
if (item.getContentType() != null && !item.getFieldName().equals("xml_submission_file") ) {
if (!new File(dir).exists()) new File(dir).mkdirs();
File file = processUploadedFile(item, dir);
map.put(item.getFieldName(), file.getPath());
} else if (item.getFieldName().equals("xml_submission_file")) {
requestBody = item.getString("UTF-8");
}
}
listOfUploadFilePaths.add(map);
} else {
requestBody = IOUtils.toString(request.getInputStream(), "UTF-8");
}
// Load user context from ecid
PFormCache cache = PFormCache.getInstance(context);
subjectContext = cache.getSubjectContext(ecid);
// Execute save as Hibernate transaction to avoid partial imports
openRosaSubmissionService.processRequest(study, subjectContext, requestBody, errors, locale , listOfUploadFilePaths);
} catch (Exception e) {
logger.error("Exception while processing xform submission.");
logger.error(e.getMessage());
logger.error(ExceptionUtils.getStackTrace(e));
if (errors.hasErrors()) {
// Send a failure response
logger.info("Submission caused internal error. Sending error response.");
return new ResponseEntity<String>(org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR);
}
}
if (!errors.hasErrors()) {
// Log submission with Participate
if (isParticipantSubmission(subjectContext)) notifier.notify(studyOID, subjectContext);
logger.info("Completed xform submission. Sending successful response");
String responseMessage = "<OpenRosaResponse xmlns=\"http://openrosa.org/http/response\">" + "<message>success</message>" + "</OpenRosaResponse>";
return new ResponseEntity<String>(responseMessage, org.springframework.http.HttpStatus.CREATED);
} else {
logger.info("Submission contained errors. Sending error response");
return new ResponseEntity<String>(org.springframework.http.HttpStatus.NOT_ACCEPTABLE);
}
}
/**
* @api {post} /pages/api/v1/editform/:studyOid/submission Submit form data
* @apiName doSubmission
* @apiPermission admin
* @apiVersion 3.8.0
* @apiParam {String} studyOid Study Oid.
* @apiParam {String} ecid Key that will be used to look up subject context information while processing submission.
* @apiGroup Form
* @apiDescription Submits the data from a completed form.
*/
@RequestMapping(value = "/{studyOID}/fieldsubmission", method = RequestMethod.POST)
public ResponseEntity<String> doFieldSubmission(HttpServletRequest request, HttpServletResponse response,
@PathVariable("studyOID") String studyOID, @RequestParam(FORM_CONTEXT) String ecid) {
logger.info("Processing xform field submission.");
HashMap<String, String> subjectContext = null;
Locale locale = LocaleResolver.getLocale(request);
DataBinder dataBinder = new DataBinder(null);
Errors errors = dataBinder.getBindingResult();
Study study = studyDao.findByOcOID(studyOID);
String requestBody=null;
String instanceId = null;
HashMap<String,String> map = new HashMap();
ArrayList <HashMap> listOfUploadFilePaths = new ArrayList();
try {
// Verify Study is allowed to submit
if (!mayProceed(studyOID)) {
logger.info("Field Submissions to the study not allowed. Aborting field submission.");
return new ResponseEntity<String>(org.springframework.http.HttpStatus.NOT_ACCEPTABLE);
}
if (ServletFileUpload.isMultipartContent(request)) {
String dir = getAttachedFilePath(studyOID);
FileProperties fileProperties= new FileProperties();
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setFileSizeMax(fileProperties.getFileSizeMax());
List<FileItem> items = upload.parseRequest(request);
for (FileItem item : items) {
if (item.getFieldName().equals("instance_id")) {
instanceId = item.getString();
} else if (item.getFieldName().equals("xml_submission_fragment_file")) {
requestBody = item.getString("UTF-8");
} else if (item.getContentType() != null) {
if (!new File(dir).exists()) new File(dir).mkdirs();
File file = processUploadedFile(item, dir);
map.put(item.getFieldName(), file.getPath());
}
}
listOfUploadFilePaths.add(map);
}
if (instanceId == null) {
logger.info("Field Submissions to the study not allowed without a valid instanceId. Aborting field submission.");
return new ResponseEntity<String>(org.springframework.http.HttpStatus.NOT_ACCEPTABLE);
}
// Load user context from ecid
PFormCache cache = PFormCache.getInstance(context);
subjectContext = cache.getSubjectContext(ecid);
// Execute save as Hibernate transaction to avoid partial imports
openRosaSubmissionService.processFieldSubmissionRequest(study, subjectContext, instanceId, requestBody, errors, locale , listOfUploadFilePaths);
} catch (Exception e) {
logger.error("Exception while processing xform submission.");
logger.error(e.getMessage());
logger.error(ExceptionUtils.getStackTrace(e));
if (!errors.hasErrors()) {
// Send a failure response
logger.info("Submission caused internal error. Sending error response.");
return new ResponseEntity<String>(org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR);
}
}
if (!errors.hasErrors()) {
// Log submission with Participate
if (isParticipantSubmission(subjectContext)) notifier.notify(studyOID, subjectContext);
logger.info("Completed xform field submission. Sending successful response");
String responseMessage = "<OpenRosaResponse xmlns=\"http://openrosa.org/http/response\">" + "<message>success</message>" + "</OpenRosaResponse>";
return new ResponseEntity<String>(responseMessage, org.springframework.http.HttpStatus.CREATED);
} else {
logger.info("Field Submission contained errors. Sending error response");
return new ResponseEntity<String>(org.springframework.http.HttpStatus.NOT_ACCEPTABLE);
}
}
private boolean isParticipantSubmission(HashMap<String, String> subjectContext) {
boolean isParticipant = true;
String userAccountId = subjectContext.get("userAccountID");
if (StringUtils.isNotEmpty(userAccountId)) {
UserAccount user = userAccountDao.findByUserId(Integer.valueOf(userAccountId));
// All Participants have a '.' in the user name. Non-participant user creation does not allow a '.' in the user name.
if (user != null && !user.getUserName().contains(".")) return false;
}
return isParticipant;
}
private Study getParentStudy(String studyOid) {
Study study = studyDao.findByOcOID(studyOid);
Study parentStudy = study.getStudy();
if (parentStudy != null && parentStudy.getStudyId() > 0)
return parentStudy;
else
return study;
}
private boolean mayProceed(String studyOid) throws Exception {
return mayProceed(studyOid, null);
}
private boolean mayProceed(String studyOid, StudySubjectBean ssBean) throws Exception {
boolean accessPermission = false;
ParticipantPortalRegistrar participantPortalRegistrar= new ParticipantPortalRegistrar();
Study study = getParentStudy(studyOid);
StudyParameterValue pStatus = studyParameterValueDao.findByStudyIdParameter(study.getStudyId(), "participantPortal");
// ACTIVE, PENDING, or INACTIVE
String pManageStatus = participantPortalRegistrar.getRegistrationStatus(studyOid).toString();
// enabled or disabled
String participateStatus = pStatus.getValue().toString();
// available, pending, frozen, or locked
String studyStatus = study.getStatus().getName().toString();
if (ssBean == null) {
logger.info("pManageStatus: " + pManageStatus + " participantStatus: " + participateStatus + " studyStatus: " + studyStatus);
//TODO: Disabled pManage status check for OC16 conference. Re-enable after.
//if (participateStatus.equalsIgnoreCase("enabled") && studyStatus.equalsIgnoreCase("available") && pManageStatus.equalsIgnoreCase("ACTIVE"))
if (participateStatus.equalsIgnoreCase("enabled") && studyStatus.equalsIgnoreCase("available"))
accessPermission = true;
} else {
logger.info("pManageStatus: " + pManageStatus + " participantStatus: " + participateStatus + " studyStatus: " + studyStatus
+ " studySubjectStatus: " + ssBean.getStatus().getName());
//TODO: Disabled pManage status check for OC16 conference. Re-enable after.
//if (participateStatus.equalsIgnoreCase("enabled") && studyStatus.equalsIgnoreCase("available") && pManageStatus.equalsIgnoreCase("ACTIVE")
if (participateStatus.equalsIgnoreCase("enabled") && studyStatus.equalsIgnoreCase("available")
&& ssBean.getStatus() == Status.AVAILABLE)
accessPermission = true;
}
return accessPermission;
}
public static String getAttachedFilePath(String studyOid) {
String attachedFilePath = CoreResources.getField("attached_file_location");
if (attachedFilePath == null || attachedFilePath.length() <= 0) {
attachedFilePath = CoreResources.getField("filePath") + "attached_files" + File.separator + studyOid + File.separator;
} else {
attachedFilePath += studyOid + File.separator;
}
return attachedFilePath;
}
private File processUploadedFile(FileItem item, String dirToSaveUploadedFileIn) {
dirToSaveUploadedFileIn = dirToSaveUploadedFileIn == null ? System.getProperty("java.io.tmpdir") : dirToSaveUploadedFileIn;
String fileName = item.getName();
// Some browsers IE 6,7 getName returns the whole path
int startIndex = fileName.lastIndexOf('\\');
if (startIndex != -1) {
fileName = fileName.substring(startIndex + 1, fileName.length());
}
File uploadedFile = new File(dirToSaveUploadedFileIn + File.separator + fileName);
try {
uploadedFile = new UploadFileServlet().new OCFileRename().rename(uploadedFile, item.getInputStream());
} catch (IOException e) {
throw new OpenClinicaSystemException(e.getMessage());
}
try {
item.write(uploadedFile);
} catch (Exception e) {
throw new OpenClinicaSystemException(e.getMessage());
}
return uploadedFile;
}
}