+29
-5
@@ -1,10 +1,13 @@
|
||||
package br.com.tasknoteapp.java_api.controller;
|
||||
|
||||
import br.com.tasknoteapp.java_api.exception.UserAlreadyExistsException;
|
||||
import br.com.tasknoteapp.java_api.exception.UserNotFoundException;
|
||||
import br.com.tasknoteapp.java_api.request.LoginRequest;
|
||||
import br.com.tasknoteapp.java_api.response.JwtAuthenticationResponse;
|
||||
import br.com.tasknoteapp.java_api.service.AuthService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
@@ -17,9 +20,12 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/** This class contains resources for handling authentication. */
|
||||
@RestController
|
||||
@RequestMapping("/auth")
|
||||
@Tag(name = "Authentication", description = "Authentication controller.")
|
||||
@Tag(
|
||||
name = "Authentication",
|
||||
description = "Authentication resources to handle user authentication.")
|
||||
@AllArgsConstructor
|
||||
public class AuthenticationController {
|
||||
|
||||
@@ -29,7 +35,8 @@ public class AuthenticationController {
|
||||
* Authenticate a user given his email and password.
|
||||
*
|
||||
* @param loginRequest User data containing email and password.
|
||||
* @return OK if authenticated, 401 - Unauthorized otherwise
|
||||
* @return JwtAuthenticationResponse with token created.
|
||||
* @throws UserNotFoundException if user not found
|
||||
*/
|
||||
@PostMapping(path = "/signin", consumes = "application/json", produces = "application/json")
|
||||
@Operation(
|
||||
@@ -37,7 +44,18 @@ public class AuthenticationController {
|
||||
description = "SigIn an existing user given his email and password",
|
||||
responses = {
|
||||
@ApiResponse(responseCode = "200", description = "User successfully logged in"),
|
||||
@ApiResponse(responseCode = "400", description = "Wrong or missing information"),
|
||||
@ApiResponse(
|
||||
responseCode = "400",
|
||||
description = "Wrong or missing information",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "403",
|
||||
description = "Forbidden. Access Denied",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "User not found",
|
||||
content = @Content(schema = @Schema(implementation = Void.class)))
|
||||
})
|
||||
public JwtAuthenticationResponse signin(@RequestBody @Valid LoginRequest loginRequest) {
|
||||
String token = authService.signin(loginRequest);
|
||||
@@ -57,8 +75,14 @@ public class AuthenticationController {
|
||||
description = "Signup a new user given his email and password",
|
||||
responses = {
|
||||
@ApiResponse(responseCode = "201", description = "User successfully created and saved"),
|
||||
@ApiResponse(responseCode = "400", description = "Wrong or missing information"),
|
||||
@ApiResponse(responseCode = "409", description = "User already exists")
|
||||
@ApiResponse(
|
||||
responseCode = "400",
|
||||
description = "Wrong or missing information",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "409",
|
||||
description = "User already exists",
|
||||
content = @Content(schema = @Schema(implementation = Void.class)))
|
||||
})
|
||||
public ResponseEntity<JwtAuthenticationResponse> signup(
|
||||
@RequestBody @Valid LoginRequest loginRequest) {
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
package br.com.tasknoteapp.java_api.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/rest/some")
|
||||
public class SomeController {
|
||||
|
||||
@GetMapping
|
||||
public String some() {
|
||||
return "Some";
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,18 @@
|
||||
package br.com.tasknoteapp.java_api.controller;
|
||||
|
||||
import br.com.tasknoteapp.java_api.entity.TaskEntity;
|
||||
import br.com.tasknoteapp.java_api.exception.TaskNotFoundException;
|
||||
import br.com.tasknoteapp.java_api.request.TaskPatchRequest;
|
||||
import br.com.tasknoteapp.java_api.request.TaskRequest;
|
||||
import br.com.tasknoteapp.java_api.response.TaskResponse;
|
||||
import br.com.tasknoteapp.java_api.service.TaskService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -19,27 +27,123 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/** This class contains resources for handling tasks. */
|
||||
@RestController
|
||||
@RequestMapping("/rest/tasks")
|
||||
@Tag(name = "Tasks", description = "Tasks resources to handle user tasks and urls.")
|
||||
@AllArgsConstructor
|
||||
public class TaskController {
|
||||
|
||||
private final TaskService taskService;
|
||||
|
||||
/**
|
||||
* Get all tasks.
|
||||
*
|
||||
* @return List of TaskResponse with all found tasks and its urls, if any.
|
||||
*/
|
||||
@GetMapping
|
||||
@Operation(
|
||||
summary = "Get all tasks",
|
||||
description = "Get all tasks for the current user and its urls, if any",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "Tasks successfully retrieved",
|
||||
content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
schema = @Schema(implementation = TaskResponse.class, type = "array"))),
|
||||
@ApiResponse(
|
||||
responseCode = "403",
|
||||
description = "Forbidden. Access Denied",
|
||||
content = @Content(schema = @Schema(implementation = Void.class)))
|
||||
})
|
||||
public List<TaskResponse> getAllTasks() {
|
||||
return taskService.getAllTasks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Patch a task.
|
||||
*
|
||||
* @param id The task id to be patched.
|
||||
* @param taskRequest Task data to be patched, including optionally its urls.
|
||||
* @return TaskResponse containing data that was updated.
|
||||
* @throws TaskNotFoundException when task not found.
|
||||
*/
|
||||
@PatchMapping("/{id}")
|
||||
@Operation(
|
||||
summary = "Patch a task",
|
||||
description = "Patch a task and all its urls. Option to patch only the urls.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "Task successfully patched",
|
||||
content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
schema = @Schema(implementation = TaskResponse.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "403",
|
||||
description = "Forbidden. Access Denied",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "Task not found",
|
||||
content = @Content(schema = @Schema(implementation = Void.class)))
|
||||
})
|
||||
public ResponseEntity<TaskResponse> putTask(
|
||||
@PathVariable Long id, @RequestBody @Valid TaskPatchRequest taskRequest) {
|
||||
@Parameter(
|
||||
name = "id",
|
||||
in = ParameterIn.PATH,
|
||||
description = "Task id to be patched.",
|
||||
required = true,
|
||||
schema = @Schema(type = "integer", format = "int64"))
|
||||
@PathVariable
|
||||
Long id,
|
||||
@io.swagger.v3.oas.annotations.parameters.RequestBody(
|
||||
description = "Task data to be patched, including optionally its urls.",
|
||||
required = true)
|
||||
@RequestBody
|
||||
@Valid
|
||||
TaskPatchRequest taskRequest) {
|
||||
return ResponseEntity.ok(taskService.patchTask(id, taskRequest));
|
||||
}
|
||||
|
||||
// https://restfulapi.net/rest-put-vs-post/
|
||||
/**
|
||||
* Create a task.
|
||||
*
|
||||
* @param taskRequest Task data to be created, including optionally its urls. Following RESTful
|
||||
* API pattern from https://restfulapi.net/rest-put-vs-post/.
|
||||
* @return TaskResponse containing data that was created.
|
||||
*/
|
||||
@PostMapping
|
||||
public ResponseEntity<TaskResponse> postTasks(@RequestBody @Valid TaskRequest taskRequest) {
|
||||
@Operation(
|
||||
summary = "Create a task",
|
||||
description = "Create a task and all its urls.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "201",
|
||||
description = "Task successfully crated.",
|
||||
content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
schema = @Schema(implementation = TaskResponse.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "400",
|
||||
description = "Wrong or missing information",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "403",
|
||||
description = "Forbidden. Access Denied",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
})
|
||||
public ResponseEntity<TaskResponse> postTasks(
|
||||
@io.swagger.v3.oas.annotations.parameters.RequestBody(
|
||||
description = "Task data to be created, including optionally its urls.",
|
||||
required = true)
|
||||
@RequestBody
|
||||
@Valid
|
||||
TaskRequest taskRequest) {
|
||||
TaskEntity createdTask = taskService.createTask(taskRequest);
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(TaskResponse.fromEntity(createdTask));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package br.com.tasknoteapp.java_api.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.util.List;
|
||||
|
||||
public record TaskPatchRequest(String description, Boolean done, List<TaskUrlPatchRequest> urls) {}
|
||||
/** This record represents a task patch payload. */
|
||||
@Schema(description = "Task patch payload.")
|
||||
public record TaskPatchRequest(
|
||||
@Schema(description = "Task description. Optional.") String description,
|
||||
@Schema(description = "Task done definition. Optional.") Boolean done,
|
||||
@Schema(description = "Task urls. Optional.") List<TaskUrlPatchRequest> urls) {}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
package br.com.tasknoteapp.java_api.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
public record TaskRequest(@NotNull String description, List<String> urls) {}
|
||||
/** This record represents a task request to be created. */
|
||||
@Schema(description = "Task request to be created.")
|
||||
public record TaskRequest(
|
||||
@Schema(description = "Task description.") @NotNull String description,
|
||||
@Schema(description = "Task urls. Optional.") List<String> urls) {}
|
||||
|
||||
@@ -2,12 +2,26 @@ package br.com.tasknoteapp.java_api.response;
|
||||
|
||||
import br.com.tasknoteapp.java_api.entity.TaskEntity;
|
||||
import br.com.tasknoteapp.java_api.entity.TaskUrlEntity;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public record TaskResponse(Long id, String description, Boolean done, List<TaskUrlResponse> urls) {
|
||||
/** This record represents a task and its urls object to be returned. */
|
||||
@Schema(description = "This record represents a task and its urls object to be returned.")
|
||||
public record TaskResponse(
|
||||
@Schema(description = "The id of the task", example = "1") Long id,
|
||||
@Schema(description = "The description of the task", example = "Task 1") String description,
|
||||
@Schema(description = "The done status of the task", example = "false") Boolean done,
|
||||
@Schema(description = "The urls of the task, zero, one or more.", example = "[]")
|
||||
List<TaskUrlResponse> urls) {
|
||||
|
||||
/**
|
||||
* Creates a TaskResponse given a TaskEntity and its Urls.
|
||||
*
|
||||
* @param entity The TaskEntity source data.
|
||||
* @return TaskResponse instance with all task data and urls, if any.
|
||||
*/
|
||||
public static TaskResponse fromEntity(TaskEntity entity) {
|
||||
List<TaskUrlEntity> urls = entity.getUrls();
|
||||
List<TaskUrlResponse> urlsResponse = new ArrayList<>();
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
package br.com.tasknoteapp.java_api.response;
|
||||
|
||||
public record TaskUrlResponse(Long id, String url) {}
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/** This record represents a task url object. */
|
||||
@Schema(description = "This record represents a task url object.")
|
||||
public record TaskUrlResponse(
|
||||
@Schema(description = "Task url id", example = "1") Long id,
|
||||
@Schema(description = "Task url link", example = "http://duckduckgo.com") String url) {}
|
||||
|
||||
@@ -5,6 +5,7 @@ import br.com.tasknoteapp.java_api.request.LoginRequest;
|
||||
import java.util.Optional;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
|
||||
/** This interface contains methods for handling user Authentication. */
|
||||
public interface AuthService {
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
/** This interface contains methods for handling user JWT tokens. */
|
||||
public interface JwtService {
|
||||
|
||||
public String getEmailFromToken(String token);
|
||||
|
||||
@@ -6,6 +6,7 @@ import br.com.tasknoteapp.java_api.request.TaskRequest;
|
||||
import br.com.tasknoteapp.java_api.response.TaskResponse;
|
||||
import java.util.List;
|
||||
|
||||
/** This interface contains methods for handling user user Tasks. */
|
||||
public interface TaskService {
|
||||
|
||||
public List<TaskResponse> getAllTasks();
|
||||
|
||||
@@ -2,6 +2,7 @@ package br.com.tasknoteapp.java_api.service;
|
||||
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
|
||||
/** This interface contains methods for handling user details withing Spring Auth. */
|
||||
public interface UserService {
|
||||
UserDetailsService userDetailsService();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/** This class contains the implementation for the Auth Service class. */
|
||||
@Slf4j
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
|
||||
@@ -12,8 +12,9 @@ import javax.crypto.SecretKey;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/** This class contains the implementation for the Jwt Service class. */
|
||||
@Service
|
||||
public class JwtServiceImpl implements JwtService {
|
||||
class JwtServiceImpl implements JwtService {
|
||||
|
||||
private final long SECOND = 1000;
|
||||
private final long MINUTE = SECOND * 60;
|
||||
|
||||
@@ -22,6 +22,7 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/** This class contains the implementation for the Task Service class. */
|
||||
@Slf4j
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
|
||||
+2
-1
@@ -9,9 +9,10 @@ import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/** This class contains the implementation for the User Service class. */
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class UserServiceImpl implements UserService {
|
||||
class UserServiceImpl implements UserService {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user