/*******************************************************************************
* Open Behavioral Health Information Technology Architecture (OBHITA.org)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package gov.samhsa.consent2share.web.controller;
import flexjson.JSONDeserializer;
import gov.samhsa.consent.ConsentGenException;
import gov.samhsa.consent2share.common.AuthenticatedUser;
import gov.samhsa.consent2share.common.UserContext;
import gov.samhsa.consent2share.domain.provider.IndividualProvider;
import gov.samhsa.consent2share.domain.provider.OrganizationalProvider;
import gov.samhsa.consent2share.domain.reference.EntityType;
import gov.samhsa.consent2share.infrastructure.CodedConceptLookupService;
import gov.samhsa.consent2share.infrastructure.PixService;
import gov.samhsa.consent2share.infrastructure.eventlistener.EventService;
import gov.samhsa.consent2share.infrastructure.security.AuthenticationFailedException;
import gov.samhsa.consent2share.infrastructure.security.EmailAddressNotExistException;
import gov.samhsa.consent2share.infrastructure.securityevent.FileDownloadedEvent;
import gov.samhsa.consent2share.service.account.pg.PatientExistingException;
import gov.samhsa.consent2share.service.admin.AdminService;
import gov.samhsa.consent2share.service.audit.AdminAuditService;
import gov.samhsa.consent2share.service.consent.ConsentHelper;
import gov.samhsa.consent2share.service.consent.ConsentNotFoundException;
import gov.samhsa.consent2share.service.consent.ConsentService;
import gov.samhsa.consent2share.service.dto.AbstractPdfDto;
import gov.samhsa.consent2share.service.dto.AddConsentFieldsDto;
import gov.samhsa.consent2share.service.dto.AddConsentIndividualProviderDto;
import gov.samhsa.consent2share.service.dto.AddConsentOrganizationalProviderDto;
import gov.samhsa.consent2share.service.dto.AdminCreatePatientResponseDto;
import gov.samhsa.consent2share.service.dto.AdminProfileDto;
import gov.samhsa.consent2share.service.dto.BasicPatientAccountDto;
import gov.samhsa.consent2share.service.dto.ConsentDto;
import gov.samhsa.consent2share.service.dto.ConsentListDto;
import gov.samhsa.consent2share.service.dto.ConsentPdfDto;
import gov.samhsa.consent2share.service.dto.ConsentRevokationPdfDto;
import gov.samhsa.consent2share.service.dto.ConsentValidationDto;
import gov.samhsa.consent2share.service.dto.IndividualProviderDto;
import gov.samhsa.consent2share.service.dto.OrganizationalProviderDto;
import gov.samhsa.consent2share.service.dto.PatientAdminDto;
import gov.samhsa.consent2share.service.dto.PatientConnectionDto;
import gov.samhsa.consent2share.service.dto.PatientProfileDto;
import gov.samhsa.consent2share.service.dto.RecentAcctivityDto;
import gov.samhsa.consent2share.service.dto.SpecificMedicalInfoDto;
import gov.samhsa.consent2share.service.dto.SystemNotificationDto;
import gov.samhsa.consent2share.service.patient.PatientNotFoundException;
import gov.samhsa.consent2share.service.patient.PatientService;
import gov.samhsa.consent2share.service.provider.HashMapResultToProviderDtoConverter;
import gov.samhsa.consent2share.service.provider.IndividualProviderService;
import gov.samhsa.consent2share.service.provider.OrganizationalProviderService;
import gov.samhsa.consent2share.service.provider.ProviderSearchLookupService;
import gov.samhsa.consent2share.service.reference.AdministrativeGenderCodeService;
import gov.samhsa.consent2share.service.reference.ClinicalDocumentTypeCodeService;
import gov.samhsa.consent2share.service.reference.LanguageCodeService;
import gov.samhsa.consent2share.service.reference.MaritalStatusCodeService;
import gov.samhsa.consent2share.service.reference.PurposeOfUseCodeService;
import gov.samhsa.consent2share.service.reference.RaceCodeService;
import gov.samhsa.consent2share.service.reference.ReligiousAffiliationCodeService;
import gov.samhsa.consent2share.service.reference.pg.StateCodeServicePg;
import gov.samhsa.consent2share.service.spirit.SpiritClientNotAvailableException;
import gov.samhsa.consent2share.service.systemnotification.SystemNotificationService;
import gov.samhsa.consent2share.service.validator.FieldValidator;
import gov.samhsa.consent2share.service.valueset.MedicalSectionService;
import gov.samhsa.consent2share.service.valueset.ValueSetCategoryService;
import gov.samhsa.consent2share.web.AjaxException;
import gov.samhsa.spirit.wsclient.adapter.SpiritConstants;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.mail.MessagingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import org.apache.commons.io.IOUtils;
import org.codehaus.jackson.map.ObjectMapper;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
/**
* The Class AdminController.
*/
@Controller
@RequestMapping("/Administrator")
public class AdminController extends AbstractController {
/** The patient service. */
@Autowired
PatientService patientService;
/** The admin service. */
@Autowired
AdminService adminService;
/** The consent service. */
@Autowired
ConsentService consentService;
/** The user context. */
@Autowired
UserContext adminUserContext;
/** The patient audit service. */
@Autowired
AdminAuditService adminAuditService;
/** The system notification service. */
@Autowired
SystemNotificationService systemNotificationService;
/** The individual provider service. */
@Autowired
IndividualProviderService individualProviderService;
/** The organizational provider service. */
@Autowired
OrganizationalProviderService organizationalProviderService;
/** The administrative gender code service. */
@Autowired
AdministrativeGenderCodeService administrativeGenderCodeService;
/** The language code service. */
@Autowired
LanguageCodeService languageCodeService;
/** The marital status code service. */
@Autowired
MaritalStatusCodeService maritalStatusCodeService;
/** The race code service. */
@Autowired
RaceCodeService raceCodeService;
/** The religious affiliation code service. */
@Autowired
ReligiousAffiliationCodeService religiousAffiliationCodeService;
/** The state code service. */
@Autowired
StateCodeServicePg stateCodeService;
/** The clinical document section type code service. */
@Autowired
private MedicalSectionService medicalSectionServiceImpl;
/** The clinical document type code service. */
@Autowired
private ClinicalDocumentTypeCodeService clinicalDocumentTypeCodeService;
/** The hippa space coded concept lookup service. */
@Autowired
private CodedConceptLookupService hippaSpaceCodedConceptLookupService;
/** The purpose of use code service. */
@Autowired
private PurposeOfUseCodeService purposeOfUseCodeService;
/** The value set category service. */
@Autowired
private ValueSetCategoryService valueSetCategoryService;
/** The field validator. */
@Autowired
private FieldValidator fieldValidator;
/** The provider search lookup service. */
@Autowired
private ProviderSearchLookupService providerSearchLookupService;
/** The consent helper. */
@Autowired
private ConsentHelper consentHelper;
/** The event service. */
@Autowired
private EventService eventService;
/** The maximum number of recent patient. */
int maximumNumberOfRecentPatient = 5;
/** The pix service. */
@Autowired
private PixService pixService;
/** The user context. */
@Autowired
private UserContext userContext;
/** The hash map result to provider dto converter. */
@Autowired
HashMapResultToProviderDtoConverter hashMapResultToProviderDtoConverter;
/** The logger. */
final Logger logger = LoggerFactory.getLogger(this.getClass());
/** The Constant NPI_LENGTH. */
public static final int NPI_LENGTH = 10;
/**
* Admin Home Page.
*
* @param model
* the model
* @param request
* the request
* @param basicPatientAccountDto
* the basic patient account dto
* @return the string
*/
@RequestMapping(value = "adminHome.html")
public String adminHome(Model model, HttpServletRequest request,
BasicPatientAccountDto basicPatientAccountDto) {
AuthenticatedUser currentUser = adminUserContext.getCurrentUser();
String notify = request.getParameter("notify");
List<RecentAcctivityDto> recentActivityDtos = adminAuditService
.findAdminHistoryByUsername(currentUser.getUsername());
AdminProfileDto adminProfileDto = adminService
.findAdminProfileByUsername(currentUser.getUsername());
model.addAttribute("adminProfileDto", adminProfileDto);
model.addAttribute("administrativeGenderCodes",
administrativeGenderCodeService
.findAllAdministrativeGenderCodes());
model.addAttribute("notifyevent", notify);
model.addAttribute("recentActivityDtos", recentActivityDtos);
return "views/Administrator/adminHome";
}
/**
* Admin Patient View Page.
*
* @param model
* the model
* @param patientId
* the patient id
* @param userName
* the user name
* @param notify
* the notify
* @param status
* the status
* @param duplicateConsent
* the duplicate consent
* @return the string
*/
@RequestMapping(value = "adminPatientView.html")
public String adminPatientViewByPatientId(
Model model,
@RequestParam(value = "id", required = false, defaultValue = "-1") long patientId,
@RequestParam(value = "username", required = false) String userName,
@RequestParam(value = "notify", required = false) String notify,
@RequestParam(value = "status", required = false) String status,
@RequestParam(value = "duplicateconsent", required = false) String duplicateConsent) {
PatientProfileDto patientProfileDto;
List<ConsentListDto> consentListDto;
List<SystemNotificationDto> systemNotificationDtos = null;
PatientConnectionDto patientConnectionDto = null;
if (patientId != -1) {
patientProfileDto = patientService.findPatient(patientId);
consentListDto = consentService
.findAllConsentsDtoByPatient(patientId);
patientConnectionDto = patientService
.findPatientConnectionById(patientId);
systemNotificationDtos = systemNotificationService
.findAllSystemNotificationDtosByPatient(patientId);
if (duplicateConsent != null) {
model.addAttribute("duplicate_consent_id", duplicateConsent);
}
} else if (userName != null) {
patientProfileDto = patientService.findByUsername(userName);
consentListDto = consentService
.findAllConsentsDtoByUserName(userName);
} else {
return "redirect:adminHome.html";
}
AuthenticatedUser currentUser = adminUserContext.getCurrentUser();
AdminProfileDto adminProfileDto = adminService
.findAdminProfileByUsername(currentUser.getUsername());
Set<String> npiList = new HashSet<String>();
for (IndividualProviderDto individualProviderDto : patientConnectionDto
.getIndividualProviders()) {
npiList.add(individualProviderDto.getNpi());
}
for (OrganizationalProviderDto organizationalProviderDto : patientConnectionDto
.getOrganizationalProviders()) {
npiList.add(organizationalProviderDto.getNpi());
}
model.addAttribute("npiList", npiList);
model.addAttribute("adminProfileDto", adminProfileDto);
model.addAttribute("individualProviders",
patientConnectionDto.getIndividualProviders());
model.addAttribute("organizationalProviders",
patientConnectionDto.getOrganizationalProviders());
model.addAttribute("patientProfileDto", patientProfileDto);
model.addAttribute("consentListDto", consentListDto);
model.addAttribute("systemNotificationDtos", systemNotificationDtos);
model.addAttribute("notifyEvent", notify);
model.addAttribute("statusEvent", status);
populateLookupCodes(model);
return "views/Administrator/adminPatientView";
}
/**
* Submit Consent.
*
* @param consentId
* the consent id
* @param patientId
* the patient id
* @return string
*/
@RequestMapping(value = "adminPatientViewSubmitConsent.html", method = RequestMethod.POST)
public String adminPatientViewSubmitConsent(
@RequestParam(value = "consentId") long consentId,
@RequestParam(value = "patientId") long patientId) {
ConsentPdfDto consentPdfDto = consentService
.findConsentPdfDto(consentId);
if (consentService.isConsentBelongToThisUser(consentId, patientId)) {
if (consentService.signConsent(consentPdfDto) == true)
;
return "redirect:adminPatientView.html?notify=submit&status=success&id="
+ patientId;
} else {
logger.warn("Unable to submit consent...");
logger.warn("...consentService.signConsent(consentPdfDto) did not return true.");
return "redirect:adminPatientView.html?notify=submit&status=fail&id="
+ patientId;
}
}
/**
* Delete consent.
*
* @param consentId
* the consent id
* @param patientId
* the patient id
* @return the string
*/
@RequestMapping(value = "adminPatientViewDeleteConsent", method = RequestMethod.POST)
public String adminPatientViewDeleteConsent(
@RequestParam(value = "consentId") long consentId,
@RequestParam(value = "patientId") long patientId) {
boolean isDeleteSuccess = false;
if (consentService.isConsentBelongToThisUser(consentId, patientId)) {
isDeleteSuccess = consentService.deleteConsent(consentId);
return "redirect:adminPatientView.html?notify=delete&status=success&id="
+ patientId;
} else {
logger.warn("Unable to delete consent...");
logger.warn("...consentService.deleteConsent(consentId) did not return true.");
return "redirect:adminPatientView.html?notify=delete&status=fail&id="
+ patientId;
}
}
/**
* Admin edit patient profile.
*
* @param patientProfileDto
* the patient profile dto
* @param bindingResult
* the binding result
* @param model
* the model
* @return the string
*/
@RequestMapping(value = "adminEditPatientProfile.html", method = RequestMethod.POST)
public String adminEditPatientProfile(
@Valid PatientProfileDto patientProfileDto,
BindingResult bindingResult, Model model) {
fieldValidator.validate(patientProfileDto, bindingResult);
Long patientId = patientProfileDto.getId();
if (bindingResult.hasErrors()) {
return "redirect:/Administrator/adminPatientView.html?notify=editpatientprofile&status=fail&id="
+ patientId;
} else {
patientProfileDto
.setAddressCountryCode(SpiritConstants.C2S_PATIENT_COUNTRY);
PatientProfileDto updatepatientProfileDto = patientService
.findPatient(patientId);
patientProfileDto
.setUsername(updatepatientProfileDto.getUsername());
patientProfileDto.setEnterpriseIdentifier(updatepatientProfileDto
.getEnterpriseIdentifier());
patientProfileDto.setMedicalRecordNumber(updatepatientProfileDto
.getMedicalRecordNumber());
try {
adminService.updatePatient(patientProfileDto);
} catch (SpiritClientNotAvailableException e) {
logger.error("Spirit Client not available");
return "redirect:/Administrator/adminPatientView.html?notify=editpatientprofile&status=fail&id="
+ patientId;
}
return "redirect:/Administrator/adminPatientView.html?notify=editpatientprofile&status=success&id="
+ patientId;
}
}
/**
* Admin Patient View Create Consent Page.
*
* @param patientId
* the patient id
* @param model
* the model
* @return the string
*/
@RequestMapping(value = "adminPatientViewCreateConsent.html")
public String adminPatientViewCreateConsent(
@RequestParam(value = "id", defaultValue = "-1") long patientId,
Model model) {
if (patientId <= -1) {
throw new IllegalArgumentException(
"Invalid id passed in query string to adminPatientViewCreateConsent.html");
} else {
PatientProfileDto currentPatient = patientService
.findPatient(patientId);
if (currentPatient == null) {
throw new PatientNotFoundException("Patient not found by id");
}
List<AddConsentIndividualProviderDto> individualProvidersDto = patientService
.findAddConsentIndividualProviderDtoByPatientId(patientId);
List<AddConsentOrganizationalProviderDto> organizationalProvidersDto = patientService
.findAddConsentOrganizationalProviderDtoByPatientId(patientId);
ConsentDto consentDto = consentService.makeConsentDto();
consentDto.setUsername(currentPatient.getUsername());
DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
Calendar today = Calendar.getInstance();
Calendar oneYearFromNow = Calendar.getInstance();
oneYearFromNow.add(Calendar.YEAR, 1);
List<AddConsentFieldsDto> sensitivityPolicyDto = valueSetCategoryService
.findAllValueSetCategoriesAddConsentFieldsDto();
List<AddConsentFieldsDto> purposeOfUseDto = purposeOfUseCodeService
.findAllPurposeOfUseCodesAddConsentFieldsDto();
List<AddConsentFieldsDto> clinicalDocumentSectionTypeDto = medicalSectionServiceImpl
.findAllMedicalSectionsAddConsentFieldsDto();
List<AddConsentFieldsDto> clinicalDocumentTypeDto = clinicalDocumentTypeCodeService
.findAllClinicalDocumentTypeCodesAddConsentFieldsDto();
populateLookupCodes(model);
AuthenticatedUser currentUser = adminUserContext.getCurrentUser();
AdminProfileDto adminProfileDto = adminService
.findAdminProfileByUsername(currentUser.getUsername());
model.addAttribute("adminProfileDto", adminProfileDto);
model.addAttribute("defaultStartDate",
dateFormat.format(today.getTime()));
model.addAttribute("defaultEndDate",
dateFormat.format(oneYearFromNow.getTime()));
model.addAttribute("patientId", currentPatient.getId());
model.addAttribute("patient_lname", currentPatient.getLastName());
model.addAttribute("patient_fname", currentPatient.getFirstName());
model.addAttribute("consentDto", consentDto);
model.addAttribute("individualProvidersDto", individualProvidersDto);
model.addAttribute("clinicalDocumentSectionType",
clinicalDocumentSectionTypeDto);
model.addAttribute("clinicalDocumentType", clinicalDocumentTypeDto);
model.addAttribute("sensitivityPolicy", sensitivityPolicyDto);
model.addAttribute("purposeOfUse", purposeOfUseDto);
model.addAttribute("organizationalProvidersDto",
organizationalProvidersDto);
model.addAttribute("addConsent", true);
model.addAttribute("isProviderAdminUser", true);
return "views/Administrator/adminPatientViewCreateConsent";
}
}
/**
* Admin patient view create consent.
*
* @param consentDto
* the consent dto
* @param patientId
* the patient id
* @param bindingResult
* the binding result
* @param model
* the model
* @param icd9
* the icd9
* @param isAddConsent
* the is add consent
* @return the string
* @throws ConsentGenException
* the consent gen exception
* @throws IOException
* Signals that an I/O exception has occurred.
* @throws JSONException
* the JSON exception
*/
@RequestMapping(value = "adminPatientViewCreateConsent.html", method = RequestMethod.POST)
public @ResponseBody String adminPatientViewCreateConsent(
@Valid ConsentDto consentDto,
@RequestParam("patientId") long patientId,
BindingResult bindingResult,
Model model,
@RequestParam(value = "ICD9", required = false) HashSet<String> icd9,
@RequestParam(value = "isAddConsent") boolean isAddConsent)
throws ConsentGenException, IOException, JSONException {
Set<String> isMadeTo = new HashSet<String>();
Set<String> isMadeFrom = new HashSet<String>();
consentDto.setConsentEnd(consentHelper.setDateAsEndOfDay(consentDto
.getConsentEnd()));
if (consentDto.getOrganizationalProvidersDisclosureIsMadeTo() != null)
isMadeTo.addAll(consentDto
.getOrganizationalProvidersDisclosureIsMadeTo());
if (consentDto.getProvidersDisclosureIsMadeTo() != null)
isMadeTo.addAll(consentDto.getProvidersDisclosureIsMadeTo());
if (consentDto.getOrganizationalProvidersPermittedToDisclose() != null)
isMadeFrom.addAll(consentDto
.getOrganizationalProvidersPermittedToDisclose());
if (consentDto.getProvidersPermittedToDisclose() != null)
isMadeFrom.addAll(consentDto.getProvidersPermittedToDisclose());
if ((!isMadeTo.isEmpty())
&& (!isMadeFrom.isEmpty())
&& consentService.areThereDuplicatesInTwoSets(isMadeTo,
isMadeFrom) == false) {
// one to one policy validation
if (isMadeTo.size() != 1 || isMadeFrom.size() != 1) {
throw new AjaxException(HttpStatus.UNPROCESSABLE_ENTITY,
"Only one provider can select from the list");
}
Set<SpecificMedicalInfoDto> doNotShareClinicalConceptCodes = new HashSet<SpecificMedicalInfoDto>();
if (icd9 != null)
doNotShareClinicalConceptCodes = consentHelper
.getDoNotShareClinicalConceptCodes(icd9);
consentDto
.setDoNotShareClinicalConceptCodes(doNotShareClinicalConceptCodes);
Object obj = null;
try {
obj = consentService.saveConsent(consentDto, patientId);
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new AjaxException(HttpStatus.INTERNAL_SERVER_ERROR,
"Failed to save the consent, please try again later.");
}
if (null != obj && obj instanceof ConsentValidationDto) {
// duplicate policy found
ObjectMapper mapper = new ObjectMapper();
throw new AjaxException(HttpStatus.CONFLICT,
mapper.writeValueAsString(obj));
}
JSONObject succObj = new JSONObject();
succObj.put("isSuccess", true);
succObj.put("isAdmin", true);
succObj.put("patientId", patientId);
if (isAddConsent == false) {
succObj.put("isAdd", false);
} else {
succObj.put("isAdd", true);
}
return succObj.toString();
} else {
throw new AjaxException(HttpStatus.INTERNAL_SERVER_ERROR,
"Resource Not Found");
}
}
/**
* Sign consent revokation.
*
* @param consentId
* the consent id
* @param revokationType
* the revokation type
* @param patientId
* the patient id
* @return the string
*/
@RequestMapping(value = "adminPatientViewRevokeConsent.html", method = RequestMethod.POST)
public String signConsentRevokation(
@RequestParam("consentId") long consentId,
@RequestParam("revokationType") String revokationType,
@RequestParam("patientId") long patientId) {
consentService.addUnsignedConsentRevokationPdf(consentId,
revokationType);
ConsentRevokationPdfDto consentRevokationPdfDto = consentService
.findConsentRevokationPdfDto(consentId);
consentRevokationPdfDto.setRevokationType(revokationType);
if (consentService.isConsentBelongToThisUser(consentId, patientId)) {
consentService.signConsentRevokation(consentRevokationPdfDto);
return "redirect:adminPatientView.html?notify=revokepatientconsent&status=success&id="
+ patientId;
}
return "redirect:adminPatientView.html?notify=revokepatientconsent&status=fail&id="
+ patientId;
}
/**
* Admin Patient View Edit Consent Page.
*
* @param consentId
* the consent id
* @param patientId
* the patient id
* @param model
* the model
* @return the string
*/
@RequestMapping(value = "adminPatientViewEditConsent.html")
public String adminPatientViewEditConsent(
@RequestParam(value = "consentId", defaultValue = "-1") long consentId,
@RequestParam("patientId") long patientId, Model model) {
if (consentId <= -1) {
throw new IllegalArgumentException(
"Invalid id passed in query string to adminPatientViewEditConsent.html");
} else {
ConsentDto consentDto = consentService.findConsentById(consentId);
if (consentDto == null) {
throw new ConsentNotFoundException("Consent not found by id");
}
PatientProfileDto currentPatient = patientService
.findPatient(patientId);
if (currentPatient == null) {
throw new PatientNotFoundException(
"Patient not found by username");
}
List<AddConsentIndividualProviderDto> individualProvidersDto = patientService
.findAddConsentIndividualProviderDtoByPatientId(patientId);
List<AddConsentOrganizationalProviderDto> organizationalProvidersDto = patientService
.findAddConsentOrganizationalProviderDtoByPatientId(patientId);
DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
Calendar today = Calendar.getInstance();
Calendar oneYearFromNow = Calendar.getInstance();
oneYearFromNow.add(Calendar.YEAR, 1);
List<AddConsentFieldsDto> sensitivityPolicyDto = valueSetCategoryService
.findAllValueSetCategoriesAddConsentFieldsDto();
List<AddConsentFieldsDto> purposeOfUseDto = purposeOfUseCodeService
.findAllPurposeOfUseCodesAddConsentFieldsDto();
List<AddConsentFieldsDto> clinicalDocumentSectionTypeDto = medicalSectionServiceImpl
.findAllMedicalSectionsAddConsentFieldsDto();
List<AddConsentFieldsDto> clinicalDocumentTypeDto = clinicalDocumentTypeCodeService
.findAllClinicalDocumentTypeCodesAddConsentFieldsDto();
populateLookupCodes(model);
AuthenticatedUser currentUser = adminUserContext.getCurrentUser();
AdminProfileDto adminProfileDto = adminService
.findAdminProfileByUsername(currentUser.getUsername());
model.addAttribute("adminProfileDto", adminProfileDto);
model.addAttribute("defaultStartDate",
dateFormat.format(today.getTime()));
model.addAttribute("defaultEndDate",
dateFormat.format(oneYearFromNow.getTime()));
model.addAttribute("patientId", currentPatient.getId());
model.addAttribute("patient_lname", currentPatient.getLastName());
model.addAttribute("patient_fname", currentPatient.getFirstName());
model.addAttribute("consentDto", consentDto);
model.addAttribute("individualProvidersDto", individualProvidersDto);
model.addAttribute("clinicalDocumentSectionType",
clinicalDocumentSectionTypeDto);
model.addAttribute("clinicalDocumentType", clinicalDocumentTypeDto);
model.addAttribute("sensitivityPolicy", sensitivityPolicyDto);
model.addAttribute("purposeOfUse", purposeOfUseDto);
model.addAttribute("organizationalProvidersDto",
organizationalProvidersDto);
model.addAttribute("addConsent", false);
model.addAttribute("isProviderAdminUser", true);
return "views/Administrator/adminPatientViewCreateConsent";
}
}
/**
* Edits the admin profile.
*
* @param model
* the model
* @return the string
*/
@RequestMapping(value = "editAdminProfile.html")
public String editAdminProfile(Model model) {
AuthenticatedUser currentUser = adminUserContext.getCurrentUser();
AdminProfileDto adminProfileDto = adminService
.findAdminProfileByUsername(currentUser.getUsername());
model.addAttribute("adminProfileDto", adminProfileDto);
model.addAttribute("currentUser", currentUser);
populateLookupCodes(model);
return "views/Administrator/editAdminProfile";
}
@RequestMapping(value = "adminReports.html")
public String adminReports(Model model) {
AuthenticatedUser currentUser = adminUserContext.getCurrentUser();
AdminProfileDto adminProfileDto = adminService
.findAdminProfileByUsername(currentUser.getUsername());
model.addAttribute("adminProfileDto", adminProfileDto);
return "views/Administrator/adminReports";
}
/**
* Profile.
*
* @param adminProfileDto
* the admin profile dto
* @param bindingResult
* the binding result
* @param model
* the model
* @return the string
*/
@RequestMapping(value = "editAdminProfile.html", method = RequestMethod.POST)
public String profile(@Valid AdminProfileDto adminProfileDto,
BindingResult bindingResult, Model model) {
fieldValidator.validate(adminProfileDto, bindingResult);
if (bindingResult.hasErrors()) {
populateLookupCodes(model);
return "views/Administrator/editAdminProfile";
} else {
AuthenticatedUser currentUser = adminUserContext.getCurrentUser();
model.addAttribute("currentUser", currentUser);
try {
adminService.updateAdministrator(adminProfileDto);
model.addAttribute("updatedMessage",
"Updated your profile successfully!");
} catch (AuthenticationFailedException e) {
model.addAttribute("updatedMessage",
"Failed. Please check your username and password and try again.");
AdminProfileDto originalAdminProfileDto = adminService
.findAdminProfileByUsername(currentUser.getUsername());
model.addAttribute("adminProfileDto", originalAdminProfileDto);
}
populateLookupCodes(model);
return "views/Administrator/editAdminProfile";
}
}
/**
* Download consent pdf file.
*
* @param request
* the request
* @param response
* the response
* @param consentId
* the consent id
* @return the string
*/
@RequestMapping(value = "/downloadPdf.html", method = RequestMethod.GET)
public String downloadConsentPdfFile(HttpServletRequest request,
HttpServletResponse response,
@RequestParam("consentId") long consentId) {
AbstractPdfDto pdfDto = consentService.findConsentContentDto(consentId);
try {
OutputStream out = response.getOutputStream();
response.setContentType("application/pdf");
IOUtils.copy(new ByteArrayInputStream(pdfDto.getContent()), out);
out.flush();
out.close();
eventService.raiseSecurityEvent(new FileDownloadedEvent(request
.getRemoteAddr(), "Admin_User_"
+ userContext.getCurrentUser().getUsername(), "Consent_"
+ consentId));
} catch (IOException e) {
logger.warn("Error while reading pdf file.");
logger.warn("The exception is: ", e);
}
return null;
}
/**
* NOTE: THIS FUNCTION IS A TEMPORARY FUNCTION TO PROCESS THE ADMIN CREATE
* PATIENT ACCOUNT FORM WHEN IT IS SUBMITTED. THIS FUNCTION MUST BE MODIFIED
* BEFORE IT IS INTEGREATED WITH THE BACK-END CODE.
*
* @param basicPatientAccountDto
* the basic patient account dto
* @param result
* the result
* @param redirectAttributes
* the redirect attributes
* @param model
* the model
* @return the string
* @throws PatientExistingException
* the patient existing exception
*/
@RequestMapping(value = "adminCreatePatientAccount.html", method = RequestMethod.POST)
public String adminCreatePatientAccount(
@Valid BasicPatientAccountDto basicPatientAccountDto,
BindingResult result, RedirectAttributes redirectAttributes,
Model model) throws PatientExistingException {
fieldValidator.validate(basicPatientAccountDto, result);
if (result.hasErrors()) {
redirectAttributes.addFlashAttribute("basicPatientAccountDto",
basicPatientAccountDto);
redirectAttributes.addFlashAttribute("notify",
"createPatientFailed");
return "redirect:/Administrator/adminHome.html";
}
try {
AdminCreatePatientResponseDto response = adminService
.createPatientAccount(basicPatientAccountDto);
return "redirect:/Administrator/adminPatientView.html?id="
+ response.getPatientId() + "&status="
+ response.getMessage();
} catch (SpiritClientNotAvailableException e) {
redirectAttributes.addFlashAttribute("basicPatientAccountDto",
basicPatientAccountDto);
redirectAttributes.addFlashAttribute("notify",
"createPatientFailed");
return "redirect:/Administrator/adminHome.html";
}
}
/**
* Admin send login info email.
*
* @param patientId
* the patient id
* @param request
* the request
* @return the string
*/
@RequestMapping(value = "sendLoginInformation.html", method = RequestMethod.GET)
public @ResponseBody String adminSendLoginInfoEmail(
@RequestParam("patientId") long patientId,
HttpServletRequest request) {
try {
String linkUrl = getServletUrl(request);
adminService.sendLoginInformationEmail(patientId, linkUrl);
return "Login information has been sent to email.";
} catch (EmailAddressNotExistException e) {
throw new AjaxException(HttpStatus.INTERNAL_SERVER_ERROR,
"Email Address is not exist.");
} catch (MessagingException e) {
throw new AjaxException(HttpStatus.INTERNAL_SERVER_ERROR,
"Message is not available, please click later");
}
}
/**
* Gets the servlet url.
*
* @param request
* the request
* @return the servlet url
*/
private String getServletUrl(HttpServletRequest request) {
String scheme = request.getScheme();
String serverName = request.getServerName();
int serverPort = request.getServerPort();
String contextPath = request.getContextPath();
StringBuffer hostName = new StringBuffer();
hostName.append(scheme).append("://").append(serverName);
if ((serverPort != 80) && (serverPort != 443)) {
hostName.append(":").append(serverPort);
}
hostName.append(contextPath);
return hostName.toString();
}
/**
* Gets the patient by first and last name.
*
* @param token
* the token
* @return the by first and last name
*/
@RequestMapping("/patientlookup/query")
@ResponseStatus(HttpStatus.OK)
public @ResponseBody List<PatientAdminDto> getByFirstAndLastName(
@RequestParam(value = "token", required = true) String token) {
String[] tokens = token.split("\\s*(=>|,|\\s)\\s*");
return patientService.findAllPatientByFirstNameAndLastName(tokens);
}
/**
* Search for a provider.
*
* @param npi
* the npi
* @param patientUserName
* the patient user name
* @param patientId
* the patient id
* @return the string
*/
/*
* TODO: Remove patientusername from list of @RequestParam's, and from all
* calls to this function from other files
*/
@RequestMapping(value = "connectionProviderAdd.html", method = RequestMethod.POST)
public @ResponseBody String addProvider(
@RequestParam("npi") String npi,
@RequestParam(value = "patientusername", defaultValue = "") String patientUserName,
@RequestParam("patientId") String patientId) {
OrganizationalProvider organizationalProviderReturned = null;
IndividualProvider individualProviderReturned = null;
boolean isOrgProvider = false;
try {
patientUserName = patientService.findUsernameById(Long.valueOf(
patientId).longValue());
} catch (IllegalArgumentException e) {
/*
* this catches the exception thrown by Long.valueOf() in case the
* input patientId string value cannot be converted to a long type,
* and then throws an AjaxException to trigger the 400 HTTP Status
* Code error to be returned to the client-side Ajax listener
*/
throw new AjaxException(
HttpStatus.BAD_REQUEST,
"Unable to add this new provider because the request parameters contained invalid data.");
}
if (npi.length() == NPI_LENGTH && npi.matches("[0-9]+")) {
String qureryResult = providerSearchLookupService
.providerSearchByNpi(npi);
HashMap<String, String> result = deserializeResult(qureryResult);
if ((EntityType.valueOf(result.get("entityType")) == EntityType.Organization)) {
isOrgProvider = true;
OrganizationalProviderDto providerDto = new OrganizationalProviderDto();
hashMapResultToProviderDtoConverter.setProviderDto(providerDto,
result);
providerDto.setOrgName(result.get("providerOrganizationName"));
providerDto.setAuthorizedOfficialLastName(result
.get("authorizedOfficialLastName"));
providerDto.setAuthorizedOfficialFirstName(result
.get("authorizedOfficialFirstName"));
providerDto.setAuthorizedOfficialTitle(result
.get("authorizedOfficialTitleorPosition"));
providerDto.setAuthorizedOfficialNamePrefix(result
.get("authorizedOfficialNamePrefixText"));
providerDto.setAuthorizedOfficialTelephoneNumber(result
.get("authorizedOfficialTelephoneNumber"));
providerDto.setUsername(patientUserName);
providerDto.setPatientId(patientId);
organizationalProviderReturned = organizationalProviderService
.addNewOrganizationalProvider(providerDto);
} else {
isOrgProvider = false;
IndividualProviderDto providerDto = new IndividualProviderDto();
hashMapResultToProviderDtoConverter.setProviderDto(providerDto,
result);
providerDto.setFirstName(result.get("providerFirstName"));
providerDto.setMiddleName(result.get("providerMiddleName"));
providerDto.setLastName(result.get("providerLastName"));
providerDto.setNamePrefix(result.get("providerNamePrefixText"));
providerDto.setNameSuffix(result.get("providerNameSuffixText"));
providerDto.setCredential(result.get("providerCredentialText"));
providerDto.setUsername(patientUserName);
providerDto.setPatientId(patientId);
individualProviderReturned = individualProviderService
.addNewIndividualProvider(providerDto);
}
}
if (isOrgProvider == true) {
if (organizationalProviderReturned != null) {
return organizationalProviderReturned.getId().toString();
} else {
throw new AjaxException(HttpStatus.INTERNAL_SERVER_ERROR,
"Unable to add this new provider because this provider already exists.");
}
} else {
if (individualProviderReturned != null) {
return individualProviderReturned.getId().toString();
} else {
throw new AjaxException(HttpStatus.INTERNAL_SERVER_ERROR,
"Unable to add this new provider because this provider already exists.");
}
}
}
/**
* Delete Individual Provider.
*
* @param individualProviderid
* the individual providerid
* @param patientId
* the patient id
* @param model
* the model
* @return the string
*/
@RequestMapping(value = "/deleteIndividualProvider", method = RequestMethod.POST)
public @ResponseBody String deleteIndividualProvider(
@RequestParam("individualProviderid") long individualProviderid,
@RequestParam("patientId") String patientId, Model model) {
PatientConnectionDto patientConnectionDto = null;
IndividualProviderDto individualProviderDto = null;
try {
patientConnectionDto = patientService
.findPatientConnectionById(Long.valueOf(patientId)
.longValue());
} catch (Exception e) {
logger.error("Unable to delete individual provider: PatientConnectionDto could not be found for specified patientId...");
logger.error("...STACK TRACE: ", e);
throw new AjaxException(HttpStatus.INTERNAL_SERVER_ERROR,
"ERROR: Unable to delete this provider.");
}
Set<IndividualProviderDto> individualProviderDtos = patientConnectionDto
.getIndividualProviders();
for (IndividualProviderDto cur_individualProviderDto : individualProviderDtos) {
if (Long.toString(individualProviderid).compareTo(
cur_individualProviderDto.getId()) == 0) {
individualProviderDto = cur_individualProviderDto;
individualProviderDto.setPatientId(patientId);
break;
}
}
if (individualProviderDto == null) {
logger.error("Unable to delete individual provider: IndividualProviderDto could not be found in PatientConnectionDto for specified individualProviderId.");
throw new AjaxException(HttpStatus.INTERNAL_SERVER_ERROR,
"ERROR: Unable to delete this provider.");
}
if (individualProviderDto.isDeletable() == false) {
logger.info("Unable to delete specifed individual provider from patient account because it is currently used in a consent for that patient.");
throw new AjaxException(
HttpStatus.CONFLICT,
"Unable to delete this provider because it is currently used in one or more of your consents.");
}
try {
individualProviderService
.deleteIndividualProviderDtoByPatientId(individualProviderDto);
} catch (Exception e) {
logger.error("Unable to delete individual provider...");
logger.error("...STACK TRACE", e);
throw new AjaxException(HttpStatus.INTERNAL_SERVER_ERROR,
"ERROR: Unable to delete this provider.");
}
return "Success";
}
/**
* Delete organizational provider.
*
* @param organizationalProviderid
* the organizational providerid
* @param patientId
* the patient id
* @param model
* the model
* @return the string
*/
@RequestMapping(value = "/deleteOrganizationalProvider", method = RequestMethod.POST)
public @ResponseBody String deleteOrganizationalProvider(
@RequestParam("organizationalProviderid") long organizationalProviderid,
@RequestParam("patientId") String patientId, Model model) {
PatientConnectionDto patientConnectionDto = null;
OrganizationalProviderDto organizationalProviderDto = null;
try {
patientConnectionDto = patientService
.findPatientConnectionById(Long.valueOf(patientId)
.longValue());
} catch (Exception e) {
logger.error("Unable to delete organazational provider: PatientConnectionDto could not be found for specified patientId...");
logger.error("...STACK TRACE: ", e);
throw new AjaxException(HttpStatus.INTERNAL_SERVER_ERROR,
"ERROR: Unable to delete this provider.");
}
Set<OrganizationalProviderDto> organizationalProviderDtos = patientConnectionDto
.getOrganizationalProviders();
for (OrganizationalProviderDto cur_organizationalProviderDto : organizationalProviderDtos) {
if (Long.toString(organizationalProviderid).compareTo(
cur_organizationalProviderDto.getId()) == 0) {
organizationalProviderDto = cur_organizationalProviderDto;
organizationalProviderDto.setPatientId(patientId);
break;
}
}
if (organizationalProviderDto == null) {
logger.error("Unable to delete organazational provider: OrganizationalProviderDto could not be found in PatientConnectionDto for specified organizationalProviderId.");
throw new AjaxException(HttpStatus.INTERNAL_SERVER_ERROR,
"ERROR: Unable to delete this provider.");
}
if (organizationalProviderDto.isDeletable() == false) {
logger.info("Unable to delete specifed organizational provider from patient account because it is currently used in a consent for that patient.");
throw new AjaxException(
HttpStatus.CONFLICT,
"Unable to delete this provider because it is currently used in one or more of your consents.");
}
try {
organizationalProviderService
.deleteOrganizationalProviderDtoByPatientId(organizationalProviderDto);
} catch (Exception e) {
logger.error("Unable to delete organazational provider...");
logger.error("...STACK TRACE", e);
throw new AjaxException(HttpStatus.INTERNAL_SERVER_ERROR,
"ERROR: Unable to delete this provider.");
}
return "Success";
}
/**
* AJAX search for a provider.
*
* @param request
* the request
* @param response
* the response
* @return the string
*/
@RequestMapping(value = "providerSearch.html", method = RequestMethod.GET)
public String ajaxProviderSearch(HttpServletRequest request,
HttpServletResponse response) {
try {
response.setHeader("Content-Type", "application/json");
OutputStream out = response.getOutputStream();
String usstate = request.getParameter("usstate");
String city = request.getParameter("city");
String zipcode = request.getParameter("zipcode");
String gender = request.getParameter("gender");
String specialty = request.getParameter("specialty");
String phone = request.getParameter("phone");
String firstname = request.getParameter("firstname");
String lastname = request.getParameter("lastname");
String orgname = request.getParameter("facilityname");
int pageNumber = Integer.parseInt(request
.getParameter("pageNumber"));
if (providerSearchLookupService.isValidatedSearch(usstate, city,
zipcode, gender, specialty, phone, firstname, lastname,
orgname) == true) {
IOUtils.copy(
new ByteArrayInputStream(providerSearchLookupService
.providerSearch(usstate, city, zipcode, gender,
specialty, phone, firstname, lastname,
orgname, pageNumber).getBytes()), out);
out.flush();
out.close();
}
} catch (IOException e) {
logger.error(
"Error when calling provider search. The exception is:", e);
}
return null;
}
/**
* Populate lookup codes.
*
* @param model
* the model
*/
private void populateLookupCodes(Model model) {
model.addAttribute("administrativeGenderCodes",
administrativeGenderCodeService
.findAllAdministrativeGenderCodes());
model.addAttribute("maritalStatusCodes",
maritalStatusCodeService.findAllMaritalStatusCodes());
model.addAttribute("religiousAffiliationCodes",
religiousAffiliationCodeService
.findAllReligiousAffiliationCodes());
model.addAttribute("raceCodes", raceCodeService.findAllRaceCodes());
model.addAttribute("languageCodes",
languageCodeService.findAllLanguageCodes());
// Fix issue #529 start
// the search for state only display MD, DC and Virginia states
model.addAttribute("stateCodes",
stateCodeService.findByMDAndDCAndVAStates());
// Fix issue #529 end
model.addAttribute("stateCodes_Edit",
stateCodeService.findAllStateCodes());
}
/**
* Deserialize result.
*
* @param providerDtoJSON
* the provider dto json
* @return the hash map
*/
public HashMap<String, String> deserializeResult(String providerDtoJSON) {
return new JSONDeserializer<HashMap<String, String>>()
.deserialize(providerDtoJSON);
}
/**
* Gets the remote address.
*
* @param request
* the request
* @return the remote address
*/
String getRemoteAddress(HttpServletRequest request) {
return request.getRemoteAddr();
}
}