From 2d9fc769fc2e8fde923b72a0f77ba0c01823b4d5 Mon Sep 17 00:00:00 2001 From: M1044292 Date: Tue, 30 May 2023 18:34:20 +0530 Subject: [PATCH 01/16] Fixed MOSIP-27402 --- .../kernel/syncdata/service/impl/SyncAuthTokenServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/kernel-syncdata-service/src/main/java/io/mosip/kernel/syncdata/service/impl/SyncAuthTokenServiceImpl.java b/admin/kernel-syncdata-service/src/main/java/io/mosip/kernel/syncdata/service/impl/SyncAuthTokenServiceImpl.java index aae59dd1b31..398bf9d4395 100644 --- a/admin/kernel-syncdata-service/src/main/java/io/mosip/kernel/syncdata/service/impl/SyncAuthTokenServiceImpl.java +++ b/admin/kernel-syncdata-service/src/main/java/io/mosip/kernel/syncdata/service/impl/SyncAuthTokenServiceImpl.java @@ -131,7 +131,7 @@ public String getAuthToken(String requestData) { Machine machine = validateRequestData(header, payload, signature); try { MachineAuthDto machineAuthDto = objectMapper.readValue(payload, MachineAuthDto.class); - if (machineAuthDto.getMachineName() != null && !machineAuthDto.getMachineName().equalsIgnoreCase(machine.getId())) { + if (machineAuthDto.getMachineName() != null && !machineAuthDto.getMachineName().equalsIgnoreCase(machine.getName())) { throw new RuntimeException("Invalid machinName found in the request"); } validateRequestTimestamp(machineAuthDto.getTimestamp()); From 8ed6416347a7c10a150134c9f2ccadbecdd43c7b Mon Sep 17 00:00:00 2001 From: ase-101 <> Date: Sat, 15 Jul 2023 22:38:55 +0530 Subject: [PATCH 02/16] MOSIP-21476 Fixed the NoSuchMethod Error --- admin/admin-service/pom.xml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/admin/admin-service/pom.xml b/admin/admin-service/pom.xml index 967984a7c10..c0c1b2b692c 100644 --- a/admin/admin-service/pom.xml +++ b/admin/admin-service/pom.xml @@ -25,6 +25,16 @@ io.mosip.kernel kernel-core ${kernel.version} + + + org.apache.logging.log4j + log4j-to-slf4j + + + org.apache.logging.log4j + log4j-api + + org.projectlombok @@ -43,12 +53,6 @@ org.apache.poi poi-ooxml 5.2.2 - - - log4j - log4j - - org.springframework.batch.extensions From b2e051eeb0a5090d030663a6109b2c26fda2f0b1 Mon Sep 17 00:00:00 2001 From: ase-101 <> Date: Sat, 15 Jul 2023 23:14:02 +0530 Subject: [PATCH 03/16] Fixed version of packet-manager --- admin/admin-service/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/admin-service/pom.xml b/admin/admin-service/pom.xml index c0c1b2b692c..2f24157900b 100644 --- a/admin/admin-service/pom.xml +++ b/admin/admin-service/pom.xml @@ -133,7 +133,7 @@ io.mosip.commons commons-packet-manager - ${kernel.version} + 1.2.0.1-SNAPSHOT org.springframework.cloud From 8609534df914a6b51fc39c862a9c0e2426c85e73 Mon Sep 17 00:00:00 2001 From: dhanendra06 <60607841+dhanendra06@users.noreply.github.com> Date: Thu, 27 Jul 2023 11:30:27 +0530 Subject: [PATCH 04/16] MOSIP-12430 (#887) * MOSIP-12430 * modified code based on review comments * updated code based on review comments * modified the code based on review comments * modified the code based on review comments * modified the code based on review comments * modified the code based on review comments --- .../admin/constant/LostRidErrorCode.java | 6 +- .../admin/controller/AdminController.java | 25 ++-- .../ApplicantDetailsController.java | 11 +- .../mosip/admin/dto/AuthorizedRolesDto.java | 16 ++- .../mosip/admin/dto/BiometricRequestDto.java | 19 +++ .../io/mosip/admin/dto/LostRidDetailsDto.java | 15 ++ .../io/mosip/admin/dto/SearchFieldDtos.java | 17 +++ .../admin/dto/SearchFieldResponseDto.java | 17 +++ .../packetstatusupdater/constant/ApiName.java | 4 +- .../io/mosip/admin/service/AdminService.java | 2 + .../admin/service/impl/AdminServiceImpl.java | 135 +++++++++++++++++- .../controller/test/AdminControllerTest.java | 32 ++++- .../resources/application-test.properties | 12 ++ .../test/resources/biometricApiResponse.json | 87 +++++++++++ 14 files changed, 379 insertions(+), 19 deletions(-) create mode 100644 admin/admin-service/src/main/java/io/mosip/admin/dto/BiometricRequestDto.java create mode 100644 admin/admin-service/src/main/java/io/mosip/admin/dto/LostRidDetailsDto.java create mode 100644 admin/admin-service/src/main/java/io/mosip/admin/dto/SearchFieldDtos.java create mode 100644 admin/admin-service/src/main/java/io/mosip/admin/dto/SearchFieldResponseDto.java create mode 100644 admin/admin-service/src/test/resources/biometricApiResponse.json diff --git a/admin/admin-service/src/main/java/io/mosip/admin/constant/LostRidErrorCode.java b/admin/admin-service/src/main/java/io/mosip/admin/constant/LostRidErrorCode.java index a4f66e1a0bb..70894d37397 100644 --- a/admin/admin-service/src/main/java/io/mosip/admin/constant/LostRidErrorCode.java +++ b/admin/admin-service/src/main/java/io/mosip/admin/constant/LostRidErrorCode.java @@ -2,7 +2,11 @@ public enum LostRidErrorCode { - UNABLE_TO_RETRIEVE_LOSTRID("ADMN-LRID-001", "Unable ro find the lost rid.."); + UNABLE_TO_RETRIEVE_LOSTRID("ADMN-LRID-001", "Unable to find the lost rid.."), + UNABLE_TO_RETRIEVE_LOSTRID_DATA("ADMN-LRID-002", "Unable to find the lost rid data"), + + UNABLE_TO_RETRIEVE_APPLICANT_PHOTO("ADMN-LRID-003", "Unable to retrieve applicantPhoto"); + private final String errorCode; private final String errorMessage; diff --git a/admin/admin-service/src/main/java/io/mosip/admin/controller/AdminController.java b/admin/admin-service/src/main/java/io/mosip/admin/controller/AdminController.java index f473f74d01d..92a6263b2fc 100644 --- a/admin/admin-service/src/main/java/io/mosip/admin/controller/AdminController.java +++ b/admin/admin-service/src/main/java/io/mosip/admin/controller/AdminController.java @@ -3,15 +3,11 @@ import java.util.ArrayList; import java.util.List; +import io.mosip.admin.dto.*; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; - -import io.mosip.admin.dto.ErrorDTO; -import io.mosip.admin.dto.LostRidExtnDto; -import io.mosip.admin.dto.LostRidResponseDto; -import io.mosip.admin.dto.SearchInfo; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + import io.mosip.admin.packetstatusupdater.util.AuditUtil; import io.mosip.admin.packetstatusupdater.util.EventEnum; import io.mosip.admin.service.AdminService; @@ -28,13 +24,24 @@ public class AdminController { @Autowired AuditUtil auditUtil; + @PreAuthorize("hasAnyRole(@authorizedRoles.getPostlostRid())") @PostMapping("/lostRid") - private ResponseWrapper lostRid(@RequestBody RequestWrapper searchInfo) { + public ResponseWrapper lostRid(@RequestBody RequestWrapper searchInfo) { auditUtil.setAuditRequestDto(EventEnum.LOST_RID_API_CALLED,null); LostRidResponseDto lostRidResponseDto = adminService.lostRid(searchInfo.getRequest()); auditUtil.setAuditRequestDto(EventEnum.LOST_RID_SUCCESS,null); return buildLostRidResponse(lostRidResponseDto); } + + @PreAuthorize("hasAnyRole(@authorizedRoles.getGetlostRiddetailsrid())") + @GetMapping("/lostRid/details/{rid}") + public ResponseWrapper getLostRidDetails(@PathVariable("rid") String rid) { + auditUtil.setAuditRequestDto(EventEnum.LOST_RID_API_CALLED,null); + ResponseWrapper responseWrapper = new ResponseWrapper<>(); + responseWrapper.setResponse(adminService.getLostRidDetails(rid)); + auditUtil.setAuditRequestDto(EventEnum.LOST_RID_SUCCESS,null); + return responseWrapper; + } private ResponseWrapper buildLostRidResponse(LostRidResponseDto lostRidResponseDto) { ResponseWrapper responseWrapper = new ResponseWrapper<>(); diff --git a/admin/admin-service/src/main/java/io/mosip/admin/controller/ApplicantDetailsController.java b/admin/admin-service/src/main/java/io/mosip/admin/controller/ApplicantDetailsController.java index ef208ad49e3..51f3f37be64 100644 --- a/admin/admin-service/src/main/java/io/mosip/admin/controller/ApplicantDetailsController.java +++ b/admin/admin-service/src/main/java/io/mosip/admin/controller/ApplicantDetailsController.java @@ -27,7 +27,8 @@ public class ApplicantDetailsController { @Autowired ApplicantDetailService applicantDetailService; - @PreAuthorize("hasRole('DIGITALCARD_ADMIN')") + //@PreAuthorize("hasRole('DIGITALCARD_ADMIN')") + @PreAuthorize("hasAnyRole(@authorizedRoles.getGetapplicantDetailsrid())") @GetMapping("/applicantDetails/{rid}") public ResponseWrapper getApplicantDetails(@PathVariable("rid") String rid) throws Exception { auditUtil.setAuditRequestDto(EventEnum.APPLICANT_VERIFICATION_API_CALLED,null); @@ -37,8 +38,9 @@ public ResponseWrapper getApplicantDetails(@PathVariable("r return responseWrapper; } - @PreAuthorize("hasRole('DIGITALCARD_ADMIN')") - @GetMapping("/applicantDetails/getLoginDetails") + // @PreAuthorize("hasRole('DIGITALCARD_ADMIN')") + @PreAuthorize("hasAnyRole(@authorizedRoles.getGetapplicantDetailsgetLoginDetails())") + @GetMapping("/applicantDetails/getLoginDetails") public ResponseWrapper getApplicantUserDetails() throws Exception { auditUtil.setAuditRequestDto(EventEnum.APPLICANT_LOGIN_DETAILS_API_CALLED,null); ResponseWrapper responseWrapper = new ResponseWrapper<>(); @@ -47,7 +49,8 @@ public ResponseWrapper getApplicantUserDetails() throws return responseWrapper; } - @PreAuthorize("hasRole('DIGITALCARD_ADMIN')") + // @PreAuthorize("hasRole('DIGITALCARD_ADMIN')") + @PreAuthorize("hasAnyRole(@authorizedRoles.getGetriddigitalcardrid())") @GetMapping("/rid-digital-card/{rid}") public ResponseEntity getRIDDigitalCard( @PathVariable("rid") String rid,@RequestParam("isAcknowledged") boolean isAcknowledged) throws Exception { diff --git a/admin/admin-service/src/main/java/io/mosip/admin/dto/AuthorizedRolesDto.java b/admin/admin-service/src/main/java/io/mosip/admin/dto/AuthorizedRolesDto.java index 69072fe85ed..d43cb4277eb 100644 --- a/admin/admin-service/src/main/java/io/mosip/admin/dto/AuthorizedRolesDto.java +++ b/admin/admin-service/src/main/java/io/mosip/admin/dto/AuthorizedRolesDto.java @@ -26,8 +26,20 @@ public class AuthorizedRolesDto { //packet status update controller private List getpacketstatusupdate; - - + + + //admin lostRid controller + + private List getlostRiddetailsrid; + private List postlostRid; + + //applicant Details controller + + private List getapplicantDetailsrid; + private List getapplicantDetailsgetLoginDetails; + private List getriddigitalcardrid; + + // keymanager controller private List getgeneratecsrcertificateapplicationidreferenceid; private List postuploadcertificate; diff --git a/admin/admin-service/src/main/java/io/mosip/admin/dto/BiometricRequestDto.java b/admin/admin-service/src/main/java/io/mosip/admin/dto/BiometricRequestDto.java new file mode 100644 index 00000000000..ec32d564a5c --- /dev/null +++ b/admin/admin-service/src/main/java/io/mosip/admin/dto/BiometricRequestDto.java @@ -0,0 +1,19 @@ +package io.mosip.admin.dto; + + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +@Data +@EqualsAndHashCode +public class BiometricRequestDto { + + private String id; + private String person; + private List modalities; + private String source; + private String process; + private boolean bypassCache; +} diff --git a/admin/admin-service/src/main/java/io/mosip/admin/dto/LostRidDetailsDto.java b/admin/admin-service/src/main/java/io/mosip/admin/dto/LostRidDetailsDto.java new file mode 100644 index 00000000000..8523d7888d0 --- /dev/null +++ b/admin/admin-service/src/main/java/io/mosip/admin/dto/LostRidDetailsDto.java @@ -0,0 +1,15 @@ +package io.mosip.admin.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class LostRidDetailsDto { + + Map lostRidDataMap=new HashMap<>(); + +} diff --git a/admin/admin-service/src/main/java/io/mosip/admin/dto/SearchFieldDtos.java b/admin/admin-service/src/main/java/io/mosip/admin/dto/SearchFieldDtos.java new file mode 100644 index 00000000000..563dcf44279 --- /dev/null +++ b/admin/admin-service/src/main/java/io/mosip/admin/dto/SearchFieldDtos.java @@ -0,0 +1,17 @@ +package io.mosip.admin.dto; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +@Data +@EqualsAndHashCode +public class SearchFieldDtos { + + private String id; + private List fields; + private String source; + private String process; + private Boolean bypassCache; +} diff --git a/admin/admin-service/src/main/java/io/mosip/admin/dto/SearchFieldResponseDto.java b/admin/admin-service/src/main/java/io/mosip/admin/dto/SearchFieldResponseDto.java new file mode 100644 index 00000000000..d13ccfe0519 --- /dev/null +++ b/admin/admin-service/src/main/java/io/mosip/admin/dto/SearchFieldResponseDto.java @@ -0,0 +1,17 @@ +package io.mosip.admin.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.Map; + +@Data +@EqualsAndHashCode +@AllArgsConstructor +@NoArgsConstructor +public class SearchFieldResponseDto { + + Map fields; +} diff --git a/admin/admin-service/src/main/java/io/mosip/admin/packetstatusupdater/constant/ApiName.java b/admin/admin-service/src/main/java/io/mosip/admin/packetstatusupdater/constant/ApiName.java index 72f9f18f82d..e7f8be624f7 100644 --- a/admin/admin-service/src/main/java/io/mosip/admin/packetstatusupdater/constant/ApiName.java +++ b/admin/admin-service/src/main/java/io/mosip/admin/packetstatusupdater/constant/ApiName.java @@ -7,6 +7,8 @@ */ public enum ApiName { - LOST_RID_API,CRYPTOMANAGERDECRYPT_API,MACHINE_GET_API,RETRIEVE_IDENTITY_API,DIGITAL_CARD_STATUS_URL; + LOST_RID_API,CRYPTOMANAGERDECRYPT_API,MACHINE_GET_API,RETRIEVE_IDENTITY_API,DIGITAL_CARD_STATUS_URL, + + PACKET_MANAGER_BIOMETRIC,PACKET_MANAGER_SEARCHFIELDS; } diff --git a/admin/admin-service/src/main/java/io/mosip/admin/service/AdminService.java b/admin/admin-service/src/main/java/io/mosip/admin/service/AdminService.java index 905c40393ce..2ebf9d7501f 100644 --- a/admin/admin-service/src/main/java/io/mosip/admin/service/AdminService.java +++ b/admin/admin-service/src/main/java/io/mosip/admin/service/AdminService.java @@ -1,5 +1,6 @@ package io.mosip.admin.service; +import io.mosip.admin.dto.LostRidDetailsDto; import io.mosip.admin.dto.LostRidResponseDto; import io.mosip.admin.dto.SearchInfo; @@ -8,4 +9,5 @@ public interface AdminService { LostRidResponseDto lostRid(SearchInfo searchInfo); + LostRidDetailsDto getLostRidDetails(String rid); } diff --git a/admin/admin-service/src/main/java/io/mosip/admin/service/impl/AdminServiceImpl.java b/admin/admin-service/src/main/java/io/mosip/admin/service/impl/AdminServiceImpl.java index ed7b7bac536..595b512b7c0 100644 --- a/admin/admin-service/src/main/java/io/mosip/admin/service/impl/AdminServiceImpl.java +++ b/admin/admin-service/src/main/java/io/mosip/admin/service/impl/AdminServiceImpl.java @@ -1,8 +1,20 @@ package io.mosip.admin.service.impl; -import java.util.List; +import java.util.*; +import io.mosip.admin.constant.ApplicantDetailErrorCode; import io.mosip.admin.dto.*; +import io.mosip.admin.util.Utility; +import io.mosip.biometrics.util.ConvertRequestDto; +import io.mosip.biometrics.util.face.FaceDecoder; +import io.mosip.kernel.core.http.RequestWrapper; +import io.mosip.kernel.core.http.ResponseWrapper; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.binary.StringUtils; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; @@ -27,6 +39,31 @@ public class AdminServiceImpl implements AdminService { @Value("${mosip.registration.processor.lostrid.id:mosip.registration.lostrid}") private String lostRidRequestId; + @Value("${mosip.admin.lostrid.details.fields:fullName,dateOfBirth}") + private String[] fields; + + @Value("${mosip.admin.lostrid.details.name.field:fullName}") + private String nameField; + + @Value("${mosip.admin.lostrid.details.biometric.field:individualBiometrics}") + private String biometricField; + + private static final String PROCESS = "NEW"; + + private static final String SOURCE = "REGISTRATION_CLIENT"; + + private static final String RESPONSE = "response"; + + private static final String SEGEMENTS = "segments"; + + private static final String VALUE = "value"; + + private static final Logger logger = LoggerFactory.getLogger(AdminServiceImpl.class); + + @Autowired + private Utility utility; + + @Autowired RestClient restClient; @@ -73,5 +110,101 @@ private void createLostRidRequest(SearchInfo searchInfoRequest) { } + public String getApplicantPhoto(byte[] isodata) throws Exception { + ConvertRequestDto convertRequestDto = new ConvertRequestDto(); + convertRequestDto.setVersion("ISO19794_5_2011"); + convertRequestDto.setInputBytes(isodata); + byte[] data = FaceDecoder.convertFaceISOToImageBytes(convertRequestDto); + String encodedBytes = new String(data); + + return encodedBytes; + } + @Override + public LostRidDetailsDto getLostRidDetails(String rid) { + LostRidDetailsDto lostRidDetailsDto=new LostRidDetailsDto(); + Map lostRidDataMap=new HashMap<>(); + SearchFieldDtos fieldDtos=new SearchFieldDtos(); + RequestWrapper fieldDtosRequestWrapper=new RequestWrapper<>(); + ConvertRequestDto convertRequestDto = new ConvertRequestDto(); + try { + SearchFieldResponseDto fieldResponseDto=new SearchFieldResponseDto(); + buildSearchFieldsRequestDto(fieldDtos,rid); + fieldDtosRequestWrapper.setRequest(fieldDtos); + ResponseWrapper fieldDtosResponseWrapper = restClient.postApi(ApiName.PACKET_MANAGER_SEARCHFIELDS, MediaType.APPLICATION_JSON, + fieldDtosRequestWrapper, ResponseWrapper.class); + fieldResponseDto = objectMapper.readValue(objectMapper.writeValueAsString(fieldDtosResponseWrapper.getResponse()), SearchFieldResponseDto.class); + for (String field: fields) { + if (fieldResponseDto.getFields().containsKey(field) && field.equalsIgnoreCase(nameField)) { + String value = fieldResponseDto.getFields().get(field); + org.json.JSONArray jsonArray = new org.json.JSONArray(value); + org.json.JSONObject jsonObject = (org.json.JSONObject) jsonArray.get(0); + lostRidDataMap.put(field, jsonObject.getString(VALUE)); + } else { + lostRidDataMap.put(field, fieldResponseDto.getFields().get(field)); + } + } + getApplicantPhoto(rid,lostRidDataMap); + lostRidDetailsDto.setLostRidDataMap(lostRidDataMap); + } catch (Exception e) { + logger.error("error is occured while searching fields",e); + throw new RequestException(LostRidErrorCode.UNABLE_TO_RETRIEVE_LOSTRID_DATA.getErrorCode(), + LostRidErrorCode.UNABLE_TO_RETRIEVE_LOSTRID_DATA.getErrorMessage() + , e); + } + return lostRidDetailsDto; + } + + + private void getApplicantPhoto(String rid, Map lostRidDataMap){ + RequestWrapper biometricRequestDtoRequestWrapper=new RequestWrapper<>(); + BiometricRequestDto biometricRequestDto=new BiometricRequestDto(); + ConvertRequestDto convertRequestDto = new ConvertRequestDto(); + try { + buildBiometricRequestDto(biometricRequestDto,rid); + biometricRequestDtoRequestWrapper.setRequest(biometricRequestDto); + String response = restClient.postApi(ApiName.PACKET_MANAGER_BIOMETRIC, MediaType.APPLICATION_JSON, + biometricRequestDtoRequestWrapper, String.class); + JSONObject responseObj= objectMapper.readValue(response,JSONObject.class); + JSONObject responseJsonObj=utility.getJSONObject(responseObj,RESPONSE); + JSONArray segements=utility.getJSONArray(responseJsonObj,SEGEMENTS); + JSONObject jsonObject=utility.getJSONObjectFromArray(segements,0); + convertRequestDto.setVersion("ISO19794_5_2011"); + convertRequestDto.setInputBytes(Base64.decodeBase64((String) jsonObject.get("bdb"))); + byte[] data = FaceDecoder.convertFaceISOToImageBytes(convertRequestDto); + String encodedBytes = StringUtils.newStringUtf8(Base64.encodeBase64(data, false)); + String imageData = "data:image/png;base64," + encodedBytes; + if(response!=null && responseObj.get("response")==null) { + logger.error("biometric api response is null : {}",response); + throw new RequestException(ApplicantDetailErrorCode.RID_NOT_FOUND.getErrorCode(), + ApplicantDetailErrorCode.RID_NOT_FOUND.getErrorMessage()); + } + lostRidDataMap.put("applicantPhoto",imageData); + } catch (Exception e) { + logger.error("error is occured while getting applicantPhoto",e); + throw new RequestException(LostRidErrorCode.UNABLE_TO_RETRIEVE_APPLICANT_PHOTO.getErrorCode(), + LostRidErrorCode.UNABLE_TO_RETRIEVE_APPLICANT_PHOTO.getErrorMessage() + ,e); + } + } + + + private void buildBiometricRequestDto(BiometricRequestDto biometricRequestDto, String rid) { + List modalities=new ArrayList<>(); + biometricRequestDto.setSource(SOURCE); + biometricRequestDto.setId(rid); + biometricRequestDto.setProcess(PROCESS); + biometricRequestDto.setPerson(biometricField); + modalities.add("Face"); + biometricRequestDto.setModalities(modalities); + } + + + private void buildSearchFieldsRequestDto(SearchFieldDtos fieldDtos, String rid) { + fieldDtos.setSource(SOURCE); + fieldDtos.setId(rid); + fieldDtos.setProcess(PROCESS); + fieldDtos.setFields(Arrays.asList(fields)); + fieldDtos.setBypassCache(false); + } } diff --git a/admin/admin-service/src/test/java/io/mosip/admin/controller/test/AdminControllerTest.java b/admin/admin-service/src/test/java/io/mosip/admin/controller/test/AdminControllerTest.java index 7e69dc8b5e3..c9e8d9fb983 100644 --- a/admin/admin-service/src/test/java/io/mosip/admin/controller/test/AdminControllerTest.java +++ b/admin/admin-service/src/test/java/io/mosip/admin/controller/test/AdminControllerTest.java @@ -1,9 +1,14 @@ package io.mosip.admin.controller.test; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doNothing; import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; import java.time.LocalDate; import java.util.ArrayList; import java.util.List; @@ -73,6 +78,12 @@ public class AdminControllerTest { @Value("${LOST_RID_API}") String lstRidUrl; + @Value("${PACKET_MANAGER_SEARCHFIELDS}") + String searchFieldsUrl; + + @Value("${PACKET_MANAGER_BIOMETRIC}") + String biometricUrl; + private RequestWrapper searchInfoReq = new RequestWrapper<>(); SearchInfo info = new SearchInfo(); @@ -80,7 +91,7 @@ public class AdminControllerTest { public void setUp() throws Exception { mapper = new ObjectMapper(); mapper.registerModule(new JavaTimeModule()); - //doNothing().when(auditUtil).setAuditRequestDto(Mockito.any()); + //doNothing().when(auditUtil).setAuditRequestDto(Mockito.any(),Mockito.anyString()); List lst = new ArrayList<>(); FilterInfo e = new FilterInfo(); @@ -115,4 +126,23 @@ public void t002lostRidTest() throws Exception { } + @Test + @WithUserDetails(value = "zonal-admin") + public void t003lostRidDetailsTest() throws Exception { + String str = "{\"id\":null,\"version\":null,\"responsetime\":\"2023-07-19T05:58:54.874Z\",\"metadata\":null,\"response\":{\"fields\":{\"fullName\":\"[ {\\n \\\"language\\\" : \\\"eng\\\",\\n \\\"value\\\" : \\\"test new 2\\\"\\n}, {\\n \\\"language\\\" : \\\"fra\\\",\\n \\\"value\\\" : \\\"test new 2\\\"\\n} ]\",\"dateOfBirth\":\"1995/01/01\"}},\"errors\":[]}"; + String biometricResponse = new String(Files.readAllBytes(Paths.get(getClass().getResource("/biometricApiResponse.json").toURI())), StandardCharsets.UTF_8); + + mockRestServiceServer.expect(requestTo(searchFieldsUrl)) + .andRespond(withSuccess().body(str).contentType(MediaType.APPLICATION_JSON)); + + mockRestServiceServer.expect(requestTo(biometricUrl)) + .andRespond(withSuccess().body(biometricResponse).contentType(MediaType.APPLICATION_JSON)); + + AdminDataUtil.checkResponse( + (mockMvc.perform(MockMvcRequestBuilders.get("/lostRid/details/"+"10002100800001020230223050340")).andReturn()), + null); + + + } + } diff --git a/admin/admin-service/src/test/resources/application-test.properties b/admin/admin-service/src/test/resources/application-test.properties index b3c2a218b43..2d28fc46708 100644 --- a/admin/admin-service/src/test/resources/application-test.properties +++ b/admin/admin-service/src/test/resources/application-test.properties @@ -343,6 +343,16 @@ mosip.role.admin.getGetbulkuploadtranscationtranscationid=GLOBAL_ADMIN mosip.role.admin.postauditmanagerlog=GLOBAL_ADMIN,ZONAL_ADMIN mosip.role.admin.getPostauditmanagerlog=GLOBAL_ADMIN,ZONAL_ADMIN +#Admin LostRid controller +mosip.role.admin.getlostRiddetailsrid=GLOBAL_ADMIN,ZONAL_ADMIN +mosip.role.admin.postlostRid=GLOBAL_ADMIN,ZONAL_ADMIN + +#Applicant Details controller +mosip.role.admin.getapplicantDetailsrid=DIGITALCARD_ADMIN +mosip.role.admin.getapplicantDetailsgetLoginDetails=DIGITALCARD_ADMIN +mosip.role.admin.getriddigitalcardrid=DIGITALCARD_ADMIN + + # In Memory DB For Test javax.persistence.jdbc.driver=org.h2.Driver javax.persistence.jdbc.url=jdbc:h2\:mem\:testdb;DB_CLOSE_DELAY=-1;IGNORECASE=TRUE;INIT=CREATE SCHEMA IF NOT EXISTS master @@ -463,3 +473,5 @@ mosip.kernel.config.server.file.storage.uri=https://dev.mosip.net/config/admin/m mosip.admin.applicant-details.exposed-identity-fields=dob,applicantPhoto DIGITAL_CARD_STATUS_URL=https://qa3.mosip.net/v1/digitalcard RETRIEVE_IDENTITY_API=https://dev.mosip.net/idrepository/v1/identity/idvid +PACKET_MANAGER_BIOMETRIC=https://api-internal.dev.mosip.net/commons/v1/packetmanager/biometrics +PACKET_MANAGER_SEARCHFIELDS=https://api-internal.dev.mosip.net/commons/v1/packetmanager/searchFields \ No newline at end of file diff --git a/admin/admin-service/src/test/resources/biometricApiResponse.json b/admin/admin-service/src/test/resources/biometricApiResponse.json new file mode 100644 index 00000000000..b5b2266bfbe --- /dev/null +++ b/admin/admin-service/src/test/resources/biometricApiResponse.json @@ -0,0 +1,87 @@ +{ + "id": "mosip.registration.packet.reader", + "version": "v1", + "responsetime": "2023-07-19T06:01:37.687Z", + "metadata": null, + "response": { + "version": null, + "cbeffversion": null, + "birInfo": null, + "segments": [ + { + "version": { + "major": 1, + "minor": 1 + }, + "cbeffversion": { + "major": 1, + "minor": 1 + }, + "birInfo": { + "creator": null, + "index": null, + "payload": null, + "integrity": false, + "creationDate": null, + "notValidBefore": null, + "notValidAfter": null + }, + "bdbInfo": { + "challengeResponse": null, + "index": "9464d24e-275a-409c-a332-ebc0aab98ec2", + "format": { + "organization": "Mosip", + "type": "8" + }, + "encryption": null, + "creationDate": [ + 2023, + 2, + 23, + 5, + 5, + 56, + 832505800 + ], + "notValidBefore": null, + "notValidAfter": null, + "type": [ + "FACE" + ], + "subtype": [], + "level": "RAW", + "product": null, + "captureDevice": null, + "featureExtractionAlgorithm": null, + "comparisonAlgorithm": null, + "compressionAlgorithm": null, + "purpose": "ENROLL", + "quality": { + "algorithm": { + "organization": "HMAC", + "type": "SHA-256" + }, + "score": 94, + "qualityCalculationFailed": null + } + }, + "bdb": "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", + "sb": "ZXlKNE5XTWlPbHNpVFVsSlJqbHFRME5CT1RablFYZEpRa0ZuU1VKQ1ZFRk9RbWRyY1docmFVYzVkekJDUVZGelJrRkVRbVpOVVhOM1ExRlpSRlpSVVVkRmQwcEtWR3BGVFUxQmIwZEJNVlZGUTBGM1JGTXlSbmxOVVhkM1EyZFpSRlpSVVVoRVFVNURZa2hKZUVWRVFVOUNaMDVXUWtGdlRVSXdVbEZOYkRscldsaFplRVZFUVU5Q1owNVdRa0Z6VFVJd1VsRk5iRGxyV2xoWmVFVkVRVTlDWjA1V1FrRk5UVUl3VWxGTmJEbHJXbGhaZDBob1kwNU5ha2wzVDFSSmVFMUVWWGxOVkZFeFYyaGpUazFxVFhkTmVrbDNUVVJWZVUxVVVURlhha0pYVFZGemQwTlJXVVJXVVZGSFJYZEtTbFJxUlUxTlFXOUhRVEZWUlVOQmQwUlRNa1o1VFZGM2QwTm5XVVJXVVZGSVJFRk9RMkpJU1hoRVZFRk1RbWRPVmtKQmIwMUNSVnBDVVRCVmVFUlVRVXhDWjA1V1FrRnpUVUpGV2tKUk1GVjRSRlJCVEVKblRsWkNRVTFOUWtWYVFsRXdWWGRuWjBscFRVRXdSME5UY1VkVFNXSXpSRkZGUWtGUlZVRkJORWxEUkhkQmQyZG5TVXRCYjBsRFFWRkVTbWw2VEZReEwwaEVkR3QyV1VVdllUWXdVak5JZHpGWVpYRlpOMHBrUzFsQ1oxZGpSWGRYUVdsck9XRkZVbVJuTm1sTlpqTjNOek55YXk5M2EwMHdSamt6VUhocVZIRjNUR2xHV0hBM2RFcERRVGgxUkZKSEswaHRXSEp0WmtoYWVIazNXREJLVml0RlJUaENhV2RhWTI5S2VWVmlWbXB1Tm1oc0wwaHFablZRTjFGWU5GcE9MMjl6U0c1TllYQktTWGxoUm1oVGFUWlNZV1oyYVUxdWN6UXJhVzE1Wm0xTGVUWjZMMnQ1UmxwVllpOWlPR1Y1V25kbk5HVjJkemRZVFdGVlUxUkdVbUpPWmtWS1MwbFhXV05oU1dGWWJFZHpNV3RQYWsxT1duUnRNRk5qWVZKWWNVWldUVWRCZENzelpWZElZbU0yYWpWalVuaGtOMEo1VlZoQkx6ZFpXWGd5UzA0NGVFSkZTVmx6WkV3NE9XMVpOV1pGVGxwTWRrcHJTa3hGVldWQlNUWjBlRkozYjI1aVZFeElVRzlyWVd4WGIwOXNkREl6Y1dNMlJYZ3JObVJQYmtkVFRYUkhiV2R0VVRoS0syMU1aM2hLVkVGUlVsbHBTMGxETlhGT1UwdFJSRlpLWjFsT1NFVTFUVVoyU1dGcGQzSkpTbXB2V0hKUlpEUXJVa2xFY3poM1VGSlFNV1kzYzJKd2FEUlpiazF0UkdKUFpsRXlWR2hQYjFGUVFtMWpaMWRzYkRnMWJGQjRVamR4V25VcmJuUkhRVUZrUjB4RWNWTkxhVE55UmpkUVdrZFBaM0ZqWjJncmMzbGxlVkZJTjA0NGIyc3dkVzF4Ulc1RGFWTnhaak5KTlRGRGJXRmtSVGRMU2paUVozazFiamxLUVRZM2VuVXlWR0pKV0docWVVbGtiR2R1VDNWaU0xTmFTbGRGTkZwblRHSnpjMFV2WkVadFdTOWlLMm81TkV0cU1FdEdhalF2YmpKMkwySjNibnBTSzB4TGNXYzJTVk5aY214MGEwVXdhVGN5Y0M5TFkwUkJTRmxrZEdwV1lXdFhhRU5GTjBWUWRFbElTVXRFUWpGRlpWbExhRFEyS3k5NlZFRnZSMHRLZGpVNFRFRm9SRkJEUmxaSFUxVnZZMFJ4VkVoYWFtTTRTRGd2ZW1WdVJUWjFhRXRDZVhGelkxZHlNVEE0VERWUlExRkpSRUZSUVVKdk5FaEdUVWxJUTAxQmEwZEJNVlZrUlhkUlEwMUJRWGRGVVZsS1dVbGFTVUZaWWpSUlowVkNRa0ZSUkVGblYyZE5SRTFIUTFkRFIxTkJSMGNyUlVsQ1JGRlJiVVpwVWxCalIxWjFWVEZPVFVsRlpHeGliVlo1V1ZoU2JGcERRa1JpUjJ4c1ltNVJaMUV5Vm5sa1IyeHRZVmRPYUdSSFZYZElVVmxFVmxJd1QwSkNXVVZHVUdjNU1URlpPSE00TlhacFpTdHZOV2w2U2taaVkzSlZkRVZNVFVJNFIwRXhWV1JKZDFGWlRVSmhRVVpQUTNOUWRHeEtiamxrUkRZd1ZrWnJSazFhTm14WFFrcEZPVmxOUVRSSFFURlZaRVIzUlVJdmQxRkZRWGRKUmpSRVFXUkNaMDVXU0ZOVlJVWnFRVlZDWjJkeVFtZEZSa0pSWTBSQloxbEpTM2RaUWtKUlZVaEJkMUYzUkZGWlNrdHZXa2xvZG1OT1FWRkZURUpSUVVSblowbENRVWRtVWpKaWNsTlNaRUpKVjFsME5UUk5OakJpWlRKNlZYRTRhbFExYW5oQmFVdGxjekZqU2psVFpVbG5hbXR0WjFkUWFTdFZVakJZWVU1a0wxQXpjWGxDY2xSUlNFNXRWM2t5ZDB4TlYweDVkeXRsVUU5MVYzQkJZMXBETkV0bVdFOUVWQ3RoV1d0VmVWQjNLMW9yVkVGS1ZGcDRia3hMYW01WlpXNTRVbVZJWkVOUGFtcEdSM1JrWmpKVk5WQmFNVTFoSzBsdmNqVmpNV000WVhKU2RXWlBXRGRtVVhwbU1UazJiM2d4YlhSblkyZEhRbmhLTlhWbU9WUTBkMlZJUVdOSVpFbGtNa2RPVDBOTU9IQjVNU3R2VEhVclJXWTBhREpWY3pkRmN5dHNkMlIzZW5rM2VqbGhka2d3TjI5QlNWbHZXU3RZZFZSQ1ozWkdlbTVpVjFCcVZFRXdWalpYVlVSb00xSXpRMFJXZVRBeE9XVnRORkpUU1c1dkt6WjNjVzF5Wm5WTVEzRmlXbHBDTlVjNVVuSnRTMk40WkVJMlpEaHdPV0ZTWjA1alpqSm9NbTB6YlhSRmFFRnlPRFJhTkZWcmJuRmFNVFJsYkRreFdreHVla3RDWjNOVFZGUllhMVJvV1ZGMVNtMXVOMGN3UTJKWFNXNTBTMlZRVWtSNU5HUkNWMlF6UlhoT01EUjROakkyWkdjelJXSkxhVUowZVVvMWVXRklkblpvVDNVMlFsVnVZVXBHYWk5WlNXRTJUbmQxTW1SVk56QldiVGRsVmtaUFRucFlaWFZMUWpCTGIwRTBaR3hKZFdoMlRHTk9NVEprVVZGRWFsb3paVWRxYW5SeFVYazFOVUowUnpCRGFsZENSVWxFSzFkbFNIaG9hak5TUTJwNGEySnhZVFpyYTBWaWFrZ3lXR29yV1dWM01DdGFSMGRyWlRCVGREUkNjWEU0UlVkQksxSjJVMnRJUzJKTFFsTlRhRlZKVEVKU05UaFZjRUZ2VkU0MlowMTFXWGRYUVVZcmVtOXFZeTkwVURGVlIxRlFRaXRrVURBclpqQklSblZJTWpoRFdXVXdXbkp4YkhsV05IaHRObmxxUlVGNGNXOXFjRll5WkZGd1VWa3pkRmhPTUhsb056ZExVRVJyUWtOMFlreEtjMjlhV1RCR1dFMXpURzg0T1dwWlJrWXZORmsxVEVOaksxcElJbDBzSW1Gc1p5STZJbEpUTWpVMklpd2lkSGx3SWpvaVNsZFVJbjAuLmxyQTM5Q1RqSDYzMW9WajJKU1RVUG5kUkR3djFxQ2pEblBVZHBOby1yaVN4X0Qxb2Rzb0N3S09aRllPZlczNXNFd0RGS0pyS0JKTnd3SHNyVFdiaVpreWx3TTA4cmdSVUh4bDBlUDRPek91OHdVUUdpTFFybnF5RlpKdGRUVnQzTFZoSjBTTjV1NFNsbmZOVHB5TFJKUExzSEl6THR2STdRR0c2LU5JZEFsampCcDdvMDdOTzZxOWFaLW16dTdUTUNvZ2JTVUpieWZlb2Y0WU5VWURNNlJ0M25CTE81SGx0cDVVSzY2bzRBLTdZbUdiLWsxMDFFSkN0YVJvYVNNOGFSQ2xUS0hiSkNSaC1tYnltT2QzYktfS3owZFFsWkd5NHJoUHZNM1M0UVpCTFFaNTFsWkNxODYzSlVGck5vQXhHQ0NDT25HNTN4MmJpMkU4YWgxNDYzZXVrYnFXUHM5QjlwSVFvQ0RIaVVBZ21vOEtzS3ExRGFvTWtya0hyUGlqcjVrdEZwbnJZeFFNb2JqNkZ0S0w2VHctelVsUHpraGlES3F5Y2ppUVEwZ3hfTUVFVVRuT0p5RERoWlpuY0ZjRk1SUW9JcFF5aUZBam84VEpPdFNFN25EYjZ1N2xuRExQQTgtY3I2ZkhiOTFqeWFmWmxZc2prTGYyYk1vTWtCdmM1eXg1ZVlHbV8zbHFGVGhJb3JpZmJPMjEyT0k1ckdsamlxWW5JLWpKWVdRRFlzamdJMlNZd1hTazBjQmF6clRJRndMUUVHQTBtM1FRTFRVakprd25fVGZwSFppOTdpdFR4WXJ5eXdHQU1HUm42N1g0ZERqTXA4d3dGZWNPVHZkTVhaYktqckNxQ2hqVnBDM1Z3U3AzdTVvR2xLdzhpWlZqaEE4T3ZUUXNEZUJZ", + "birs": null, + "sbInfo": null, + "others": { + "SPEC_VERSION": "0.9.5", + "RETRIES": "1", + "FORCE_CAPTURED": "false", + "EXCEPTION": "false", + "PAYLOAD": "{\"digitalId\":\"eyJ4NWMiOlsiTUlJRjlqQ0NBOTZnQXdJQkFnSUJCVEFOQmdrcWhraUc5dzBCQVFzRkFEQmZNUXN3Q1FZRFZRUUdFd0pKVGpFTU1Bb0dBMVVFQ0F3RFMyRnlNUXd3Q2dZRFZRUUhEQU5DYkhJeEVEQU9CZ05WQkFvTUIwUlFNbDlrWlhZeEVEQU9CZ05WQkFzTUIwUlFNbDlrWlhZeEVEQU9CZ05WQkFNTUIwUlFNbDlrWlhZd0hoY05Nakl3T1RJeE1EVXlNVFExV2hjTk1qTXdNekl3TURVeU1UUTFXakJXTVFzd0NRWURWUVFHRXdKSlRqRU1NQW9HQTFVRUNBd0RTMkZ5TVF3d0NnWURWUVFIREFOQ2JISXhEVEFMQmdOVkJBb01CRVpCUTBVeERUQUxCZ05WQkFzTUJFWkJRMFV4RFRBTEJnTlZCQU1NQkVaQlEwVXdnZ0lpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElDRHdBd2dnSUtBb0lDQVFESml6TFQxL0hEdGt2WUUvYTYwUjNIdzFYZXFZN0pkS1lCZ1djRXdXQWlrOWFFUmRnNmlNZjN3NzNyay93a00wRjkzUHhqVHF3TGlGWHA3dEpDQTh1RFJHK0htWHJtZkhaeHk3WDBKVitFRThCaWdaY29KeVViVmpuNmhsL0hqZnVQN1FYNFpOL29zSG5NYXBKSXlhRmhTaTZSYWZ2aU1uczQraW15Zm1LeTZ6L2t5RlpVYi9iOGV5WndnNGV2dzdYTWFVU1RGUmJOZkVKS0lXWWNhSWFYbEdzMWtPak1OWnRtMFNjYVJYcUZWTUdBdCszZVdIYmM2ajVjUnhkN0J5VVhBLzdZWXgyS044eEJFSVlzZEw4OW1ZNWZFTlpMdkprSkxFVWVBSTZ0eFJ3b25iVExIUG9rYWxXb09sdDIzcWM2RXgrNmRPbkdTTXRHbWdtUThKK21MZ3hKVEFRUllpS0lDNXFOU0tRRFZKZ1lOSEU1TUZ2SWFpd3JJSmpvWHJRZDQrUklEczh3UFJQMWY3c2JwaDRZbk1tRGJPZlEyVGhPb1FQQm1jZ1dsbDg1bFB4UjdxWnUrbnRHQUFkR0xEcVNLaTNyRjdQWkdPZ3FjZ2grc3lleVFIN044b2swdW1xRW5DaVNxZjNJNTFDbWFkRTdLSjZQZ3k1bjlKQTY3enUyVGJJWGhqeUlkbGduT3ViM1NaSldFNFpnTGJzc0UvZEZtWS9iK2o5NEtqMEtGajQvbjJ2L2J3bnpSK0xLcWc2SVNZcmx0a0UwaTcycC9LY0RBSFlkdGpWYWtXaENFN0VQdElISUtEQjFFZVlLaDQ2Ky96VEFvR0tKdjU4TEFoRFBDRlZHU1VvY0RxVEhaamM4SDgvemVuRTZ1aEtCeXFzY1dyMTA4TDVRQ1FJREFRQUJvNEhGTUlIQ01Ba0dBMVVkRXdRQ01BQXdFUVlKWUlaSUFZYjRRZ0VCQkFRREFnV2dNRE1HQ1dDR1NBR0crRUlCRFFRbUZpUlBjR1Z1VTFOTUlFZGxibVZ5WVhSbFpDQkRiR2xsYm5RZ1EyVnlkR2xtYVdOaGRHVXdIUVlEVlIwT0JCWUVGUGc5MTFZOHM4NXZpZStvNWl6SkZiY3JVdEVMTUI4R0ExVWRJd1FZTUJhQUZPQ3NQdGxKbjlkRDYwVkZrRk1aNmxXQkpFOVlNQTRHQTFVZER3RUIvd1FFQXdJRjREQWRCZ05WSFNVRUZqQVVCZ2dyQmdFRkJRY0RBZ1lJS3dZQkJRVUhBd1F3RFFZSktvWklodmNOQVFFTEJRQURnZ0lCQUdmUjJiclNSZEJJV1l0NTRNNjBiZTJ6VXE4alQ1anhBaUtlczFjSjlTZUlnamttZ1dQaStVUjBYYU5kL1AzcXlCclRRSE5tV3kyd0xNV0x5dytlUE91V3BBY1pDNEtmWE9EVCthWWtVeVB3K1orVEFKVFp4bkxLam5ZZW54UmVIZENPampGR3RkZjJVNVBaMU1hK0lvcjVjMWM4YXJSdWZPWDdmUXpmMTk2b3gxbXRnY2dHQnhKNXVmOVQ0d2VIQWNIZElkMkdOT0NMOHB5MStvTHUrRWY0aDJVczdFcytsd2R3enk3ejlhdkgwN29BSVlvWStYdVRCZ3ZGem5iV1BqVEEwVjZXVURoM1IzQ0RWeTAxOWVtNFJTSW5vKzZ3cW1yZnVMQ3FiWlpCNUc5UnJtS2N4ZEI2ZDhwOWFSZ05jZjJoMm0zbXRFaEFyODRaNFVrbnFaMTRlbDkxWkxuektCZ3NTVFRYa1RoWVF1Sm1uN0cwQ2JXSW50S2VQUkR5NGRCV2QzRXhOMDR4NjI2ZGczRWJLaUJ0eUo1eWFIdnZoT3U2QlVuYUpGai9ZSWE2Tnd1MmRVNzBWbTdlVkZPTnpYZXVLQjBLb0E0ZGxJdWh2TGNOMTJkUVFEalozZUdqanRxUXk1NUJ0RzBDaldCRUlEK1dlSHhoajNSQ2p4a2JxYTZra0ViakgyWGorWWV3MCtaR0drZTBTdDRCcXE4RUdBK1J2U2tIS2JLQlNTaFVJTEJSNThVcEFvVE42Z011WXdXQUYrem9qYy90UDFVR1FQQitkUDArZjBIRnVIMjhDWWUwWnJxbHlWNHhtNnlqRUF4cW9qcFYyZFFwUVkzdFhOMHloNzdLUERrQkN0YkxKc29aWTBGWE1zTG84OWpZRkYvNFk1TENjK1pIIl0sImFsZyI6IlJTMjU2IiwidHlwIjoiSldUIn0.eyJzZXJpYWxObyI6IjIzNDU2Nzg5MDEiLCJtYWtlIjoiTU9TSVAiLCJtb2RlbCI6IkZBQ0UwMSIsInR5cGUiOiJGYWNlIiwiZGV2aWNlU3ViVHlwZSI6IkZ1bGwgZmFjZSIsImRldmljZVByb3ZpZGVySWQiOiJNT1NJUC5QUk9YWS5TQkkiLCJkZXZpY2VQcm92aWRlciI6Ik1PU0lQIiwiZGF0ZVRpbWUiOiIyMDIzLTAyLTIzVDA1OjA1OjQyWiJ9.J23q10YKrx0-foBqI4w1MXmSLWcUd4VaYw7wBY7f7LoyZMOXVyjAMzPlj8kMUCshebJYsos1CVOHiIG8KfU4a57Fa2NQAg3r4lINze2XmBpyIZ6XTPUHF8XcDAly1nCXwYa86QWjH2Oc-W_aeiYhEHzs3dH8VT3LFQti-j-py6S7ueflZ7oA9JcVBMah8lr5svjHWbCE04nMX0tpd1etYxHtc7zMOIqT-8irRHe2Bihfv4I1e0dPASDj6FH8USy-bmfXZ8sDmO_OW6yfqM8YUEd5YhbfgdMYV491hw8iiy5n1FyPOwM1pYB3cZHCsoGbQ8-rh_vZCxexHXDcAuOFeF1dEZ3Fk45-ioh5X5Su-S0c3SMz27nzGLwz1MjV_q8lSWN-zLsbBA1q2twuJqPtpuupwY6lgxeplrzxLBpg8JSdLwU-p6dn19KJ4vYawT-fCfQS1tQ2ItJZlE9Irce1eDNqA7hzeM6yCaNBvCUSrMe3F6FMVkxugCrfmQXwrUTrElEHX-ZellNWRm9Ogbd-o9-IQB8gtpwbzMJR-dguvr7kSarddQU1yF66aZbHGwPr7HdryUgEkmP9EsmR84QxMrqFiDINNzRXm3p57PKXDChZWBVGkOPU6OYLGL06hJHGiy-MZANi9HK1dRGBcI6SQfYXbFMKO5eN-1u8VRfq_9w\",\"deviceCode\":\"b692b595-3523-face-99fc-bd76e35f190f\",\"deviceServiceVersion\":\"0.9.5\",\"bioType\":\"Face\",\"purpose\":\"Registration\",\"env\":\"Staging\",\"bioValue\":\"\",\"transactionId\":\"dada1829-6a36-4ad7-8c26-6f9c912c5db9\",\"timestamp\":\"2023-02-23T05:05:42Z\",\"requestedScore\":\"90\",\"qualityScore\":\"94\"}", + "SDK_SCORE": "0.0" + } + } + ], + "others": { + "CONFIGURED": "leftEye,rightEye,rightIndex,rightLittle,rightRing,rightMiddle,leftIndex,leftLittle,leftRing,leftMiddle,leftThumb,rightThumb,face" + } + }, + "errors": [] +} \ No newline at end of file From 9c1d21bcbb2530e0393fdeaaa95945b96ab74c12 Mon Sep 17 00:00:00 2001 From: Himaja Dhanyamraju <43470317+HimajaDhanyamraju2@users.noreply.github.com> Date: Thu, 17 Aug 2023 20:00:23 +0530 Subject: [PATCH 05/16] Changes in script response (#893) Co-authored-by: M1044292 --- .../kernel/syncdata/service/helper/ClientSettingsHelper.java | 5 +++-- .../syncdata/service/impl/SyncMasterDataServiceImpl.java | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/admin/kernel-syncdata-service/src/main/java/io/mosip/kernel/syncdata/service/helper/ClientSettingsHelper.java b/admin/kernel-syncdata-service/src/main/java/io/mosip/kernel/syncdata/service/helper/ClientSettingsHelper.java index e7b4fc7dbef..25cdceb711b 100644 --- a/admin/kernel-syncdata-service/src/main/java/io/mosip/kernel/syncdata/service/helper/ClientSettingsHelper.java +++ b/admin/kernel-syncdata-service/src/main/java/io/mosip/kernel/syncdata/service/helper/ClientSettingsHelper.java @@ -235,7 +235,7 @@ private SyncDataBaseDto getEncryptedSyncDataBaseDto(Class clazz, RegistrationCen return null; } - public List getConfiguredScriptUrlDetail(String publicKey) { + public List getConfiguredScriptUrlDetail(RegistrationCenterMachineDto regCenterMachineDto) { List list = new ArrayList<>(); scriptNames.forEach(fileName -> { Map urlDetail = buildUrlDetailMap(fileName); @@ -243,7 +243,8 @@ public List getConfiguredScriptUrlDetail(String publicKey) { TpmCryptoRequestDto tpmCryptoRequestDto = new TpmCryptoRequestDto(); tpmCryptoRequestDto .setValue(CryptoUtil.encodeToURLSafeBase64(mapper.getObjectAsJsonString(urlDetail).getBytes())); - tpmCryptoRequestDto.setPublicKey(publicKey); + tpmCryptoRequestDto.setPublicKey(regCenterMachineDto.getPublicKey()); + tpmCryptoRequestDto.setClientType(regCenterMachineDto.getClientType()); TpmCryptoResponseDto tpmCryptoResponseDto = clientCryptoManagerService.csEncrypt(tpmCryptoRequestDto); list.add(new SyncDataBaseDto(fileName, "script", tpmCryptoResponseDto.getValue())); } catch (Exception e) { diff --git a/admin/kernel-syncdata-service/src/main/java/io/mosip/kernel/syncdata/service/impl/SyncMasterDataServiceImpl.java b/admin/kernel-syncdata-service/src/main/java/io/mosip/kernel/syncdata/service/impl/SyncMasterDataServiceImpl.java index edbcf7364b6..7115eb15c94 100644 --- a/admin/kernel-syncdata-service/src/main/java/io/mosip/kernel/syncdata/service/impl/SyncMasterDataServiceImpl.java +++ b/admin/kernel-syncdata-service/src/main/java/io/mosip/kernel/syncdata/service/impl/SyncMasterDataServiceImpl.java @@ -245,7 +245,7 @@ public SyncDataResponseDto syncClientSettingsV2(String regCenterId, String keyIn } List list = clientSettingsHelper.retrieveData(futureMap, regCenterMachineDto, true); - list.addAll(clientSettingsHelper.getConfiguredScriptUrlDetail(regCenterMachineDto.getPublicKey())); + list.addAll(clientSettingsHelper.getConfiguredScriptUrlDetail(regCenterMachineDto)); response.setDataToSync(list); return response; } From 5e9fc68b4b76c5e9e5f53c92338b661c52a6b82c Mon Sep 17 00:00:00 2001 From: Akila Lakshmanan <77330852+akilalakshmanan@users.noreply.github.com> Date: Mon, 21 Aug 2023 15:32:32 +0530 Subject: [PATCH 06/16] [MOSIP-28484] Added error handling for deploy.sh script (#891) * [MOSIP-28484] Added error handling for deploy.sh script * [MOSIP-28484] Updated error handling for deploy.sh script * [MOSIP-28484] Removed exit command --------- Co-authored-by: akilalakshmanan --- db_scripts/mosip_hotlist/deploy.sh | 16 ++++++++-------- db_scripts/mosip_master/deploy.sh | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/db_scripts/mosip_hotlist/deploy.sh b/db_scripts/mosip_hotlist/deploy.sh index 8cafd84f7c2..ef9cc3c091e 100644 --- a/db_scripts/mosip_hotlist/deploy.sh +++ b/db_scripts/mosip_hotlist/deploy.sh @@ -17,28 +17,28 @@ fi ## Terminate existing connections echo "Terminating active connections" -CONN=$(PGPASSWORD=$SU_USER_PWD psql --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -t -c "SELECT count(pg_terminate_backend(pg_stat_activity.pid)) FROM pg_stat_activity WHERE datname = '$MOSIP_DB_NAME' AND pid <> pg_backend_pid()";exit;) +CONN=$(PGPASSWORD=$SU_USER_PWD psql -v ON_ERROR_STOP=1 --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -t -c "SELECT count(pg_terminate_backend(pg_stat_activity.pid)) FROM pg_stat_activity WHERE datname = '$MOSIP_DB_NAME' AND pid <> pg_backend_pid()";exit;) echo "Terminated connections" ## Drop db and role -PGPASSWORD=$SU_USER_PWD psql --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f drop_db.sql -PGPASSWORD=$SU_USER_PWD psql --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f drop_role.sql +PGPASSWORD=$SU_USER_PWD psql -v ON_ERROR_STOP=1 --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f drop_db.sql +PGPASSWORD=$SU_USER_PWD psql -v ON_ERROR_STOP=1 --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f drop_role.sql ## Create users echo `date "+%m/%d/%Y %H:%M:%S"` ": Creating database users" | tee -PGPASSWORD=$SU_USER_PWD psql --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f role_dbuser.sql -v dbuserpwd=\'$DBUSER_PWD\' +PGPASSWORD=$SU_USER_PWD psql -v ON_ERROR_STOP=1 --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f role_dbuser.sql -v dbuserpwd=\'$DBUSER_PWD\' ## Create DB -PGPASSWORD=$SU_USER_PWD psql --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f db.sql -PGPASSWORD=$SU_USER_PWD psql --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f ddl.sql +PGPASSWORD=$SU_USER_PWD psql -v ON_ERROR_STOP=1 --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f db.sql +PGPASSWORD=$SU_USER_PWD psql -v ON_ERROR_STOP=1 --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f ddl.sql ## Grants -PGPASSWORD=$SU_USER_PWD psql --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f grants.sql +PGPASSWORD=$SU_USER_PWD psql -v ON_ERROR_STOP=1 --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f grants.sql ## Populate tables if [ ${DML_FLAG} == 1 ] then echo `date "+%m/%d/%Y %H:%M:%S"` ": Deploying DML for ${MOSIP_DB_NAME} database" - PGPASSWORD=$SU_USER_PWD psql --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -a -b -f dml.sql + PGPASSWORD=$SU_USER_PWD psql -v ON_ERROR_STOP=1 --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -a -b -f dml.sql fi diff --git a/db_scripts/mosip_master/deploy.sh b/db_scripts/mosip_master/deploy.sh index 8cafd84f7c2..ef9cc3c091e 100644 --- a/db_scripts/mosip_master/deploy.sh +++ b/db_scripts/mosip_master/deploy.sh @@ -17,28 +17,28 @@ fi ## Terminate existing connections echo "Terminating active connections" -CONN=$(PGPASSWORD=$SU_USER_PWD psql --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -t -c "SELECT count(pg_terminate_backend(pg_stat_activity.pid)) FROM pg_stat_activity WHERE datname = '$MOSIP_DB_NAME' AND pid <> pg_backend_pid()";exit;) +CONN=$(PGPASSWORD=$SU_USER_PWD psql -v ON_ERROR_STOP=1 --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -t -c "SELECT count(pg_terminate_backend(pg_stat_activity.pid)) FROM pg_stat_activity WHERE datname = '$MOSIP_DB_NAME' AND pid <> pg_backend_pid()";exit;) echo "Terminated connections" ## Drop db and role -PGPASSWORD=$SU_USER_PWD psql --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f drop_db.sql -PGPASSWORD=$SU_USER_PWD psql --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f drop_role.sql +PGPASSWORD=$SU_USER_PWD psql -v ON_ERROR_STOP=1 --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f drop_db.sql +PGPASSWORD=$SU_USER_PWD psql -v ON_ERROR_STOP=1 --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f drop_role.sql ## Create users echo `date "+%m/%d/%Y %H:%M:%S"` ": Creating database users" | tee -PGPASSWORD=$SU_USER_PWD psql --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f role_dbuser.sql -v dbuserpwd=\'$DBUSER_PWD\' +PGPASSWORD=$SU_USER_PWD psql -v ON_ERROR_STOP=1 --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f role_dbuser.sql -v dbuserpwd=\'$DBUSER_PWD\' ## Create DB -PGPASSWORD=$SU_USER_PWD psql --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f db.sql -PGPASSWORD=$SU_USER_PWD psql --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f ddl.sql +PGPASSWORD=$SU_USER_PWD psql -v ON_ERROR_STOP=1 --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f db.sql +PGPASSWORD=$SU_USER_PWD psql -v ON_ERROR_STOP=1 --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f ddl.sql ## Grants -PGPASSWORD=$SU_USER_PWD psql --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f grants.sql +PGPASSWORD=$SU_USER_PWD psql -v ON_ERROR_STOP=1 --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -f grants.sql ## Populate tables if [ ${DML_FLAG} == 1 ] then echo `date "+%m/%d/%Y %H:%M:%S"` ": Deploying DML for ${MOSIP_DB_NAME} database" - PGPASSWORD=$SU_USER_PWD psql --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -a -b -f dml.sql + PGPASSWORD=$SU_USER_PWD psql -v ON_ERROR_STOP=1 --username=$SU_USER --host=$DB_SERVERIP --port=$DB_PORT --dbname=$DEFAULT_DB_NAME -a -b -f dml.sql fi From cc90a4bc3b43e7fdd247ade9d3d965da6d15f8e0 Mon Sep 17 00:00:00 2001 From: VSIVAKALYAN <103260988+VSIVAKALYAN@users.noreply.github.com> Date: Wed, 20 Sep 2023 19:29:46 +0530 Subject: [PATCH 07/16] [MOSIP-29162] Updated Workflow as per Resusable Template. (#899) --- .github/workflows/postgres-init_trigger.yml | 83 ---- .github/workflows/push-trigger.yml | 94 ++++ .github/workflows/push_trigger.yml | 466 -------------------- .github/workflows/release-changes.yml | 26 ++ .github/workflows/release_changes.yml | 56 --- .github/workflows/release_trigger.yml | 326 -------------- .github/workflows/tag.yml | 33 ++ 7 files changed, 153 insertions(+), 931 deletions(-) delete mode 100644 .github/workflows/postgres-init_trigger.yml create mode 100644 .github/workflows/push-trigger.yml delete mode 100644 .github/workflows/push_trigger.yml create mode 100644 .github/workflows/release-changes.yml delete mode 100644 .github/workflows/release_changes.yml delete mode 100644 .github/workflows/release_trigger.yml create mode 100644 .github/workflows/tag.yml diff --git a/.github/workflows/postgres-init_trigger.yml b/.github/workflows/postgres-init_trigger.yml deleted file mode 100644 index 3de4c6f32c5..00000000000 --- a/.github/workflows/postgres-init_trigger.yml +++ /dev/null @@ -1,83 +0,0 @@ -name: Trigger postgres-init repo upon db scripts updates - -on: - push: - branches: - - master - - 1.* - - develop - - release* - paths: - - db_release_scripts/** - - db_scripts/** - -jobs: - paths-filter: - runs-on: ubuntu-latest - outputs: - db_release_scripts: ${{ steps.filter.outputs.db_release_scripts }} - db_scripts: ${{ steps.filter.outputs.db_scripts }} - steps: - - uses: actions/checkout@v2 - - uses: dorny/paths-filter@v2 - id: filter - with: - base: ${{ github.ref }} - filters: | - db_release_scripts: - - 'db_release_scripts/**' - db_scripts: - - 'db_scripts/**' - - # run only if 'db_release_scripts' files were changed - db_release_scripts_updates: - needs: paths-filter - if: needs.paths-filter.outputs.db_release_scripts == 'true' - runs-on: ubuntu-latest - steps: - - name: Check for updates - run: echo "Updates are present in db_release_scripts directory, Triggering postgres-init repo" - - uses: 8398a7/action-slack@v3 - with: - status: ${{ job.status }} - fields: repo,message,commit,author,job,took,ref # selectable (default: repo,message) - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_DEVOPS }} # required - if: success() # Pick up events when the job is successful. - - # run only if not 'db_release_scripts' files were changed - - name: Check for no updates - if: needs.paths-filter.outputs.db_release_scripts != 'true' - run: echo "Updates are not present in db_release_scripts directory" - - # run only if 'db_scripts' files were changed - db_scripts_updates: - needs: paths-filter - if: needs.paths-filter.outputs.db_scripts == 'true' - runs-on: ubuntu-latest - steps: - - name: Check for updates - run: echo "Updates are present in db_scripts directory, Triggering postgres-init repo" - - uses: 8398a7/action-slack@v3 - with: - status: ${{ job.status }} - fields: repo,message,commit,author,job,took,ref # selectable (default: repo,message) - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_DEVOPS }} # required - if: success() # Pick up events when the job is successful. - - # run only if not 'db_scripts' files were changed - - name: Check for no updates - if: needs.paths-filter.outputs.db_scripts != 'true' - run: echo "Updates are not present in db_scripts directory" - - # This job is to trigger postgres-init repo. - trigger-postgres_init_repo: - runs-on: ubuntu-latest - steps: - - uses: peter-evans/repository-dispatch@v2 - with: - token: ${{ secrets.ACTION_PAT }} - repository: mosip/postgres-init - base: ${{ github.ref }} - event-type: db-event diff --git a/.github/workflows/push-trigger.yml b/.github/workflows/push-trigger.yml new file mode 100644 index 00000000000..39904afc3e5 --- /dev/null +++ b/.github/workflows/push-trigger.yml @@ -0,0 +1,94 @@ +name: Maven Package upon a push + +on: + release: + types: [published] + pull_request: + types: [opened] + workflow_dispatch: + inputs: + message: + description: 'Message for manually triggering' + required: false + default: 'Triggered for Updates' + type: string + push: + branches: + - '!release-branch' + - release-1* + - master + - 1.* + - develop + - MOSIP* + +jobs: + build-maven-admin-services: + uses: mosip/kattu/.github/workflows/maven-build.yml@master + with: + SERVICE_LOCATION: ./admin + BUILD_ARTIFACT: admin + secrets: + OSSRH_USER: ${{ secrets.OSSRH_USER }} + OSSRH_SECRET: ${{ secrets.OSSRH_SECRET }} + OSSRH_TOKEN: ${{ secrets.OSSRH_TOKEN }} + GPG_SECRET: ${{ secrets.GPG_SECRET }} + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} + + publish_to_nexus: + if: "${{ !contains(github.ref, 'master') && github.event_name != 'pull_request' }}" + needs: build-maven-admin-services + uses: mosip/kattu/.github/workflows/maven-publish-to-nexus.yml@master + with: + SERVICE_LOCATION: ./admin + secrets: + OSSRH_USER: ${{ secrets.OSSRH_USER }} + OSSRH_SECRET: ${{ secrets.OSSRH_SECRET }} + OSSRH_URL: ${{ secrets.OSSRH_SNAPSHOT_URL }} + OSSRH_TOKEN: ${{ secrets.OSSRH_TOKEN }} + GPG_SECRET: ${{ secrets.GPG_SECRET }} + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} + + build-dockers: + needs: build-maven-admin-services + strategy: + matrix: + include: + - SERVICE_LOCATION: 'admin/admin-service' + SERVICE_NAME: 'admin-service' + BUILD_ARTIFACT: 'admin' + - SERVICE_LOCATION: 'admin/hotlist-service' + SERVICE_NAME: 'hotlist-service' + BUILD_ARTIFACT: 'admin' + - SERVICE_LOCATION: 'admin/kernel-masterdata-service' + SERVICE_NAME: 'kernel-masterdata-service' + BUILD_ARTIFACT: 'admin' + - SERVICE_LOCATION: 'admin/kernel-syncdata-service' + SERVICE_NAME: 'kernel-syncdata-service' + BUILD_ARTIFACT: 'admin' + fail-fast: false + name: ${{ matrix.SERVICE_NAME }} + uses: mosip/kattu/.github/workflows/docker-build.yml@master + with: + SERVICE_LOCATION: ${{ matrix.SERVICE_LOCATION }} + SERVICE_NAME: ${{ matrix.SERVICE_NAME }} + BUILD_ARTIFACT: ${{ matrix.BUILD_ARTIFACT }} + secrets: + DEV_NAMESPACE_DOCKER_HUB: ${{ secrets.DEV_NAMESPACE_DOCKER_HUB }} + ACTOR_DOCKER_HUB: ${{ secrets.ACTOR_DOCKER_HUB }} + RELEASE_DOCKER_HUB: ${{ secrets.RELEASE_DOCKER_HUB }} + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} + + sonar_analysis: + needs: build-maven-admin-services + if: "${{ github.event_name != 'pull_request' }}" + uses: mosip/kattu/.github/workflows/maven-sonar-analysis.yml@master + with: + SERVICE_LOCATION: ./admin + secrets: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + ORG_KEY: ${{ secrets.ORG_KEY }} + OSSRH_USER: ${{ secrets.OSSRH_USER }} + OSSRH_SECRET: ${{ secrets.OSSRH_SECRET }} + OSSRH_TOKEN: ${{ secrets.OSSRH_TOKEN }} + GPG_SECRET: ${{ secrets.GPG_SECRET }} + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} diff --git a/.github/workflows/push_trigger.yml b/.github/workflows/push_trigger.yml deleted file mode 100644 index 75f5b34d2ad..00000000000 --- a/.github/workflows/push_trigger.yml +++ /dev/null @@ -1,466 +0,0 @@ - -name: Maven Package upon a push - -on: - push: - branches: - - '!release-branch' - - release-1* - - master - - 1.* - - develop - -jobs: - build: - - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Set up JDK 11 - uses: actions/setup-java@v1 - with: - ref: ${{ github.ref }} - java-version: 11 - server-id: ossrh # Value of the distributionManagement/repository/id field of the pom.xml - settings-path: ${{ github.workspace }} # location for the settings.xml file - - - - name: Setup branch and env - run: | - # Strip git ref prefix from version - echo "BRANCH_NAME=$(echo ${{ github.ref }} | sed -e 's,.*/\(.*\),\1,')" >> $GITHUB_ENV - echo "GPG_TTY=$(tty)" >> $GITHUB_ENV - - - name: Setup branch and GPG public key - run: | - # Strip git ref prefix from version - echo ${{ env.BRANCH_NAME }} - echo ${{ env.GPG_TTY }} - sudo apt-get --yes install gnupg2 - gpg2 --import ./.github/keys/mosipgpgkey_pub.gpg - gpg2 --quiet --batch --passphrase=${{secrets.gpg_secret}} --allow-secret-key-import --import ./.github/keys/mosipgpgkey_sec.gpg - - - uses: actions/cache@v1 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven-${{ env.BRANCH_NAME }} - - - name: Setup the settings file for ossrh server - run: echo " ossrh ${{secrets.ossrh_user}} ${{secrets.ossrh_secret}} ossrh true gpg2 ${{secrets.gpg_secret}} allow-snapshots true snapshots-repo https://oss.sonatype.org/content/repositories/snapshots false true releases-repo https://oss.sonatype.org/service/local/staging/deploy/maven2 true false staged-releases https://oss.sonatype.org/service/local/staging/deploy/maven2/ sonar . https://sonarcloud.io false " > $GITHUB_WORKSPACE/settings.xml - - - name: Install xmllint - run: | - sudo apt-get update - sudo apt-get install libxml2-utils - - name: Build with Maven - run: | - cd admin - mvn -B -U package -s $GITHUB_WORKSPACE/settings.xml --file pom.xml - - name: Ready the springboot artifacts - run: find -name '*.jar' -executable -type f -exec zip release.zip {} + - - - name: Upload the springboot jars - uses: actions/upload-artifact@v1 - with: - name: release - path: ./release.zip - - - uses: 8398a7/action-slack@v3 - with: - status: ${{ job.status }} - fields: repo,message,commit,workflow,job # selectable (default: repo,message) - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} # required - if: failure() # Pick up events even if the job fails or is canceled. - - publish_to_nexus: - if: "!contains(github.ref, 'master')" - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Set up JDK 11 - uses: actions/setup-java@v1 - with: - ref: ${{ github.ref }} - java-version: 11 - server-id: ossrh # Value of the distributionManagement/repository/id field of the pom.xml - settings-path: ${{ github.workspace }} # location for the settings.xml file - - - name: Setup branch and env - run: | - # Strip git ref prefix from version - echo "BRANCH_NAME=$(echo ${{ github.ref }} | sed -e 's,.*/\(.*\),\1,')" >> $GITHUB_ENV - echo "GPG_TTY=$(tty)" >> $GITHUB_ENV - - - name: Setup branch and GPG public key - run: | - # Strip git ref prefix from version - - echo ${{ env.BRANCH_NAME }} - - echo ${{ env.GPG_TTY }} - sudo apt-get --yes install gnupg2 - gpg2 --import ./.github/keys/mosipgpgkey_pub.gpg - gpg2 --quiet --batch --passphrase=${{secrets.gpg_secret}} --allow-secret-key-import --import ./.github/keys/mosipgpgkey_sec.gpg - - - uses: actions/cache@v1 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven-${{ env.BRANCH_NAME }} - - - name: Setup the settings file for ossrh server - run: echo " ossrh ${{secrets.ossrh_user}} ${{secrets.ossrh_secret}} ossrh true gpg2 ${{secrets.gpg_secret}} allow-snapshots true snapshots-repo https://oss.sonatype.org/content/repositories/snapshots false true releases-repo https://oss.sonatype.org/service/local/staging/deploy/maven2 true false staged-releases https://oss.sonatype.org/service/local/staging/deploy/maven2/ sonar . https://sonarcloud.io false " > $GITHUB_WORKSPACE/settings.xml - - - name: Install xmllint - run: | - sudo apt-get update - sudo apt-get install libxml2-utils - - name: Build with Maven - run: | - cd admin - mvn -B -U package -s $GITHUB_WORKSPACE/settings.xml --file pom.xml - - - name: Publish the maven package - run: | - cd admin && mvn deploy -DaltDeploymentRepository=ossrh::default::${{ secrets.OSSRH_SNAPSHOT_URL }} -s $GITHUB_WORKSPACE/settings.xml -f pom.xml - env: - GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} - GPG_TTY: $(tty) - - # - uses: 8398a7/action-slack@v3 - # with: - # status: ${{ job.status }} - # fields: repo,message,commit,workflow,job # selectable (default: repo,message) - # env: - # SLACK_WEBHOOK_URL: ${{ secrets.SLACK_DEVOPS_WEBHOOK }} # required - # if: failure() # Pick up events even if the job fails or is canceled. - - docker-admin-service: - needs: build - - runs-on: ubuntu-latest - env: - NAMESPACE: ${{ secrets.dev_namespace_docker_hub }} - SERVICE_NAME: admin-service - SERVICE_LOCATION: admin/admin-service - - steps: - - uses: actions/checkout@v2 - - uses: actions/download-artifact@v1 - with: - name: release - path: ./ - - - name: Setup branch name - run: | - # Strip git ref prefix from version - echo "BRANCH_NAME=$(echo ${{ github.ref }} | sed -e 's,.*/\(.*\),\1,')" >> $GITHUB_ENV - echo ${{ env.BRANCH_NAME }} - - - name: Get version info from pom - id: getPomVersion - uses: mavrosxristoforos/get-xml-info@1.0 - with: - xml-file: ./${{ env.SERVICE_LOCATION }}/pom.xml - xpath: /*[local-name()="project"]/*[local-name()="version"] - - - name: Unzip and extract the admin-service - run: unzip -uj "release.zip" "${{ env.SERVICE_LOCATION }}/target/*" -d "./${{ env.SERVICE_LOCATION }}/target" - - - name: Get current date - id: date - run: echo "::set-output name=date::$(date +'%Y-%m-%d')" - - - name: Build image - run: | - cd "./${{env.SERVICE_LOCATION}}" - docker build . --file Dockerfile --build-arg SOURCE=mosip --build-arg COMMIT_HASH=$(git rev-parse HEAD) --build-arg COMMIT_ID=$(git rev-parse --short HEAD) --build-arg BUILD_TIME=${{steps.date.outputs.date}} --tag ${{ env.SERVICE_NAME }} - - name: Log into registry - run: echo "${{ secrets.release_docker_hub }}" | docker login -u ${{ secrets.actor_docker_hub }} --password-stdin - - - name: Push image - run: | - IMAGE_ID=$NAMESPACE/$SERVICE_NAME - - # Change all uppercase to lowercase - IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') - echo "push version ${{steps.getPomVersion.outputs.info}}" - if [[ $BRANCH_NAME == master ]]; then - VERSION=latest - else - VERSION=$BRANCH_NAME - fi - echo IMAGE_ID=$IMAGE_ID - echo VERSION=$VERSION - docker tag $SERVICE_NAME $IMAGE_ID:$VERSION - docker push $IMAGE_ID:$VERSION - - uses: 8398a7/action-slack@v3 - with: - status: ${{ job.status }} - fields: repo,message,commit,workflow,job # selectable (default: repo,message) - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_DEVOPS_WEBHOOK }} # required - if: failure() # Pick up events even if the job fails or is canceled. - - docker-kernel-masterdata-service: - needs: build - - runs-on: ubuntu-latest - env: - NAMESPACE: ${{ secrets. dev_namespace_docker_hub }} - SERVICE_NAME: kernel-masterdata-service - SERVICE_LOCATION: admin/kernel-masterdata-service - - steps: - - uses: actions/checkout@v2 - - uses: actions/download-artifact@v1 - with: - name: release - path: ./ - - - name: Setup branch name - run: | - # Strip git ref prefix from version - echo "BRANCH_NAME=$(echo ${{ github.ref }} | sed -e 's,.*/\(.*\),\1,')" >> $GITHUB_ENV - echo ${{ env.BRANCH_NAME }} - - - name: Get version info from pom - id: getPomVersion - uses: mavrosxristoforos/get-xml-info@1.0 - with: - xml-file: ./${{ env.SERVICE_LOCATION }}/pom.xml - xpath: /*[local-name()="project"]/*[local-name()="version"] - - - name: Unzip and extract the id-repository-vid-service - run: unzip -uj "release.zip" "${{ env.SERVICE_LOCATION }}/target/*" -d "./${{ env.SERVICE_LOCATION }}/target" - - - name: Get current date - id: date - run: echo "::set-output name=date::$(date +'%Y-%m-%d')" - - - name: Build image - run: | - cd "./${{env.SERVICE_LOCATION}}" - docker build . --file Dockerfile --build-arg SOURCE=mosip --build-arg COMMIT_HASH=$(git rev-parse HEAD) --build-arg COMMIT_ID=$(git rev-parse --short HEAD) --build-arg BUILD_TIME=${{steps.date.outputs.date}} --tag ${{ env.SERVICE_NAME }} - - - name: Log into registry - run: echo "${{ secrets.release_docker_hub }}" | docker login -u ${{ secrets.actor_docker_hub }} --password-stdin - - - name: Push image - run: | - IMAGE_ID=$NAMESPACE/$SERVICE_NAME - - # Change all uppercase to lowercase - IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') - echo "push version ${{steps.getPomVersion.outputs.info}}" - if [[ $BRANCH_NAME == master ]]; then - VERSION=latest - else - VERSION=$BRANCH_NAME - fi - echo IMAGE_ID=$IMAGE_ID - echo VERSION=$VERSION - docker tag $SERVICE_NAME $IMAGE_ID:$VERSION - docker push $IMAGE_ID:$VERSION - - uses: 8398a7/action-slack@v3 - with: - status: ${{ job.status }} - fields: repo,message,commit,workflow,job # selectable (default: repo,message) - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_DEVOPS_WEBHOOK }} # required - if: failure() # Pick up events even if the job fails or is canceled. - - docker-kernel-syncdata-service: - needs: build - - runs-on: ubuntu-latest - env: - NAMESPACE: ${{ secrets. dev_namespace_docker_hub }} - SERVICE_NAME: kernel-syncdata-service - SERVICE_LOCATION: admin/kernel-syncdata-service - - steps: - - uses: actions/checkout@v2 - - uses: actions/download-artifact@v1 - with: - name: release - path: ./ - - - name: Setup branch name - run: | - # Strip git ref prefix from version - echo "BRANCH_NAME=$(echo ${{ github.ref }} | sed -e 's,.*/\(.*\),\1,')" >> $GITHUB_ENV - echo ${{ env.BRANCH_NAME }} - - - name: Get version info from pom - id: getPomVersion - uses: mavrosxristoforos/get-xml-info@1.0 - with: - xml-file: ./${{ env.SERVICE_LOCATION }}/pom.xml - xpath: /*[local-name()="project"]/*[local-name()="version"] - - - name: Unzip and extract the id-repository-vid-service - run: unzip -uj "release.zip" "${{ env.SERVICE_LOCATION }}/target/*" -d "./${{ env.SERVICE_LOCATION }}/target" - - - name: Get current date - id: date - run: echo "::set-output name=date::$(date +'%Y-%m-%d')" - - - name: Build image - run: | - cd "./${{env.SERVICE_LOCATION}}" - docker build . --file Dockerfile --build-arg SOURCE=mosip --build-arg COMMIT_HASH=$(git rev-parse HEAD) --build-arg COMMIT_ID=$(git rev-parse --short HEAD) --build-arg BUILD_TIME=${{steps.date.outputs.date}} --tag ${{ env.SERVICE_NAME }} - - - name: Log into registry - run: echo "${{ secrets.release_docker_hub }}" | docker login -u ${{ secrets.actor_docker_hub }} --password-stdin - - - name: Push image - run: | - IMAGE_ID=$NAMESPACE/$SERVICE_NAME - - # Change all uppercase to lowercase - IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') - echo "push version ${{steps.getPomVersion.outputs.info}}" - if [[ $BRANCH_NAME == master ]]; then - VERSION=latest - else - VERSION=$BRANCH_NAME - fi - echo IMAGE_ID=$IMAGE_ID - echo VERSION=$VERSION - docker tag $SERVICE_NAME $IMAGE_ID:$VERSION - docker push $IMAGE_ID:$VERSION - - uses: 8398a7/action-slack@v3 - with: - status: ${{ job.status }} - fields: repo,message,commit,workflow,job # selectable (default: repo,message) - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_DEVOPS_WEBHOOK }} # required - if: failure() # Pick up events even if the job fails or is canceled. - - docker-hotlist-service: - needs: build - - runs-on: ubuntu-latest - env: - NAMESPACE: ${{ secrets. dev_namespace_docker_hub }} - SERVICE_NAME: hotlist-service - SERVICE_LOCATION: admin/hotlist-service - - steps: - - uses: actions/checkout@v2 - - uses: actions/download-artifact@v1 - with: - name: release - path: ./ - - - name: Setup branch name - run: | - # Strip git ref prefix from version - echo "BRANCH_NAME=$(echo ${{ github.ref }} | sed -e 's,.*/\(.*\),\1,')" >> $GITHUB_ENV - echo ${{ env.BRANCH_NAME }} - - - name: Get version info from pom - id: getPomVersion - uses: mavrosxristoforos/get-xml-info@1.0 - with: - xml-file: ./${{ env.SERVICE_LOCATION }}/pom.xml - xpath: /*[local-name()="project"]/*[local-name()="version"] - - - name: Unzip and extract the hotlist-service - run: unzip -uj "release.zip" "${{ env.SERVICE_LOCATION }}/target/*" -d "./${{ env.SERVICE_LOCATION }}/target" - - - name: Get current date - id: date - run: echo "::set-output name=date::$(date +'%Y-%m-%d')" - - - name: Build image - run: | - cd "./${{env.SERVICE_LOCATION}}" - docker build . --file Dockerfile --build-arg SOURCE=mosip --build-arg COMMIT_HASH=$(git rev-parse HEAD) --build-arg COMMIT_ID=$(git rev-parse --short HEAD) --build-arg BUILD_TIME=${{steps.date.outputs.date}} --tag ${{ env.SERVICE_NAME }} - - - name: Log into registry - run: echo "${{ secrets.release_docker_hub }}" | docker login -u ${{ secrets.actor_docker_hub }} --password-stdin - - - name: Push image - run: | - IMAGE_ID=$NAMESPACE/$SERVICE_NAME - - # Change all uppercase to lowercase - IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') - echo "push version ${{steps.getPomVersion.outputs.info}}" - if [[ $BRANCH_NAME == master ]]; then - VERSION=latest - else - VERSION=$BRANCH_NAME - fi - echo IMAGE_ID=$IMAGE_ID - echo VERSION=$VERSION - docker tag $SERVICE_NAME $IMAGE_ID:$VERSION - docker push $IMAGE_ID:$VERSION - - uses: 8398a7/action-slack@v3 - with: - status: ${{ job.status }} - fields: repo,message,commit,workflow,job # selectable (default: repo,message) - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_DEVOPS_WEBHOOK }} # required - if: failure() # Pick up events even if the job fails or is canceled. - - sonar_analysis: - - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Set up JDK 11 - uses: actions/setup-java@v1 - with: - ref: ${{ github.ref }} - java-version: 11 - server-id: ossrh # Value of the distributionManagement/repository/id field of the pom.xml - settings-path: ${{ github.workspace }} # location for the settings.xml file - - - - name: Setup branch and env - run: | - # Strip git ref prefix from version - echo "BRANCH_NAME=$(echo ${{ github.ref }} | sed -e 's,.*/\(.*\),\1,')" >> $GITHUB_ENV - echo "GPG_TTY=$(tty)" >> $GITHUB_ENV - - - uses: actions/cache@v1 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven-${{ env.BRANCH_NAME }} - - - name: Setup the settings file for ossrh server - run: echo " ossrh ${{secrets.ossrh_user}} ${{secrets.ossrh_secret}} ossrh true gpg2 ${{secrets.gpg_secret}} allow-snapshots true snapshots-repo https://oss.sonatype.org/content/repositories/snapshots false true releases-repo https://oss.sonatype.org/service/local/staging/deploy/maven2 true false staged-releases https://oss.sonatype.org/service/local/staging/deploy/maven2/ sonar . https://sonarcloud.io false " > $GITHUB_WORKSPACE/settings.xml - - - name: Install xmllint - run: | - sudo apt-get update - sudo apt-get install libxml2-utils - - - name: Build with Maven - run: | - cd admin - mvn -B -U package -s $GITHUB_WORKSPACE/settings.xml --file pom.xml - - - name: Analyze with SonarCloud - run: | - cd admin - mvn -B -Dgpg.skip verify sonar:sonar -Dsonar.projectKey=mosip_${{ github.event.repository.name }} -Dsonar.organization=${{ secrets.ORG_KEY }} -Dsonar.host.url=https://sonarcloud.io -Dsonar.login=${{ secrets.SONAR_TOKEN }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - - uses: 8398a7/action-slack@v3 - with: - status: ${{ job.status }} - fields: repo,message,commit,workflow,job # selectable (default: repo,message) - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_DEVOPS_WEBHOOK }} # required - if: failure() # Pick up events even if the job fails or is canceled. diff --git a/.github/workflows/release-changes.yml b/.github/workflows/release-changes.yml new file mode 100644 index 00000000000..2579ea836f1 --- /dev/null +++ b/.github/workflows/release-changes.yml @@ -0,0 +1,26 @@ +name: Release/pre-release Preparation. + +on: + workflow_dispatch: + inputs: + MESSAGE: + description: 'Triggered for release or pe-release' + required: false + default: 'Release Preparation' + RELEASE_TAG: + description: 'tag to update' + required: true + SNAPSHOT_TAG: + description: 'tag to be replaced' + required: true + BASE: + description: 'base branch for PR' + required: true +jobs: + maven-release-preparation: + uses: mosip/kattu/.github/workflows/release-changes.yml@master + with: + MESSAGE: ${{ inputs.MESSAGE }} + RELEASE_TAG: ${{ inputs.RELEASE_TAG }} + SNAPSHOT_TAG: ${{ inputs.SNAPSHOT_TAG }} + BASE: ${{ inputs.BASE }} \ No newline at end of file diff --git a/.github/workflows/release_changes.yml b/.github/workflows/release_changes.yml deleted file mode 100644 index cc9c2956d9e..00000000000 --- a/.github/workflows/release_changes.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: Release/pre-release Preparation. - -on: - workflow_dispatch: - inputs: - message: - description: 'Triggered for release or pe-release' - required: false - default: 'Release Preparation' - releaseTags: - description: 'tag to update' - required: true - snapshotTags: - description: 'tag to be replaced' - required: true - base: - description: 'base branch for PR' - required: true -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Setup branch and env - run: | - # Strip git ref prefix from version - echo "BRANCH_NAME=$(echo ${{ github.ref }} | sed -e 's,.*/\(.*\),\1,')" >> $GITHUB_ENV - echo "GPG_TTY=$(tty)" >> $GITHUB_ENV - - - name: Mannualy changing the pom versions - run: find . -type f -name "*pom.xml" -print0 | xargs -0 sed -i "s/${{ github.event.inputs.snapshotTags }}/${{ github.event.inputs.releaseTags }}/g" - - - name: Updating the Release URL in POM - run: | - cd .github/workflows - sed -i 's/OSSRH_SNAPSHOT_URL/RELEASE_URL/g' push_trigger.yml - - - name: Updating libs-snapshot-local to libs-release local for artifactory URL's. - run: find . -type f -name "*Dockerfile" -print0 | xargs -0 sed -i "s/libs-snapshot-local/libs-release-local/g" - - - name: removing -DskipTests - run: find . -type f -name "*push_trigger.yml" -print0 | xargs -0 sed -i "s/"-DskipTests"//g" - -# - name: removing --Dgpg.skip -# run: find . -type f -name "*push_trigger.yml" -print0 | xargs -0 sed -i "s/"-Dgpg.skip"//g" - - - name: Create Pull Request - uses: peter-evans/create-pull-request@v3 - with: - token: ${{ secrets.ACTION_PAT }} - commit-message: Updated Pom versions for release changes - title: Release changes - body: Automated PR for ${{ github.event.inputs.releaseTags }} release. - branch: release-branch - delete-branch: true - base: ${{ github.event.inputs.base }} diff --git a/.github/workflows/release_trigger.yml b/.github/workflows/release_trigger.yml deleted file mode 100644 index 62d100157f2..00000000000 --- a/.github/workflows/release_trigger.yml +++ /dev/null @@ -1,326 +0,0 @@ - -name: Release maven packages and docker upon a release - -on: - release: - types: [published] - -jobs: - build: - - runs-on: ubuntu-latest - if: github.event.pull_request.merged == true - - steps: - - uses: actions/checkout@v2 - - name: Set up JDK 11 - uses: actions/setup-java@v1 - with: - ref: ${{ github.ref }} - java-version: 11 - server-id: ossrh # Value of the distributionManagement/repository/id field of the pom.xml - settings-path: ${{ github.workspace }} # location for the settings.xml file - - - name: Setup branch and GPG public key - run: | - # Strip git ref prefix from version - echo "::set-env name=BRANCH_NAME::$(echo ${{ github.ref }} | sed -e 's,.*/\(.*\),\1,')" - echo ${{ env.BRANCH_NAME }} - echo "::set-env name=GPG_TTY::$(tty)" - echo ${{ env.GPG_TTY }} - sudo apt-get --yes install gnupg2 - gpg2 --import ./.github/keys/mosipgpgkey_pub.gpg - gpg2 --quiet --batch --passphrase=${{secrets.gpg_secret}} --allow-secret-key-import --import ./.github/keys/mosipgpgkey_sec.gpg - - - uses: actions/cache@v1 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven-${{ env.BRANCH_NAME }} - - - name: Setup the settings file for ossrh server - run: echo " ossrh ${{secrets.ossrh_user}} ${{secrets.ossrh_secret}} ossrh true gpg2 ${{secrets.gpg_secret}} allow-snapshots true snapshots-repo https://oss.sonatype.org/content/repositories/snapshots false true releases-repo https://oss.sonatype.org/service/local/staging/deploy/maven2 true false sonar . https://sonarcloud.io false " > $GITHUB_WORKSPACE/settings.xml - - - name: Install xmllint - run: | - sudo apt-get update - sudo apt-get install libxml2-utils - - name: Build with Maven - run: | - cd admin - mvn -B package -s $GITHUB_WORKSPACE/settings.xml --file pom.xml - - name: Ready the springboot artifacts - run: find -name '*.jar' -executable -type f -exec zip release.zip {} + - - - name: Upload the springboot jars - uses: actions/upload-artifact@v1 - with: - name: release - path: ./release.zip - - publish_to_nexus: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: Set up JDK 11 - uses: actions/setup-java@v1 - with: - ref: ${{ github.ref }} - java-version: 11 - server-id: ossrh # Value of the distributionManagement/repository/id field of the pom.xml - settings-path: ${{ github.workspace }} # location for the settings.xml file - - - name: Setup branch and GPG public key - run: | - # Strip git ref prefix from version - echo "::set-env name=BRANCH_NAME::$(echo ${{ github.ref }} | sed -e 's,.*/\(.*\),\1,')" - echo ${{ env.BRANCH_NAME }} - echo "::set-env name=GPG_TTY::$(tty)" - echo ${{ env.GPG_TTY }} - sudo apt-get --yes install gnupg2 - gpg2 --import ./.github/keys/mosipgpgkey_pub.gpg - gpg2 --quiet --batch --passphrase=${{secrets.gpg_secret}} --allow-secret-key-import --import ./.github/keys/mosipgpgkey_sec.gpg - - - uses: actions/cache@v1 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven-${{ env.BRANCH_NAME }} - - - name: Setup the settings file for ossrh server - run: echo " ossrh ${{secrets.ossrh_user}} ${{secrets.ossrh_secret}} ossrh true gpg2 ${{secrets.gpg_secret}} allow-snapshots true snapshots-repo https://oss.sonatype.org/content/repositories/snapshots false true releases-repo https://oss.sonatype.org/service/local/staging/deploy/maven2 true false sonar . https://sonarcloud.io false " > $GITHUB_WORKSPACE/settings.xml - - - name: Install xmllint - run: | - sudo apt-get update - sudo apt-get install libxml2-utils - - name: Build with Maven - run: | - cd admin - mvn -B package -s $GITHUB_WORKSPACE/settings.xml --file pom.xml - - name: Publish the maven package - run: | - chmod +x ./deploy.sh - ./deploy.sh admin $GITHUB_WORKSPACE/settings.xml .* - env: - GPG_TTY: $(tty) - - name: Analyze with SonarCloud - run: | - cd admin - mvn -B verify sonar:sonar -Dsonar.projectKey=${{ secrets.PROJECT_KEY }} -Dsonar.organization=${{ secrets.ORG_KEY }} -Dsonar.host.url=https://sonarcloud.io -Dsonar.login=${{ secrets.SONAR_TOKEN }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - docker-admin-service: - needs: build - - runs-on: ubuntu-latest - env: - NAMESPACE: ${{ secrets.dev_namespace_docker_hub }} - SERVICE_NAME: admin-service - SERVICE_LOCATION: admin/admin-service - - steps: - - uses: actions/checkout@v2 - - uses: actions/download-artifact@v1 - with: - name: release - path: ./ - - - name: Setup branch name - run: | - # Strip git ref prefix from version - echo "::set-env name=BRANCH_NAME::$(echo ${{ github.ref }} | sed -e 's,.*/\(.*\),\1,')" - echo ${{ env.BRANCH_NAME }} - - name: Get version info from pom - id: getPomVersion - uses: mavrosxristoforos/get-xml-info@1.0 - with: - xml-file: ./${{ env.SERVICE_LOCATION }}/pom.xml - xpath: /*[local-name()="project"]/*[local-name()="version"] - - - name: Unzip and extract the admin-service - run: unzip -uj "release.zip" "${{ env.SERVICE_LOCATION }}/target/*" -d "./${{ env.SERVICE_LOCATION }}/target" - - - name: Build image - run: | - cd "./${{env.SERVICE_LOCATION}}" - docker build . --file Dockerfile --tag ${{ env.SERVICE_NAME }} - - name: Log into registry - run: echo "${{ secrets.release_docker_hub }}" | docker login -u ${{ secrets.actor_docker_hub }} --password-stdin - - - name: Push image - run: | - IMAGE_ID=$NAMESPACE/$SERVICE_NAME - - # Change all uppercase to lowercase - IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') - echo "push version ${{steps.getPomVersion.outputs.info}}" - VERSION=$BRANCH_NAME - echo IMAGE_ID=$IMAGE_ID - echo VERSION=$VERSION - docker tag $SERVICE_NAME $IMAGE_ID:$VERSION - docker push $IMAGE_ID:$VERSION - - docker-kernel-masterdata-service: - needs: build - - runs-on: ubuntu-latest - env: - NAMESPACE: ${{ secrets. dev_namespace_docker_hub }} - SERVICE_NAME: kernel-masterdata-service - SERVICE_LOCATION: admin/kernel-masterdata-service - - steps: - - uses: actions/checkout@v2 - - uses: actions/download-artifact@v1 - with: - name: release - path: ./ - - - name: Setup branch name - run: | - # Strip git ref prefix from version - echo "BRANCH_NAME=$(echo ${{ github.ref }} | sed -e 's,.*/\(.*\),\1,')" >> $GITHUB_ENV - echo ${{ env.BRANCH_NAME }} - - - name: Get version info from pom - id: getPomVersion - uses: mavrosxristoforos/get-xml-info@1.0 - with: - xml-file: ./${{ env.SERVICE_LOCATION }}/pom.xml - xpath: /*[local-name()="project"]/*[local-name()="version"] - - - name: Unzip and extract the id-repository-vid-service - run: unzip -uj "release.zip" "${{ env.SERVICE_LOCATION }}/target/*" -d "./${{ env.SERVICE_LOCATION }}/target" - - - name: Build image - run: | - cd "./${{env.SERVICE_LOCATION}}" - docker build . --file Dockerfile --tag ${{ env.SERVICE_NAME }} - - - name: Log into registry - run: echo "${{ secrets.release_docker_hub }}" | docker login -u ${{ secrets.actor_docker_hub }} --password-stdin - - - name: Push image - run: | - IMAGE_ID=$NAMESPACE/$SERVICE_NAME - - # Change all uppercase to lowercase - IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') - echo "push version ${{steps.getPomVersion.outputs.info}}" - VERSION=$BRANCH_NAME - echo IMAGE_ID=$IMAGE_ID - echo VERSION=$VERSION - docker tag $SERVICE_NAME $IMAGE_ID:$VERSION - docker push $IMAGE_ID:$VERSION - - docker-kernel-syncdata-service: - needs: build - - runs-on: ubuntu-latest - env: - NAMESPACE: ${{ secrets. dev_namespace_docker_hub }} - SERVICE_NAME: kernel-syncdata-service - SERVICE_LOCATION: kernel/kernel-syncdata-service - - steps: - - uses: actions/checkout@v2 - - uses: actions/download-artifact@v1 - with: - name: release - path: ./ - - - name: Setup branch name - run: | - # Strip git ref prefix from version - echo "BRANCH_NAME=$(echo ${{ github.ref }} | sed -e 's,.*/\(.*\),\1,')" >> $GITHUB_ENV - echo ${{ env.BRANCH_NAME }} - - - name: Get version info from pom - id: getPomVersion - uses: mavrosxristoforos/get-xml-info@1.0 - with: - xml-file: ./${{ env.SERVICE_LOCATION }}/pom.xml - xpath: /*[local-name()="project"]/*[local-name()="version"] - - - name: Unzip and extract the id-repository-vid-service - run: unzip -uj "release.zip" "${{ env.SERVICE_LOCATION }}/target/*" -d "./${{ env.SERVICE_LOCATION }}/target" - - - name: Build image - run: | - cd "./${{env.SERVICE_LOCATION}}" - docker build . --file Dockerfile --tag ${{ env.SERVICE_NAME }} - - - name: Log into registry - run: echo "${{ secrets.release_docker_hub }}" | docker login -u ${{ secrets.actor_docker_hub }} --password-stdin - - - name: Push image - run: | - IMAGE_ID=$NAMESPACE/$SERVICE_NAME - - # Change all uppercase to lowercase - IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') - echo "push version ${{steps.getPomVersion.outputs.info}}" - VERSION=$BRANCH_NAME - echo IMAGE_ID=$IMAGE_ID - echo VERSION=$VERSION - docker tag $SERVICE_NAME $IMAGE_ID:$VERSION - docker push $IMAGE_ID:$VERSION - - docker-hotlist-service: - needs: build - - runs-on: ubuntu-latest - env: - NAMESPACE: ${{ secrets. dev_namespace_docker_hub }} - SERVICE_NAME: hotlist-service - SERVICE_LOCATION: kernel/hotlist-service - - steps: - - uses: actions/checkout@v2 - - uses: actions/download-artifact@v1 - with: - name: release - path: ./ - - - name: Setup branch name - run: | - # Strip git ref prefix from version - echo "BRANCH_NAME=$(echo ${{ github.ref }} | sed -e 's,.*/\(.*\),\1,')" >> $GITHUB_ENV - echo ${{ env.BRANCH_NAME }} - - - name: Get version info from pom - id: getPomVersion - uses: mavrosxristoforos/get-xml-info@1.0 - with: - xml-file: ./${{ env.SERVICE_LOCATION }}/pom.xml - xpath: /*[local-name()="project"]/*[local-name()="version"] - - - name: Unzip and extract the hotlist-service - run: unzip -uj "release.zip" "${{ env.SERVICE_LOCATION }}/target/*" -d "./${{ env.SERVICE_LOCATION }}/target" - - - name: Build image - run: | - cd "./${{env.SERVICE_LOCATION}}" - docker build . --file Dockerfile --tag ${{ env.SERVICE_NAME }} - - - name: Log into registry - run: echo "${{ secrets.release_docker_hub }}" | docker login -u ${{ secrets.actor_docker_hub }} --password-stdin - - - name: Push image - run: | - IMAGE_ID=$NAMESPACE/$SERVICE_NAME - - # Change all uppercase to lowercase - IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') - echo "push version ${{steps.getPomVersion.outputs.info}}" - VERSION=$BRANCH_NAME - echo IMAGE_ID=$IMAGE_ID - echo VERSION=$VERSION - docker tag $SERVICE_NAME $IMAGE_ID:$VERSION - docker push $IMAGE_ID:$VERSION \ No newline at end of file diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml new file mode 100644 index 00000000000..c4939a6e8ce --- /dev/null +++ b/.github/workflows/tag.yml @@ -0,0 +1,33 @@ +name: Tagging of repos + +on: + workflow_dispatch: + inputs: + TAG: + description: 'Tag to be published' + required: true + type: string + BODY: + description: 'Release body message' + required: true + default: 'Changes in this Release' + type: string + PRE_RELEASE: + description: 'Pre-release? True/False' + required: true + default: False + type: string + DRAFT: + description: 'Draft? True/False' + required: false + default: False + type: string + +jobs: + tag-branch: + uses: mosip/kattu/.github/workflows/tag.yml@master + with: + TAG: ${{ inputs.TAG }} + BODY: ${{ inputs.BODY }} + PRE_RELEASE: ${{ inputs.PRE_RELEASE }} + DRAFT: ${{ inputs.DRAFT }} From 300d30033483603203d6e0b50e6c5ce77c9f2055 Mon Sep 17 00:00:00 2001 From: kameshsr <47484458+kameshsr@users.noreply.github.com> Date: Thu, 21 Sep 2023 14:52:12 +0530 Subject: [PATCH 08/16] MOSIP-29472 Create API dynamicfields/all. (#897) * MOSIP-29472 Create API dynamicfields/all. * MOSIP-29472 Create API dynamicfields/all. * MOSIP-29472 Create API dynamicfields/all. * MOSIP-29472 Covered Junit for Dynamic field all API. * MOSIP-29472 Covered Junit for Dynamic field all API. * MOSIP-29472 Changed logic as per review comment. * MOSIP-29472 Changed logic as per review comment. * MOSIP-29472 Changed logic as per review comment. --- .../controller/DynamicFieldController.java | 12 ++- .../getresponse/extn/DynamicFieldExtnDto.java | 1 - .../repository/DynamicFieldRepository.java | 1 - .../service/DynamicFieldService.java | 2 +- .../service/impl/DynamicFieldServiceImpl.java | 77 ++++++++++++------- .../DynamicFieldControllerTest.java | 45 ++++++----- .../test/service/SchemaServiceTest.java | 67 ++++++++-------- 7 files changed, 123 insertions(+), 82 deletions(-) diff --git a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/controller/DynamicFieldController.java b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/controller/DynamicFieldController.java index 4ac8c37ad50..7fcad875988 100644 --- a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/controller/DynamicFieldController.java +++ b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/controller/DynamicFieldController.java @@ -5,7 +5,6 @@ import java.util.List; import javax.validation.Valid; -import javax.websocket.server.PathParam; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; @@ -39,7 +38,6 @@ import io.mosip.kernel.masterdata.dto.response.FilterResponseCodeDto; import io.mosip.kernel.masterdata.dto.response.FilterResponseDto; import io.mosip.kernel.masterdata.dto.response.PageResponseDto; -import io.mosip.kernel.masterdata.entity.DynamicField; import io.mosip.kernel.masterdata.service.DynamicFieldService; import io.mosip.kernel.masterdata.service.GenericService; import io.mosip.kernel.masterdata.utils.AuditUtil; @@ -93,6 +91,16 @@ public ResponseWrapper getDynamicFieldByName responseWrapper.setResponse(dynamicFieldService.getDynamicFieldByNameAndLangcode(fieldName,langCode,withValue)); return responseWrapper; } + + @ResponseFilter + @GetMapping("/all/{fieldName}") + @ApiOperation(value = " Service to fetch one dynamic field in all the languages") + public ResponseWrapper> getAllDynamicFieldByName( + @PathVariable("fieldName") String fieldName){ + ResponseWrapper> responseWrapper = new ResponseWrapper<>(); + responseWrapper.setResponse(dynamicFieldService.getAllDynamicFieldByName(fieldName)); + return responseWrapper; + } @ResponseFilter diff --git a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/dto/getresponse/extn/DynamicFieldExtnDto.java b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/dto/getresponse/extn/DynamicFieldExtnDto.java index 21893ee23fb..30767953f85 100644 --- a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/dto/getresponse/extn/DynamicFieldExtnDto.java +++ b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/dto/getresponse/extn/DynamicFieldExtnDto.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.databind.JsonNode; import lombok.Data; -import org.json.JSONArray; import java.time.LocalDateTime; import java.util.List; diff --git a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/DynamicFieldRepository.java b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/DynamicFieldRepository.java index 9b11a2737e3..fbcb0975edf 100644 --- a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/DynamicFieldRepository.java +++ b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/DynamicFieldRepository.java @@ -142,7 +142,6 @@ int updateDynamicField(String id, String description, String langCode, String da /** * update isDeleted as true - * @param id * @param updatedDateTime * @param updatedBy * @return diff --git a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/DynamicFieldService.java b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/DynamicFieldService.java index d40677997b3..22a97a2ca0e 100644 --- a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/DynamicFieldService.java +++ b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/DynamicFieldService.java @@ -16,7 +16,6 @@ import io.mosip.kernel.masterdata.dto.request.SearchDto; import io.mosip.kernel.masterdata.dto.response.FilterResponseCodeDto; import io.mosip.kernel.masterdata.dto.response.PageResponseDto; -import io.mosip.kernel.masterdata.entity.DynamicField; /** * Methods to create / update / inactivate / addValues dynamic field @@ -83,4 +82,5 @@ public PageDto getAllDynamicField(int pageNumber, int pageS public DynamicFieldConsolidateResponseDto getDynamicFieldByNameAndLangcode(String fieldName,String langCode,boolean withValue); + List getAllDynamicFieldByName(String fieldName); } diff --git a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/impl/DynamicFieldServiceImpl.java b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/impl/DynamicFieldServiceImpl.java index f66c4d2c9d7..02f84529128 100644 --- a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/impl/DynamicFieldServiceImpl.java +++ b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/impl/DynamicFieldServiceImpl.java @@ -13,7 +13,6 @@ import javax.transaction.Transactional; -import org.json.JSONArray; import org.json.JSONException; import io.mosip.kernel.masterdata.dto.response.FilterResult; @@ -31,10 +30,7 @@ import org.springframework.stereotype.Service; import org.springframework.util.Assert; -import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -75,17 +71,17 @@ @Service public class DynamicFieldServiceImpl implements DynamicFieldService { - + private static final Logger LOGGER = LoggerFactory.getLogger(DynamicFieldServiceImpl.class); - + private final ObjectMapper objectMapper = new ObjectMapper(); - + @Autowired private DynamicFieldRepository dynamicFieldRepository; - + @Autowired private MasterdataCreationUtil masterdataCreationUtil; - + @Autowired private MasterdataSearchHelper masterdataSearchHelper; @@ -103,11 +99,11 @@ public class DynamicFieldServiceImpl implements DynamicFieldService { @Autowired AuditUtil auditUtil; - + /* * (non-Javadoc) - * + * * @see * io.mosip.kernel.masterdata.service.DynamicFieldService#getAllDynamicField() */ @@ -116,18 +112,18 @@ public class DynamicFieldServiceImpl implements DynamicFieldService { condition="#langCode != null") @Override public PageDto getAllDynamicField(int pageNumber, int pageSize, String sortBy, String orderBy, String langCode, - LocalDateTime lastUpdated, LocalDateTime currentTimestamp) { + LocalDateTime lastUpdated, LocalDateTime currentTimestamp) { Page pagedResult = null; if (lastUpdated == null) { lastUpdated = LocalDateTime.ofEpochSecond(0, 0, ZoneOffset.UTC); } try { - - PageRequest pageRequest = PageRequest.of(pageNumber, pageSize, Sort.by(Direction.fromString(orderBy), sortBy)); + + PageRequest pageRequest = PageRequest.of(pageNumber, pageSize, Sort.by(Direction.fromString(orderBy), sortBy)); pagedResult = langCode == null ? dynamicFieldRepository.findAllLatestDynamicFieldNames(lastUpdated, currentTimestamp, pageRequest) : - dynamicFieldRepository.findAllLatestDynamicFieldNamesByLangCode(langCode,lastUpdated, currentTimestamp, pageRequest); - + dynamicFieldRepository.findAllLatestDynamicFieldNamesByLangCode(langCode,lastUpdated, currentTimestamp, pageRequest); + } catch (DataAccessException | DataAccessLayerException e) { throw new MasterDataServiceException(SchemaErrorCode.DYNAMIC_FIELD_FETCH_EXCEPTION.getErrorCode(), SchemaErrorCode.DYNAMIC_FIELD_FETCH_EXCEPTION.getErrorMessage() + " " @@ -153,11 +149,11 @@ public PageDto getAllDynamicField(int pageNumber, int pageS list.add(getDynamicFieldDto(groupedValues.get(lang))); } }); - + pagedFields.setPageNo(pagedResult.getNumber()); pagedFields.setTotalPages(pagedResult.getTotalPages()); pagedFields.setTotalItems(pagedResult.getTotalElements()); - } + } return pagedFields; } @@ -208,7 +204,7 @@ public List getDistinctDynamicFields(String langCode) { /* * (non-Javadoc) - * + * * @see * io.mosip.kernel.masterdata.service.DynamicFieldService#createDynamicField() */ @@ -245,7 +241,7 @@ public DynamicFieldResponseDto createDynamicField(DynamicFieldDto dto) { /* * (non-Javadoc) - * + * * @see * io.mosip.kernel.masterdata.service.DynamicFieldService#updateDynamicField() */ @@ -258,10 +254,10 @@ public DynamicFieldResponseDto updateDynamicField(String id, DynamicFieldPutDto String valueJson = getValidatedFieldValue(dto.getFieldVal()); - int updatedRows = dynamicFieldRepository.updateDynamicField(id, dto.getDescription(), dto.getLangCode(), + int updatedRows = dynamicFieldRepository.updateDynamicField(id, dto.getDescription(), dto.getLangCode(), dto.getDataType(), MetaDataUtils.getCurrentDateTime(), MetaDataUtils.getContextUser(), valueJson); - + if (updatedRows < 1) { throw new DataNotFoundException(SchemaErrorCode.DYNAMIC_FIELD_NOT_FOUND_EXCEPTION.getErrorCode(), SchemaErrorCode.DYNAMIC_FIELD_NOT_FOUND_EXCEPTION.getErrorMessage()); @@ -285,14 +281,14 @@ public StatusResponseDto deleteDynamicFieldValue(String id) { if(dynamicField == null) throw new DataNotFoundException(SchemaErrorCode.DYNAMIC_FIELD_NOT_FOUND_EXCEPTION.getErrorCode(), SchemaErrorCode.DYNAMIC_FIELD_NOT_FOUND_EXCEPTION.getErrorMessage()); - if(dynamicField.getValueJson()==null) - throw new DataNotFoundException(SchemaErrorCode.DYNAMIC_FIELD_VALUE_NOT_FOUND_EXCEPTION.getErrorCode(), + if(dynamicField.getValueJson()==null) + throw new DataNotFoundException(SchemaErrorCode.DYNAMIC_FIELD_VALUE_NOT_FOUND_EXCEPTION.getErrorCode(), SchemaErrorCode.DYNAMIC_FIELD_VALUE_NOT_FOUND_EXCEPTION.getErrorMessage()); JsonNode valueJson =objectMapper.readTree(dynamicField.getValueJson()); String code = valueJson.get("code").toString(); - - - + + + int deletedRows = dynamicFieldRepository.deleteDynamicField(dynamicField.getName(), "%"+code+"%", MetaDataUtils.getCurrentDateTime(), MetaDataUtils.getContextUser()); @@ -539,4 +535,29 @@ public DynamicFieldConsolidateResponseDto getDynamicFieldByNameAndLangcode(Strin } -} + @Override + @Cacheable(value = "dynamic-field", key = "'dynamicfield'.concat('-').concat(#fieldName)") + public List getAllDynamicFieldByName(String fieldName) { + List fields = null; + try { + fields = dynamicFieldRepository.findAllDynamicFieldByName(fieldName); + } catch (DataAccessException | DataAccessLayerException e) { + throw new MasterDataServiceException(SchemaErrorCode.DYNAMIC_FIELD_FETCH_EXCEPTION.getErrorCode(), + SchemaErrorCode.DYNAMIC_FIELD_FETCH_EXCEPTION.getErrorMessage() + " " + + ExceptionUtils.parseException(e)); + } + List list = new ArrayList<>(); + if(fields != null && !fields.isEmpty()) { + Map> groupedValues = fields + .stream() + .collect(Collectors.groupingBy(DynamicField::getLangCode)); + list = groupedValues.keySet() + .stream() + .map(lang -> getDynamicFieldDto(groupedValues.get(lang))) + .collect(Collectors.toList()); + + } + return list; + } + +} \ No newline at end of file diff --git a/admin/kernel-masterdata-service/src/test/java/io/mosip/kernel/masterdata/test/controller/DynamicFieldControllerTest.java b/admin/kernel-masterdata-service/src/test/java/io/mosip/kernel/masterdata/test/controller/DynamicFieldControllerTest.java index 46eea46fe16..5c094b25689 100644 --- a/admin/kernel-masterdata-service/src/test/java/io/mosip/kernel/masterdata/test/controller/DynamicFieldControllerTest.java +++ b/admin/kernel-masterdata-service/src/test/java/io/mosip/kernel/masterdata/test/controller/DynamicFieldControllerTest.java @@ -1,13 +1,22 @@ package io.mosip.kernel.masterdata.test.controller; -import java.util.ArrayList; -import java.util.List; - -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import io.mosip.kernel.masterdata.dto.request.*; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import io.mosip.kernel.core.http.RequestWrapper; +import io.mosip.kernel.core.websub.model.EventModel; +import io.mosip.kernel.core.websub.spi.PublisherClient; +import io.mosip.kernel.masterdata.dto.DynamicFieldDto; +import io.mosip.kernel.masterdata.dto.DynamicFieldPutDto; +import io.mosip.kernel.masterdata.dto.request.FilterDto; +import io.mosip.kernel.masterdata.dto.request.FilterValueDto; +import io.mosip.kernel.masterdata.dto.request.Pagination; +import io.mosip.kernel.masterdata.dto.request.SearchDto; +import io.mosip.kernel.masterdata.dto.request.SearchSort; +import io.mosip.kernel.masterdata.test.TestBootApplication; +import io.mosip.kernel.masterdata.test.utils.MasterDataTest; +import io.mosip.kernel.masterdata.utils.AuditUtil; import io.mosip.kernel.masterdata.validator.FilterColumnEnum; -import org.json.JSONObject; import org.junit.Before; import org.junit.FixMethodOrder; import org.junit.Test; @@ -24,18 +33,8 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; - -import io.mosip.kernel.core.http.RequestWrapper; -import io.mosip.kernel.core.websub.model.EventModel; -import io.mosip.kernel.core.websub.spi.PublisherClient; -import io.mosip.kernel.masterdata.dto.DynamicFieldDto; -import io.mosip.kernel.masterdata.dto.DynamicFieldPutDto; -import io.mosip.kernel.masterdata.test.TestBootApplication; -import io.mosip.kernel.masterdata.test.utils.MasterDataTest; -import io.mosip.kernel.masterdata.utils.AuditUtil; +import java.util.ArrayList; +import java.util.List; @RunWith(SpringRunner.class) @SpringBootTest(classes = TestBootApplication.class) @@ -418,4 +417,12 @@ public void t022getDynamicFieldByNameTest2() throws Exception { "KER-SCH-003"); } + @Test + @WithUserDetails("global-admin") + public void t000getAllDynamicFieldByNameTest() throws Exception { + MasterDataTest.checkResponse( + mockMvc.perform(MockMvcRequestBuilders.get("/dynamicfields/all/gender")).andReturn(), + null); + } + } diff --git a/admin/kernel-masterdata-service/src/test/java/io/mosip/kernel/masterdata/test/service/SchemaServiceTest.java b/admin/kernel-masterdata-service/src/test/java/io/mosip/kernel/masterdata/test/service/SchemaServiceTest.java index 01906e1043c..0c60f6508bc 100644 --- a/admin/kernel-masterdata-service/src/test/java/io/mosip/kernel/masterdata/test/service/SchemaServiceTest.java +++ b/admin/kernel-masterdata-service/src/test/java/io/mosip/kernel/masterdata/test/service/SchemaServiceTest.java @@ -1,35 +1,6 @@ package io.mosip.kernel.masterdata.test.service; -import static org.junit.Assert.assertEquals; - -import java.time.LocalDateTime; -import java.time.ZoneOffset; -import java.util.ArrayList; -import java.util.List; - -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import io.mosip.kernel.masterdata.service.impl.SchemaDefinitionServiceImpl; -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mockito; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Sort; -import org.springframework.data.domain.Sort.Direction; -import org.springframework.http.HttpHeaders; -import org.springframework.security.test.context.support.WithUserDetails; -import org.springframework.test.context.junit4.SpringRunner; - import io.mosip.kernel.core.dataaccess.exception.DataAccessLayerException; import io.mosip.kernel.core.websub.model.EventModel; import io.mosip.kernel.core.websub.spi.PublisherClient; @@ -50,7 +21,34 @@ import io.mosip.kernel.masterdata.service.DynamicFieldService; import io.mosip.kernel.masterdata.service.IdentitySchemaService; import io.mosip.kernel.masterdata.service.TemplateService; +import io.mosip.kernel.masterdata.service.impl.SchemaDefinitionServiceImpl; import io.mosip.kernel.masterdata.test.TestBootApplication; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.data.domain.Sort.Direction; +import org.springframework.http.HttpHeaders; +import org.springframework.security.test.context.support.WithUserDetails; +import org.springframework.test.context.junit4.SpringRunner; + +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertEquals; /** * @@ -95,10 +93,12 @@ public class SchemaServiceTest { private DynamicField mstatusField; PageRequest pageRequest = null; + + List list; @Before public void setup() { - List list = new ArrayList(); + list = new ArrayList(); bloodTypeField = new DynamicField(); bloodTypeField.setDataType("simpleType"); bloodTypeField.setDescription("test"); @@ -328,4 +328,11 @@ public void testDeleteIdentitySchemaFailedUpdate() throws Exception { identitySchemaService.deleteSchema("test-test"); } + @Test + @WithUserDetails("reg-officer") + public void testFetchAllDynamicFieldsAllLang() throws Exception { + Mockito.when(dynamicFieldRepository.findAllDynamicFieldByName(Mockito.anyString())).thenReturn(list); + dynamicFieldService.getAllDynamicFieldByName("gender"); + } + } From b33ef47f1d6f4fc8bc26be224fc76404e8afb781 Mon Sep 17 00:00:00 2001 From: VSIVAKALYAN <103260988+VSIVAKALYAN@users.noreply.github.com> Date: Fri, 22 Sep 2023 20:03:37 +0530 Subject: [PATCH 09/16] [MOSIP-29162] Added Secrets in tag & release-changes. (#902) * [MOSIP-29162] Added Secrets in tag & release-changes Signed-off-by: VSIVAKALYAN <103260988+VSIVAKALYAN@users.noreply.github.com> * [MOSIP-29162] Added Secrets in tag & release-changes Signed-off-by: VSIVAKALYAN <103260988+VSIVAKALYAN@users.noreply.github.com> --------- Signed-off-by: VSIVAKALYAN <103260988+VSIVAKALYAN@users.noreply.github.com> --- .github/workflows/release-changes.yml | 5 ++++- .github/workflows/tag.yml | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-changes.yml b/.github/workflows/release-changes.yml index 2579ea836f1..c10da751791 100644 --- a/.github/workflows/release-changes.yml +++ b/.github/workflows/release-changes.yml @@ -23,4 +23,7 @@ jobs: MESSAGE: ${{ inputs.MESSAGE }} RELEASE_TAG: ${{ inputs.RELEASE_TAG }} SNAPSHOT_TAG: ${{ inputs.SNAPSHOT_TAG }} - BASE: ${{ inputs.BASE }} \ No newline at end of file + BASE: ${{ inputs.BASE }} + secrets: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} + ACTION_PAT: ${{ secrets.ACTION_PAT }} diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml index c4939a6e8ce..c131f5aa9bb 100644 --- a/.github/workflows/tag.yml +++ b/.github/workflows/tag.yml @@ -31,3 +31,5 @@ jobs: BODY: ${{ inputs.BODY }} PRE_RELEASE: ${{ inputs.PRE_RELEASE }} DRAFT: ${{ inputs.DRAFT }} + secrets: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} From 50a1dbda2f3b9c040f4743f329eaa730faadc6e8 Mon Sep 17 00:00:00 2001 From: kameshsr <47484458+kameshsr@users.noreply.github.com> Date: Tue, 26 Sep 2023 13:01:28 +0530 Subject: [PATCH 10/16] MOSIP-29472 Added API /locations/immediatechildren/{locationcode} (#904) * MOSIP-29472 Create API dynamicfields/all. * MOSIP-29472 Create API dynamicfields/all. * MOSIP-29472 Create API dynamicfields/all. * MOSIP-29472 Covered Junit for Dynamic field all API. * MOSIP-29472 Covered Junit for Dynamic field all API. * MOSIP-29472 Changed logic as per review comment. * MOSIP-29472 Changed logic as per review comment. * MOSIP-29472 Changed logic as per review comment. * MOSIP-29472 Added API {{url}}/v1/masterdata/locations/immediatechildren/{locationCode}. * MOSIP-29472 Removed un-used class. * MOSIP-29472 Added Junit for new API /immediatechildren/locationcode * MOSIP-29472 Added Junit for new API /immediatechildren/locationcode * MOSIP-29472 Added Junit for new API /immediatechildren/locationcode * MOSIP-29472 Added Junit for new API /immediatechildren/locationcode * MOSIP-29472 Added Junit for new API /immediatechildren/locationcode --- .../controller/LocationController.java | 17 +++++++++++++ .../repository/LocationRepository.java | 3 +++ .../masterdata/service/LocationService.java | 1 + .../service/impl/LocationServiceImpl.java | 24 ++++++++++++++++-- .../controller/LocationControllerTest.java | 8 ++++++ .../test/service/MasterDataServiceTest.java | 25 ++++++++++++++++++- 6 files changed, 75 insertions(+), 3 deletions(-) diff --git a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/controller/LocationController.java b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/controller/LocationController.java index 9be30f376f9..7db7db9bd5e 100644 --- a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/controller/LocationController.java +++ b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/controller/LocationController.java @@ -230,6 +230,23 @@ public ResponseWrapper getImmediateChildrenByLocCodeAndLang return responseWrapper; } + /** + * + * @param locationCode location code + * @param languageCodes language codes + * @return list of location hierarchies + */ + @ResponseFilter + @GetMapping(value = "/immediatechildren/{locationcode}") + public ResponseWrapper getImmediateChildrenByLocCode( + @PathVariable("locationcode") String locationCode, @RequestParam("languageCodes") List languageCodes) { + + ResponseWrapper responseWrapper = new ResponseWrapper<>(); + responseWrapper + .setResponse(locationHierarchyService.getImmediateChildrenByLocCode(locationCode, languageCodes)); + return responseWrapper; + } + /** * checks whether the given location name is valid or not * diff --git a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/LocationRepository.java b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/LocationRepository.java index c47876bd38b..419735474e2 100644 --- a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/LocationRepository.java +++ b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/LocationRepository.java @@ -160,4 +160,7 @@ List findLocationByHierarchyLevelStartsWith(Short hierarchyLevel, Stri @Query(value = "FROM Location l where l.langCode=?1 and l.hierarchyLevel=?2") List getAllLocationsByLangCodeWithHierarchyLevel(String langCode, Short level); + @Query(value = "FROM Location l WHERE parentLocCode = ?1 AND l.langCode IN (?2) AND (l.isDeleted IS NULL OR l.isDeleted = false) AND l.isActive = true") + List findLocationHierarchyByParentLocCode(String parentLocCode, List languageCodes); + } diff --git a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/LocationService.java b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/LocationService.java index 74f52bc059c..e2c8a0d0452 100644 --- a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/LocationService.java +++ b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/LocationService.java @@ -137,4 +137,5 @@ public interface LocationService { public FilterResponseCodeDto locFilterValues(FilterValueDto filterValueDto); + LocationResponseDto getImmediateChildrenByLocCode(String locationCode, List languageCodes); } diff --git a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/impl/LocationServiceImpl.java b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/impl/LocationServiceImpl.java index 7cad5c2ea24..d3dd6c8fd76 100644 --- a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/impl/LocationServiceImpl.java +++ b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/impl/LocationServiceImpl.java @@ -5,10 +5,8 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.TreeMap; -import java.util.stream.Collectors; import io.mosip.kernel.masterdata.dto.response.*; import org.springframework.beans.factory.annotation.Autowired; @@ -958,4 +956,26 @@ public FilterResponseCodeDto locFilterValues(FilterValueDto filterValueDto) { } return filterResponseDto; } + + + @Override + public LocationResponseDto getImmediateChildrenByLocCode(String locationCode, List languageCodes) { + List locationlist = null; + LocationResponseDto locationHierarchyResponseDto = new LocationResponseDto(); + try { + locationlist = locationRepository.findLocationHierarchyByParentLocCode(locationCode, languageCodes); + + } catch (DataAccessException | DataAccessLayerException e) { + throw new MasterDataServiceException(LocationErrorCode.LOCATION_FETCH_EXCEPTION.getErrorCode(), + LocationErrorCode.LOCATION_FETCH_EXCEPTION.getErrorMessage() + ExceptionUtils.parseException(e)); + } + + if (locationlist.isEmpty()) { + throw new DataNotFoundException(LocationErrorCode.LOCATION_NOT_FOUND_EXCEPTION.getErrorCode(), + LocationErrorCode.LOCATION_NOT_FOUND_EXCEPTION.getErrorMessage()); + } + List locationDtoList = MapperUtils.mapAll(locationlist, LocationDto.class); + locationHierarchyResponseDto.setLocations(locationDtoList); + return locationHierarchyResponseDto; + } } diff --git a/admin/kernel-masterdata-service/src/test/java/io/mosip/kernel/masterdata/test/controller/LocationControllerTest.java b/admin/kernel-masterdata-service/src/test/java/io/mosip/kernel/masterdata/test/controller/LocationControllerTest.java index eb693eddf38..ed32cf0b380 100644 --- a/admin/kernel-masterdata-service/src/test/java/io/mosip/kernel/masterdata/test/controller/LocationControllerTest.java +++ b/admin/kernel-masterdata-service/src/test/java/io/mosip/kernel/masterdata/test/controller/LocationControllerTest.java @@ -674,4 +674,12 @@ public void t021updateLocationStatusFailTest() throws Exception { } + @Test + @WithUserDetails("global-admin") + public void t021getImmediateChildrenByLocCode() throws Exception { + + MasterDataTest + .checkResponse(mockMvc.perform(MockMvcRequestBuilders.get("/locations/immediatechildren/RSK?languageCodes=eng,tam")).andReturn(), null); + } + } diff --git a/admin/kernel-masterdata-service/src/test/java/io/mosip/kernel/masterdata/test/service/MasterDataServiceTest.java b/admin/kernel-masterdata-service/src/test/java/io/mosip/kernel/masterdata/test/service/MasterDataServiceTest.java index 4a5600b55a2..4d21559491d 100644 --- a/admin/kernel-masterdata-service/src/test/java/io/mosip/kernel/masterdata/test/service/MasterDataServiceTest.java +++ b/admin/kernel-masterdata-service/src/test/java/io/mosip/kernel/masterdata/test/service/MasterDataServiceTest.java @@ -12,7 +12,6 @@ import java.time.Month; import java.time.format.DateTimeFormatter; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import io.mosip.kernel.core.exception.ServiceError; @@ -3105,4 +3104,28 @@ public void validateRegCenterUpdateTest() { Assert.assertEquals("KER-MSD-259", serviceErrors.get(4).getErrorCode()); } + @Test + public void getImmediateChildrenByLocCodeTest() { + Mockito.when(locationHierarchyRepository + .findLocationHierarchyByParentLocCode(Mockito.anyString(), Mockito.anyList())) + .thenReturn(locationHierarchies); + Assert.assertEquals("IND", locationHierarchyService.getImmediateChildrenByLocCode("KAR", List.of("eng")).getLocations().get(0).getCode()); + } + + @Test(expected = MasterDataServiceException.class) + public void getImmediateChildrenByLocCodeTestExceptionTest() { + Mockito.when(locationHierarchyRepository + .findLocationHierarchyByParentLocCode(Mockito.anyString(), Mockito.anyList())) + .thenThrow(DataRetrievalFailureException.class); + locationHierarchyService.getImmediateChildrenByLocCode("KAR", List.of("eng")); + } + + @Test(expected = DataNotFoundException.class) + public void getImmediateChildrenByLocCodeTestDataExceptionTest() { + Mockito.when(locationHierarchyRepository + .findLocationHierarchyByParentLocCode(Mockito.anyString(), Mockito.anyList())) + .thenReturn(new ArrayList()); + locationHierarchyService.getImmediateChildrenByLocCode("KAR", List.of("eng")); + } + } From 3e83eaa7899acf2207885c88ac5635877e328f04 Mon Sep 17 00:00:00 2001 From: Balaji Alluru <74903654+balaji-alluru@users.noreply.github.com> Date: Thu, 12 Oct 2023 12:35:24 +0530 Subject: [PATCH 11/16] [MOSIP-29726]Update LocationExtnDto.java (#906) Signed-off-by: Balaji Alluru <74903654+balaji-alluru@users.noreply.github.com> --- .../kernel/masterdata/dto/getresponse/extn/LocationExtnDto.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/dto/getresponse/extn/LocationExtnDto.java b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/dto/getresponse/extn/LocationExtnDto.java index 23f71cfb66a..ed8a742fadb 100644 --- a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/dto/getresponse/extn/LocationExtnDto.java +++ b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/dto/getresponse/extn/LocationExtnDto.java @@ -34,7 +34,7 @@ public class LocationExtnDto extends BaseDto { @JsonDeserialize(using = CustomIntegerDeserializer.class) @Range(min = 0) @ApiModelProperty(value = "hierarchyLevel", required = true, dataType = "java.lang.Integer") - private int hierarchyLevel; + private short hierarchyLevel; @FilterType(types = { FilterTypeEnum.EQUALS, FilterTypeEnum.CONTAINS, FilterTypeEnum.STARTSWITH }) @ApiModelProperty(value = "hierarchyName", required = true, dataType = "java.lang.String") From 46ba584c3bd06f4c2ae60c8e7bf4b0d1cc2fa46a Mon Sep 17 00:00:00 2001 From: Rakshithb1 <79500257+Rakshithb1@users.noreply.github.com> Date: Wed, 15 Nov 2023 10:52:31 +0530 Subject: [PATCH 12/16] [MOSIP-29918] added db-test.yml (#912) * [MOSIP-29918] added db-test.yml Signed-off-by: Rakshithb1 * [MOSIP-29918] added db-test.yml Signed-off-by: Rakshithb1 * [MOSIP-29918] added db-test.yml Signed-off-by: Rakshithb1 --------- Signed-off-by: Rakshithb1 --- .github/workflows/db-test.yml | 41 +++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 .github/workflows/db-test.yml diff --git a/.github/workflows/db-test.yml b/.github/workflows/db-test.yml new file mode 100644 index 00000000000..974cce0eb47 --- /dev/null +++ b/.github/workflows/db-test.yml @@ -0,0 +1,41 @@ +name: PostgreSQL Test + +on: + release: + types: [published] + pull_request: + types: [opened, reopened, synchronize] + paths: + - 'db_scripts/**' + workflow_dispatch: + inputs: + message: + description: 'Message for manually triggering' + required: false + default: 'Triggered for Updates' + type: string + push: + branches: + - '!release-branch' + - release* + - master + - 1.* + - develop* + - MOSIP* + paths: + - 'db_scripts/**' + +jobs: + build-db-test: + strategy: + matrix: + include: + - DB_LOCATION: 'db_scripts/mosip_hotlist' + DB_NAME: 'mosip_hotlist' + - DB_LOCATION: 'db_scripts/mosip_master' + DB_NAME: 'mosip_master' + fail-fast: false + name: ${{ matrix.DB_NAME }} + uses: mosip/kattu/.github/workflows/db-test.yml@master + with: + DB_LOCATION: ${{ matrix.DB_LOCATION}} From e813e111555c3a86f13458f1ccc51a9b4093898b Mon Sep 17 00:00:00 2001 From: Rakshith B <79500257+Rakshithb1@users.noreply.github.com> Date: Wed, 13 Dec 2023 10:09:56 +0530 Subject: [PATCH 13/16] [MOSIP-29961] Updated push-trigger.yml (#922) Signed-off-by: Rakshith B <79500257+Rakshithb1@users.noreply.github.com> --- .github/workflows/push-trigger.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/push-trigger.yml b/.github/workflows/push-trigger.yml index 39904afc3e5..a7bd29b72b7 100644 --- a/.github/workflows/push-trigger.yml +++ b/.github/workflows/push-trigger.yml @@ -4,7 +4,7 @@ on: release: types: [published] pull_request: - types: [opened] + types: [opened, reopened, synchronize] workflow_dispatch: inputs: message: From 2c695fb8be41222d24904b442a94b17f36881397 Mon Sep 17 00:00:00 2001 From: Rakshith B <79500257+Rakshithb1@users.noreply.github.com> Date: Wed, 13 Dec 2023 15:38:39 +0530 Subject: [PATCH 14/16] [MOSIP-29961] removed paths from db-test.yml (#924) Signed-off-by: Rakshith B <79500257+Rakshithb1@users.noreply.github.com> --- .github/workflows/db-test.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/db-test.yml b/.github/workflows/db-test.yml index 974cce0eb47..8d3c454576b 100644 --- a/.github/workflows/db-test.yml +++ b/.github/workflows/db-test.yml @@ -5,8 +5,6 @@ on: types: [published] pull_request: types: [opened, reopened, synchronize] - paths: - - 'db_scripts/**' workflow_dispatch: inputs: message: From eab87a3200f28cb2c32069d2c99435eb9b09e5e9 Mon Sep 17 00:00:00 2001 From: PRAFUL RAKHADE <99539100+Prafulrakhade@users.noreply.github.com> Date: Wed, 20 Dec 2023 20:06:09 +0530 Subject: [PATCH 15/16] [DSD-3932] removed release-changes.yml, tag.yml and updated push-trigger.yml file (#926) Signed-off-by: techno-467 --- .github/workflows/push-trigger.yml | 2 +- .github/workflows/release-changes.yml | 29 ---------------------- .github/workflows/tag.yml | 35 --------------------------- 3 files changed, 1 insertion(+), 65 deletions(-) delete mode 100644 .github/workflows/release-changes.yml delete mode 100644 .github/workflows/tag.yml diff --git a/.github/workflows/push-trigger.yml b/.github/workflows/push-trigger.yml index a7bd29b72b7..c0e79f091a7 100644 --- a/.github/workflows/push-trigger.yml +++ b/.github/workflows/push-trigger.yml @@ -35,7 +35,7 @@ jobs: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} publish_to_nexus: - if: "${{ !contains(github.ref, 'master') && github.event_name != 'pull_request' }}" + if: "${{ !contains(github.ref, 'master') && github.event_name != 'pull_request' && github.event_name != 'release' && github.event_name != 'prerelease' && github.event_name != 'publish' }}" needs: build-maven-admin-services uses: mosip/kattu/.github/workflows/maven-publish-to-nexus.yml@master with: diff --git a/.github/workflows/release-changes.yml b/.github/workflows/release-changes.yml deleted file mode 100644 index c10da751791..00000000000 --- a/.github/workflows/release-changes.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Release/pre-release Preparation. - -on: - workflow_dispatch: - inputs: - MESSAGE: - description: 'Triggered for release or pe-release' - required: false - default: 'Release Preparation' - RELEASE_TAG: - description: 'tag to update' - required: true - SNAPSHOT_TAG: - description: 'tag to be replaced' - required: true - BASE: - description: 'base branch for PR' - required: true -jobs: - maven-release-preparation: - uses: mosip/kattu/.github/workflows/release-changes.yml@master - with: - MESSAGE: ${{ inputs.MESSAGE }} - RELEASE_TAG: ${{ inputs.RELEASE_TAG }} - SNAPSHOT_TAG: ${{ inputs.SNAPSHOT_TAG }} - BASE: ${{ inputs.BASE }} - secrets: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} - ACTION_PAT: ${{ secrets.ACTION_PAT }} diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml deleted file mode 100644 index c131f5aa9bb..00000000000 --- a/.github/workflows/tag.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Tagging of repos - -on: - workflow_dispatch: - inputs: - TAG: - description: 'Tag to be published' - required: true - type: string - BODY: - description: 'Release body message' - required: true - default: 'Changes in this Release' - type: string - PRE_RELEASE: - description: 'Pre-release? True/False' - required: true - default: False - type: string - DRAFT: - description: 'Draft? True/False' - required: false - default: False - type: string - -jobs: - tag-branch: - uses: mosip/kattu/.github/workflows/tag.yml@master - with: - TAG: ${{ inputs.TAG }} - BODY: ${{ inputs.BODY }} - PRE_RELEASE: ${{ inputs.PRE_RELEASE }} - DRAFT: ${{ inputs.DRAFT }} - secrets: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} From b34aba030278916c71e8a8488ea32a68ce6c9913 Mon Sep 17 00:00:00 2001 From: Balaji Alluru <74903654+balaji-alluru@users.noreply.github.com> Date: Mon, 22 Jan 2024 00:03:38 +0530 Subject: [PATCH 16/16] [MOSIP-29094]Updated sql queries with case insensitive search (#920) * Updated sql queries with case insensitive search Signed-off-by: Balaji <74903654+balaji-alluru@users.noreply.github.com> * updated getter methods Signed-off-by: Balaji <74903654+balaji-alluru@users.noreply.github.com> * Updated user detail History and zone user history repositories Signed-off-by: Balaji <74903654+balaji-alluru@users.noreply.github.com> * Updated zone user repository Signed-off-by: Balaji <74903654+balaji-alluru@users.noreply.github.com> * Fixed admin build issues Signed-off-by: Balaji <74903654+balaji-alluru@users.noreply.github.com> --------- Signed-off-by: Balaji <74903654+balaji-alluru@users.noreply.github.com> --- admin/admin-service/pom.xml | 27 ++++++++++++++++++- .../io/mosip/admin/TestBootApplication.java | 8 ++++++ .../controller/UserDetailsController.java | 2 +- .../kernel/masterdata/dto/UserDetailsDto.java | 5 ++++ .../kernel/masterdata/entity/ZoneUser.java | 4 +++ .../UserDetailsHistoryRepository.java | 4 +-- .../repository/UserDetailsRepository.java | 10 +++---- .../repository/ZoneUserHistoryRepository.java | 2 +- .../repository/ZoneUserRepository.java | 22 +++++++++------ .../service/UserDetailsService.java | 2 +- .../service/impl/UserDetailsServiceImpl.java | 2 +- .../service/impl/ZoneUserServiceImpl.java | 3 +-- 12 files changed, 69 insertions(+), 22 deletions(-) diff --git a/admin/admin-service/pom.xml b/admin/admin-service/pom.xml index 2f24157900b..72c33550af4 100644 --- a/admin/admin-service/pom.xml +++ b/admin/admin-service/pom.xml @@ -36,6 +36,26 @@ + + com.fasterxml.jackson.core + jackson-core + 2.12.0 + + + com.fasterxml.jackson.core + jackson-databind + 2.12.0 + + + com.fasterxml.jackson.core + jackson-annotations + 2.12.0 + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + 2.12.0 + org.projectlombok lombok @@ -129,7 +149,12 @@ - + + javax.validation + validation-api + 2.0.1.Final + + io.mosip.commons commons-packet-manager diff --git a/admin/admin-service/src/test/java/io/mosip/admin/TestBootApplication.java b/admin/admin-service/src/test/java/io/mosip/admin/TestBootApplication.java index 57022f9d24e..17592a1a5d1 100644 --- a/admin/admin-service/src/test/java/io/mosip/admin/TestBootApplication.java +++ b/admin/admin-service/src/test/java/io/mosip/admin/TestBootApplication.java @@ -2,9 +2,13 @@ import io.mosip.commons.packet.impl.OnlinePacketCryptoServiceImpl; import io.mosip.commons.packet.keeper.PacketKeeper; + +import javax.validation.Validator; + import org.mockito.Mockito; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; import org.springframework.web.client.RestTemplate; @@ -36,4 +40,8 @@ public PacketKeeper packetKeeper() { return Mockito.mock(PacketKeeper.class); } + @Bean + public Validator validator() { + return Mockito.mock(Validator.class); + } } diff --git a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/controller/UserDetailsController.java b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/controller/UserDetailsController.java index 3d6dd76a08f..6ad6fcdbc1e 100644 --- a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/controller/UserDetailsController.java +++ b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/controller/UserDetailsController.java @@ -267,7 +267,7 @@ public ResponseWrapper> serachUserCent auditUtil.auditRequest(MasterDataConstant.SEARCH_USER_DETAILS_API_IS_CALLED + SearchDto.class.getCanonicalName(), MasterDataConstant.AUDIT_SYSTEM, MasterDataConstant.SEARCH_USER_DETAILS_API_IS_CALLED + SearchDto.class.getCanonicalName(),"ADM-922"); - responseWrapper.setResponse(userDetailsService.serachUserCenterMappingDetails(dto.getRequest())); + responseWrapper.setResponse(userDetailsService.searchUserCenterMappingDetails(dto.getRequest())); return responseWrapper; } diff --git a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/dto/UserDetailsDto.java b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/dto/UserDetailsDto.java index 558c7103934..aabb5b4a794 100644 --- a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/dto/UserDetailsDto.java +++ b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/dto/UserDetailsDto.java @@ -37,5 +37,10 @@ public class UserDetailsDto { private String langCode; + + + public String getId() { + return this.id.toLowerCase(); + } } diff --git a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/entity/ZoneUser.java b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/entity/ZoneUser.java index 902f5d2b96b..e277d317822 100644 --- a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/entity/ZoneUser.java +++ b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/entity/ZoneUser.java @@ -35,5 +35,9 @@ public class ZoneUser extends BaseEntity implements Serializable { @Column(name = "lang_code", nullable = true, length = 3) private String langCode; + + public String getUserId() { + return this.userId.toLowerCase(); + } } diff --git a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/UserDetailsHistoryRepository.java b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/UserDetailsHistoryRepository.java index 1dea216e648..bb3e807ebea 100644 --- a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/UserDetailsHistoryRepository.java +++ b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/UserDetailsHistoryRepository.java @@ -25,11 +25,11 @@ public interface UserDetailsHistoryRepository extends BaseRepository getByUserIdAndTimestamp(String userId, LocalDateTime effDTimes); // (?2 BETWEEN effDTimes AND CURRENT_TIMESTAMP) - @Query(value = "Select * from master.user_detail_h m where m.regcntr_id = ?1 and m.id = ?2 and m.eff_dtimes <= ?3 and ( m.is_deleted = false or m.is_deleted is null) order by m.eff_dtimes desc ", nativeQuery = true) + @Query(value = "Select * from master.user_detail_h m where m.regcntr_id = ?1 and LOWER(m.id) = LOWER(?2) and m.eff_dtimes <= ?3 and ( m.is_deleted = false or m.is_deleted is null) order by m.eff_dtimes desc ", nativeQuery = true) List findByCntrIdAndUsrIdAndEffectivetimesLessThanEqualAndIsDeletedFalseOrIsDeletedIsNull( String registrationCenterId, String userId, LocalDateTime lDateAndTime); diff --git a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/UserDetailsRepository.java b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/UserDetailsRepository.java index a04b5660ec4..dfe5e90fa06 100644 --- a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/UserDetailsRepository.java +++ b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/UserDetailsRepository.java @@ -28,25 +28,25 @@ public interface UserDetailsRepository extends BaseRepository findByRegIdAndIsDeletedFalseOrIsDeletedIsNull(String centerId, Pageable pageable); - @Query("FROM UserDetails m where m.id = ?1 and (m.isDeleted is null or m.isDeleted = false)") + @Query("FROM UserDetails m where LOWER(m.id) = LOWER(?1) and (m.isDeleted is null or m.isDeleted = false)") UserDetails findByIdAndIsDeletedFalseorIsDeletedIsNull(String id); - @Query("FROM UserDetails m where m.id = ?1") + @Query("FROM UserDetails m where LOWER(m.id) = LOWER(?1)") UserDetails findUserDetailsById(String id); @Query("FROM UserDetails m where (m.isDeleted is null or m.isDeleted = false)") List findAllByAndIsDeletedFalseorIsDeletedIsNull(); - @Query("FROM UserDetails m where m.id = ?1 and (m.isDeleted is null or m.isDeleted = false) and isActive = true") + @Query("FROM UserDetails m where LOWER(m.id) = LOWER(?1) and (m.isDeleted is null or m.isDeleted = false) and isActive = true") UserDetails findByIdAndIsDeletedFalseorIsDeletedIsNullAndIsActive(String id); @Query("FROM UserDetails m where (m.isDeleted is null or m.isDeleted = false) and m.isActive = true") Page findAllByIsDeletedFalseorIsDeletedIsNull(Pageable pageable); - @Query("FROM UserDetails m where m.id = ?1 and m.langCode = ?2 and (m.isDeleted is null or m.isDeleted = false)") + @Query("FROM UserDetails m where LOWER(m.id) = LOWER(?1) and m.langCode = ?2 and (m.isDeleted is null or m.isDeleted = false)") UserDetails findByIdAndIsDeletedFalseorIsDeletedIsNull(String id,String langCode); @Modifying - @Query("UPDATE UserDetails m SET m.updatedBy=?3, m.isDeleted =true, m.isActive = false, m.updatedDateTime=?2 ,m.deletedDateTime = ?2 WHERE m.id =?1 and (m.isDeleted is null or m.isDeleted =false)") + @Query("UPDATE UserDetails m SET m.updatedBy=?3, m.isDeleted =true, m.isActive = false, m.updatedDateTime=?2 ,m.deletedDateTime = ?2 WHERE LOWER(m.id) = LOWER(?1) and (m.isDeleted is null or m.isDeleted =false)") int deleteUserCenterMapping(String id, LocalDateTime deletedDateTime, String updatedBy); } diff --git a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/ZoneUserHistoryRepository.java b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/ZoneUserHistoryRepository.java index 5f605907454..2e7ed573522 100644 --- a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/ZoneUserHistoryRepository.java +++ b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/ZoneUserHistoryRepository.java @@ -11,7 +11,7 @@ import io.mosip.kernel.masterdata.entity.id.ZoneUserHistoryId; @Repository public interface ZoneUserHistoryRepository extends BaseRepository{ - @Query(value = "SELECT * FROM master.zone_user_h m WHERE usr_id = ?1 AND eff_dtimes>= ?2 ORDER BY eff_dtimes DESC ", nativeQuery = true) + @Query(value = "SELECT * FROM master.zone_user_h m WHERE LOWER(usr_id) = LOWER(?1) AND eff_dtimes>= ?2 ORDER BY eff_dtimes DESC ", nativeQuery = true) List getByUserIdAndTimestamp(String userId, LocalDateTime localDateTime); } diff --git a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/ZoneUserRepository.java b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/ZoneUserRepository.java index bcea2fb5584..7bc5f11ff2e 100644 --- a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/ZoneUserRepository.java +++ b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/repository/ZoneUserRepository.java @@ -21,34 +21,40 @@ */ public interface ZoneUserRepository extends BaseRepository { - @Query("FROM ZoneUser zu WHERE zu.userId=?1 and (zu.isDeleted IS NULL OR zu.isDeleted = false) ") + @Query("FROM ZoneUser zu WHERE LOWER(zu.userId)=LOWER(?1) and (zu.isDeleted IS NULL OR zu.isDeleted = false) ") public List findByUserIdNonDeleted(String userId); - @Query("FROM ZoneUser zu WHERE zu.userId=?1 and (zu.isDeleted IS NULL OR zu.isDeleted = false) ") + @Query("FROM ZoneUser zu WHERE LOWER(zu.userId)=LOWER(?1) and (zu.isDeleted IS NULL OR zu.isDeleted = false) ") public ZoneUser findZoneByUserIdNonDeleted(String userId); - @Query("FROM ZoneUser zu WHERE zu.userId=?1 ") + @Query("FROM ZoneUser zu WHERE LOWER(zu.userId)=LOWER(?1) ") public ZoneUser findByUserId(String userId); - @Query("FROM ZoneUser zu WHERE zu.userId=?1 and zu.zoneCode=?2 ") + @Query("FROM ZoneUser zu WHERE LOWER(zu.userId)=LOWER(?1) and zu.zoneCode=?2 ") public List findByUserIdAndZoneCode(String userId, String zoneCode); - @Query("FROM ZoneUser zu WHERE zu.userId=?1 and zu.zoneCode=?2 and (zu.isDeleted IS NULL OR zu.isDeleted = false) ") + @Query("FROM ZoneUser zu WHERE LOWER(zu.userId)=LOWER(?1) and zu.zoneCode=?2 and (zu.isDeleted IS NULL OR zu.isDeleted = false) ") public ZoneUser findByIdAndIsDeletedFalseOrIsDeletedIsNull(String userId, String zoneCode); @Query("FROM ZoneUser zu WHERE zu.zoneCode=?1 and (zu.isDeleted IS NULL OR zu.isDeleted = false) ") public List findtoUpdateZoneUserByCode(String zoneCode); - @Query("FROM ZoneUser zu WHERE zu.userId=?1 and zu.langCode=?2 and zu.zoneCode=?3 and (zu.isDeleted IS NULL OR zu.isDeleted = false) and zu.isActive=true") + @Query("FROM ZoneUser zu WHERE LOWER(zu.userId)=LOWER(?1) and zu.langCode=?2 and zu.zoneCode=?3 and (zu.isDeleted IS NULL OR zu.isDeleted = false) and zu.isActive=true") public ZoneUser findZoneUserByUserIdZoneCodeLangCodeIsActive(String userId, String langCode, String zoneCode); @Query("FROM ZoneUser zu WHERE zu.userId IN :userids") public List findByUserIds(@Param("userids") List userIds); - @Query("FROM ZoneUser zu WHERE zu.userId=?1 and zu.isActive=true and (zu.isDeleted IS NULL OR zu.isDeleted = false) ") + @Query("FROM ZoneUser zu WHERE LOWER(zu.userId)=LOWER(?1) and zu.isActive=true and (zu.isDeleted IS NULL OR zu.isDeleted = false) ") public ZoneUser findZoneByUserIdActiveAndNonDeleted(String userId); - @Query("FROM ZoneUser zu WHERE LOWER(zu.zoneCode) like (%?1%) and (zu.isDeleted IS NULL OR zu.isDeleted = false) ") + /* + * This is a query used by a deprecated end point /users/search, this should be removed in next release. + * The end point using this query was added in version 1.2.0-rc1 and marked as deprecated in version 1.2.0 + * For security reason, we replaced the 'LIKE' query with equals in where clause. + */ + + @Query("FROM ZoneUser zu WHERE LOWER(zu.zoneCode)=?1 and (zu.isDeleted IS NULL OR zu.isDeleted = false) ") public List findZoneByZoneCodeActiveAndNonDeleted(String zoneCode); @Modifying diff --git a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/UserDetailsService.java b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/UserDetailsService.java index 0cb388b2e05..cc83b6f9649 100644 --- a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/UserDetailsService.java +++ b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/UserDetailsService.java @@ -126,6 +126,6 @@ public UsersDto getUsers(String roleName,int pageStart, int pageFetch, public StatusResponseDto updateUserStatus(String id, @Valid boolean isActive); - public PageResponseDto serachUserCenterMappingDetails(SearchDtoWithoutLangCode request); + public PageResponseDto searchUserCenterMappingDetails(SearchDtoWithoutLangCode request); } diff --git a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/impl/UserDetailsServiceImpl.java b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/impl/UserDetailsServiceImpl.java index bcc1384d6a7..773dd4dfd7a 100644 --- a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/impl/UserDetailsServiceImpl.java +++ b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/impl/UserDetailsServiceImpl.java @@ -653,7 +653,7 @@ public PageResponseDto searchUserDetails(SearchDtoWithoutLan } @Override - public PageResponseDto serachUserCenterMappingDetails(SearchDtoWithoutLangCode searchDto) { + public PageResponseDto searchUserCenterMappingDetails(SearchDtoWithoutLangCode searchDto) { PageResponseDto pageDto = new PageResponseDto<>(); PageResponseDto userCenterPageDto = new PageResponseDto<>(); List userCenterMappingExtnDtos = null; diff --git a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/impl/ZoneUserServiceImpl.java b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/impl/ZoneUserServiceImpl.java index 55b1d5db121..b91dde392fb 100644 --- a/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/impl/ZoneUserServiceImpl.java +++ b/admin/kernel-masterdata-service/src/main/java/io/mosip/kernel/masterdata/service/impl/ZoneUserServiceImpl.java @@ -127,7 +127,6 @@ public ZoneUserExtnDto createZoneUserMapping(ZoneUserDto zoneUserDto) { // Throws exception if not found zoneservice.getZone(zoneUserDto.getZoneCode(), languageUtils.getDefaultLanguage()); - zu = zoneUserRepo.save(zu); ZoneUserHistory zuh = new ZoneUserHistory(); MapperUtils.map(zu, zuh); @@ -309,7 +308,7 @@ public StatusResponseDto updateZoneUserMapping(String userId, boolean isActive) throw new MasterDataServiceException(ZoneUserErrorCode.USER_MAPPING_EXIST.getErrorCode(), ZoneUserErrorCode.USER_MAPPING_EXIST.getErrorMessage()); } - masterdataCreationUtil.updateMasterDataStatus(ZoneUser.class, userId, isActive, "userId"); + masterdataCreationUtil.updateMasterDataStatus(ZoneUser.class, userId.toLowerCase(), isActive, "userId"); ZoneUserHistory zoneUserHistory = new ZoneUserHistory(); MetaDataUtils.setUpdateMetaData(zoneUser, zoneUserHistory, true);