/*******************************************************************************
* 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.service.admin;
import gov.samhsa.consent2share.common.AuthenticatedUser;
import gov.samhsa.consent2share.common.UniqueValueGeneratorException;
import gov.samhsa.consent2share.common.UserContext;
import gov.samhsa.consent2share.domain.account.EmailToken;
import gov.samhsa.consent2share.domain.account.EmailTokenRepository;
import gov.samhsa.consent2share.domain.account.TokenGenerator;
import gov.samhsa.consent2share.domain.account.TokenType;
import gov.samhsa.consent2share.domain.account.Users;
import gov.samhsa.consent2share.domain.account.UsersRepository;
import gov.samhsa.consent2share.domain.commondomainservices.EmailSender;
import gov.samhsa.consent2share.domain.commondomainservices.EmailType;
import gov.samhsa.consent2share.domain.patient.Patient;
import gov.samhsa.consent2share.domain.patient.PatientRepository;
import gov.samhsa.consent2share.domain.reference.AdministrativeGenderCode;
import gov.samhsa.consent2share.domain.reference.AdministrativeGenderCodeRepository;
import gov.samhsa.consent2share.domain.staff.Staff;
import gov.samhsa.consent2share.domain.staff.StaffRepository;
import gov.samhsa.consent2share.infrastructure.DtoToDomainEntityMapper;
import gov.samhsa.consent2share.infrastructure.PixService;
import gov.samhsa.consent2share.infrastructure.security.AuthenticationFailedException;
import gov.samhsa.consent2share.infrastructure.security.EmailAddressNotExistException;
import gov.samhsa.consent2share.pixclient.util.PixManagerBean;
import gov.samhsa.consent2share.service.account.MrnService;
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.PatientProfileDto;
import gov.samhsa.consent2share.service.util.TypeConverter;
import java.util.Date;
import java.util.UUID;
import javax.mail.MessagingException;
import org.modelmapper.ModelMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
/**
* The Class AdminServiceImpl.
*/
@Transactional
public class AdminServiceImpl implements AdminService {
/** The logger. */
private final Logger logger = LoggerFactory.getLogger(this.getClass());
/** The account verification token expire in hours. */
protected Integer accountVerificationTokenExpireInHours;
/** The Administrator repository. */
protected StaffRepository administratorRepository;
/** The patient repository. */
protected PatientRepository patientRepository;
/** The patient profile dto to patient mapper. */
protected DtoToDomainEntityMapper<PatientProfileDto, Patient> patientProfileDtoToPatientMapper;
/** The admin profile dto to administrator mapper. */
protected AdminProfileDtoToAdministratorMapper adminProfileDtoToAdministratorMapper;
/** The model mapper. */
protected ModelMapper modelMapper;
/** The user context. */
protected UserContext userContext;
/** The password encoder. */
protected PasswordEncoder passwordEncoder;
/** The email sender. */
protected EmailSender emailSender;
/** The token generator. */
protected TokenGenerator tokenGenerator;
/** The email token repository. */
protected EmailTokenRepository emailTokenRepository;
/** The users repository. */
protected UsersRepository usersRepository;
/** The administrative gender code repository. */
protected AdministrativeGenderCodeRepository administrativeGenderCodeRepository;
/** The mrn service. */
private MrnService mrnService;
/** The pix service. */
private PixService pixService;
/**
* Instantiates a new admin service impl.
*
* @param accountVerificationTokenExpireInHours
* the account verification token expire in hours
* @param administratorRepository
* the administrator repository
* @param patientRepository
* the patient repository
* @param patientProfileDtoToPatientMapper
* the patient profile dto to patient mapper
* @param adminProfileDtoToAdministratorMapper
* the admin profile dto to administrator mapper
* @param modelMapper
* the model mapper
* @param userContext
* the user context
* @param passwordEncoder
* the password encoder
* @param emailSender
* the email sender
* @param tokenGenerator
* the token generator
* @param emailTokenRepository
* the email token repository
* @param usersRepository
* the users repository
* @param administrativeGenderCodeRepository
* the administrative gender code repository
* @param mrnService
* the mrn service
* @param pixService
* the pix query service
*/
public AdminServiceImpl(
Integer accountVerificationTokenExpireInHours,
StaffRepository administratorRepository,
PatientRepository patientRepository,
DtoToDomainEntityMapper<PatientProfileDto, Patient> patientProfileDtoToPatientMapper,
AdminProfileDtoToAdministratorMapper adminProfileDtoToAdministratorMapper,
ModelMapper modelMapper,
UserContext userContext,
PasswordEncoder passwordEncoder,
EmailSender emailSender,
TokenGenerator tokenGenerator,
EmailTokenRepository emailTokenRepository,
UsersRepository usersRepository,
AdministrativeGenderCodeRepository administrativeGenderCodeRepository,
MrnService mrnService, PixService pixService) {
super();
this.accountVerificationTokenExpireInHours = accountVerificationTokenExpireInHours;
this.administratorRepository = administratorRepository;
this.patientRepository = patientRepository;
this.patientProfileDtoToPatientMapper = patientProfileDtoToPatientMapper;
this.adminProfileDtoToAdministratorMapper = adminProfileDtoToAdministratorMapper;
this.modelMapper = modelMapper;
this.userContext = userContext;
this.passwordEncoder = passwordEncoder;
this.emailSender = emailSender;
this.tokenGenerator = tokenGenerator;
this.emailTokenRepository = emailTokenRepository;
this.usersRepository = usersRepository;
this.administrativeGenderCodeRepository = administrativeGenderCodeRepository;
this.mrnService = mrnService;
this.pixService = pixService;
}
/*
* (non-Javadoc)
*
* @see gov.samhsa.consent2share.service.patient.PatientService#
* findPatientProfileByUsername(java.lang.String)
*/
@Override
public AdminProfileDto findAdminProfileByUsername(String username) {
Staff admin = administratorRepository.findByUsername(username);
AdminProfileDto adminProfileDto = modelMapper.map(admin,
AdminProfileDto.class);
return adminProfileDto;
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.consent2share.service.patient.PatientService#updatePatient
* (gov.samhsa.consent2share.service.dto.PatientProfileDto)
*/
@Override
@Transactional
public void updateAdministrator(AdminProfileDto adminProfileDto)
throws AuthenticationFailedException {
AuthenticatedUser currentUser = userContext.getCurrentUser();
String username = adminProfileDto.getUsername();
if (!currentUser.getUsername().equals(username))
throw new AuthenticationFailedException(
"Username does not match current active user.");
Users user = usersRepository.loadUserByUsername(username);
if (user != null)
if (!passwordEncoder.matches(adminProfileDto.getPassword(),
user.getPassword()))
throw new AuthenticationFailedException(
"Password is incorrect.");
logger.info("{} being run...", "updatePatient");
Staff admin = adminProfileDtoToAdministratorMapper.map(adminProfileDto);
administratorRepository.save(admin);
try {
emailSender.sendMessage(adminProfileDto.getFirstName() + " "
+ adminProfileDto.getLastName(),
adminProfileDto.getEmail(), EmailType.USER_PROFILE_CHANGE,
null, null);
} catch (MessagingException e) {
logger.warn("Error when sending the email message.");
}
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.consent2share.service.admin.AdminService#updatePatient(gov
* .samhsa.consent2share.service.dto.PatientProfileDto)
*/
@Override
@Transactional
public void updatePatient(PatientProfileDto patientProfileDto) {
patientProfileDto.setAddressCountryCode("US");
// Find MRN
Patient patient = patientRepository.findOne(patientProfileDto.getId());
final String mrn = patient.getMedicalRecordNumber();
patientProfileDto.setUsername(patient.getUsername());
// Update patient profile on MPI
PixManagerBean pixManagerBean = pixService.updatePatient(TypeConverter
.patientProfileDtoToPixPatientDto(patientProfileDto, mrn));
Assert.isTrue(
pixManagerBean.isSuccess(),
"Patient cannot be updated on MPI! Error: "
+ pixManagerBean.getUpdateMessage());
// Get EID
final String eid = pixService.getEid(mrn);
Assert.hasText(eid, "EID cannot be retrieved from MPI!");
patient.setEnterpriseIdentifier(eid);
// Save
patient = patientProfileDtoToPatientMapper.map(patientProfileDto);
patientRepository.save(patient);
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.consent2share.service.admin.AdminService#createPatientAccount
* (gov.samhsa.consent2share.service.dto.BasicPatientAccountDto)
*/
@Override
public AdminCreatePatientResponseDto createPatientAccount(
BasicPatientAccountDto basicPatientAccountDto) {
String eid = null;
final String mrn = generateMrn();
try {
PixManagerBean pixManagerBean = pixService.addPatient(TypeConverter
.basicPatientAccountDtoToPixPatientDto(
basicPatientAccountDto, mrn));
Assert.isTrue(
pixManagerBean.isSuccess(),
"Patient cannot be added to MPI! Error: "
+ pixManagerBean.getAddMessage());
eid = pixService.getEid(mrn);
Assert.hasText(eid, "EID cannot be retrieved from MPI!");
} catch (IllegalArgumentException e) {
logger.error(e.getMessage(), e);
throw e;
}
Patient patient = mapBasicPatientAccountDtoToPatient(mrn,
basicPatientAccountDto);
patient.setEnterpriseIdentifier(eid);
AdministrativeGenderCode administrativeGenderCode = administrativeGenderCodeRepository
.findByCode(basicPatientAccountDto
.getAdministrativeGenderCode());
patient.setAdministrativeGenderCode(administrativeGenderCode);
patient.setVerificationCode(UUID.randomUUID().toString()
.substring(0, 7));
patientRepository.save(patient);
return new AdminCreatePatientResponseDto(
AdminCreatePatientResponseDto.PATIENT_STATUS_UNKNOWN,
patient.getId());
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.consent2share.service.admin.AdminService#sendLoginInformationEmail
* (long, java.lang.String)
*/
@Override
public Boolean sendLoginInformationEmail(long patientId, String linkUrl)
throws EmailAddressNotExistException, MessagingException {
Patient patient = patientRepository.findOne(patientId);
// create emailToken
if (patient.getEmail() == null) {
String message = String
.format("Email address %s doesn't exist for username %s.");
logger.info("message");
throw new EmailAddressNotExistException(message);
}
EmailToken accountLoginInfoToken = new EmailToken();
accountLoginInfoToken
.setExpireInHours(accountVerificationTokenExpireInHours);
accountLoginInfoToken.setRequestDateTime(new Date());
String token = tokenGenerator.generateToken();
accountLoginInfoToken.setToken(token);
accountLoginInfoToken.setIsTokenUsed(false);
accountLoginInfoToken.setPatientId(patientId);
accountLoginInfoToken.setTokenType(TokenType.NEW_LOGIN_ACCOUNT);
emailTokenRepository.save(accountLoginInfoToken);
emailSender
.sendMessage(
patient.getFirstName() + " " + patient.getLastName(),
patient.getEmail(), EmailType.NEW_LOGIN_ACCOUNT,
linkUrl, token);
return true;
}
/**
* Generate mrn.
*
* @return the string
*/
protected String generateMrn() {
String mrn = null;
StringBuilder errorBuilder = new StringBuilder();
try {
mrn = mrnService.generateMrn();
} catch (UniqueValueGeneratorException e) {
errorBuilder.append(". ");
errorBuilder.append(e.getMessage());
logger.error(e.getMessage(), e);
} finally {
Assert.hasText(mrn,
errorBuilder.insert(0, "MRN cannot be generated by PCM!")
.toString());
}
return mrn;
}
protected Patient mapBasicPatientAccountDtoToPatient(final String mrn,
BasicPatientAccountDto basicPatientAccountDto) {
Patient patient = new Patient();
patient.setMedicalRecordNumber(mrn);
patient.setBirthDay(basicPatientAccountDto.getBirthDate());
patient.setFirstName(basicPatientAccountDto.getFirstName());
patient.setLastName(basicPatientAccountDto.getLastName());
patient.setEmail(basicPatientAccountDto.getEmail());
return patient;
}
}