Commit c12f8cc5 authored by Syed Asif's avatar Syed Asif

profile poc added

parent 6ed90cf0
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version> <version>2.3.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository --> <relativePath/> <!-- lookup parent from repository -->
</parent> </parent>
<groupId>com.timtech</groupId>
<artifactId>timtech-profile</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>timtech-profile</name>
<description>Tim Tech Profile</description>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version> <java.version>1.8</java.version>
</properties> </properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency> </dependency>
<dependency> <dependency>
...@@ -35,6 +31,24 @@ ...@@ -35,6 +31,24 @@
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>
...@@ -46,5 +60,4 @@ ...@@ -46,5 +60,4 @@
</plugins> </plugins>
</build> </build>
</project> </project>
package com.timtech.profile;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class TimtechProfileApplication {
public static void main(String[] args) {
SpringApplication.run(TimtechProfileApplication.class, args);
}
}
package com.timtech.profile.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.AbstractReactiveMongoConfiguration;
import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories;
import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoClients;
@Configuration
@EnableReactiveMongoRepositories(basePackages = "com.timtech.profile")
public class MongoConfig extends AbstractReactiveMongoConfiguration {
@Override
protected String getDatabaseName() {
return "profiles";
}
@Override
public MongoClient reactiveMongoClient() {
return MongoClients.create();
}
}
package com.timtech.profile.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import com.timtech.profile.dto.ProfileDto;
import com.timtech.profile.dto.ProfileDto.ProfileUpdate;
import com.timtech.profile.service.ProfileService;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/profile")
public class ProfileController {
@Autowired
private ProfileService profileService;
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Mono<ProfileDto> saveProfile(@RequestBody ProfileDto profileDto) {
return profileService.save(profileDto);
}
@PutMapping
@ResponseStatus(HttpStatus.ACCEPTED)
public Mono<ProfileDto> updateProfile(@Validated(ProfileUpdate.class) @RequestBody ProfileDto profileDto) {
return profileService.update(profileDto);
}
@GetMapping
public Flux<ProfileDto> findAllProfiles(){
return profileService.findAll();
}
@GetMapping("/{profileId}")
public Mono<ProfileDto> findOneProfiles(@PathVariable String profileId){
return profileService.findOne(profileId);
}
@DeleteMapping("/{profileId}")
public Mono<String> deleteOne(@PathVariable String profileId){
return profileService.deleteOne(profileId);
}
}
package com.timtech.profile.dto;
import java.io.Serializable;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ProfileDto implements Serializable {
private static final long serialVersionUID = 1L;
@NotNull(message = "Id must not be null", groups = ProfileUpdate.class)
private String profileId;
@NotNull(message = "First Name is Mandatory")
@Pattern(regexp = "^[a-zA-Z]+$", message = "First Name should only contain alphabets and spaces")
private String firstName;
@NotNull(message = "Last Name is Mandatory")
@Pattern(regexp = "^[a-zA-Z]+$", message = "Last Name should only contain alphabets and spaces")
private String lastName;
@NotNull(message = "Date of Birth is Mandatory")
@Pattern(regexp = "^\\d{2}-\\d{2}-\\d{4}$", message = "Date of Birth should be in MM-DD-YYYY format")
private String dateOfBirth;
// @Pattern(regexp = "^[A-Z]{5}\\d{4}[A-Z]$", message = "Invalid PAN format")
@Pattern(regexp = "[A-Z]{5}[0-9]{4}[A-Z]{1}", message = "Invalid PAN format")
private String permanentAccountNumber;
@Size(min = 12, max = 12, message = "Aadhar Number should be a 12-digit number")
// @Pattern(regexp = "^[1-9]\\d{11}$", message = "Aadhar Number should not start with 0")
@Pattern(regexp = "^[2-9]\\d{1}[0-9]\\d{10}$", message = "Aadhar Number should not start with 0")
private String adharNumber;
@NotBlank(message = "Mobile Number is mandatory")
@Pattern(regexp = "^[6-9]\\d{9}$", message = "Mobile Number should be 10-digit number starting with 6/7/8/9")
private String mobileNumber;
private String status;
public interface ProfileCreate{}
public interface ProfileUpdate{}
}
package com.timtech.profile.entity;
import java.io.Serializable;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Document(collection = "profile")
public class Profile implements Serializable {
private static final long serialVersionUID = 1L;
@Id
private String profileId;
private String firstName;
private String lastName;
private String dateOfBirth;
@Indexed(unique = true)
private String permanentAccountNumber;
@Indexed(unique = true)
private String adharNumber;
private String mobileNumber;
private String status;
}
package com.timtech.profile.exception;
import org.springframework.http.HttpStatus;
public class BusinessException extends RuntimeException {
private static final long serialVersionUID = 1L;
private final HttpStatus status;
private final String message;
public BusinessException(HttpStatus status, String message) {
this.status = status;
this.message = message;
}
public HttpStatus getStatus() {
return status;
}
@Override
public String getMessage() {
return message;
}
}
package com.timtech.profile.repository;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import com.timtech.profile.entity.Profile;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public interface ProfileRepository extends ReactiveMongoRepository<Profile, String> {
Flux<Profile> findByStatus(String profileStatus);
Mono<Boolean> existsByPermanentAccountNumber(String permanentAccountNumber);
Mono<Boolean> existsByAdharNumber(String adharNumber);
}
package com.timtech.profile.service;
import com.timtech.profile.dto.ProfileDto;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public interface ProfileService {
Mono<ProfileDto> save(ProfileDto profileDto);
Mono<ProfileDto> update(ProfileDto profileDto);
Flux<ProfileDto> findAll();
Mono<ProfileDto> findOne(String profileId);
Mono<String> deleteOne(String profileId);
}
package com.timtech.profile.service.impl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;
import com.timtech.profile.dto.ProfileDto;
import com.timtech.profile.entity.Profile;
import com.timtech.profile.exception.BusinessException;
import com.timtech.profile.repository.ProfileRepository;
import com.timtech.profile.service.ProfileService;
import com.timtech.profile.util.Utils;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Service
@Slf4j
public class ProfileServiceImpl implements ProfileService {
@Autowired
private ProfileRepository profileRepository;
@Transactional
public Mono<ProfileDto> save(ProfileDto profileDto) {
log.debug("Request to save Profile " + profileDto);
if (profileDto == null) {
return Mono.error(new RuntimeException("Profile Should Not be NULL"));
}
boolean isValidPan = Utils.builder().build().isValidPanCard(profileDto.getPermanentAccountNumber());
boolean isValidAadhar = Utils.builder().build().isValidAadhar(profileDto.getAdharNumber());
if (isValidPan || isValidAadhar) {
return profileRepository.existsByPermanentAccountNumber(profileDto.getPermanentAccountNumber())
.zipWith(profileRepository.existsByAdharNumber(profileDto.getAdharNumber())).flatMap(tuple -> {
if (tuple.getT1() || tuple.getT2()) {
return Mono.error(
new ResponseStatusException(HttpStatus.CONFLICT, "Duplicate PAN or Aadhar Number"));
} else {
Profile profileSave = new Profile();
profileDto.setStatus("ACTIVE");
BeanUtils.copyProperties(profileDto, profileSave);
return profileRepository.save(profileSave).map(this::convertProfileToDto);
}
})
.onErrorResume(DuplicateKeyException.class,
ex -> Mono.error(
new ResponseStatusException(HttpStatus.CONFLICT, "Duplicate PAN or Aadhar Number")))
.onErrorResume(ex -> Mono.error(
new BusinessException(HttpStatus.INTERNAL_SERVER_ERROR, "Internal Server Error !!!")));
} else {
return Mono.error(new BusinessException(HttpStatus.BAD_REQUEST, "Invalid PAN or Aadhar Number"));
}
}
@Transactional
public Mono<ProfileDto> update(ProfileDto profileDto) {
log.debug("Request to update profile " + profileDto);
if (profileDto == null) {
return Mono.error(new RuntimeException("Profile Should Not be NULL"));
}
return findOne(profileDto.getProfileId()).flatMap(existingProfileDto -> {
if ("ACTIVE".equals(existingProfileDto.getStatus())) {
Profile profile = convertDtoToProfile(existingProfileDto);
profile.setStatus("IN-ACTIVE");
return profileRepository.save(profile).map(this::convertProfileToDto)
.onErrorMap(DuplicateKeyException.class, ex -> {
throw new RuntimeException("Duplicate PAN or Aadhar Number");
});
} else {
return Mono.error(new RuntimeException("Profile has been Deleted !!!"));
}
});
}
@Transactional(readOnly = true)
public Flux<ProfileDto> findAll() {
log.debug("Request to find all profiles ");
return profileRepository.findByStatus("ACTIVE").map(this::convertProfileToDto);
}
@Transactional(readOnly = true)
public Mono<ProfileDto> findOne(String profileId) {
log.debug("Request to find one profile ");
return profileRepository.findById(profileId).map(this::convertProfileToDto);
}
@Transactional
public Mono<String> deleteOne(String profileId) {
log.debug("Request to delete one profile ");
return findOne(profileId).flatMap(profileDto -> {
Profile profile = convertDtoToProfile(profileDto);
profile.setStatus("IN-ACTIVE");
return profileRepository.save(profile);
}).flatMap(savedProfile -> Mono.just("SUCCESS")).onErrorResume(throwable -> Mono.just("FAILURE"));
}
private ProfileDto convertProfileToDto(Profile profile) {
ProfileDto profileDto = ProfileDto.builder().build();
BeanUtils.copyProperties(profile, profileDto);
return profileDto;
}
private Profile convertDtoToProfile(ProfileDto profileDto) {
Profile profile = Profile.builder().build();
BeanUtils.copyProperties(profileDto, profile);
return profile;
}
}
package com.timtech.profile.util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.Builder;
@Builder
public class Utils {
public boolean isValidPanCard(String panCardNo)
{
String regex = "[A-Z]{5}[0-9]{4}[A-Z]{1}";
Pattern p = Pattern.compile(regex);
if (panCardNo == null)
{
return false;
}
Matcher m = p.matcher(panCardNo);
return m.matches();
}
public boolean isValidAadhar(String adhar)
{
String regex = "[1-9]{12}";
Pattern p = Pattern.compile(regex);
if (adhar == null)
{
return false;
}
Matcher m = p.matcher(adhar);
return m.matches();
}
// public static void main(String[] args) {
//
// boolean validAadhar = Utils.builder().build().isValidAadhar("011234567891");
// System.out.println(validAadhar);
//
// }
}
server.port=9091
spring.data.mongodb.uri=mongodb://localhost:27017/profiles
package com.timtech.profile;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class TimtechProfileApplicationTests {
@Test
void contextLoads() {
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment