Skip to content

Feature/core functions #20

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
544 changes: 544 additions & 0 deletions docs/Assignment.postman_collection.json

Large diffs are not rendered by default.

45 changes: 44 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,62 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.accenture.codingtest.springbootcodingtest.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
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.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SecurityConfig {

@Bean
public AuthenticationManager authenticationManager(HttpSecurity http, UserDetailsService customUserDetailsService) throws Exception {
return http.getSharedObject(AuthenticationManagerBuilder.class)
.userDetailsService(customUserDetailsService)
.passwordEncoder(bCryptPasswordEncoder())
.and()
.build();
}

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/v1/users/**").hasRole("ADMIN")
.antMatchers(HttpMethod.POST, "/api/v1/projects").hasRole("PRODUCT_OWNER")
.antMatchers(HttpMethod.POST, "/api/v1/tasks").hasRole("PRODUCT_OWNER")
.antMatchers(HttpMethod.POST, "/api/v1/projects/assignTasks/{project_id}/{user_id}").hasRole("PRODUCT_OWNER")
.antMatchers(HttpMethod.PATCH, "/api/v1/tasks/{task_id}").hasRole("MEMBER")
.antMatchers(HttpMethod.PUT, "/api/v1/tasks/{task_id}").hasRole("MEMBER")
.anyRequest()
.authenticated()
.and()
.httpBasic();

return http.build();
}

@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.accenture.codingtest.springbootcodingtest.controller;

import com.accenture.codingtest.springbootcodingtest.model.ProjectDTO;
import com.accenture.codingtest.springbootcodingtest.service.ProjectService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@RestController
@RequestMapping("/api/v1/projects")
public class ProjectController {

private final ProjectService projectService;

ProjectController(ProjectService projectService) {
this.projectService = projectService;
}

@GetMapping
private ResponseEntity<List<ProjectDTO>> getProjectList() {
if (!projectService.getAllProjects().isEmpty()) {
return new ResponseEntity<>(projectService.getAllProjects(), HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
}

@GetMapping("/{project_id}")
private ResponseEntity<ProjectDTO> getProject(@PathVariable("project_id") UUID projectId) {
ProjectDTO project = projectService.getProject(projectId);
return new ResponseEntity<>(project, HttpStatus.OK);
}

@PostMapping
private ResponseEntity<ProjectDTO> saveProject(@RequestBody @Valid ProjectDTO projectDTO) {
return new ResponseEntity<>(projectService.createProject(projectDTO), HttpStatus.CREATED);
}

@PutMapping("/{project_id}")
private ResponseEntity<ProjectDTO> updateProjectByPUT(@PathVariable("project_id") UUID projectId, @RequestBody @Valid ProjectDTO projectDTO) {
return new ResponseEntity<>(projectService.updateProjectByPUT(projectId, projectDTO), HttpStatus.OK);
}

@PatchMapping("/{project_id}")
private ResponseEntity<?> updateProjectByPATCH(@PathVariable("project_id") UUID projectId, @RequestBody ProjectDTO projectDTO) {
return projectService.updateProjectByPatch(projectId, projectDTO);
}

@DeleteMapping("/{project_id}")
private ResponseEntity<?> deleteProject(@PathVariable("project_id") UUID projectId) {
projectService.deleteProject(projectId);
return new ResponseEntity<>("Project deleted successfully!", HttpStatus.OK);
}

@PostMapping("/assignTasks/{project_id}/{user_id}")
private ResponseEntity<?> assignTasksToTeamMember(@PathVariable("project_id") UUID projectId,
@PathVariable("user_id") UUID userID,
@RequestParam List<UUID> tasks){
return projectService.assignTasksToMembers(projectId, userID, tasks);
}

@GetMapping
private ResponseEntity<Map<String, Object>> getProjectWithPaginationAndSort(@RequestParam(required = false) String q,
@RequestParam(defaultValue = "0") int pageIndex,
@RequestParam(defaultValue = "3") int pageSize,
@RequestParam(defaultValue = "name") String sortBy,
@RequestParam(defaultValue = "ASC") String sortDirection){
return projectService.getProjectWithPaginationAndSort(q, pageIndex, pageSize, sortBy, sortDirection);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.accenture.codingtest.springbootcodingtest.controller;

import com.accenture.codingtest.springbootcodingtest.model.TaskDTO;
import com.accenture.codingtest.springbootcodingtest.service.TaskService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;
import java.util.UUID;

@RestController
@RequestMapping("/api/v1")
public class TaskController {

private final TaskService taskService;

public TaskController(TaskService taskService) {
this.taskService = taskService;
}

@GetMapping("/tasks")
private ResponseEntity<List<TaskDTO>> getTaskList() {
if (!taskService.getAllTasks().isEmpty()) {
return new ResponseEntity<>(taskService.getAllTasks(), HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
}

@GetMapping("/tasks/{task_id}")
private ResponseEntity<TaskDTO> getTask(@PathVariable("task_id") UUID taskId) {
TaskDTO task = taskService.getTask(taskId);
return new ResponseEntity<>(task, HttpStatus.OK);
}

@PostMapping("/tasks")
private ResponseEntity<TaskDTO> saveTask(@RequestBody @Valid TaskDTO taskDTO) {
return new ResponseEntity<>(taskService.createTask(taskDTO), HttpStatus.CREATED);
}

@PutMapping("/tasks/{task_id}")
private ResponseEntity<TaskDTO> updateTaskByPUT(@PathVariable("task_id") UUID taskId, @RequestBody @Valid TaskDTO taskDTO) {
return new ResponseEntity<>(taskService.updateTaskByPUT(taskId, taskDTO), HttpStatus.OK);
}

@PatchMapping("/tasks/{task_id}")
private ResponseEntity<?> updateTaskByPATCH(@PathVariable("task_id") UUID taskId, @RequestBody TaskDTO taskDTO) {
return taskService.updateTaskByPatch(taskId, taskDTO);
}

@DeleteMapping("/tasks/{task_id}")
private ResponseEntity<?> deleteTask(@PathVariable("task_id") UUID taskId) {
taskService.deleteTask(taskId);
return new ResponseEntity<>("Project deleted successfully!", HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.accenture.codingtest.springbootcodingtest.controller;

import com.accenture.codingtest.springbootcodingtest.model.UserDTO;
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 javax.validation.Valid;
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
private ResponseEntity<List<UserDTO>> getUserList() {
if (!userService.getAllUsers().isEmpty()) {
return new ResponseEntity<>(userService.getAllUsers(), HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
}

@GetMapping("/{user_id}")
private ResponseEntity<UserDTO> getUser(@PathVariable("user_id") UUID userId) {
UserDTO user = userService.getUser(userId);
return new ResponseEntity<>(user, HttpStatus.OK);
}

@PostMapping
private ResponseEntity<UserDTO> saveUser(@RequestBody @Valid UserDTO userDTO) {
return new ResponseEntity<>(userService.createUser(userDTO), HttpStatus.CREATED);
}

@PutMapping("/{user_id}")
private ResponseEntity<UserDTO> updateUserByPUT(@PathVariable("user_id") UUID userID, @RequestBody @Valid UserDTO userDTO) {
return new ResponseEntity<>(userService.updateUserByPUT(userID, userDTO), HttpStatus.OK);
}

@PatchMapping("/{user_id}")
private ResponseEntity<?> updateUserByPATCH(@PathVariable("user_id") UUID userID, @RequestBody UserDTO userDTO) {
return userService.updateUserByPatch(userID, userDTO);
}

@DeleteMapping("/{user_id}")
private ResponseEntity<?> deleteUser(@PathVariable("user_id") UUID userID) {
userService.deleteUser(userID);
return new ResponseEntity<>("user deleted successfully!", HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.accenture.codingtest.springbootcodingtest.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "project")
public class Project {

@Id
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Type(type = "uuid-char")
private UUID id;
@Column(nullable = false, unique = true)
private String name;
@OneToMany
private Set<User> User = new HashSet<>();

public Project(String name) {
this.name = name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.accenture.codingtest.springbootcodingtest.entity;

import com.accenture.codingtest.springbootcodingtest.util.TaskStatus;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;

import javax.persistence.*;
import java.util.UUID;

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "task")
public class Task {

@Id
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Type(type = "uuid-char")
private UUID id;
@Column(nullable = false)
private String title;
private String description;
@Enumerated(EnumType.STRING)
private TaskStatus status = TaskStatus.NOT_STARTED;
@ManyToOne
@JoinColumn(name = "project_id", nullable = false)
private Project project;
@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
private User user;

public Task(String title, String description, TaskStatus status, Project project, User user) {
this.title = title;
this.description = description;
this.status = status;
this.project = project;
this.user = user;
}

public Task(String title, String description, Project project, User user) {
this.title = title;
this.description = description;
this.project = project;
this.user = user;
}
}
Loading