diff --git a/pom.xml b/pom.xml index b0a6389..73cd692 100644 --- a/pom.xml +++ b/pom.xml @@ -22,6 +22,86 @@ spring-boot-starter + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.security + spring-security-core + + + + org.springframework.security + spring-security-web + + + + org.springframework.security + spring-security-config + + + io.jsonwebtoken + jjwt + 0.9.1 + + + + + javax.xml.bind + jaxb-api + 2.3.0 + + + + + org.springframework.boot + spring-boot-starter-security + + + io.springfox + springfox-swagger2 +2.9.2 + + + io.springfox + springfox-swagger-ui + 2.9.2 + + + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + mysql + mysql-connector-java + runtime + + + org.projectlombok + lombok + true + + + org.mindrot + jbcrypt + 0.4 + + org.springframework.boot spring-boot-starter-test diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/SpringBootCodingTestApplication.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/SpringBootCodingTestApplication.java index 14e2bbf..6609973 100644 --- a/src/main/java/com/accenture/codingtest/springbootcodingtest/SpringBootCodingTestApplication.java +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/SpringBootCodingTestApplication.java @@ -2,12 +2,20 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + + +@Configuration @SpringBootApplication +@ComponentScan(basePackages = "com.accenture.codingtest.springbootcodingtest") + public class SpringBootCodingTestApplication { public static void main(String[] args) { SpringApplication.run(SpringBootCodingTestApplication.class, args); + System.out.println("****************BOOOOOOOOOOOOOOTED*******************"); } } diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/config/SecurityConfig.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/config/SecurityConfig.java new file mode 100644 index 0000000..da8909d --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/config/SecurityConfig.java @@ -0,0 +1,72 @@ +package com.accenture.codingtest.springbootcodingtest.config; + +import java.util.Arrays; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; + +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true) +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Autowired + UserDetailsService userDetailsService; + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(userDetailsService); + super.configure(auth); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.csrf().disable() + .authorizeRequests().antMatchers("/v1/**","/swagger-resources/configuration/ui", "/swagger-resources", + "/swagger-ui.html", "/webjars/**") + .permitAll() + .antMatchers("/v1/User/**").access("hasRole('ROLE_ADMIN')") + .antMatchers("/v1/Task/**", "/v1/Project/**").access("hasRole('ROLE_PROJECT_OWNER')") + + .anyRequest().authenticated().and().sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS); + + } + + @Bean + public BCryptPasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + + } + + @Bean + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManager(); + + } + + CorsConfigurationSource corsConfigurationSource() { + CorsConfiguration configuration = new CorsConfiguration(); + configuration.addAllowedOrigin(""); + configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE")); + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", configuration); + return source; + } + + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/config/SwaggerConfig.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/config/SwaggerConfig.java new file mode 100644 index 0000000..7302dfc --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/config/SwaggerConfig.java @@ -0,0 +1,41 @@ +package com.accenture.codingtest.springbootcodingtest.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; + +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiKey; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@Configuration +@EnableSwagger2 +public class SwaggerConfig { + + + public static final String AUTHORIZATION_HEADER= "Authorization"; + + private ApiKey apiKeys() { + + return new ApiKey ("Jwt",AUTHORIZATION_HEADER ,"header"); + + } + + @Bean + public Docket api() { + return new Docket(DocumentationType.SWAGGER_2) + .select().apis(RequestHandlerSelectors.any()) + .paths(PathSelectors.any()).build(); + } + + + + + + +} + + diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/constant/RoleConstants.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/constant/RoleConstants.java new file mode 100644 index 0000000..4a9b2fd --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/constant/RoleConstants.java @@ -0,0 +1,12 @@ +package com.accenture.codingtest.springbootcodingtest.constant; + +import org.springframework.stereotype.Component; + +@Component +public class RoleConstants { + + public static final String DEFAULT_ROLE = "ROLE_USER"; + public static final String[] ADMIN_ACCESS = {"ROLE_ADMIN" ,"ROLE_PRODUCT_OWNER"}; + public static final String[] PRODUCT_OWNER_ACCESS = {"ROLE_PRODUCT_OWNER"}; + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/constant/TaskStatus.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/constant/TaskStatus.java new file mode 100644 index 0000000..256cc52 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/constant/TaskStatus.java @@ -0,0 +1,15 @@ +package com.accenture.codingtest.springbootcodingtest.constant; + +public class TaskStatus { + + + public static final String[] TaskStatus = {"NOT_STARTED","IN_PROGRESS","READY_FOR_TEST","COMPLETED"}; + + public static final String NOT_STARTED = "NOT_STARTED"; + + public static final String IN_PROGRESS = "IN_PROGRESS"; + + public static final String READY_FOR_TEST = "READY_FOR_TEST"; + + public static final String COMPLETED = "COMPLETED"; +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/JwtController.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/JwtController.java new file mode 100644 index 0000000..924ac1f --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/JwtController.java @@ -0,0 +1,58 @@ +package com.accenture.codingtest.springbootcodingtest.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.annotation.Secured; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import com.accenture.codingtest.springbootcodingtest.filter.JwtUtil; +import com.accenture.codingtest.springbootcodingtest.model.JwtRequestModel; +import com.accenture.codingtest.springbootcodingtest.model.JwtResponseModel; +import com.accenture.codingtest.springbootcodingtest.model.TaskModel; +import com.accenture.codingtest.springbootcodingtest.service.GroupUserDetailsService; + +@RestController +public class JwtController { + + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private GroupUserDetailsService groupUserDetailsService; + + @Autowired + private AuthenticationManager authenticationManager; + + @PostMapping(value = "/Token/GenerateToken") + public ResponseEntity GenerateToken(@RequestBody JwtRequestModel jwtRequestM) throws Exception { + try { + + this.authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(jwtRequestM.getUsername(), jwtRequestM.getPassword())); + + }catch(UsernameNotFoundException e) + { + e.printStackTrace(); + throw new Exception("Bad Credentials"); + } + //fine area + UserDetails userDetails = this.groupUserDetailsService.loadUserByUsername(jwtRequestM.getUsername()); + + String token = jwtUtil.generateToken(jwtRequestM.getUsername()); + System.out.println(token); + + + return ResponseEntity.ok( new JwtResponseModel(token)); + // } + + + } + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/ProjectController.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/ProjectController.java new file mode 100644 index 0000000..e001d51 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/ProjectController.java @@ -0,0 +1,76 @@ +package com.accenture.codingtest.springbootcodingtest.controller; + +import java.util.List; +import java.util.UUID; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.annotation.Secured; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +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.RestController; + +import com.accenture.codingtest.springbootcodingtest.model.ProjectModel; +import com.accenture.codingtest.springbootcodingtest.service.ProjectService; + +@RestController +@RequestMapping("/v1") +@SuppressWarnings("rawtypes") +public class ProjectController { + + @Autowired + ProjectService projectService; + + + @PostMapping(value = "/Project/Project") + @PreAuthorize("hasAuthority('ROLE_PRODUCT_OWNER')") + @Secured("ROLE_PRODUCT_OWNER") + public ResponseEntity project(@RequestBody ProjectModel projectModel) throws Exception { + ProjectModel projectModel1 = projectService.project(projectModel); + return new ResponseEntity<>(projectModel1, HttpStatus.CREATED); + } + + @PutMapping(value = "/Project/updateProjectIdempotent") + @PreAuthorize("hasAuthority('ROLE_PRODUCT_OWNER')") + @Secured("ROLE_PRODUCT_OWNER") + public ResponseEntity updateProjectIdempotent(@PathVariable UUID id) throws Exception{ + ProjectModel projectModel = projectService.getProjectById(id); + return new ResponseEntity<>(projectService.updateProjectIdempotent(projectModel), HttpStatus.OK); + } + + @PatchMapping(value = "/Project/updateProject") + @PreAuthorize("hasAuthority('ROLE_PRODUCT_OWNER')") + @Secured("ROLE_PRODUCT_OWNER") + public ResponseEntity updateProjects (@PathVariable UUID id) throws Exception{ + ProjectModel projectModel = projectService.getProjectById(id); + return new ResponseEntity<>(projectService.updateProjects(projectModel,null), HttpStatus.OK); + } + + @DeleteMapping(value = "/Project/DeleteProject") + public ResponseEntity deleteProjectById (@PathVariable UUID id) throws Exception{ + return new ResponseEntity<>(projectService.deleteProjectById(id), HttpStatus.OK); + } + + @GetMapping(value = "/Project/GetProjectById") + public ResponseEntity getProjectById (@PathVariable UUID id) throws Exception{ + return new ResponseEntity<>(projectService.getProjectById(id), HttpStatus.OK); + } + + @GetMapping(value = "/Project/GetAllProjects") + public ResponseEntity> getAllProjects () throws Exception{ + return new ResponseEntity<>(projectService.getAllProjects(), HttpStatus.OK); + } + + + +} + + diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/TaskController.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/TaskController.java new file mode 100644 index 0000000..0b88e5d --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/TaskController.java @@ -0,0 +1,68 @@ +package com.accenture.codingtest.springbootcodingtest.controller; + +import java.util.List; +import java.util.UUID; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.annotation.Secured; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +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.RestController; + +import com.accenture.codingtest.springbootcodingtest.model.TaskModel; +import com.accenture.codingtest.springbootcodingtest.service.TaskService; + +@RestController +@RequestMapping("/v1") +@SuppressWarnings("rawtypes") +public class TaskController { + + @Autowired + TaskService taskService; + + + @PostMapping(value = "/Task/Task") + @PreAuthorize("hasAuthority('ROLE_PRODUCT_OWNER')") + @Secured("ROLE_PRODUCT_OWNER") + public ResponseEntity task(@RequestBody TaskModel taskModel) throws Exception { + TaskModel taskModel1 = taskService.task(taskModel); + return new ResponseEntity<>(taskModel1, HttpStatus.CREATED); + } + + @PutMapping(value = "/Task/updateTaskIdempotent") + public ResponseEntity updateTaskIdempotent(@PathVariable UUID id) throws Exception{ + TaskModel taskModel = taskService.getTaskById(id); + return new ResponseEntity<>(taskService.updateTaskIdempotent(taskModel), HttpStatus.OK); + } + + @PatchMapping(value = "/Task/updateTask") + public ResponseEntity updateTask (@PathVariable UUID id) throws Exception{ + TaskModel taskModel = taskService.getTaskById(id); + return new ResponseEntity<>(taskService.updateTask(taskModel,null), HttpStatus.OK); + } + + @DeleteMapping(value = "/Task/DeleteTask") + public ResponseEntity deleteTaskById (@PathVariable UUID id) throws Exception{ + return new ResponseEntity<>(taskService.deleteTaskById(id), HttpStatus.OK); + } + + @GetMapping(value = "/Task/GetTaskById") + public ResponseEntity getTaskById (@PathVariable UUID id) throws Exception{ + return new ResponseEntity<>(taskService.getTaskById(id), HttpStatus.OK); + } + + @GetMapping(value = "/Task/GetAllTasks") + public ResponseEntity> getAllTasks () throws Exception{ + return new ResponseEntity<>(taskService.getAllTasks(), HttpStatus.OK); + } + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/TaskStatusController.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/TaskStatusController.java new file mode 100644 index 0000000..2834fc5 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/TaskStatusController.java @@ -0,0 +1,46 @@ +package com.accenture.codingtest.springbootcodingtest.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.annotation.Secured; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + + +import com.accenture.codingtest.springbootcodingtest.model.TaskStatusModel; +import com.accenture.codingtest.springbootcodingtest.service.TaskStatusService; + +@RestController +@RequestMapping("/v1") +@SuppressWarnings("rawtypes") +public class TaskStatusController { + + @Autowired + TaskStatusService taskStatusService; + + @PostMapping(value = "/TaskStatus/AddTaskStatus") + @PreAuthorize("hasAuthority('ROLE_PRODUCT_OWNER')") + @Secured("ROLE_PRODUCT_OWNER") + public ResponseEntity addTaskStatus(@RequestBody TaskStatusModel taskStatusModel) throws Exception { + String respon = taskStatusService.addTaskStatus(taskStatusModel); + return new ResponseEntity<>(respon, HttpStatus.CREATED); + } + + @PostMapping(value = "/TaskStatus/deleteTaskStatus") + public ResponseEntity deleteTaskStatus(@PathVariable String taskStatus) throws Exception { + String respon = taskStatusService.deleteTaskStatus(taskStatus); + return new ResponseEntity<>(respon, HttpStatus.OK); + } + + @PostMapping(value = "/TaskStatus/getAllTaskStatus") + public ResponseEntity> getAllTaskStatus () throws Exception { + return new ResponseEntity<>(taskStatusService.getTasks(), HttpStatus.OK); + } +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/UserController.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/UserController.java new file mode 100644 index 0000000..212b3a0 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/UserController.java @@ -0,0 +1,96 @@ +package com.accenture.codingtest.springbootcodingtest.controller; + +import java.security.Principal; +import java.util.List; +import java.util.UUID; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.annotation.Secured; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +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.RestController; + +import com.accenture.codingtest.springbootcodingtest.model.UserModel; +import com.accenture.codingtest.springbootcodingtest.service.UserService; + + + +@RestController +@RequestMapping("/v1") +@SuppressWarnings("rawtypes") +public class UserController { + + @Autowired + UserService userService; + + + + @PostMapping(value = "/User/User") + // @PreAuthorize("hasAuthority('ROLE_ADMIN')") + // @Secured("ROLE_ADMIN") + public ResponseEntityuser(@RequestBody UserModel userModel) throws Exception { + UserModel userModel1 = userService.user(userModel); + return new ResponseEntity<>(userModel1, HttpStatus.CREATED); + } + + + @GetMapping(value = "/User/Access/{userId}/{userRole}") + // @PreAuthorize("hasAuthority('ROLE_ADMIN')") + // @Secured("ROLE_ADMIN") + public ResponseEntity giveaccessToUser(@PathVariable UUID id, @PathVariable String UserRole, Principal principal) throws Exception{ + return new ResponseEntity<>(userService.giveaccessToUser(id, UserRole, principal), HttpStatus.OK); + } + + @PutMapping(value = "/User/updateUserIdempotent") + @PreAuthorize("hasAuthority('ROLE_ADMIN')") + @Secured("ROLE_ADMIN") + public ResponseEntity updateUserIdempotent(@PathVariable UUID id) throws Exception{ + UserModel userModel = userService.getUserById(id); + return new ResponseEntity<>(userService.updateUserIdempotent(userModel), HttpStatus.OK); + } + + @PatchMapping(value = "/User/updateUser") + @PreAuthorize("hasAuthority('ROLE_ADMIN')") + @Secured("ROLE_ADMIN") + public ResponseEntity updateUser (@PathVariable UUID id) throws Exception{ + UserModel userModel = userService.getUserById(id); + return new ResponseEntity<>(userService.updateUser(userModel,null), HttpStatus.OK); + } + + @DeleteMapping(value = "/User/DeleteUser") + @PreAuthorize("hasAuthority('ROLE_ADMIN')") + @Secured("ROLE_ADMIN") + public ResponseEntity deleteUserById (@PathVariable UUID id) throws Exception{ + return new ResponseEntity<>(userService.deleteUserById(id), HttpStatus.OK); + } + + @GetMapping(value = "/User/GetUserById") + @PreAuthorize("hasAuthority('ROLE_ADMIN')") + @Secured("ROLE_ADMIN") + public ResponseEntity getProjectById (@PathVariable UUID id) throws Exception{ + return new ResponseEntity<>(userService.getUserById(id), HttpStatus.OK); + } + + @GetMapping(value = "/User/GetAllUsers") + // @PreAuthorize("hasAuthority('ROLE_ADMIN')") + // @Secured("ROLE_ADMIN") + public ResponseEntity> getAllUsers () throws Exception{ + return new ResponseEntity<>(userService.getAllUsers(), HttpStatus.OK); + } + + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/package-info.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/package-info.java index e69de29..8b2177b 100644 --- a/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/package-info.java +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/package-info.java @@ -0,0 +1 @@ +package com.accenture.codingtest.springbootcodingtest.controller; \ No newline at end of file diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/Project.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/Project.java new file mode 100644 index 0000000..66c8d09 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/Project.java @@ -0,0 +1,35 @@ +package com.accenture.codingtest.springbootcodingtest.entity; + +import java.io.Serializable; +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Entity +public class Project implements Serializable{ + + + + /** + * + */ + private static final long serialVersionUID = -6476940302896158570L; + + @Id + @Column(name = "id") + private UUID id; + + @Column(name = "name", unique = true) + private String name; + + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/Role.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/Role.java new file mode 100644 index 0000000..466a8b6 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/Role.java @@ -0,0 +1,35 @@ +package com.accenture.codingtest.springbootcodingtest.entity; + +import java.io.Serializable; +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Id; + + + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Role implements Serializable{ + + + + /** + * + */ + private static final long serialVersionUID = 1898433577523417600L; + + @Id + @Column(name = "id") + private UUID id; + + @Column(name = "username") + private String username; + + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/Task.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/Task.java new file mode 100644 index 0000000..aed739f --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/Task.java @@ -0,0 +1,46 @@ +package com.accenture.codingtest.springbootcodingtest.entity; + +import java.io.Serializable; +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Entity +public class Task implements Serializable{ + + + + /** + * + */ + private static final long serialVersionUID = 8861012910247808543L; + + @Id + @Column(name = "id") + private UUID id; + + @Column(name = "title") + private String title; + + @Column(name = "description") + private String description; + + @Column(name = "status") + private String status; + + @Column(name = "project_id") + private UUID project_id; + + @Column(name = "user_id") + private UUID user_id; + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/TaskStatusMD.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/TaskStatusMD.java new file mode 100644 index 0000000..b920ea4 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/TaskStatusMD.java @@ -0,0 +1,33 @@ +package com.accenture.codingtest.springbootcodingtest.entity; + +import java.io.Serializable; +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Entity +public class TaskStatusMD implements Serializable{ + + /** + * + */ + private static final long serialVersionUID = -6328607138767139580L; + @Id + @Column(name = "sid") + private int sid; + + @Column(name = "status") + private String status; + + + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/User.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/User.java new file mode 100644 index 0000000..a0d83cf --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/User.java @@ -0,0 +1,45 @@ +package com.accenture.codingtest.springbootcodingtest.entity; + +import java.io.Serializable; +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Entity +public class User implements Serializable { + + + + /** + * + */ + private static final long serialVersionUID = 2716137732048439160L; + + @Id + @Column(name = "id") + private UUID id; + + @Column(name = "username" ,unique = true) + private String username; + + @Column(name = "password") + private String password; + + @Column(name = "isActive") + private Boolean isActive; + + @Column(name = "role") + private String role; + + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/filter/JwtUtil.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/filter/JwtUtil.java new file mode 100644 index 0000000..32cfad2 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/filter/JwtUtil.java @@ -0,0 +1,91 @@ +package com.accenture.codingtest.springbootcodingtest.filter; + + +import org.springframework.stereotype.Component; + + +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.PropertySource; + + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; + + +@PropertySource(value = {"classpath:application.properties"}) +@Component +public class JwtUtil implements Serializable{ + + + /** + * + */ + private static final long serialVersionUID = -8325036297193567264L; + + + + + @Value("${jwt.secret}") + private String secret; + + @Value("${jwt.expiry.hour}") + private int expiryHour; + + // retrieve username from jwt token + public String getUsernameFromToken(String token) { + return getClaimFromToken(token, Claims::getSubject); + } + + // retrieve expiration date from jwt token + public Date getExpirationDateFromToken(String token) { + return getClaimFromToken(token, Claims::getExpiration); + } + + public T getClaimFromToken(String token, Function claimsResolver) { + final Claims claims = getAllClaimsFromToken(token); + return claimsResolver.apply(claims); + } + + // for retrieveing any information from token we will need the secret key + private Claims getAllClaimsFromToken(String token) { + return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); + } + + // check if the token has expired + private Boolean isTokenExpired(String token) { + final Date expiration = getExpirationDateFromToken(token); + return expiration.before(new Date()); + } + + // generate token for user + public String generateToken(String username) { + Map claims = new HashMap<>(); + return doGenerateToken(claims, username); + } + + // while creating the token - + // 1. Define claims of the token, like Issuer, Expiration, Subject, and the ID + // 2. Sign the JWT using the HS512 algorithm and secret key. + // 3. According to JWS Compact + // Serialization(https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41#section-3.1) + // compaction of the JWT to a URL-safe string + private String doGenerateToken(Map claims, String subject) { + return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis())) + .setExpiration(new Date(System.currentTimeMillis() + (expiryHour * 60 * 60 * 1000))) + .signWith(SignatureAlgorithm.HS512, secret).compact(); + } + + // validate token + public Boolean isValidToken(String token, String api) { + final String usernameToken = getUsernameFromToken(token); + return !isTokenExpired(token); + } + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/model/JwtRequestModel.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/model/JwtRequestModel.java new file mode 100644 index 0000000..acdc79a --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/model/JwtRequestModel.java @@ -0,0 +1,43 @@ +package com.accenture.codingtest.springbootcodingtest.model; + +public class JwtRequestModel { + + String username; + + String password; + + public JwtRequestModel() { + super(); + // TODO Auto-generated constructor stub + } + + public JwtRequestModel(String username, String password) { + super(); + this.username = username; + this.password = password; + } + + @Override + public String toString() { + return "JwtRequestModel [username=" + username + ", password=" + password + "]"; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/model/JwtResponseModel.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/model/JwtResponseModel.java new file mode 100644 index 0000000..bb6ee1d --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/model/JwtResponseModel.java @@ -0,0 +1,32 @@ +package com.accenture.codingtest.springbootcodingtest.model; + +public class JwtResponseModel { + + String token; + + public JwtResponseModel() { + super(); + // TODO Auto-generated constructor stub + } + + public JwtResponseModel(String token) { + super(); + this.token = token; + } + + @Override + public String toString() { + return "JwtResponseModel [token=" + token + "]"; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/model/ProjectModel.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/model/ProjectModel.java new file mode 100644 index 0000000..18a044a --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/model/ProjectModel.java @@ -0,0 +1,27 @@ +package com.accenture.codingtest.springbootcodingtest.model; + +import java.io.Serializable; +import java.util.UUID; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ProjectModel implements Serializable { + + + + /** + * + */ + private static final long serialVersionUID = 1560371548692436354L; + + private UUID id; + + private String name; + + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/model/RoleModel.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/model/RoleModel.java new file mode 100644 index 0000000..2d4f1de --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/model/RoleModel.java @@ -0,0 +1,28 @@ +package com.accenture.codingtest.springbootcodingtest.model; + +import java.io.Serializable; +import java.util.UUID; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class RoleModel implements Serializable{ + + + + /** + * + */ + private static final long serialVersionUID = 1322907224617771740L; + + private UUID id; + + private String username; + + + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/model/TaskModel.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/model/TaskModel.java new file mode 100644 index 0000000..09118c9 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/model/TaskModel.java @@ -0,0 +1,35 @@ +package com.accenture.codingtest.springbootcodingtest.model; + +import java.io.Serializable; +import java.util.UUID; + + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class TaskModel implements Serializable{ + + + + /** + * + */ + private static final long serialVersionUID = 4352086038378546132L; + + private UUID id; + + private String title; + + private String description; + + private String status; + + private UUID project_id; + + private UUID user_id; + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/model/TaskStatusModel.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/model/TaskStatusModel.java new file mode 100644 index 0000000..744f3de --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/model/TaskStatusModel.java @@ -0,0 +1,24 @@ +package com.accenture.codingtest.springbootcodingtest.model; + +import java.io.Serializable; +import java.util.UUID; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class TaskStatusModel implements Serializable{ + + + /** + * + */ + private static final long serialVersionUID = 3754540549554061689L; + + private int sid; + private String status; + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/model/UserModel.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/model/UserModel.java new file mode 100644 index 0000000..b5af0e8 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/model/UserModel.java @@ -0,0 +1,36 @@ +package com.accenture.codingtest.springbootcodingtest.model; + +import java.io.Serializable; +import java.util.UUID; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UserModel implements Serializable{ + + /** + * + */ + private static final long serialVersionUID = 1185129676552210354L; + + private UUID id; + + private String username; + + private String password; + + private Boolean isActive; + + private String role; + + + + + + + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/ProjectRepo.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/ProjectRepo.java new file mode 100644 index 0000000..9e25342 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/ProjectRepo.java @@ -0,0 +1,11 @@ +package com.accenture.codingtest.springbootcodingtest.repository; + +import java.util.UUID; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.accenture.codingtest.springbootcodingtest.entity.Project; + +public interface ProjectRepo extends JpaRepository { + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/TaskRepo.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/TaskRepo.java new file mode 100644 index 0000000..9c496ab --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/TaskRepo.java @@ -0,0 +1,11 @@ +package com.accenture.codingtest.springbootcodingtest.repository; + +import java.util.UUID; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.accenture.codingtest.springbootcodingtest.entity.Task; + +public interface TaskRepo extends JpaRepository{ + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/TaskStatusRepo.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/TaskStatusRepo.java new file mode 100644 index 0000000..4bb5cb6 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/TaskStatusRepo.java @@ -0,0 +1,11 @@ +package com.accenture.codingtest.springbootcodingtest.repository; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.accenture.codingtest.springbootcodingtest.entity.TaskStatusMD; + +public interface TaskStatusRepo extends JpaRepository{ + + public void deleteByStatus(String taskStatus); + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/UserRepo.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/UserRepo.java new file mode 100644 index 0000000..8496b2d --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/UserRepo.java @@ -0,0 +1,14 @@ +package com.accenture.codingtest.springbootcodingtest.repository; + +import java.util.Optional; +import java.util.UUID; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.accenture.codingtest.springbootcodingtest.entity.User; + +public interface UserRepo extends JpaRepository { + + Optional findByUsername(String username); + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/service/GroupUserDetails.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/GroupUserDetails.java new file mode 100644 index 0000000..f8689fa --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/GroupUserDetails.java @@ -0,0 +1,84 @@ +package com.accenture.codingtest.springbootcodingtest.service; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Service; + +import com.accenture.codingtest.springbootcodingtest.entity.User; +import com.accenture.codingtest.springbootcodingtest.model.UserModel; + + +public class GroupUserDetails implements UserDetails { + + /** + * + */ + private static final long serialVersionUID = 751053069909157468L; + + private String username; + private String password; + private Boolean isActive; + private List authorities; + + public GroupUserDetails(User userM) + { + this.username = userM.getUsername(); + this.password = userM.getPassword(); + this.isActive = userM.getIsActive(); + + + this.authorities = Arrays.stream(userM.getRole().split(",")) + .map(SimpleGrantedAuthority ::new).collect(Collectors.toList()); + + + + } + @Override + public Collection getAuthorities() { + // TODO Auto-generated method stub + return authorities; + } + + @Override + public String getPassword() { + // TODO Auto-generated method stub + return password; + } + + @Override + public String getUsername() { + // TODO Auto-generated method stub + return username; + } + + @Override + public boolean isAccountNonExpired() { + // TODO Auto-generated method stub + return true; + } + + @Override + public boolean isAccountNonLocked() { + // TODO Auto-generated method stub + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + // TODO Auto-generated method stub + return true; + } + + @Override + public boolean isEnabled() { + // TODO Auto-generated method stub + return isActive; + } + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/service/GroupUserDetailsService.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/GroupUserDetailsService.java new file mode 100644 index 0000000..86b49a5 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/GroupUserDetailsService.java @@ -0,0 +1,32 @@ +package com.accenture.codingtest.springbootcodingtest.service; + +import java.util.Optional; + +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import com.accenture.codingtest.springbootcodingtest.entity.User; +import com.accenture.codingtest.springbootcodingtest.model.UserModel; +import com.accenture.codingtest.springbootcodingtest.repository.UserRepo; + +@Service +public class GroupUserDetailsService implements UserDetailsService{ + + @Autowired + UserRepo userRepo; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + Optional userD = userRepo.findByUsername(username); + Optional userM = null ; + BeanUtils.copyProperties(userD, userM); + return userD.map(GroupUserDetails :: new) + .orElseThrow(()-> new UsernameNotFoundException(username +"User Doesnt Exist")); + } + +} + \ No newline at end of file diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/service/ProjectService.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/ProjectService.java new file mode 100644 index 0000000..3edd2e2 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/ProjectService.java @@ -0,0 +1,23 @@ +package com.accenture.codingtest.springbootcodingtest.service; + +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import com.accenture.codingtest.springbootcodingtest.model.ProjectModel; + +public interface ProjectService { + + public ProjectModel project (ProjectModel projetModel)throws Exception; + + public String updateProjectIdempotent (ProjectModel projectModel)throws Exception; + + public String updateProjects(ProjectModel projectModel, Map updates) throws Exception; + + public String deleteProjectById (UUID id)throws Exception; + + public ProjectModel getProjectById (UUID id)throws Exception; + + public List getAllProjects ()throws Exception; + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/service/ProjectServiceImpl.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/ProjectServiceImpl.java new file mode 100644 index 0000000..475cce1 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/ProjectServiceImpl.java @@ -0,0 +1,119 @@ +package com.accenture.codingtest.springbootcodingtest.service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.web.server.ResponseStatusException; + +import com.accenture.codingtest.springbootcodingtest.entity.Project; +import com.accenture.codingtest.springbootcodingtest.model.ProjectModel; +import com.accenture.codingtest.springbootcodingtest.repository.ProjectRepo; +import com.accenture.codingtest.springbootcodingtest.utils.IDGenerate; +import com.fasterxml.jackson.databind.ObjectMapper; + + +@Service +public class ProjectServiceImpl implements ProjectService { + + @Autowired + ProjectRepo projectRepo; + + @Autowired + IDGenerate idGenerate; + + + @Override + public ProjectModel project(ProjectModel projetModel) throws Exception { + Project projectDomain = new Project(); + UUID id = idGenerate.GenerateId(); + projetModel.setId(id); + BeanUtils.copyProperties(projetModel, projectDomain); + projectRepo.save(projectDomain); + return projetModel; + } + + @Override + public String updateProjectIdempotent(ProjectModel projectModel) throws Exception { + Project projectDomain = new Project(); + BeanUtils.copyProperties(projectModel, projectDomain); + if(projectRepo.existsById(projectModel.getId())) + { + projectRepo.save(projectDomain); + } + else + { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Project not found"); + } + return "Project Updated Successfully"; + } + + @Override + public String updateProjects(ProjectModel projectModel, Map updates) throws Exception { + Project projectDomain = new Project(); + projectDomain = projectRepo.getById(projectModel.getId()); + if(projectDomain ==null) + { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Project not found"); + } + ObjectMapper objectMapper = new ObjectMapper(); + ProjectModel projectM = objectMapper.convertValue(updates, ProjectModel.class); + + if(projectM.getName()!=null) + { + projectDomain.setName(projectM.getName()); + } + projectRepo.save(projectDomain); + return "Project Updated Successfully"; + } + + @Override + public String deleteProjectById(UUID id) throws Exception { + if(projectRepo.existsById(id)) + { + projectRepo.deleteById(id); + } + else + { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Project not found"); + } + return "Project Deleted Successfully"; + } + + @Override + public ProjectModel getProjectById(UUID id) throws Exception { + ProjectModel projectModel = new ProjectModel(); + Project projectDomain = new Project(); + if(id==null) + { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Project_id is Null"); + } + else + { + projectDomain = projectRepo.getById(id); + BeanUtils.copyProperties(projectDomain, projectModel); + } + return projectModel; + } + + @Override + public List getAllProjects() throws Exception { + List projectModel = new ArrayList(); + List projectDomain = new ArrayList(); + projectDomain = projectRepo.findAll(); + for(Project projectD : projectDomain) + { + ProjectModel projectM = new ProjectModel(); + BeanUtils.copyProperties(projectD, projectM); + projectModel.add(projectM); + } + + return projectModel; + } + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/service/TaskService.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/TaskService.java new file mode 100644 index 0000000..ae443ad --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/TaskService.java @@ -0,0 +1,23 @@ +package com.accenture.codingtest.springbootcodingtest.service; + +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import com.accenture.codingtest.springbootcodingtest.model.TaskModel; + +public interface TaskService { + + public TaskModel task (TaskModel taskModel)throws Exception; + + public String updateTaskIdempotent (TaskModel taskModel)throws Exception; + + public String updateTask(TaskModel taskModel, Map updates) throws Exception; + + public String deleteTaskById (UUID id)throws Exception; + + public TaskModel getTaskById (UUID id)throws Exception; + + public List getAllTasks ()throws Exception; + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/service/TaskServiceImpl.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/TaskServiceImpl.java new file mode 100644 index 0000000..955ab18 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/TaskServiceImpl.java @@ -0,0 +1,142 @@ +package com.accenture.codingtest.springbootcodingtest.service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.web.server.ResponseStatusException; + +import com.accenture.codingtest.springbootcodingtest.constant.TaskStatus; +import com.accenture.codingtest.springbootcodingtest.entity.Task; +import com.accenture.codingtest.springbootcodingtest.model.TaskModel; +import com.accenture.codingtest.springbootcodingtest.repository.TaskRepo; +import com.accenture.codingtest.springbootcodingtest.utils.IDGenerate; +import com.fasterxml.jackson.databind.ObjectMapper; + +@Service +public class TaskServiceImpl implements TaskService{ + + @Autowired + TaskRepo taskRepo; + + @Autowired + IDGenerate idGenerate; + + @Override + public TaskModel task(TaskModel taskModel) throws Exception { + Task taskDomain = new Task(); + UUID id = idGenerate.GenerateId(); + taskModel.setId(id); + taskModel.setStatus(TaskStatus.NOT_STARTED); + BeanUtils.copyProperties(taskModel, taskDomain); + taskRepo.save(taskDomain); + return taskModel; + } + + @Override + public String updateTaskIdempotent(TaskModel taskModel) throws Exception { + Task taskDomain = new Task(); + BeanUtils.copyProperties(taskModel, taskDomain); + if(taskRepo.existsById(taskModel.getId())) + { + taskRepo.save(taskDomain); + } + else + { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Task not found"); + } + return "Task Updated Successfully"; + } + + + @Override + public String updateTask(TaskModel taskModel, Map updates) throws Exception { + Task taskDomain = new Task(); + taskDomain = taskRepo.getById(taskModel.getId()); + if(taskDomain ==null) + { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Task not found"); + } + ObjectMapper objectMapper = new ObjectMapper(); + TaskModel taskM = objectMapper.convertValue(updates, TaskModel.class); + + if(taskM.getDescription()!=null) + { + taskDomain.setDescription(taskM.getDescription()); + + } + if(taskM.getTitle()!=null) + { + taskDomain.setTitle(taskM.getTitle()); + + } + if(taskM.getStatus()!=null) + { + taskDomain.setStatus(taskM.getStatus()); + + } + if(taskM.getProject_id()!=null) + { + taskDomain.setProject_id(taskM.getProject_id()); + + } + if(taskM.getUser_id()!=null) + { + taskDomain.setUser_id(taskM.getUser_id()); + + } + taskRepo.save(taskDomain); + return "Task Updated Successfully"; +} + @Override + public String deleteTaskById(UUID id) throws Exception { + if(taskRepo.existsById(id)) + { + taskRepo.deleteById(id); + } + else + { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Task not found"); + } + return "Task Deleted Successfully"; + } + + @Override + public TaskModel getTaskById(UUID id) throws Exception { + TaskModel taskModel = new TaskModel(); + Task taskDomain = new Task(); + if(id==null) + { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Task_id is Null"); + } + else + { + taskDomain = taskRepo.getById(id); + BeanUtils.copyProperties(taskDomain, taskModel); + } + return taskModel; + } + + @Override + public List getAllTasks() throws Exception { + List taskModel = new ArrayList(); + List taskDomain = new ArrayList(); + taskDomain = taskRepo.findAll(); + for(Task taskD : taskDomain) + { + TaskModel taskM = new TaskModel(); + BeanUtils.copyProperties(taskD, taskM); + taskModel.add(taskM); + } + + return taskModel; + } + + + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/service/TaskStatusService.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/TaskStatusService.java new file mode 100644 index 0000000..590879d --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/TaskStatusService.java @@ -0,0 +1,15 @@ +package com.accenture.codingtest.springbootcodingtest.service; + +import java.util.List; + +import com.accenture.codingtest.springbootcodingtest.model.TaskStatusModel; + +public interface TaskStatusService { + + public String addTaskStatus (TaskStatusModel taskModel)throws Exception; + + public String deleteTaskStatus (String taskStatus) throws Exception; + + public List getTasks ()throws Exception; + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/service/TaskStatusServiceImpl.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/TaskStatusServiceImpl.java new file mode 100644 index 0000000..d5afd32 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/TaskStatusServiceImpl.java @@ -0,0 +1,45 @@ +package com.accenture.codingtest.springbootcodingtest.service; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.accenture.codingtest.springbootcodingtest.entity.TaskStatusMD; +import com.accenture.codingtest.springbootcodingtest.model.TaskStatusModel; +import com.accenture.codingtest.springbootcodingtest.repository.TaskStatusRepo; + +@Service +class TaskStatusServiceImpl implements TaskStatusService{ + + @Autowired + TaskStatusRepo taskStatusRepo; + + @Override + public String addTaskStatus(TaskStatusModel taskStatusModel) throws Exception { + TaskStatusMD taskStatusDomain = new TaskStatusMD(); + BeanUtils.copyProperties(taskStatusModel, taskStatusDomain); + taskStatusRepo.save(taskStatusDomain); + return "Task Status Added Successfully"; + } + + @Override + public String deleteTaskStatus(String taskStatus) throws Exception { + taskStatusRepo.deleteByStatus(taskStatus); + return "Task Status Deleted Successfully"; + } + + @Override + public List getTasks() throws Exception { + List taskStatusDomain = new ArrayList<>(); + List taskStatusModel = new ArrayList(); + taskStatusDomain = taskStatusRepo.findAll(); + BeanUtils.copyProperties(taskStatusDomain, taskStatusModel); + return taskStatusModel; + } + + + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/service/UserService.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/UserService.java new file mode 100644 index 0000000..6d9730e --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/UserService.java @@ -0,0 +1,30 @@ +package com.accenture.codingtest.springbootcodingtest.service; + +import java.security.Principal; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.springframework.web.bind.annotation.PathVariable; + +import com.accenture.codingtest.springbootcodingtest.model.UserModel; + +public interface UserService { + + public UserModel user (UserModel UserModel)throws Exception; + + public String giveaccessToUser(@PathVariable UUID id, @PathVariable String UserRole, Principal principal)throws Exception; + + public String updateUserIdempotent (UserModel UserModel)throws Exception; + + public String updateUser(UserModel UserModel, Map updates) throws Exception; + + public String deleteUserById (UUID id)throws Exception; + + public UserModel getUserById (UUID id)throws Exception; + + public List getAllUsers ()throws Exception; + + + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/service/UserServiceImpl.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/UserServiceImpl.java new file mode 100644 index 0000000..537d51b --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/UserServiceImpl.java @@ -0,0 +1,183 @@ +package com.accenture.codingtest.springbootcodingtest.service; + +import java.security.Principal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; + +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.server.ResponseStatusException; +import org.mindrot.jbcrypt.BCrypt; + +import com.accenture.codingtest.springbootcodingtest.constant.RoleConstants; +import com.accenture.codingtest.springbootcodingtest.entity.User; +import com.accenture.codingtest.springbootcodingtest.model.UserModel; +import com.accenture.codingtest.springbootcodingtest.repository.UserRepo; +import com.accenture.codingtest.springbootcodingtest.utils.IDGenerate; +import com.fasterxml.jackson.databind.ObjectMapper; + +@Service +public class UserServiceImpl implements UserService { + + @Autowired + UserRepo userRepo; + + @Autowired + IDGenerate idGenerate; + + + + @Override + public UserModel user(UserModel userModel) throws Exception { + User userDomain = new User(); + UUID id = idGenerate.GenerateId(); + userModel.setId(id); + String hashpassword = encode(userModel.getPassword()); + userModel.setPassword(hashpassword); + userModel.setIsActive(true); + userModel.setRole(RoleConstants.DEFAULT_ROLE); + BeanUtils.copyProperties(userModel, userDomain); + userRepo.save(userDomain); + return userModel; + } + + public static String encode(String password) { + String salt = BCrypt.gensalt(); + return BCrypt.hashpw(password, salt); + } + + @Override + public String giveaccessToUser(@PathVariable UUID id, @PathVariable String UserRole, Principal principal) { + UserModel userModel = new UserModel(); + User userDomain = userRepo.getById(id); + BeanUtils.copyProperties(userDomain, userModel); + List activeRoles = getRolesByLoggedInUser(principal); + String newRole = ""; + if(activeRoles.contains(UserRole)) { + newRole = userModel.getRole() +","+UserRole; + userModel.setRole(newRole); + } + User userD = new User(); + BeanUtils.copyProperties(userModel, userD); + userRepo.save(userD); + return "New Role has been assigned to "+userModel.getUsername()+" by "+principal.getName(); + } + + private List getRolesByLoggedInUser(Principal principal){ + + String roles = getLoggedInUser(principal).getRole(); + List assignRoles = Arrays.stream(roles.split(",")).collect(Collectors.toList()); + if(assignRoles.contains("ROLE_ADMIN")) { + return Arrays.stream(RoleConstants.ADMIN_ACCESS).collect(Collectors.toList()); + } + if(assignRoles.contains("ROLE_PRODUCT_OWNER")) { + return Arrays.stream(RoleConstants.PRODUCT_OWNER_ACCESS).collect(Collectors.toList()); + } + return Collections.emptyList(); + } + + private UserModel getLoggedInUser(Principal principal) { + UserModel userM = new UserModel(); + User userD = userRepo.findByUsername(principal.getName()).get(); + BeanUtils.copyProperties(userD, userM); + return userM; + } + + + + @Override + public String updateUserIdempotent(UserModel userModel) throws Exception { + User userDomain = new User(); + String hashpassword = encode(userModel.getPassword()); + userModel.setPassword(hashpassword); + BeanUtils.copyProperties(userModel, userDomain); + if(userRepo.existsById(userModel.getId())) + { + userRepo.save(userDomain); + } + else + { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "User not found"); + } + return "User Updated Successfully"; + } + + @Override + public String updateUser(UserModel userModel, Map updates) throws Exception { + User userDomain = new User(); + String hashpassword = encode(userModel.getPassword()); + userModel.setPassword(hashpassword); + userDomain = userRepo.getById(userModel.getId()); + if(userDomain ==null) + { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "User not found"); + } + ObjectMapper objectMapper = new ObjectMapper(); + UserModel userM = objectMapper.convertValue(updates, UserModel.class); + + + if(userM.getUsername()!=null) + { + userDomain.setUsername(userM.getUsername()); + } + + userRepo.save(userDomain); + return "User Updated Successfully"; + } + + @Override + public String deleteUserById(UUID id) throws Exception { + if(userRepo.existsById(id)) + { + userRepo.deleteById(id); + } + else + { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "User not found"); + } + return "User Deleted Successfully"; + } + + @Override + public UserModel getUserById(UUID id) throws Exception { + UserModel userModel = new UserModel(); + User userDomain = new User(); + if(id==null) + { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "User_id is Null"); + } + else + { + userDomain = userRepo.getById(id); + BeanUtils.copyProperties(userDomain, userModel); + } + + return userModel; + } + @Override + public List getAllUsers() throws Exception { + List userModel = new ArrayList(); + List userDomain = new ArrayList(); + userDomain = userRepo.findAll(); + for(User userD : userDomain) + { + UserModel userM = new UserModel(); + BeanUtils.copyProperties(userD, userM); + userModel.add(userM); + } + + return userModel; + } + + +} + diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/utils/IDGenerate.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/utils/IDGenerate.java new file mode 100644 index 0000000..2127eff --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/utils/IDGenerate.java @@ -0,0 +1,18 @@ +package com.accenture.codingtest.springbootcodingtest.utils; + +import java.util.UUID; + +import org.springframework.stereotype.Component; + +@Component +public class IDGenerate +{ +//generates random UUID + + public UUID GenerateId() + { + UUID uuid=UUID.randomUUID(); + return uuid; + } +} + diff --git a/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 0000000..cf01318 --- /dev/null +++ b/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,5 @@ +{"properties": [{ + "name": "jwt.expiry.hour", + "type": "java.lang.String", + "description": "A description for 'jwt.expiry.hour'" +}]} \ No newline at end of file diff --git a/src/main/resources/application-local.properties b/src/main/resources/application-local.properties new file mode 100644 index 0000000..bd44c4b --- /dev/null +++ b/src/main/resources/application-local.properties @@ -0,0 +1,27 @@ +# + +spring.datasource.url=jdbc:mysql://localhost:3306/coding_test?createDatabaseIfNotExist=True&useSSL=false +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver +spring.datasource.username=root +spring.datasource.password=root +spring.datasource.initialize = true +server.port=8082 + +# HikariCP settings + +spring.datasource.hikari.connection-timeout=60000 +spring.datasource.hikari.maximum-pool-size=5 +server.port=8082 + + +spring.jpa.database-platform = org.hibernate.dialect.MySQL5Dialect +spring.jpa.generate-ddl=true +spring.jpa.hibernate.ddl-auto = update + +spring.mvc.pathmatch.matching-strategy = ANT_PATH_MATCHER + + +jwt.secret=jwtAccentureCodingSecret +jwt.expiry.hour=24 + + diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8b13789..4fdd7ad 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1 @@ - +spring.profiles.active=local