Skip to content
Merged
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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ This project is designed to be easily testable by anyone, whether they are a dev

### **2. Interactive API Testing (Swagger)**
* Navigate to `http://localhost:8080/swagger-ui.html`.
* Explore all documented REST endpoints.
* Explore all documented REST endpoints with **detailed operation descriptions** and **predefined API responses**.
* Click **"Try it out"** on any endpoint (like `POST /api/tasks`) to send real JSON requests and see the live responses directly in your browser.

### **3. Database Inspection (PostgreSQL)**
Expand Down Expand Up @@ -86,7 +86,7 @@ To run the tests locally, use:
* **Quick Status Toggle**: Instantly mark tasks as Done or Undone from the main list view.
* **User Lifecycle**: Public registration and secure login system.
* **Task Metadata**: Categorize tasks by **Status** (TODO, DONE) and **Priority** (HIGH, MEDIUM, LOW).
* **RESTful API**: Comprehensive API endpoints for programmatic task management, fully documented with Swagger.
* **RESTful API**: Comprehensive API endpoints for programmatic task management, fully documented with professional-grade OpenAPI descriptions and responses.

---

Expand Down
39 changes: 34 additions & 5 deletions src/main/java/com/lucc/taskmanager/controller/TaskController.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
import jakarta.validation.Valid;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
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.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
Expand All @@ -25,35 +29,60 @@ public TaskController(TaskService taskService)
}

@GetMapping
@Operation(summary = "Get all tasks for the logged-in user")
@Operation(summary = "Get all tasks for the logged-in user", description = "Retrieves a list of all tasks associated with the currently authenticated user.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Successfully retrieved tasks"),
@ApiResponse(responseCode = "401", description = "You are not authorized to view the resource", content = @Content)
})
public List<Task> getTaskByUser(@AuthenticationPrincipal @Parameter(hidden = true) User user)
{
return taskService.getTasksByUser(user);
}

@PostMapping
@Operation(summary = "Add a new task for the logged-in user")
@Operation(summary = "Add a new task", description = "Creates a new task for the currently authenticated user.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Successfully created the task", content = @Content(schema = @Schema(implementation = Task.class))),
@ApiResponse(responseCode = "400", description = "Invalid input data", content = @Content),
@ApiResponse(responseCode = "401", description = "You are not authorized to create a task", content = @Content)
})
public Task addTask(@Valid @RequestBody Task task, @AuthenticationPrincipal @Parameter(hidden = true) User user)
{
return taskService.addTask(task, user);
}

@PutMapping("/{taskId}")
@Operation(summary = "Update an existing task")
@Operation(summary = "Update an existing task", description = "Updates the details of an existing task identified by its ID. Users can only update their own tasks.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Successfully updated the task", content = @Content(schema = @Schema(implementation = Task.class))),
@ApiResponse(responseCode = "400", description = "Invalid task ID or input data", content = @Content),
@ApiResponse(responseCode = "401", description = "You are not authorized to update this task", content = @Content),
@ApiResponse(responseCode = "404", description = "Task not found", content = @Content)
})
public Task updateTask(@PathVariable int taskId, @Valid @RequestBody Task task, @AuthenticationPrincipal @Parameter(hidden = true) User user)
{
return taskService.updateTask(taskId, task, user);
}

@DeleteMapping("/{taskId}")
@Operation(summary = "Delete a task by ID")
@Operation(summary = "Delete a task by ID", description = "Removes a task from the system identified by its ID. Users can only delete their own tasks.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Successfully deleted the task"),
@ApiResponse(responseCode = "401", description = "You are not authorized to delete this task", content = @Content),
@ApiResponse(responseCode = "404", description = "Task not found", content = @Content)
})
public void deleteTask(@PathVariable int taskId, @AuthenticationPrincipal @Parameter(hidden = true) User user)
{
taskService.deleteTask(taskId, user);
}

@PatchMapping("/{taskId}/toggle")
@Operation(summary = "Toggle task status between TODO and DONE")
@Operation(summary = "Toggle task status", description = "Toggles the status of a task between 'TODO' and 'DONE'. Also manages the 'completionDate' automatically.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Successfully toggled task status", content = @Content(schema = @Schema(implementation = Task.class))),
@ApiResponse(responseCode = "401", description = "You are not authorized to toggle this task", content = @Content),
@ApiResponse(responseCode = "404", description = "Task not found", content = @Content)
})
public Task toggleTaskStatus(@PathVariable int taskId, @AuthenticationPrincipal @Parameter(hidden = true) User user)
{
return taskService.toggleTaskStatus(taskId, user);
Expand Down
18 changes: 16 additions & 2 deletions src/main/java/com/lucc/taskmanager/controller/UserController.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
import com.lucc.taskmanager.service.UserService;
import jakarta.validation.Valid;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.ArraySchema;
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.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
Expand All @@ -24,14 +29,23 @@ public UserController(UserService userService)
}

@GetMapping
@Operation(summary = "Get all users (Admin only)")
@Operation(summary = "Get all users", description = "Retrieves a comprehensive list of all registered users in the system. This endpoint is restricted to users with the ADMIN role.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Successfully retrieved users", content = @Content(array = @ArraySchema(schema = @Schema(implementation = User.class)))),
@ApiResponse(responseCode = "403", description = "Access denied - Admin role required", content = @Content)
})
public List<User> getUsers()
{
return userService.getUsers();
}

@PostMapping
@Operation(summary = "Add a new user (Admin only)")
@Operation(summary = "Add a new user", description = "Creates a new user account. This endpoint is restricted to users with the ADMIN role.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Successfully created the user", content = @Content(schema = @Schema(implementation = User.class))),
@ApiResponse(responseCode = "400", description = "Invalid user data provided", content = @Content),
@ApiResponse(responseCode = "403", description = "Access denied - Admin role required", content = @Content)
})
public User addUser(@Valid @RequestBody User user)
{
return userService.addUser(user);
Expand Down
Loading