Integrate User Service
Overview
The User Service provides the capabilities of creating a user, searching for a user and retrieving the details of a user. This module will search for a user and, if not found, create that user with the user service.
DIGIT's user service masks PII that gets stored in the database using the Encryption Service.
Steps
Create a class by the name of UserService under the service folder and add the following content to it:
UserService.java
package digit.service;
import digit.config.BTRConfiguration;
import digit.util.UserUtil;
import digit.web.models.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.egov.common.contract.request.RequestInfo;
import org.egov.common.contract.request.User;
import org.egov.common.contract.user.CreateUserRequest;
import org.egov.common.contract.user.UserDetailResponse;
import org.egov.common.contract.user.UserSearchRequest;
import org.egov.tracer.model.CustomException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
@Slf4j
public class UserService {
private UserUtil userUtils;
private BTRConfiguration config;
@Autowired
public UserService(UserUtil userUtils, BTRConfiguration config) {
this.userUtils = userUtils;
this.config = config;
}
/**
* Calls user service to enrich user from search or upsert user
* @param request
*/
public void callUserService(BirthRegistrationRequest request){
request.getBirthRegistrationApplications().forEach(application -> {
if(!StringUtils.isEmpty(application.getFather().getUuid()))
enrichUser(application, request.getRequestInfo());
else {
User user = createFatherUser(application);
application.getFather().setUuid(upsertUser(user, request.getRequestInfo()).getUuid());
}
});
request.getBirthRegistrationApplications().forEach(application -> {
if(!StringUtils.isEmpty(application.getMother().getUuid()))
enrichUser(application, request.getRequestInfo());
else {
User user = createMotherUser(application);
application.getMother().setUuid(upsertUser(user, request.getRequestInfo()).getUuid());
}
});
}
private User createFatherUser(BirthRegistrationApplication application){
User father = application.getFather();
User user = User.builder().userName(father.getUserName())
.name(father.getName())
.userName((father.getUserName()))
.mobileNumber(father.getMobileNumber())
.emailId(father.getEmailId())
.tenantId(father.getTenantId())
.type(father.getType())
.roles(father.getRoles())
.build();
return user;
}
private User createMotherUser(BirthRegistrationApplication application){
User mother = application.getMother();
User user = User.builder().userName(mother.getUserName())
.name(mother.getName())
.userName((mother.getUserName()))
.mobileNumber(mother.getMobileNumber())
.emailId(mother.getEmailId())
.tenantId(mother.getTenantId())
.type(mother.getType())
.roles(mother.getRoles())
.build();
return user;
}
private User upsertUser(User user, RequestInfo requestInfo){
String tenantId = user.getTenantId();
User userServiceResponse = null;
// Search on mobile number as user name
UserDetailResponse userDetailResponse = searchUser(userUtils.getStateLevelTenant(tenantId),null, user.getUserName());
if (!userDetailResponse.getUser().isEmpty()) {
User userFromSearch = userDetailResponse.getUser().get(0);
log.info(userFromSearch.toString());
if(!user.getUserName().equalsIgnoreCase(userFromSearch.getUserName())){
userServiceResponse = updateUser(requestInfo,user,userFromSearch);
}
else userServiceResponse = userDetailResponse.getUser().get(0);
}
else {
userServiceResponse = createUser(requestInfo,tenantId,user);
}
// Enrich the accountId
// user.setId(userServiceResponse.getUuid());
return userServiceResponse;
}
private void enrichUser(BirthRegistrationApplication application, RequestInfo requestInfo){
String accountIdFather = application.getFather().getUuid();
String accountIdMother = application.getMother().getUuid();
String tenantId = application.getTenantId();
UserDetailResponse userDetailResponseFather = searchUser(userUtils.getStateLevelTenant(tenantId),accountIdFather,null);
UserDetailResponse userDetailResponseMother = searchUser(userUtils.getStateLevelTenant(tenantId),accountIdMother,null);
if(userDetailResponseFather.getUser().isEmpty())
throw new CustomException("INVALID_ACCOUNTID","No user exist for the given accountId");
else application.getFather().setUuid(userDetailResponseFather.getUser().get(0).getUuid());
if(userDetailResponseMother.getUser().isEmpty())
throw new CustomException("INVALID_ACCOUNTID","No user exist for the given accountId");
else application.getMother().setUuid(userDetailResponseMother.getUser().get(0).getUuid());
}
/**
* Creates the user from the given userInfo by calling user service
* @param requestInfo
* @param tenantId
* @param userInfo
* @return
*/
private User createUser(RequestInfo requestInfo,String tenantId, User userInfo) {
userUtils.addUserDefaultFields(userInfo.getMobileNumber(),tenantId, userInfo);
StringBuilder uri = new StringBuilder(config.getUserHost())
.append(config.getUserContextPath())
.append(config.getUserCreateEndpoint());
CreateUserRequest user = new CreateUserRequest(requestInfo, userInfo);
log.info(user.getUser().toString());
UserDetailResponse userDetailResponse = userUtils.userCall(user, uri);
return userDetailResponse.getUser().get(0);
}
/**
* Updates the given user by calling user service
* @param requestInfo
* @param user
* @param userFromSearch
* @return
*/
private User updateUser(RequestInfo requestInfo,User user,User userFromSearch) {
userFromSearch.setName(user.getName());
StringBuilder uri = new StringBuilder(config.getUserHost())
.append(config.getUserContextPath())
.append(config.getUserUpdateEndpoint());
UserDetailResponse userDetailResponse = userUtils.userCall(new CreateUserRequest(requestInfo, userFromSearch), uri);
return userDetailResponse.getUser().get(0);
}
/**
* calls the user search API based on the given accountId and userName
* @param stateLevelTenant
* @param accountId
* @param userName
* @return
*/
public UserDetailResponse searchUser(String stateLevelTenant, String accountId, String userName){
UserSearchRequest userSearchRequest =new UserSearchRequest();
userSearchRequest.setActive(false);
// userSearchRequest.setUserType("CITIZEN");
userSearchRequest.setTenantId(stateLevelTenant);
if(StringUtils.isEmpty(accountId) && StringUtils.isEmpty(userName))
return null;
if(!StringUtils.isEmpty(accountId))
userSearchRequest.setUuid(Collections.singletonList(accountId));
if(!StringUtils.isEmpty(userName))
userSearchRequest.setUserName(userName);
StringBuilder uri = new StringBuilder(config.getUserHost()).append(config.getUserSearchEndpoint());
return userUtils.userCall(userSearchRequest,uri);
}
/**
* calls the user search API based on the given list of user uuids
* @param uuids
* @return
*/
private Map<String,User> searchBulkUser(List<String> uuids){
UserSearchRequest userSearchRequest =new UserSearchRequest();
userSearchRequest.setActive(false);
userSearchRequest.setUserType("CITIZEN");
if(!CollectionUtils.isEmpty(uuids))
userSearchRequest.setUuid(uuids);
StringBuilder uri = new StringBuilder(config.getUserHost()).append(config.getUserSearchEndpoint());
UserDetailResponse userDetailResponse = userUtils.userCall(userSearchRequest,uri);
List<User> users = userDetailResponse.getUser();
if(CollectionUtils.isEmpty(users))
throw new CustomException("USER_NOT_FOUND","No user found for the uuids");
Map<String,User> idToUserMap = users.stream().collect(Collectors.toMap(User::getUuid, Function.identity()));
return idToUserMap;
}
}2. Update the code in userUtil
UserUtil.java
package digit.util;
import com.fasterxml.jackson.databind.ObjectMapper;
import digit.config.Configuration;
import static digit.config.ServiceConstants.*;
import org.egov.common.contract.request.Role;
import org.egov.common.contract.request.User;
import org.egov.common.contract.user.UserDetailResponse;
import org.egov.common.contract.user.enums.UserType;
import digit.repository.ServiceRequestRepository;
import org.egov.tracer.model.CustomException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
@Component
public class UserUtil {
@Autowired
private ObjectMapper mapper;
@Autowired
private ServiceRequestRepository serviceRequestRepository;
@Autowired
private Configuration configs;
@Autowired
public UserUtil(ObjectMapper mapper, ServiceRequestRepository serviceRequestRepository) {
this.mapper = mapper;
this.serviceRequestRepository = serviceRequestRepository;
}
/**
* Returns UserDetailResponse by calling user service with given uri and object
* @param userRequest Request object for user service
* @param uri The address of the endpoint
* @return Response from user service as parsed as userDetailResponse
*/
public UserDetailResponse userCall(Object userRequest, StringBuilder uri) {
String dobFormat = null;
if(uri.toString().contains(configs.getUserSearchEndpoint()) || uri.toString().contains(configs.getUserUpdateEndpoint()))
dobFormat=DOB_FORMAT_Y_M_D;
else if(uri.toString().contains(configs.getUserCreateEndpoint()))
dobFormat = DOB_FORMAT_D_M_Y;
try{
LinkedHashMap responseMap = (LinkedHashMap)serviceRequestRepository.fetchResult(uri, userRequest);
parseResponse(responseMap,dobFormat);
UserDetailResponse userDetailResponse = mapper.convertValue(responseMap,UserDetailResponse.class);
return userDetailResponse;
}
catch(IllegalArgumentException e)
{
throw new CustomException(ILLEGAL_ARGUMENT_EXCEPTION_CODE,OBJECTMAPPER_UNABLE_TO_CONVERT);
}
}
/**
* Parses date formats to long for all users in responseMap
* @param responseMap LinkedHashMap got from user api response
*/
public void parseResponse(LinkedHashMap responseMap, String dobFormat){
List<LinkedHashMap> users = (List<LinkedHashMap>)responseMap.get(USER);
String format1 = DOB_FORMAT_D_M_Y_H_M_S;
if(users!=null){
users.forEach( map -> {
map.put(CREATED_DATE,dateTolong((String)map.get(CREATED_DATE),format1));
if((String)map.get(LAST_MODIFIED_DATE)!=null)
map.put(LAST_MODIFIED_DATE,dateTolong((String)map.get(LAST_MODIFIED_DATE),format1));
if((String)map.get(DOB)!=null)
map.put(DOB,dateTolong((String)map.get(DOB),dobFormat));
if((String)map.get(PWD_EXPIRY_DATE)!=null)
map.put(PWD_EXPIRY_DATE,dateTolong((String)map.get(PWD_EXPIRY_DATE),format1));
}
);
}
}
/**
* Converts date to long
* @param date date to be parsed
* @param format Format of the date
* @return Long value of date
*/
private Long dateTolong(String date,String format){
SimpleDateFormat f = new SimpleDateFormat(format);
Date d = null;
try {
d = f.parse(date);
} catch (ParseException e) {
throw new CustomException(INVALID_DATE_FORMAT_CODE,INVALID_DATE_FORMAT_MESSAGE);
}
return d.getTime();
}
/**
* enriches the userInfo with statelevel tenantId and other fields
* The function creates user with username as mobile number.
* @param mobileNumber
* @param tenantId
* @param userInfo
*/
public void addUserDefaultFields(String mobileNumber,String tenantId, User userInfo){
Role role = getCitizenRole(tenantId);
userInfo.setMobileNumber(mobileNumber);
userInfo.setTenantId(getStateLevelTenant(tenantId));
userInfo.setType("CITIZEN");
}
/**
* Returns role object for citizen
* @param tenantId
* @return
*/
private Role getCitizenRole(String tenantId){
Role role = Role.builder().build();
role.setCode(CITIZEN_UPPER);
role.setName(CITIZEN_LOWER);
role.setTenantId(getStateLevelTenant(tenantId));
return role;
}
public String getStateLevelTenant(String tenantId){
return tenantId.split("\\.")[0];
}
}Changes to BirthApplicationEnrichment.java
Add the methods below to the enrichment class we created. When we search for an application, the code below will search for the users associated with the application and add their details to the response object.
Changes to BirthRegistrationService.java
Add in a userService object:
And enhance the following two methods in BirthRegistrationService.java:
Add the following properties in the application.properties file:
Note: If you're port-forwarding using k8s, use "localhost". Otherwise, if you have a valid auth token, provide the hostname here.
Last updated
Was this helpful?