From a7ecd1cfeab2b606d041df3a6959e4a94970de82 Mon Sep 17 00:00:00 2001 From: Kailas Kakade Date: Sat, 14 Jan 2023 12:03:43 +0530 Subject: [PATCH 1/2] Create entities --- pom.xml | 10 ++- .../controller/package-info.java | 1 + .../springbootcodingtest/entity/Project.java | 34 +++++++++ .../springbootcodingtest/entity/Task.java | 73 +++++++++++++++++++ .../springbootcodingtest/entity/User.java | 44 +++++++++++ src/main/resources/Sql.sql | 3 + src/main/resources/application.properties | 9 +++ 7 files changed, 172 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/entity/Project.java create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/entity/Task.java create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/entity/User.java create mode 100644 src/main/resources/Sql.sql diff --git a/pom.xml b/pom.xml index b0a6389..16b35bd 100644 --- a/pom.xml +++ b/pom.xml @@ -1,12 +1,13 @@ - 4.0.0 org.springframework.boot spring-boot-starter-parent 2.6.3 - + com.accenture.codingtest spring-boot-coding-test @@ -27,6 +28,11 @@ spring-boot-starter-test test + + org.springframework.boot + spring-boot-starter-data-jpa + + 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..b9ee1af --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/Project.java @@ -0,0 +1,34 @@ +package com.accenture.codingtest.springbootcodingtest.entity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "project") +public class Project { + + @Id + @Column(name = "id") + private String id; + @Column(name = "name", length = 200, unique = true) + private String name; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} \ No newline at end of file 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..0a43e2c --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/Task.java @@ -0,0 +1,73 @@ +package com.accenture.codingtest.springbootcodingtest.entity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "task") +public class Task { + + @Id + @Column(name = "id") + private String id; + @Column(name = "title", length = 250, nullable = false) + private String title; + @Column(name = "description") + private String description; + @Column(name = "status", nullable = false) + private String status; + @Column(name = "project_id", nullable = false) + private String projectId; + @Column(name = "user_id", nullable = false) + private String userId; + + public String getId() { + return id; + } + + public void setId(String 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 String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getProjectId() { + return projectId; + } + + public void setProjectId(String projectId) { + this.projectId = projectId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } +} \ No newline at end of file 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..be4d9f9 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/User.java @@ -0,0 +1,44 @@ +package com.accenture.codingtest.springbootcodingtest.entity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "user") +public class User { + + @Id + @Column(name = "id") + private String id; + @Column(name = "user_name", length = 150, unique = true) + private String userName; + @Column(name = "password", length = 50) + private String password; + + public String getId() { + return id; + } + + public void setId(String 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; + } + +} \ No newline at end of file diff --git a/src/main/resources/Sql.sql b/src/main/resources/Sql.sql new file mode 100644 index 0000000..dacf56d --- /dev/null +++ b/src/main/resources/Sql.sql @@ -0,0 +1,3 @@ +CREATE TABLE USER (id varchar,user_name varchar(150) unique,password varchar(50)); +CREATE TABLE PROJECT (id varchar,name varchar(150)); +CREATE TABLE TASK (id varchar,title varchar(250),description varchar,status varchar,project_id varchar,user_id varchar); \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8b13789..49fdf17 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,10 @@ +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver +spring.datasource.url = jdbc:mysql://localhost:3306/product +spring.datasource.username = root +spring.datasource.password = root +spring.jpa.show-sql = true +spring.jpa.hibernate.ddl-auto = update +spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect +server.port=6060 +spring.mvc.pathmatch.matching-strategy=ant-path-matcher From 7a017672b66501c3b066e172c65c293033863339 Mon Sep 17 00:00:00 2001 From: Kailas Kakade Date: Sat, 14 Jan 2023 20:42:57 +0530 Subject: [PATCH 2/2] Create REST APIs --- pom.xml | 20 ++++ .../controller/ProjectController.java | 60 ++++++++++++ .../controller/TaskController.java | 97 +++++++++++++++++++ .../controller/UserController.java | 77 +++++++++++++++ .../springbootcodingtest/entity/Project.java | 33 +++---- .../springbootcodingtest/entity/Task.java | 80 ++++++--------- .../entity/TaskStatusEnum.java | 5 + .../springbootcodingtest/entity/User.java | 40 +++----- .../entity/exception/BusinessException.java | 62 ++++++++++++ .../RecordAlreadyExistException.java | 14 +++ .../entity/exception/RecordException.java | 20 ++++ .../exception/RecordNotFoundException.java | 14 +++ .../handler/BusinessExceptionTranslator.java | 25 +++++ .../entity/model/ErrorDto.java | 43 ++++++++ .../entity/model/ProjectDto.java | 11 +++ .../entity/model/TaskDto.java | 23 +++++ .../entity/model/UserDto.java | 13 +++ .../repository/ProjectRepository.java | 18 ++++ .../repository/TaskRepository.java | 22 +++++ .../repository/UserRepository.java | 20 ++++ .../service/ProjectService.java | 16 +++ .../service/TaskService.java | 22 +++++ .../service/UserService.java | 22 +++++ .../service/impl/ProjectServiceImpl.java | 33 +++++++ .../service/impl/TaskServiceImpl.java | 54 +++++++++++ .../service/impl/UserServiceImpl.java | 63 ++++++++++++ 26 files changed, 807 insertions(+), 100 deletions(-) create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/controller/ProjectController.java create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/controller/TaskController.java create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/controller/UserController.java create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/entity/TaskStatusEnum.java create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/entity/exception/BusinessException.java create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/entity/exception/RecordAlreadyExistException.java create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/entity/exception/RecordException.java create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/entity/exception/RecordNotFoundException.java create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/entity/exception/handler/BusinessExceptionTranslator.java create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/entity/model/ErrorDto.java create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/entity/model/ProjectDto.java create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/entity/model/TaskDto.java create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/entity/model/UserDto.java create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/repository/ProjectRepository.java create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/repository/TaskRepository.java create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/repository/UserRepository.java create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/service/ProjectService.java create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/service/TaskService.java create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/service/UserService.java create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/service/impl/ProjectServiceImpl.java create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/service/impl/TaskServiceImpl.java create mode 100644 src/main/java/com/accenture/codingtest/springbootcodingtest/service/impl/UserServiceImpl.java diff --git a/pom.xml b/pom.xml index 16b35bd..4de53dd 100644 --- a/pom.xml +++ b/pom.xml @@ -32,6 +32,26 @@ org.springframework.boot spring-boot-starter-data-jpa + + + org.projectlombok + lombok + 1.18.24 + provided + + + + org.springframework + spring-web + 6.0.2 + + + + + org.springframework.boot + spring-boot-starter-web + 3.0.1 + 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..35dad17 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/ProjectController.java @@ -0,0 +1,60 @@ +package com.accenture.codingtest.springbootcodingtest.controller; + +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.accenture.codingtest.springbootcodingtest.entity.Project; +import com.accenture.codingtest.springbootcodingtest.entity.exception.RecordNotFoundException; +import com.accenture.codingtest.springbootcodingtest.entity.model.ProjectDto; +import com.accenture.codingtest.springbootcodingtest.service.ProjectService; + +@RestController +@RequestMapping(value = "/api/v1/projects") +public class ProjectController { + + @Autowired + private ProjectService projectService; + + @PostMapping("") + public ProjectDto create(@RequestBody ProjectDto projectDto) { + return this.convertProjectEntityToProjectDto( + projectService.save(this.convertProjectDtoToProjectEntity(projectDto))); + } + + @GetMapping("") + public List findAll() { + return projectService.findAll().stream().map(this::convertProjectEntityToProjectDto) + .collect(Collectors.toList()); + } + + @GetMapping("/{id}") + public ProjectDto findById(@PathVariable String id) { + return projectService.findById(id).map(this::convertProjectEntityToProjectDto) + .orElseThrow(RecordNotFoundException::new); + } + + private ProjectDto convertProjectEntityToProjectDto(Project project) { + ProjectDto projectDto = new ProjectDto(); + projectDto.setId(project.getId()); + projectDto.setName(projectDto.getName()); + + return projectDto; + } + + private Project convertProjectDtoToProjectEntity(ProjectDto projectDto) { + Project project = new Project(); + project.setId(projectDto.getId()); + project.setName(projectDto.getName()); + + return project; + } + +} \ No newline at end of file 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..f076726 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/TaskController.java @@ -0,0 +1,97 @@ +package com.accenture.codingtest.springbootcodingtest.controller; + +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.annotation.Autowired; +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.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.accenture.codingtest.springbootcodingtest.entity.Project; +import com.accenture.codingtest.springbootcodingtest.entity.Task; +import com.accenture.codingtest.springbootcodingtest.entity.TaskStatusEnum; +import com.accenture.codingtest.springbootcodingtest.entity.User; +import com.accenture.codingtest.springbootcodingtest.entity.exception.RecordNotFoundException; +import com.accenture.codingtest.springbootcodingtest.entity.model.TaskDto; +import com.accenture.codingtest.springbootcodingtest.service.ProjectService; +import com.accenture.codingtest.springbootcodingtest.service.TaskService; +import com.accenture.codingtest.springbootcodingtest.service.UserService; + +@RestController +@RequestMapping(value = "/api/v1/tasks") +public class TaskController { + + @Autowired + private TaskService taskService; + + @Autowired + private UserService userService; + + @Autowired + private ProjectService projectService; + + @PostMapping("") + public TaskDto create(@RequestBody TaskDto taskDto) { + Task task = taskService.save(this.convertTaskDtoToTaskEntity(taskDto)); + return this.convertTaskEntityToTaskDto(task); + } + + @PatchMapping("/{id}") + public TaskDto update(@RequestBody TaskDto taskDto, @PathVariable String id) { + Task task = taskService.update(this.convertTaskDtoToTaskEntity(taskDto), id); + return this.convertTaskEntityToTaskDto(task); + } + + @GetMapping("") + public List findAll() { + return taskService.findAll().stream().map(this::convertTaskEntityToTaskDto).collect(Collectors.toList()); + } + + @GetMapping("/project/{projectId}") + public List findByProjectId(@PathVariable String projectId) { + return taskService.findByProjectId(projectId).stream().map(this::convertTaskEntityToTaskDto) + .collect(Collectors.toList()); + } + + @GetMapping("/user/{userId}") + public List findByUserId(@PathVariable String userId) { + return taskService.findByUserId(userId).stream().map(this::convertTaskEntityToTaskDto) + .collect(Collectors.toList()); + } + + private TaskDto convertTaskEntityToTaskDto(Task task) { + TaskDto taskDto = new TaskDto(); + taskDto.setId(task.getId()); + taskDto.setTitle(task.getTitle()); + taskDto.setDescription(task.getDescription()); + taskDto.setStatus(task.getStatus().toString()); + taskDto.setProjectId(task.getProject().getId()); + taskDto.setProjectName(task.getProject().getName()); + taskDto.setUserId(task.getUser().getId()); + taskDto.setUsername(task.getUser().getUsername()); + + return taskDto; + } + + private Task convertTaskDtoToTaskEntity(TaskDto taskDto) { + Task task = new Task(); + task.setId(taskDto.getId()); + task.setTitle(taskDto.getTitle()); + task.setDescription(taskDto.getDescription()); + task.setStatus(TaskStatusEnum.valueOf(taskDto.getStatus())); + + User user = userService.findByUserId(taskDto.getUserId()).orElseThrow(RecordNotFoundException::new); + Project project = projectService.findById(taskDto.getProjectId()).orElseThrow(RecordNotFoundException::new); + + task.setUser(user); + task.setProject(project); + + return task; + } + +} \ No newline at end of file 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..1d3a258 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/controller/UserController.java @@ -0,0 +1,77 @@ +package com.accenture.codingtest.springbootcodingtest.controller; + +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.annotation.Autowired; +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.entity.User; +import com.accenture.codingtest.springbootcodingtest.entity.exception.RecordNotFoundException; +import com.accenture.codingtest.springbootcodingtest.entity.model.UserDto; +import com.accenture.codingtest.springbootcodingtest.service.UserService; + +@RestController +@RequestMapping(value = "/api/v1/users") +public class UserController { + + @Autowired + private UserService userService; + + @GetMapping(value = "") + public List findAll() { + return userService.findAll().stream().map(this::convertUserEntityToUserDto).collect(Collectors.toList()); + } + + @GetMapping(value = "/{userId}") + public UserDto findByUserId(@PathVariable String userId) { + return userService.findByUserId(userId).map(this::convertUserEntityToUserDto) + .orElseThrow(RecordNotFoundException::new); + } + + @PostMapping("") + public UserDto create(@RequestBody UserDto userDto) { + return this.convertUserEntityToUserDto(userService.save(this.convertUserDtoToUserEntity(userDto))); + } + + @PutMapping("/{userId}") + public UserDto updateIdempotent(@RequestBody UserDto userDto, @PathVariable String userId) { + return this.convertUserEntityToUserDto(userService.update(this.convertUserDtoToUserEntity(userDto), userId)); + } + + @PatchMapping("/{userId}") + public UserDto update(@RequestBody UserDto userDto, @PathVariable String userId) { + return this.convertUserEntityToUserDto(userService.update(this.convertUserDtoToUserEntity(userDto), userId)); + } + + @DeleteMapping("/{userId}") + public void delete(@PathVariable String userId) { + userService.delete(userId); + } + + private UserDto convertUserEntityToUserDto(User user) { + UserDto userDto = new UserDto(); + userDto.setId(user.getId()); + userDto.setUsername(user.getUsername()); + + return userDto; + } + + private User convertUserDtoToUserEntity(UserDto userDto) { + User user = new User(); + user.setId(userDto.getId()); + user.setUsername(userDto.getUsername()); + user.setPassword(userDto.getPassword()); + + return user; + } + +} \ 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 index b9ee1af..71c8b99 100644 --- a/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/Project.java +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/Project.java @@ -2,33 +2,26 @@ import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; +import org.hibernate.annotations.GenericGenerator; + +import lombok.Data; + +@Data @Entity @Table(name = "project") public class Project { - @Id - @Column(name = "id") - private String id; - @Column(name = "name", length = 200, unique = true) - private String name; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getName() { - return name; - } + @Id + @Column(name = "id", length = 40) + @GeneratedValue(generator = "system-uuid") + @GenericGenerator(name = "system-uuid", strategy = "uuid2") + private String id; - public void setName(String name) { - this.name = name; - } + @Column(name = "name", nullable = false, unique = true) + private String name; } \ No newline at end of file diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/Task.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/Task.java index 0a43e2c..c33b674 100644 --- a/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/Task.java +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/Task.java @@ -2,72 +2,46 @@ import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; import javax.persistence.Table; +import org.hibernate.annotations.GenericGenerator; + +import lombok.Data; + +@Data @Entity @Table(name = "task") public class Task { @Id - @Column(name = "id") + @Column(name = "id", length = 40) + @GeneratedValue(generator = "system-uuid") + @GenericGenerator(name = "system-uuid", strategy = "uuid2") private String id; - @Column(name = "title", length = 250, nullable = false) - private String title; - @Column(name = "description") - private String description; - @Column(name = "status", nullable = false) - private String status; - @Column(name = "project_id", nullable = false) - private String projectId; - @Column(name = "user_id", nullable = false) - private String userId; - - public String getId() { - return id; - } - - public void setId(String 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 String getStatus() { - return status; - } + @Column(name = "title", nullable = false) + private String title; - public void setStatus(String status) { - this.status = status; - } + @Column(name = "description", nullable = true) + private String description; - public String getProjectId() { - return projectId; - } + @Enumerated(EnumType.STRING) + @Column(name = "status", length = 40, nullable = false) + private TaskStatusEnum status; - public void setProjectId(String projectId) { - this.projectId = projectId; - } + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "project_id", nullable = false) + private Project project; - public String getUserId() { - return userId; - } + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + private User user; - public void setUserId(String userId) { - this.userId = userId; - } } \ No newline at end of file diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/TaskStatusEnum.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/TaskStatusEnum.java new file mode 100644 index 0000000..db913ba --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/TaskStatusEnum.java @@ -0,0 +1,5 @@ +package com.accenture.codingtest.springbootcodingtest.entity; + +public enum TaskStatusEnum { + NOT_STARTED, IN_PROGRESS, READY_FOR_TEST, COMPLETED +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/User.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/User.java index be4d9f9..ca70d77 100644 --- a/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/User.java +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/User.java @@ -2,43 +2,29 @@ import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; +import org.hibernate.annotations.GenericGenerator; + +import lombok.Data; + +@Data @Entity @Table(name = "user") public class User { @Id - @Column(name = "id") + @Column(name = "id", length = 40) + @GeneratedValue(generator = "system-uuid") + @GenericGenerator(name = "system-uuid", strategy = "uuid2") private String id; - @Column(name = "user_name", length = 150, unique = true) - private String userName; - @Column(name = "password", length = 50) - private String password; - - public String getId() { - return id; - } - public void setId(String id) { - this.id = id; - } + @Column(name = "username", length = 100, nullable = false, unique = true) + private String username; - 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; - } + @Column(name = "password", length = 150, nullable = false) + private String password; } \ No newline at end of file diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/exception/BusinessException.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/exception/BusinessException.java new file mode 100644 index 0000000..2a9c88f --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/exception/BusinessException.java @@ -0,0 +1,62 @@ +package com.accenture.codingtest.springbootcodingtest.entity.exception; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.util.StringUtils; + +public class BusinessException extends RuntimeException { + + private final String code; + private Map params = new HashMap<>(); + + public BusinessException(String code) { + this.code = code; + } + + public BusinessException(String code, String message) { + super(message); + this.code = code; + } + + public BusinessException(String code, Map params) { + this.code = code; + this.params = params; + } + + public BusinessException(String code, String message, Map params) { + super(message); + this.code = code; + this.params = params; + } + + public void put(String key, String value) { + this.params.put(key, value); + } + + public String getMessage() { + StringBuilder builder = new StringBuilder(); + builder.append("["); + builder.append(this.code); + builder.append("]"); + if (StringUtils.hasText(super.getMessage())) { + builder.append(" - "); + builder.append(super.getMessage()); + } + + return builder.toString(); + } + + public String getOriginalMessage() { + return super.getMessage(); + } + + public String getCode() { + return this.code; + } + + public Map getParams() { + return this.params; + } + +} \ No newline at end of file diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/exception/RecordAlreadyExistException.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/exception/RecordAlreadyExistException.java new file mode 100644 index 0000000..98454cf --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/exception/RecordAlreadyExistException.java @@ -0,0 +1,14 @@ +package com.accenture.codingtest.springbootcodingtest.entity.exception; + +public class RecordAlreadyExistException extends RecordException { + + public RecordAlreadyExistException() { + super("EXC-0001", "Record Already Exist"); + } + + public RecordAlreadyExistException(String value) { + this(); + this.put("key", value); + } + +} \ No newline at end of file diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/exception/RecordException.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/exception/RecordException.java new file mode 100644 index 0000000..ea1e4d5 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/exception/RecordException.java @@ -0,0 +1,20 @@ +package com.accenture.codingtest.springbootcodingtest.entity.exception; + +public class RecordException extends BusinessException { + + public RecordException(String code, String message) { + super(code, message); + } + + public String getMessage() { + StringBuilder builder = new StringBuilder(super.getMessage()); + if (this.getParams().containsKey("key")) { + builder.append(" ("); + builder.append(this.getParams().get("key")); + builder.append(")"); + } + + return builder.toString(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/exception/RecordNotFoundException.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/exception/RecordNotFoundException.java new file mode 100644 index 0000000..cbf5d8c --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/exception/RecordNotFoundException.java @@ -0,0 +1,14 @@ +package com.accenture.codingtest.springbootcodingtest.entity.exception; + +public class RecordNotFoundException extends RecordException { + + public RecordNotFoundException() { + super("EXC-0002", "Record Not Found"); + } + + public RecordNotFoundException(String value) { + this(); + this.put("key", value); + } + +} \ No newline at end of file diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/exception/handler/BusinessExceptionTranslator.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/exception/handler/BusinessExceptionTranslator.java new file mode 100644 index 0000000..6a50d5f --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/exception/handler/BusinessExceptionTranslator.java @@ -0,0 +1,25 @@ +package com.accenture.codingtest.springbootcodingtest.entity.exception.handler; + +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.http.HttpStatus; + +import com.accenture.codingtest.springbootcodingtest.entity.exception.BusinessException; +import com.accenture.codingtest.springbootcodingtest.entity.model.ErrorDto; + +@ControllerAdvice +public class BusinessExceptionTranslator { + + public BusinessExceptionTranslator() { + + } + + @ResponseBody + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ExceptionHandler({ BusinessException.class }) + public ErrorDto handleBusinessException(BusinessException ex) { + return new ErrorDto("BusinessException", ex.getCode(), ex.getMessage(), ex.getParams()); + } +} \ No newline at end of file diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/model/ErrorDto.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/model/ErrorDto.java new file mode 100644 index 0000000..08abfb7 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/model/ErrorDto.java @@ -0,0 +1,43 @@ +package com.accenture.codingtest.springbootcodingtest.entity.model; + +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonInclude; + +import lombok.Data; + +@Data +public class ErrorDto { + + private static final long serialVersionUID = 1L; + + private String type; + + private String code; + + private String message; + + @JsonInclude(JsonInclude.Include.NON_NULL) + private String host; + + @JsonInclude(JsonInclude.Include.NON_NULL) + private Map params; + + public ErrorDto() { + + } + + public ErrorDto(String type, String code, String message, Map params) { + this.type = type; + this.code = code; + this.message = message; + this.params = params; + } + + public ErrorDto(String type, String code, String message) { + this.type = type; + this.code = code; + this.message = message; + } + +} \ No newline at end of file diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/model/ProjectDto.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/model/ProjectDto.java new file mode 100644 index 0000000..432df6a --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/model/ProjectDto.java @@ -0,0 +1,11 @@ +package com.accenture.codingtest.springbootcodingtest.entity.model; + +import lombok.Data; + +@Data +public class ProjectDto { + private String id; + + private String name; + +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/model/TaskDto.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/model/TaskDto.java new file mode 100644 index 0000000..bac5b2e --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/model/TaskDto.java @@ -0,0 +1,23 @@ +package com.accenture.codingtest.springbootcodingtest.entity.model; + +import lombok.Data; + +@Data +public class TaskDto { + + private String id; + + private String title; + + private String description; + + private String status; + + private String projectId; + + private String projectName; + + private String userId; + + private String username; +} diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/model/UserDto.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/model/UserDto.java new file mode 100644 index 0000000..fb080de --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/entity/model/UserDto.java @@ -0,0 +1,13 @@ +package com.accenture.codingtest.springbootcodingtest.entity.model; + +import lombok.Data; + +@Data +public class UserDto { + + private String id; + + private String username; + + private String password; +} 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..eb118f5 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/ProjectRepository.java @@ -0,0 +1,18 @@ +package com.accenture.codingtest.springbootcodingtest.repository; + +import java.util.List; +import java.util.Optional; + +import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.stereotype.Repository; + +import com.accenture.codingtest.springbootcodingtest.entity.Project; + +@Repository +public interface ProjectRepository extends PagingAndSortingRepository { + + List findAll(); + + Optional findById(String id); + +} \ No newline at end of file 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..7d940be --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/TaskRepository.java @@ -0,0 +1,22 @@ +package com.accenture.codingtest.springbootcodingtest.repository; + +import java.util.List; +import java.util.Optional; + +import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.stereotype.Repository; + +import com.accenture.codingtest.springbootcodingtest.entity.Task; + +@Repository +public interface TaskRepository extends PagingAndSortingRepository { + + List findAll(); + + List findByProjectId(String projectId); + + List findByUserId(String userId); + + Optional findById(String id); + +} \ No newline at end of file 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..a318e43 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/repository/UserRepository.java @@ -0,0 +1,20 @@ +package com.accenture.codingtest.springbootcodingtest.repository; + +import java.util.List; +import java.util.Optional; + +import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.stereotype.Repository; + +import com.accenture.codingtest.springbootcodingtest.entity.User; + +@Repository +public interface UserRepository extends PagingAndSortingRepository { + + List findAll(); + + Optional findById(String userId); + + Optional findByUsername(String username); + +} \ 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..29df640 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/ProjectService.java @@ -0,0 +1,16 @@ +package com.accenture.codingtest.springbootcodingtest.service; + +import java.util.List; +import java.util.Optional; + +import com.accenture.codingtest.springbootcodingtest.entity.Project; + +public interface ProjectService { + + Project save(Project project); + + List findAll(); + + Optional findById(String id); + +} \ No newline at end of file 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..340b0f3 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/TaskService.java @@ -0,0 +1,22 @@ +package com.accenture.codingtest.springbootcodingtest.service; + +import java.util.List; +import java.util.Optional; + +import com.accenture.codingtest.springbootcodingtest.entity.Task; + +public interface TaskService { + + Task save(Task task); + + Optional findById(String id); + + List findAll(); + + List findByProjectId(String projectId); + + List findByUserId(String userId); + + Task update(Task task, String id); + +} \ No newline at end of file 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..8b8f5ac --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/UserService.java @@ -0,0 +1,22 @@ +package com.accenture.codingtest.springbootcodingtest.service; + +import java.util.List; +import java.util.Optional; + +import com.accenture.codingtest.springbootcodingtest.entity.User; + +public interface UserService { + + List findAll(); + + Optional findByUserId(String userId); + + Optional findByUsername(String username); + + User save(User user); + + User update(User user, String userId); + + void delete(String userId); + +} \ No newline at end of file diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/service/impl/ProjectServiceImpl.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/impl/ProjectServiceImpl.java new file mode 100644 index 0000000..969bb84 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/impl/ProjectServiceImpl.java @@ -0,0 +1,33 @@ +package com.accenture.codingtest.springbootcodingtest.service.impl; + +import java.util.List; +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.accenture.codingtest.springbootcodingtest.entity.Project; +import com.accenture.codingtest.springbootcodingtest.repository.ProjectRepository; +import com.accenture.codingtest.springbootcodingtest.service.ProjectService; + +@Service +public class ProjectServiceImpl implements ProjectService { + + @Autowired + private ProjectRepository projectRepository; + + @Override + public Project save(Project project) { + return projectRepository.save(project); + } + + @Override + public List findAll() { + return projectRepository.findAll(); + } + + @Override + public Optional findById(String id) { + return projectRepository.findById(id); + } +} \ No newline at end of file diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/service/impl/TaskServiceImpl.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/impl/TaskServiceImpl.java new file mode 100644 index 0000000..6a53932 --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/impl/TaskServiceImpl.java @@ -0,0 +1,54 @@ +package com.accenture.codingtest.springbootcodingtest.service.impl; + +import java.util.List; +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +import com.accenture.codingtest.springbootcodingtest.entity.Task; +import com.accenture.codingtest.springbootcodingtest.entity.exception.RecordNotFoundException; +import com.accenture.codingtest.springbootcodingtest.repository.TaskRepository; +import com.accenture.codingtest.springbootcodingtest.service.TaskService; + +@Repository +public class TaskServiceImpl implements TaskService { + + @Autowired + private TaskRepository taskRepository; + + @Override + public Task save(Task task) { + return taskRepository.save(task); + } + + @Override + public Optional findById(String id) { + return taskRepository.findById(id); + } + + @Override + public List findAll() { + return taskRepository.findAll(); + } + + @Override + public List findByProjectId(String projectId) { + return taskRepository.findByProjectId(projectId); + } + + @Override + public List findByUserId(String userId) { + return taskRepository.findByUserId(userId); + } + + @Override + public Task update(Task task, String id) { + Task existingTask = taskRepository.findById(id).orElseThrow(RecordNotFoundException::new); + existingTask.setTitle(task.getTitle()); + existingTask.setDescription(task.getDescription()); + existingTask.setStatus(task.getStatus()); + + return taskRepository.save(existingTask); + } +} \ No newline at end of file diff --git a/src/main/java/com/accenture/codingtest/springbootcodingtest/service/impl/UserServiceImpl.java b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..beeb36f --- /dev/null +++ b/src/main/java/com/accenture/codingtest/springbootcodingtest/service/impl/UserServiceImpl.java @@ -0,0 +1,63 @@ +package com.accenture.codingtest.springbootcodingtest.service.impl; + +import java.util.List; +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.accenture.codingtest.springbootcodingtest.entity.User; +import com.accenture.codingtest.springbootcodingtest.entity.exception.RecordAlreadyExistException; +import com.accenture.codingtest.springbootcodingtest.entity.exception.RecordNotFoundException; +import com.accenture.codingtest.springbootcodingtest.repository.UserRepository; +import com.accenture.codingtest.springbootcodingtest.service.UserService; + +@Service +public class UserServiceImpl implements UserService { + + @Autowired + private UserRepository userRepository; + + @Override + public List findAll() { + return userRepository.findAll(); + } + + @Override + public Optional findByUserId(String userId) { + return userRepository.findById(userId); + } + + @Override + public Optional findByUsername(String username) { + return userRepository.findByUsername(username); + } + + @Override + public User save(User user) { + Optional existingUserOptional = userRepository.findByUsername(user.getUsername()); + if (existingUserOptional.isPresent()) { + throw new RecordAlreadyExistException(); + } + + return userRepository.save(user); + } + + @Override + public User update(User user, String userId) { + Optional existingUserOptional = userRepository.findById(userId); + if (existingUserOptional.isEmpty()) { + throw new RecordNotFoundException(); + } + + User existingUser = existingUserOptional.get(); + existingUser.setUsername(user.getUsername()); + return userRepository.save(existingUser); + } + + @Override + public void delete(String userId) { + User existingUser = userRepository.findById(userId).orElseThrow(RecordNotFoundException::new); + userRepository.deleteById(existingUser.getId()); + } +} \ No newline at end of file