diff --git a/docs/spring_boot_coding_test.postman_collection.json b/docs/spring_boot_coding_test.postman_collection.json
new file mode 100644
index 0000000..4e64425
--- /dev/null
+++ b/docs/spring_boot_coding_test.postman_collection.json
@@ -0,0 +1,454 @@
+{
+ "info": {
+ "_postman_id": "88a0d749-6f0e-4000-abc9-4a87de218946",
+ "name": "spring_boot_coding_test",
+ "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
+ "_exporter_id": "27536794"
+ },
+ "item": [
+ {
+ "name": "Users",
+ "item": [
+ {
+ "name": "GetAllUsers",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "localhost:8080/api/v1/users",
+ "host": [
+ "localhost"
+ ],
+ "port": "8080",
+ "path": [
+ "api",
+ "v1",
+ "users"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "CreateUser",
+ "request": {
+ "auth": {
+ "type": "basic",
+ "basic": [
+ {
+ "key": "password",
+ "value": "29207796-400d-4653-a5ca-5e5b5f8f6540",
+ "type": "string"
+ },
+ {
+ "key": "username",
+ "value": "admin",
+ "type": "string"
+ }
+ ]
+ },
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\r\n \"username\": \"Ram\",\r\n \"password\": \"abcd\"\r\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://localhost:8080/api/v1/users",
+ "protocol": "http",
+ "host": [
+ "localhost"
+ ],
+ "port": "8080",
+ "path": [
+ "api",
+ "v1",
+ "users"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "UpdateUserById",
+ "request": {
+ "method": "PUT",
+ "header": [],
+ "url": {
+ "raw": "http://localhost:8080/api/v1/users/0f2f0a79-0640-4cca-8b07-e683c70e33fc",
+ "protocol": "http",
+ "host": [
+ "localhost"
+ ],
+ "port": "8080",
+ "path": [
+ "api",
+ "v1",
+ "users",
+ "0f2f0a79-0640-4cca-8b07-e683c70e33fc"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "FetchUserById",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "localhost:8080/api/v1/users/192a2472-9d91-4016-99fb-9b0882d916b3",
+ "host": [
+ "localhost"
+ ],
+ "port": "8080",
+ "path": [
+ "api",
+ "v1",
+ "users",
+ "192a2472-9d91-4016-99fb-9b0882d916b3"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "PatchUserById",
+ "request": {
+ "method": "PATCH",
+ "header": [],
+ "url": {
+ "raw": "localhost:8080/api/v1/users/192a2472-9d91-4016-99fb-9b0882d916b3",
+ "host": [
+ "localhost"
+ ],
+ "port": "8080",
+ "path": [
+ "api",
+ "v1",
+ "users",
+ "192a2472-9d91-4016-99fb-9b0882d916b3"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "DeleteUser",
+ "request": {
+ "method": "DELETE",
+ "header": [],
+ "url": {
+ "raw": "localhost:8080/api/v1/users/192a2472-9d91-4016-99fb-9b0882d916b3",
+ "host": [
+ "localhost"
+ ],
+ "port": "8080",
+ "path": [
+ "api",
+ "v1",
+ "users",
+ "192a2472-9d91-4016-99fb-9b0882d916b3"
+ ]
+ }
+ },
+ "response": []
+ }
+ ]
+ },
+ {
+ "name": "Projects",
+ "item": [
+ {
+ "name": "GetAllProjects",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "localhost:8080/api/v1/projects",
+ "host": [
+ "localhost"
+ ],
+ "port": "8080",
+ "path": [
+ "api",
+ "v1",
+ "projects"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "CreateProject",
+ "request": {
+ "auth": {
+ "type": "basic",
+ "basic": [
+ {
+ "key": "password",
+ "value": "0e9a0d44-f14c-4515-ba03-449b0223dcce",
+ "type": "string"
+ },
+ {
+ "key": "username",
+ "value": "product_owner",
+ "type": "string"
+ }
+ ]
+ },
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\r\n \"name\":\"Project1\"\r\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://localhost:8080/api/v1/projects",
+ "protocol": "http",
+ "host": [
+ "localhost"
+ ],
+ "port": "8080",
+ "path": [
+ "api",
+ "v1",
+ "projects"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "UpdateOrPatchProjectById",
+ "request": {
+ "method": "PUT",
+ "header": [],
+ "url": {
+ "raw": "http://localhost:8080/api/v1/projects/0f2f0a79-0640-4cca-8b07-e683c70e33fc",
+ "protocol": "http",
+ "host": [
+ "localhost"
+ ],
+ "port": "8080",
+ "path": [
+ "api",
+ "v1",
+ "projects",
+ "0f2f0a79-0640-4cca-8b07-e683c70e33fc"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "FetchProjectById",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "localhost:8080/api/v1/projects/192a2472-9d91-4016-99fb-9b0882d916b3",
+ "host": [
+ "localhost"
+ ],
+ "port": "8080",
+ "path": [
+ "api",
+ "v1",
+ "projects",
+ "192a2472-9d91-4016-99fb-9b0882d916b3"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "DeleteProject",
+ "request": {
+ "method": "DELETE",
+ "header": [],
+ "url": {
+ "raw": "localhost:8080/api/v1/projects/192a2472-9d91-4016-99fb-9b0882d916b3",
+ "host": [
+ "localhost"
+ ],
+ "port": "8080",
+ "path": [
+ "api",
+ "v1",
+ "projects",
+ "192a2472-9d91-4016-99fb-9b0882d916b3"
+ ]
+ }
+ },
+ "response": []
+ }
+ ]
+ },
+ {
+ "name": "Tasks",
+ "item": [
+ {
+ "name": "GetAllTasks",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "localhost:8080/api/v1/tasks",
+ "host": [
+ "localhost"
+ ],
+ "port": "8080",
+ "path": [
+ "api",
+ "v1",
+ "tasks"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "CreateTask",
+ "request": {
+ "auth": {
+ "type": "basic",
+ "basic": [
+ {
+ "key": "password",
+ "value": "0e9a0d44-f14c-4515-ba03-449b0223dcce",
+ "type": "string"
+ },
+ {
+ "key": "username",
+ "value": "product_owner",
+ "type": "string"
+ }
+ ]
+ },
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\r\n \"title\" : \"Eating\",\r\n \"description\" : \"Eating with Teeth\",\r\n \"status\" : \"Work In Progress\",\r\n \"project\":{\r\n \"id\" : \"e8c57a39-fe41-4523-977c-2b97e21e936c\"\r\n },\r\n \"user\" : {\r\n \"id\" : \"e960b50f-1f95-4dcf-b8f6-1522dcf051bb\"\r\n }\r\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://localhost:8080/api/v1/tasks",
+ "protocol": "http",
+ "host": [
+ "localhost"
+ ],
+ "port": "8080",
+ "path": [
+ "api",
+ "v1",
+ "tasks"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "UpdateTaskById",
+ "request": {
+ "method": "PUT",
+ "header": [],
+ "url": {
+ "raw": "http://localhost:8080/api/v1/tasks/0f2f0a79-0640-4cca-8b07-e683c70e33fc",
+ "protocol": "http",
+ "host": [
+ "localhost"
+ ],
+ "port": "8080",
+ "path": [
+ "api",
+ "v1",
+ "tasks",
+ "0f2f0a79-0640-4cca-8b07-e683c70e33fc"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "FetchTaskById",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "localhost:8080/api/v1/tasks/192a2472-9d91-4016-99fb-9b0882d916b3",
+ "host": [
+ "localhost"
+ ],
+ "port": "8080",
+ "path": [
+ "api",
+ "v1",
+ "tasks",
+ "192a2472-9d91-4016-99fb-9b0882d916b3"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "PatchTaskById",
+ "request": {
+ "method": "PATCH",
+ "header": [],
+ "url": {
+ "raw": "localhost:8080/api/v1/tasks/192a2472-9d91-4016-99fb-9b0882d916b3",
+ "host": [
+ "localhost"
+ ],
+ "port": "8080",
+ "path": [
+ "api",
+ "v1",
+ "tasks",
+ "192a2472-9d91-4016-99fb-9b0882d916b3"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "DeleteTask",
+ "request": {
+ "method": "DELETE",
+ "header": [],
+ "url": {
+ "raw": "localhost:8080/api/v1/tasks/192a2472-9d91-4016-99fb-9b0882d916b3",
+ "host": [
+ "localhost"
+ ],
+ "port": "8080",
+ "path": [
+ "api",
+ "v1",
+ "tasks",
+ "192a2472-9d91-4016-99fb-9b0882d916b3"
+ ]
+ }
+ },
+ "response": []
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index b0a6389..bfb1ae6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,13 +21,37 @@
org.springframework.boot
spring-boot-starter
-
+
+ org.springframework.boot
+ spring-boot-starter-web
+
org.springframework.boot
spring-boot-starter-test
test
-
+
+ org.springframework.boot
+ spring-boot-devtools
+ runtime
+ true
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+ com.h2database
+ h2
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+
+
@@ -35,7 +59,15 @@
org.springframework.boot
spring-boot-maven-plugin
-
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 15
+ 15
+
+
+
diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/SpringBootCodingTestApplication.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/SpringBootCodingTestApplication.java
index 14e2bbf..e79cc63 100644
--- a/src/main/java/com/accenture/codingtest/springbootcodingtest/SpringBootCodingTestApplication.java
+++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/SpringBootCodingTestApplication.java
@@ -1,13 +1,23 @@
package com.accenture.codingtest.springbootcodingtest;
+import com.accenture.codingtest.springbootcodingtest.entity.Project;
+import com.accenture.codingtest.springbootcodingtest.service.ProjectService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+
@SpringBootApplication
public class SpringBootCodingTestApplication {
- public static void main(String[] args) {
- SpringApplication.run(SpringBootCodingTestApplication.class, args);
- }
+ public static void main(String[] args) {
+ SpringApplication.run(SpringBootCodingTestApplication.class, args);
+
+
+
+ }
}
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..a1679eb
--- /dev/null
+++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/config/SecurityConfig.java
@@ -0,0 +1,72 @@
+package com.accenture.codingtest.springbootcodingtest.config;
+
+import com.accenture.codingtest.springbootcodingtest.model.Role;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+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.core.userdetails.UserDetailsService;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+@Configuration
+@EnableWebSecurity
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+
+ private final UserDetailsService userDetailsService;
+
+ public SecurityConfig(UserDetailsService userDetailsService) {
+ this.userDetailsService = userDetailsService;
+ }
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.authorizeRequests()
+ .antMatchers(HttpMethod.GET, "/api/v1/users").hasRole(Role.ADMIN.name())
+ .antMatchers(HttpMethod.GET, "/api/v1/users/{user_id}").hasRole(Role.ADMIN.name())
+ .antMatchers(HttpMethod.POST, "/api/v1/users").hasRole(Role.ADMIN.name())
+ .antMatchers(HttpMethod.PUT, "/api/v1/users/{user_id}").hasRole(Role.ADMIN.name())
+ .antMatchers(HttpMethod.PATCH, "/api/v1/users/{user_id}").hasRole(Role.ADMIN.name())
+ .antMatchers(HttpMethod.DELETE, "/api/v1/users/{user_id}").hasRole(Role.ADMIN.name())
+
+ .antMatchers(HttpMethod.GET, "/api/v1/projects").hasAnyRole(Role.ADMIN.name(),Role.PROJECT_OWNER.name())
+ .antMatchers(HttpMethod.GET, "/api/v1/projects/{project_id}").hasAnyRole(Role.ADMIN.name(),Role.PROJECT_OWNER.name())
+ .antMatchers(HttpMethod.POST, "/api/v1/projects").hasRole(Role.PROJECT_OWNER.name())
+ .antMatchers(HttpMethod.PUT, "/api/v1/projects/{project_id}").hasAnyRole(Role.ADMIN.name(),Role.PROJECT_OWNER.name())
+ .antMatchers(HttpMethod.DELETE, "/api/v1/projects/{project_id}").hasRole(Role.ADMIN.name())
+
+ .antMatchers(HttpMethod.GET, "/api/v1/tasks").hasAnyRole(Role.ADMIN.name(),Role.PROJECT_OWNER.name())
+ .antMatchers(HttpMethod.GET, "/api/v1/tasks/{task_id}").hasAnyRole(Role.ADMIN.name(),Role.PROJECT_OWNER.name())
+ .antMatchers(HttpMethod.POST, "/api/v1/tasks").hasRole(Role.PROJECT_OWNER.name())
+ .antMatchers(HttpMethod.PUT, "/api/v1/tasks/{task_id}").hasRole(Role.PROJECT_OWNER.name())
+ .antMatchers(HttpMethod.PATCH, "/api/v1/tasks/{task_id}").hasRole(Role.PROJECT_OWNER.name())
+ .antMatchers(HttpMethod.DELETE, "/api/v1/tasks/{task_id}").hasAnyRole(Role.ADMIN.name(),Role.PROJECT_OWNER.name())
+ .antMatchers(HttpMethod.PATCH, "/api/v1/tasks/{task_id}/status").hasRole(Role.TEAM_MEMBER.name())
+
+ .anyRequest().authenticated()
+ .and()
+ .httpBasic();
+ }
+
+
+ @Override
+ public void configure(WebSecurity web) throws Exception {
+ web
+ .ignoring()
+ .antMatchers("/h2-console/**");
+ }
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
+ }
+
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
+}
diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/config/UserDetailsServiceImpl.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/config/UserDetailsServiceImpl.java
new file mode 100644
index 0000000..4a2f595
--- /dev/null
+++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/config/UserDetailsServiceImpl.java
@@ -0,0 +1,44 @@
+package com.accenture.codingtest.springbootcodingtest.config;
+
+import com.accenture.codingtest.springbootcodingtest.entity.User;
+import com.accenture.codingtest.springbootcodingtest.repository.UserRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+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 java.util.Set;
+import java.util.stream.Collectors;
+
+@Service
+public class UserDetailsServiceImpl implements UserDetailsService {
+ private final UserRepository userRepository;
+
+ @Autowired
+ public UserDetailsServiceImpl(UserRepository userRepository) {
+ this.userRepository = userRepository;
+ }
+
+ @Override
+ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+ User user = userRepository.findByUsername(username)
+ .orElseThrow(() -> new UsernameNotFoundException("User not found"));
+
+
+ Set authorities = user.getRoles().stream()
+ .map(role -> new SimpleGrantedAuthority(role.getAuthority()))
+ .collect(Collectors.toSet());
+
+ return new org.springframework.security.core.userdetails.User(
+ user.getUsername(),
+ user.getPassword(),
+ authorities
+ );
+ }
+
+}
+
+
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..e74b2c2
--- /dev/null
+++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/ProjectController.java
@@ -0,0 +1,68 @@
+package com.accenture.codingtest.springbootcodingtest.controller;
+
+import com.accenture.codingtest.springbootcodingtest.entity.Project;
+import com.accenture.codingtest.springbootcodingtest.service.ProjectService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.UUID;
+
+@RestController
+@RequestMapping(value = "api/v1/projects")
+public class ProjectController {
+
+ private final ProjectService projectService;
+
+ @Autowired
+ public ProjectController(ProjectService projectService) {
+ this.projectService = projectService;
+ }
+
+
+ @GetMapping
+ public ResponseEntity> getAllProjects(
+ @RequestParam(defaultValue = "0") int page,
+ @RequestParam(defaultValue = "5") int size,
+ @RequestParam(defaultValue = "name") String sortBy
+ ) {
+ Pageable pageable = PageRequest.of(page, size, Sort.by(sortBy));
+ Page projects = projectService.getAllProjects(pageable);
+ return ResponseEntity.ok(projects);
+ }
+
+
+ @GetMapping("/{project_id}")
+ public ResponseEntity getProjectById (@PathVariable("project_id") UUID projectId){
+ Project project = projectService.findById(projectId);
+ return ResponseEntity.ok(project);
+ }
+
+ @PostMapping
+ public ResponseEntity createProject (@RequestBody Project project){
+ Project savedProject = projectService.save(project);
+ return ResponseEntity.status(HttpStatus.CREATED).body(savedProject);
+ }
+
+ @PutMapping("/{project_id}")
+ public ResponseEntity updateProjectById (@PathVariable("project_id") UUID projectId,
+ @RequestBody Project project){
+ Project updated = projectService.updateProject(projectId, project);
+
+ return ResponseEntity.ok(updated);
+ }
+
+ @DeleteMapping("/{project_id}")
+ public ResponseEntity deleteProject (@PathVariable("project_id") UUID projectId){
+ projectService.delete(projectId);
+ return ResponseEntity.noContent().build();
+ }
+
+
+ }
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..dd082ce
--- /dev/null
+++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/TaskController.java
@@ -0,0 +1,78 @@
+package com.accenture.codingtest.springbootcodingtest.controller;
+
+import com.accenture.codingtest.springbootcodingtest.entity.Task;
+import com.accenture.codingtest.springbootcodingtest.model.TaskStatus;
+import com.accenture.codingtest.springbootcodingtest.service.TaskService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.UUID;
+
+@RestController
+@RequestMapping(value = "/api/v1/tasks")
+public class TaskController {
+ private final TaskService taskService;
+
+ @Autowired
+ public TaskController(TaskService taskService) {
+ this.taskService = taskService;
+ }
+
+ @GetMapping
+ public ResponseEntity> getAllTasks() {
+ List taskList = taskService.findAll();
+ return ResponseEntity.ok(taskList);
+ }
+
+ @GetMapping("/{task_id}")
+ public ResponseEntity getTaskById(@PathVariable("task_id") UUID taskId) {
+ Task task = taskService.findById(taskId);
+ return ResponseEntity.ok(task);
+ }
+
+ @PostMapping
+ public ResponseEntity createTask(@RequestBody Task task) {
+ task.setStatus(TaskStatus.NOT_STARTED);
+ Task savedTask = taskService.save(task);
+ return ResponseEntity.status(HttpStatus.CREATED).body(savedTask);
+ }
+
+ @PutMapping("/{task_id}")
+ public ResponseEntity updateTask(@PathVariable("task_id") UUID taskId,
+ @RequestBody Task updatedTask) {
+ Task task = taskService.updateTask(taskId,updatedTask);
+ return ResponseEntity.ok(task);
+ }
+
+
+ @PatchMapping("/{task_id}")
+ public ResponseEntity patchTask(@PathVariable("task_id") UUID taskId,
+ @RequestBody Task updatedTask) {
+ Task task = taskService.patchTask(taskId,updatedTask);
+
+ return ResponseEntity.ok(task);
+ }
+
+ @DeleteMapping("/{task_id}")
+ public ResponseEntity deleteTask(@PathVariable("task_id") UUID taskId) {
+
+ taskService.delete(taskId);
+ return ResponseEntity.noContent().build();
+ }
+
+
+ @PatchMapping("/{task_id}/status")
+ public ResponseEntity updateTaskStatus(@PathVariable("task_id") UUID taskId,
+ @RequestParam("status") TaskStatus status) {
+ Task task = taskService.updateTaskStatus(taskId,status);
+ return ResponseEntity.ok(task);
+ }
+
+
+
+
+}
+
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..c213d7a
--- /dev/null
+++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/UserController.java
@@ -0,0 +1,65 @@
+package com.accenture.codingtest.springbootcodingtest.controller;
+
+
+import com.accenture.codingtest.springbootcodingtest.entity.User;
+import com.accenture.codingtest.springbootcodingtest.service.UserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.UUID;
+
+@RestController
+@RequestMapping("/api/v1/users")
+public class UserController {
+
+ private final UserService userService;
+
+ @Autowired
+ public UserController(UserService userService) {
+ this.userService = userService;
+ }
+
+ @GetMapping
+ public ResponseEntity> getAllUsers(){
+ List userList = userService.findAll();
+ return ResponseEntity.ok(userList);
+ }
+
+ @GetMapping("/{user_id}")
+ public ResponseEntity getUserById(@PathVariable("user_id") UUID userId) {
+ User user = userService.findById(userId);
+ return ResponseEntity.ok(user);
+ }
+
+ @PostMapping
+ public ResponseEntity createUser(@RequestBody User user){
+ User savedUser = userService.save(user);
+ return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);
+ }
+
+ @PutMapping("/{user_id}")
+ public ResponseEntity updateUser(@PathVariable("user_id") UUID userId,
+ @RequestBody User user){
+
+ User updatedUser = userService.updateUser(userId,user);
+ return ResponseEntity.ok(updatedUser);
+ }
+
+ @PatchMapping("/{user_id}")
+ public ResponseEntity patchUser(@PathVariable("user_id") UUID userId,
+ @RequestBody User user){
+ User patchedUser = userService.patchUser(userId,user);
+ return ResponseEntity.ok(patchedUser);
+
+ }
+
+ @DeleteMapping("/{user_id}")
+ public ResponseEntity deleteUser(@PathVariable("user_id") UUID userId){
+ userService.delete(userId);
+ return ResponseEntity.noContent().build();
+ }
+
+}
diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/dataInitializer/ProjectInitializer.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/dataInitializer/ProjectInitializer.java
new file mode 100644
index 0000000..46cc19d
--- /dev/null
+++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/dataInitializer/ProjectInitializer.java
@@ -0,0 +1,83 @@
+package com.accenture.codingtest.springbootcodingtest.dataInitializer;
+
+import com.accenture.codingtest.springbootcodingtest.entity.Project;
+import com.accenture.codingtest.springbootcodingtest.repository.ProjectRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ProjectInitializer implements CommandLineRunner {
+ private final ProjectRepository projectRepository;
+
+ @Autowired
+ public ProjectInitializer(ProjectRepository projectRepository) {
+ this.projectRepository = projectRepository;
+ }
+
+ @Override
+ public void run(String... args) {
+
+ Project project1 = new Project();
+ project1.setName("project1");
+ projectRepository.save(project1);
+
+ Project project2 = new Project();
+ project2.setName("project2");
+ projectRepository.save(project2);
+
+ Project project3 = new Project();
+ project3.setName("project3");
+ projectRepository.save(project3);
+
+ Project project4 = new Project();
+ project4.setName("project4");
+ projectRepository.save(project4);
+
+ Project project5 = new Project();
+ project5.setName("project5");
+ projectRepository.save(project5);
+
+ Project project6 = new Project();
+ project6.setName("project6");
+ projectRepository.save(project6);
+
+ Project project7 = new Project();
+ project7.setName("project7");
+ projectRepository.save(project7);
+
+ Project project8 = new Project();
+ project8.setName("project8");
+ projectRepository.save(project8);
+
+ Project project9 = new Project();
+ project9.setName("project9");
+ projectRepository.save(project9);
+
+ Project project10 = new Project();
+ project10.setName("project10");
+ projectRepository.save(project10);
+
+ Project project11 = new Project();
+ project11.setName("project11");
+ projectRepository.save(project11);
+
+ Project project12 = new Project();
+ project12.setName("project12");
+ projectRepository.save(project12);
+
+ Project project13 = new Project();
+ project13.setName("project13");
+ projectRepository.save(project13);
+
+ Project project14 = new Project();
+ project14.setName("project14");
+ projectRepository.save(project14);
+
+ Project project15 = new Project();
+ project15.setName("project15");
+ projectRepository.save(project15);
+
+
+ }
+}
diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/dataInitializer/UserInitializer.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/dataInitializer/UserInitializer.java
new file mode 100644
index 0000000..3650441
--- /dev/null
+++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/dataInitializer/UserInitializer.java
@@ -0,0 +1,46 @@
+package com.accenture.codingtest.springbootcodingtest.dataInitializer;
+
+import com.accenture.codingtest.springbootcodingtest.entity.User;
+import com.accenture.codingtest.springbootcodingtest.model.Role;
+import com.accenture.codingtest.springbootcodingtest.repository.UserRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Component;
+
+@Component
+public class UserInitializer implements CommandLineRunner {
+
+ private final UserRepository userRepository;
+
+ @Autowired
+ public UserInitializer(UserRepository userRepository) {
+ this.userRepository = userRepository;
+ }
+
+ @Override
+ public void run(String... args) throws Exception {
+ User user1 = new User();
+ user1.setUsername("projectOwner");
+ user1.setPassword(passwordEncoder().encode("1234"));
+ user1.getRoles().add(Role.PROJECT_OWNER);
+ userRepository.save(user1);
+
+ User user2 = new User();
+ user2.setUsername("admin");
+ user2.setPassword(passwordEncoder().encode("1234"));
+ user2.getRoles().add(Role.ADMIN);
+ userRepository.save(user2);
+
+ User user3 = new User();
+ user3.setUsername("teamMember");
+ user3.setPassword(passwordEncoder().encode("1234"));
+ user3.getRoles().add(Role.TEAM_MEMBER);
+ userRepository.save(user3);
+ }
+
+ private PasswordEncoder passwordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
+}
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..0875f85
--- /dev/null
+++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/Project.java
@@ -0,0 +1,39 @@
+package com.accenture.codingtest.springbootcodingtest.entity;
+
+import javax.persistence.*;
+import java.util.UUID;
+
+@Entity
+@Table(name = "projects")
+public class Project {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private UUID id;
+ @Column(name = "name",nullable = false,unique = true)
+ private String name;
+
+ public UUID getId() {
+ return id;
+ }
+
+ public void setId(UUID id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return "Project { " +
+ "id= " + id +
+ " , name='" + name +
+ "' }";
+ }
+}
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..6bf6fa7
--- /dev/null
+++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/Task.java
@@ -0,0 +1,77 @@
+package com.accenture.codingtest.springbootcodingtest.entity;
+
+
+import com.accenture.codingtest.springbootcodingtest.model.TaskStatus;
+
+import javax.persistence.*;
+import java.util.UUID;
+
+@Entity
+@Table(name = "tasks")
+public class Task {
+
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private UUID id;
+ @Column(nullable = false)
+ private String title;
+ private String description;
+ @Column(nullable = false)
+ @Enumerated(EnumType.STRING)
+ private TaskStatus status;
+ @ManyToOne
+ @JoinColumn(name = "project_id",nullable = false)
+ private Project project;
+ @ManyToOne
+ @JoinColumn(name = "user_id",nullable = false)
+ private User user;
+
+ public UUID getId() {
+ return id;
+ }
+
+ public void setId(UUID id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public TaskStatus getStatus() {
+ return status;
+ }
+
+ public void setStatus(TaskStatus status) {
+ this.status = status;
+ }
+
+ public Project getProject() {
+ return project;
+ }
+
+ public void setProject(Project project) {
+ this.project = project;
+ }
+
+ public User getUser() {
+ return user;
+ }
+
+ public void setUser(User user) {
+ this.user = user;
+ }
+}
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..34c81fd
--- /dev/null
+++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/User.java
@@ -0,0 +1,59 @@
+package com.accenture.codingtest.springbootcodingtest.entity;
+
+import com.accenture.codingtest.springbootcodingtest.model.Role;
+
+import javax.persistence.*;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
+
+@Entity
+@Table(name = "users")
+public class User {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private UUID id;
+
+ @Column(nullable = false,unique = true)
+ private String username;
+ @Column(nullable = false)
+ private String password;
+
+ @ElementCollection(targetClass = Role.class, fetch = FetchType.EAGER)
+ @CollectionTable(name = "user_roles", joinColumns = @JoinColumn(name = "user_id"))
+ @Enumerated(EnumType.STRING)
+ private Set roles = new HashSet<>();
+
+ public Set getRoles() {
+ return roles;
+ }
+
+ public void setRoles(Set roles) {
+ this.roles = roles;
+ }
+
+ public UUID getId() {
+ return id;
+ }
+
+ public void setId(UUID id) {
+ this.id = id;
+ }
+
+ 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/Role.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/model/Role.java
new file mode 100644
index 0000000..8bc2f47
--- /dev/null
+++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/model/Role.java
@@ -0,0 +1,23 @@
+package com.accenture.codingtest.springbootcodingtest.model;
+
+public enum Role {
+ PROJECT_OWNER("Project Owner", "ROLE_PROJECT_OWNER"),
+ ADMIN("Admin", "ROLE_ADMIN"),
+ TEAM_MEMBER("Team Member", "ROLE_TEAM_MEMBER");
+
+ private final String roleName;
+ private final String authority;
+
+ Role(String roleName, String authority) {
+ this.roleName = roleName;
+ this.authority = authority;
+ }
+
+ public String getRoleName() {
+ return roleName;
+ }
+
+ public String getAuthority() {
+ return authority;
+ }
+}
diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/model/TaskStatus.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/model/TaskStatus.java
new file mode 100644
index 0000000..21e1af7
--- /dev/null
+++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/model/TaskStatus.java
@@ -0,0 +1,8 @@
+package com.accenture.codingtest.springbootcodingtest.model;
+
+public enum TaskStatus {
+ NOT_STARTED,
+ IN_PROGRESS,
+ READY_FOR_TEST,
+ COMPLETED
+}
diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/ProjectRepository.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/ProjectRepository.java
new file mode 100644
index 0000000..d2839ce
--- /dev/null
+++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/ProjectRepository.java
@@ -0,0 +1,13 @@
+package com.accenture.codingtest.springbootcodingtest.repository;
+
+import com.accenture.codingtest.springbootcodingtest.entity.Project;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.UUID;
+
+public interface ProjectRepository extends JpaRepository {
+
+ Page findByNameContainingIgnoreCase(String q, PageRequest pageRequest);
+}
diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/TaskRepository.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/TaskRepository.java
new file mode 100644
index 0000000..deb954b
--- /dev/null
+++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/TaskRepository.java
@@ -0,0 +1,10 @@
+package com.accenture.codingtest.springbootcodingtest.repository;
+
+import com.accenture.codingtest.springbootcodingtest.entity.Task;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.UUID;
+
+public interface TaskRepository extends JpaRepository {
+
+}
diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/UserRepository.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/UserRepository.java
new file mode 100644
index 0000000..14c3767
--- /dev/null
+++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/UserRepository.java
@@ -0,0 +1,12 @@
+package com.accenture.codingtest.springbootcodingtest.repository;
+
+import com.accenture.codingtest.springbootcodingtest.entity.User;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.Optional;
+import java.util.UUID;
+
+public interface UserRepository extends JpaRepository {
+ Optional findByUsername(String userName);
+
+}
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..9ffd250
--- /dev/null
+++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/ProjectService.java
@@ -0,0 +1,53 @@
+package com.accenture.codingtest.springbootcodingtest.service;
+
+import com.accenture.codingtest.springbootcodingtest.entity.Project;
+import com.accenture.codingtest.springbootcodingtest.repository.ProjectRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.UUID;
+
+@Service("projectService")
+public class ProjectService {
+
+ private final ProjectRepository projectRepository;
+
+ @Autowired
+ public ProjectService(ProjectRepository projectRepository) {
+ this.projectRepository = projectRepository;
+ }
+
+
+ public Project findById(UUID projectId) {
+ return projectRepository.findById(projectId)
+ .orElseThrow(() -> new RuntimeException("Project not found with Id: " + projectId));
+ }
+
+ public Page getAllProjects(Pageable pageable) {
+ return projectRepository.findAll(pageable);
+ }
+
+
+ public Project save(Project project) {
+ return projectRepository.save(project);
+ }
+
+ public Project updateProject(UUID projectId, Project project) {
+ Project fetch = findById(projectId);
+ fetch.setName(project.getName());
+ return projectRepository.save(fetch);
+ }
+
+ public void delete(UUID projectId) {
+ Project fetch = findById(projectId);
+ projectRepository.delete(fetch);
+ }
+
+
+
+}
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..0c9757b
--- /dev/null
+++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/TaskService.java
@@ -0,0 +1,103 @@
+package com.accenture.codingtest.springbootcodingtest.service;
+
+import com.accenture.codingtest.springbootcodingtest.entity.Project;
+import com.accenture.codingtest.springbootcodingtest.entity.Task;
+import com.accenture.codingtest.springbootcodingtest.entity.User;
+import com.accenture.codingtest.springbootcodingtest.model.TaskStatus;
+import com.accenture.codingtest.springbootcodingtest.repository.TaskRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.UUID;
+
+@Service
+public class TaskService {
+ private final TaskRepository taskRepository;
+ private final UserService userService;
+ private final ProjectService projectService;
+
+ @Autowired
+ public TaskService(TaskRepository taskRepository, UserService userService, ProjectService projectService) {
+ this.taskRepository = taskRepository;
+ this.userService = userService;
+ this.projectService = projectService;
+ }
+
+ public Task findById(UUID taskId) {
+ return taskRepository.findById(taskId)
+ .orElseThrow(() -> new RuntimeException("Task not found with Id: " + taskId));
+ }
+
+ public List findAll() {
+ return taskRepository.findAll();
+ }
+
+ public Task save(Task task) {
+
+ assignProject(task);
+
+ assignUser(task);
+
+ return taskRepository.save(task);
+ }
+
+ private void assignUser(Task task) {
+ UUID userId = task.getUser().getId();
+ User user = userService.findById(userId);
+ task.setUser(user);
+ }
+
+ private void assignProject(Task task) {
+ UUID projectId = task.getProject().getId();
+ Project project = projectService.findById(projectId);
+ task.setProject(project);
+ }
+
+ public Task updateTask(UUID taskId, Task task) {
+ Task fetch = findById(taskId);
+
+
+ fetch.setTitle(task.getTitle());
+ fetch.setDescription(task.getDescription());
+ fetch.setStatus(task.getStatus());
+ assignProject(task);
+ assignUser(task);
+
+ return taskRepository.save(fetch);
+ }
+
+ public Task patchTask(UUID taskId, Task task) {
+ Task fetch = findById(taskId);
+
+ if (task.getTitle() != null) {
+ fetch.setTitle(task.getTitle());
+ }
+ if (task.getDescription() != null) {
+ fetch.setDescription(task.getDescription());
+ }
+ if (task.getStatus() != null) {
+ fetch.setStatus(task.getStatus());
+ }
+ if (task.getProject() != null) {
+ assignProject(task);
+ }
+ if (task.getUser() != null) {
+ assignUser(task);
+ }
+
+ return taskRepository.save(fetch);
+ }
+
+ public void delete(UUID taskId) {
+ Task fetch = findById(taskId);
+ taskRepository.delete(fetch);
+ }
+
+
+ public Task updateTaskStatus(UUID taskId, TaskStatus status) {
+ Task fetch = findById(taskId);
+ patchTask(taskId,fetch).setStatus(status);
+ return null;
+ }
+}
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..eb1d6a6
--- /dev/null
+++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/UserService.java
@@ -0,0 +1,60 @@
+package com.accenture.codingtest.springbootcodingtest.service;
+
+import com.accenture.codingtest.springbootcodingtest.entity.User;
+import com.accenture.codingtest.springbootcodingtest.repository.UserRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.UUID;
+
+@Service
+public class UserService {
+
+
+ private final UserRepository userRepository;
+
+ @Autowired
+ public UserService(UserRepository userRepository) {
+ this.userRepository = userRepository;
+ }
+
+ public User save(User user) {
+ userRepository.save(user);
+ return user;
+ }
+
+ public User findById(UUID userId) {
+ return userRepository.findById(userId)
+ .orElseThrow(() -> new RuntimeException("User not found with userId: " + userId));
+ }
+
+ public List findAll() {
+ return userRepository.findAll();
+ }
+
+ public User updateUser(UUID userId, User user) {
+ User fetch = findById(userId);
+ fetch.setUsername(user.getUsername());
+ fetch.setPassword(user.getPassword());
+ return userRepository.save(fetch);
+ }
+
+ public User patchUser(UUID userId, User user){
+ User fetch = findById(userId);
+ if (user.getUsername() != null){
+ fetch.setUsername(user.getUsername());
+ }
+ if (user.getPassword() != null){
+ fetch.setPassword(user.getPassword());
+ }
+
+ return userRepository.save(fetch);
+ }
+
+ public void delete(UUID userId) {
+ User fetch = findById(userId);
+ userRepository.deleteById(userId);
+ }
+
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 8b13789..f6f4510 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1 +1,8 @@
+# H2 Database
+spring.h2.console.enabled=true
+spring.datasource.url=jdbc:h2:mem:dcbapp
+spring.datasource.driverClassName=org.h2.Driver
+spring.datasource.username=sa
+spring.datasource.password=
+spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
diff --git a/src/test/java/com/accenture/codingtest/springbootcodingtest/UserControllerTest.java b/src/test/java/com/accenture/codingtest/springbootcodingtest/UserControllerTest.java
new file mode 100644
index 0000000..f3408ea
--- /dev/null
+++ b/src/test/java/com/accenture/codingtest/springbootcodingtest/UserControllerTest.java
@@ -0,0 +1,51 @@
+package com.accenture.codingtest.springbootcodingtest;
+
+import com.accenture.codingtest.springbootcodingtest.entity.User;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.http.*;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import java.net.URI;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+public class UserControllerTest {
+
+ @Autowired
+ private TestRestTemplate restTemplate;
+
+ @Test
+ public void testCreateUser() {
+ String createUserUrl = "/api/v1/users";
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.APPLICATION_JSON);
+ headers.setBasicAuth("admin", "admin");
+
+ String requestBody = """
+ {
+ "username":"Ram",
+ "password":"1234"
+ }
+ """;
+ HttpEntity requestEntity = new HttpEntity<>(requestBody, headers);
+
+ URI uri = UriComponentsBuilder.fromUriString(createUserUrl).build().toUri();
+
+ ResponseEntity response = restTemplate.exchange(
+ uri,
+ HttpMethod.POST,
+ requestEntity,
+ User.class
+ );
+
+ assertEquals(HttpStatus.CREATED, response.getStatusCode());
+ User createdUser = response.getBody();
+ assertEquals("Ram", createdUser.getUsername());
+ }
+
+
+}