Skip to content
Open
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.egov.individual;

public interface Constants {
String NAME_BASED_SEARCH_EXCEPTION_MESSAGE = "Error during individual-name-based search: ";
String NAME_BASED_SEARCH_FAILED_CODE = "INDIVIDUAL_NAME_SEARCH_FAILED";
String SET_INDIVIDUALS = "setIndividuals";
String VALIDATION_ERROR = "VALIDATION_ERROR";
String SYSTEM_GENERATED = "SYSTEM_GENERATED";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.egov.individual.config;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class ApplicationContextProvider implements ApplicationContextAware {

private static ApplicationContext context;

@Override
public void setApplicationContext(ApplicationContext ctx) {
context = ctx;
}

public static <T> T getBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import jakarta.annotation.PostConstruct;

import java.util.ArrayList;
import java.util.List;

@Data
Expand Down Expand Up @@ -68,6 +71,12 @@ public class IndividualProperties {
@Value("${notification.sms.disabled.roles}")
private List<String> smsDisabledRoles;

@Value("${egov.enc.host}")
private String encServiceHost;

@Value("${egov.enc.decrypt.endpoint}")
private String encDecryptEndpoint;

//Localization
@Value("${egov.localization.host}")
private String localizationHost;
Expand All @@ -86,4 +95,23 @@ public class IndividualProperties {

@Value("${egov.boundary.search.url}")
private String boundarySearchUrl;

@Value("${individual.allowed-response-fields}")
private List<String> allowedResponseFields;

@PostConstruct
private void ensureDefaultFieldsPresent() {
if (allowedResponseFields == null) {
allowedResponseFields = new ArrayList<>();
}

if (!allowedResponseFields.contains("username")) {
allowedResponseFields.add("username");
}

if (!allowedResponseFields.contains("mobilenumber")) {
allowedResponseFields.add("mobilenumber");
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.util.stream.Collectors;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.egov.common.data.query.builder.GenericQueryBuilder;
import org.egov.common.data.query.builder.QueryFieldChecker;
Expand All @@ -29,6 +30,8 @@
import org.egov.individual.repository.rowmapper.IdentifierRowMapper;
import org.egov.individual.repository.rowmapper.IndividualRowMapper;
import org.egov.individual.repository.rowmapper.SkillRowMapper;
import org.egov.individual.web.models.IndividualMapped;
import org.egov.individual.web.models.IndividualMappedSearch;
import org.egov.tracer.model.CustomException;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
Expand Down Expand Up @@ -148,6 +151,82 @@ public SearchResponse<Individual> find(IndividualSearch searchObject, Integer li
return SearchResponse.<Individual>builder().build();
}
}
public SearchResponse<Individual> findByName(String givenName, String familyName, String otherNames, String tenantId, Integer limit, Integer offset, Boolean includeDeleted) throws InvalidTenantIdException{
Map<String, Object> paramsMap = new HashMap<>();
String query = String.format(getQuery("SELECT * FROM %s.individual WHERE tenantId = :tenantId", includeDeleted), SCHEMA_REPLACE_STRING);
query = multiStateInstanceUtil.replaceSchemaPlaceholder(query, tenantId);

if (StringUtils.isNotBlank(givenName)) {
query += " AND givenName ILIKE :givenName";
paramsMap.put("givenName", "%" + givenName + "%");
}

if (StringUtils.isNotBlank(familyName)) {
query += " AND familyName ILIKE :familyName";
paramsMap.put("familyName", "%" + familyName + "%");
}

if (StringUtils.isNotBlank(otherNames)) {
query += " AND otherNames ILIKE :otherNames";
paramsMap.put("otherNames", "%" + otherNames + "%");
}

if (Boolean.FALSE.equals(includeDeleted)) {
query += " AND isDeleted = false";
}

query += " ORDER BY createdTime DESC LIMIT :limit OFFSET :offset";

paramsMap.put("tenantId", tenantId);
paramsMap.put("limit", limit);
paramsMap.put("offset", offset);

List<Individual> individuals = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper);

return SearchResponse.<Individual>builder()
.totalCount((long) individuals.size())
.response(individuals)
.build();
}

public Map<String, IndividualMapped> find(IndividualMappedSearch searchObject, Integer limit, Integer offset,
String tenantId) {
Map<String, Object> paramsMap = new HashMap<>();
String query = getQueryForMappedIndividualSearch(searchObject, limit, offset, tenantId, paramsMap);

List<Map<String, Object>> results = this.namedParameterJdbcTemplate.queryForList(query, paramsMap);

Map<String, IndividualMapped> response = new HashMap<>();

if (!results.isEmpty()) {
results.forEach(row -> {
IndividualMapped individualMapped = new IndividualMapped();

// Dynamically set fields based on searchObject parameters
for (String field : searchObject.getResponseFields()) {
if (row.containsKey(field)) {
individualMapped.setField(field, row.get(field));
}
}

// Set the key dynamically based on the provided search fields.
String key = null;

if (searchObject.getMobileNumber() != null) {
// Use mobilenumber as the key if provided
key = (String) row.get("mobilenumber");
} else if (searchObject.getUsername() != null) {
// Fall back to username as the key if mobilenumber is not provided
key = (String) row.get("username");
}
if (key != null) {
response.put(key, individualMapped);
}
});
}

return response;
}

/**
* @param query
Expand Down Expand Up @@ -334,6 +413,57 @@ private String getQueryForIndividual(IndividualSearch searchObject, Integer limi
return query;
}

private String getQueryForMappedIndividualSearch(IndividualMappedSearch searchObject,
Integer limit,
Integer offset,
String tenantId,
Map<String, Object> paramsMap) {

// Start with a base query structure
StringBuilder queryBuilder = new StringBuilder("SELECT ");



if(searchObject.getMobileNumber()!=null && searchObject.getMobileNumber().size() > 0){
searchObject.getResponseFields().add("mobilenumber");
}
if(searchObject.getUsername()!=null && searchObject.getUsername().size() > 0){
searchObject.getResponseFields().add("username");
}
// Directly select the fields from responseFields
String selectedFields = String.join(",", searchObject.getResponseFields());
queryBuilder.append(selectedFields);

queryBuilder.append(" FROM individual WHERE tenantId = :tenantId");

// Add tenant ID parameter
paramsMap.put("tenantId", tenantId);

// Filter by mobile numbers if provided
if (searchObject.getMobileNumber() != null && !searchObject.getMobileNumber().isEmpty()) {
queryBuilder.append(" AND mobilenumber IN (:mobileNumbers)");
paramsMap.put("mobileNumbers", searchObject.getMobileNumber());
}

// Filter by username if provided
if (searchObject.getUsername() != null && !searchObject.getUsername().isEmpty()) {
queryBuilder.append(" AND username IN (:usernames)");
paramsMap.put("usernames", searchObject.getUsername());
}

// Pagination: Add limit and offset
queryBuilder.append(" ORDER BY createdtime DESC LIMIT :limit OFFSET :offset");
paramsMap.put("limit", limit);
paramsMap.put("offset", offset);

// Log the query and parameters
log.info("Mapped search query: {}", queryBuilder.toString());
log.info("Params: {}", paramsMap);

return queryBuilder.toString();
}


private String getIdentifierQuery(String tenantId, Identifier identifier, Map<String, Object> paramMap) throws InvalidTenantIdException {
String identifierQuery = String.format("SELECT * FROM %s.individual_identifier", SCHEMA_REPLACE_STRING);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,22 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.egov.common.contract.request.RequestInfo;
import org.egov.common.http.client.ServiceRequestClient;
import org.egov.common.models.Error;
import org.egov.common.models.ErrorDetails;
import org.egov.common.models.individual.Identifier;
import org.egov.common.models.individual.Individual;
import org.egov.common.models.individual.IndividualBulkRequest;
import org.egov.common.models.individual.IndividualSearch;
import org.egov.individual.config.IndividualProperties;
import org.egov.individual.repository.IndividualRepository;
import org.egov.individual.util.EncryptionDecryptionUtil;
import org.egov.individual.web.models.IndividualMappedSearch;
import org.egov.tracer.model.CustomException;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -35,10 +39,18 @@ public class IndividualEncryptionService {

private final IndividualRepository individualRepository;

private final ServiceRequestClient serviceRequestClient;

private final IndividualProperties individualProperties;

public IndividualEncryptionService(EncryptionDecryptionUtil encryptionDecryptionUtil,
IndividualRepository individualRepository) {
IndividualRepository individualRepository,
ServiceRequestClient serviceRequestClient,
IndividualProperties individualProperties) {
this.encryptionDecryptionUtil = encryptionDecryptionUtil;
this.individualRepository = individualRepository;
this.serviceRequestClient = serviceRequestClient;
this.individualProperties = individualProperties;
}


Expand All @@ -55,6 +67,12 @@ public IndividualSearch encrypt(IndividualSearch individualSearch, String key) {
return encryptedIndividualSearch;
}

public IndividualMappedSearch encrypt(IndividualMappedSearch individualMappedSearch, String key) {
IndividualMappedSearch encryptedIndividualSearch = (IndividualMappedSearch) encryptionDecryptionUtil
.encryptObject(individualMappedSearch, key, IndividualMappedSearch.class);
return encryptedIndividualSearch;
}

public List<Individual> decrypt(List<Individual> individuals, String key, RequestInfo requestInfo) {
List<Individual> encryptedIndividuals = filterEncryptedIndividuals(individuals);
List<Individual> decryptedIndividuals = (List<Individual>) encryptionDecryptionUtil
Expand All @@ -73,6 +91,32 @@ public List<Individual> decrypt(List<Individual> individuals, String key, Reques
return decryptedIndividuals;
}

public List<String> decryptStringArray(List<String> encryptedValues) throws Exception {
// Check if input is null or empty
if (encryptedValues == null || encryptedValues.isEmpty()) {
return Collections.emptyList();
}

// Create the URI for the decryption API
StringBuilder uri = new StringBuilder(individualProperties.getEncServiceHost())
.append(individualProperties.getEncDecryptEndpoint());

// Prepare the request body (wrap in a list)
List<List<String>> requestBody = Collections.singletonList(encryptedValues);

// Fetch the decrypted data using the service request client
List<List<String>> decryptedValues = serviceRequestClient.fetchResult(
uri, // URI for the decryption API
requestBody, // Encrypted values to be decrypted
List.class // Expected response type
);

// Assuming the decryption API returns a list of decrypted values, return the first list
return decryptedValues != null && !decryptedValues.isEmpty() ? decryptedValues.get(0) : Collections.emptyList();
}



private List<Individual> filterEncryptedIndividuals(List<Individual> individuals) {
return individuals.stream()
.filter(individual -> isCipherText(individual.getMobileNumber())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.egov.individual.service;

import java.util.Optional;
import java.util.Random;
import java.util.UUID;
import java.util.stream.Collectors;
Expand All @@ -8,12 +9,16 @@
import org.egov.common.models.individual.Address;
import org.egov.common.models.individual.AddressType;
import org.egov.common.models.individual.Individual;
import org.egov.common.models.individual.UserDetails;
import org.egov.common.models.user.RoleRequest;
import org.egov.common.models.user.UserRequest;
import org.egov.common.models.user.UserType;
import org.egov.individual.config.IndividualProperties;
import org.egov.individual.web.models.IndividualMapped;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class IndividualMapper {

private static final Random RANDOM = new Random();
Expand Down Expand Up @@ -67,4 +72,21 @@ private static String generateDummyMobileNumber(String mobileNumber) {
return mobileNumber;
}
}

public IndividualMapped getIndividualMapped(Individual individual) {
IndividualMapped individualMapped = new IndividualMapped();

// Set fields only if they are not null
Optional.ofNullable(individual.getMobileNumber())
.ifPresent(mobileNumber -> individualMapped.setField("mobilenumber", mobileNumber));

Optional.ofNullable(individual.getUserDetails())
.map(UserDetails::getUsername)
.ifPresent(username -> individualMapped.setField("username", username));

Optional.ofNullable(individual.getUserUuid())
.ifPresent(userUuid -> individualMapped.setField("useruuid", userUuid));

return individualMapped;
}
}
Loading
Loading