From 0ad75edc4bddcf598d09c6c5a18c51bf16c590dd Mon Sep 17 00:00:00 2001 From: Dibbiii Date: Tue, 5 Aug 2025 01:10:32 +0200 Subject: [PATCH 1/2] Permit all OPTIONS requests in security configuration --- .../alessandra_alessandro/ketchapp/config/SecurityConfig.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/alessandra_alessandro/ketchapp/config/SecurityConfig.java b/src/main/java/com/alessandra_alessandro/ketchapp/config/SecurityConfig.java index b749bc6..166ba10 100644 --- a/src/main/java/com/alessandra_alessandro/ketchapp/config/SecurityConfig.java +++ b/src/main/java/com/alessandra_alessandro/ketchapp/config/SecurityConfig.java @@ -5,6 +5,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; +import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; @@ -77,6 +78,8 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) ) .authorizeHttpRequests(authorize -> authorize + .requestMatchers(HttpMethod.OPTIONS, "/**") + .permitAll() .requestMatchers("/**") .authenticated() .anyRequest() From 3dfc843d34f65e8fc57b3c8b1d6e3a8a9c50ac02 Mon Sep 17 00:00:00 2001 From: Dibbiii Date: Wed, 6 Aug 2025 07:25:16 +0200 Subject: [PATCH 2/2] Refactor Users and Tomatoes controllers and routes - Add UsersDto for user list responses, update UsersControllers and UsersRoutes to use it - Add email field to UserDto - Add getTomato endpoint and method for Tomatoes - Improve OpenAPI annotations and response schemas - Remove unused sendEmailNotification from PlanBuilderControllers - Update Kafka bootstrap server config to use service name --- .../controllers/PlanBuilderControllers.java | 64 --- .../controllers/TomatoesControllers.java | 45 ++- .../controllers/UsersControllers.java | 22 +- .../ketchapp/models/dto/UserDto.java | 8 +- .../ketchapp/models/dto/UsersDto.java | 18 + .../ketchapp/routes/TomatoesRoutes.java | 133 +++++-- .../ketchapp/routes/UsersRoutes.java | 365 ++++++++++++------ src/main/resources/application.properties | 2 +- 8 files changed, 426 insertions(+), 231 deletions(-) create mode 100644 src/main/java/com/alessandra_alessandro/ketchapp/models/dto/UsersDto.java diff --git a/src/main/java/com/alessandra_alessandro/ketchapp/controllers/PlanBuilderControllers.java b/src/main/java/com/alessandra_alessandro/ketchapp/controllers/PlanBuilderControllers.java index ec38110..1a2165f 100644 --- a/src/main/java/com/alessandra_alessandro/ketchapp/controllers/PlanBuilderControllers.java +++ b/src/main/java/com/alessandra_alessandro/ketchapp/controllers/PlanBuilderControllers.java @@ -136,70 +136,6 @@ private String resolveUserEmail(java.util.UUID userUUID) { return userEmail; } - /** - * Sends an email notification to the user with the Gemini API response. - * - * @param userEmail The email address of the user. - * @param geminiResponse The response DTO from the Gemini API. - */ - private void sendEmailNotification( - String userEmail, - PlanBuilderRequestDto geminiResponse - ) { - // Sanitize email: trim whitespace and remove newlines - String cleanEmail = userEmail == null - ? "" - : userEmail.trim().replaceAll("[\r\n]+", ""); - String mailUrl = - "http://151.61.228.91:8082/api/mail/" + - URLEncoder.encode(cleanEmail, StandardCharsets.UTF_8); - log.info( - "Sending email request to: {} with payload: {}", - mailUrl, - geminiResponse.toJson() - ); - - // Retrieve JWT from the current request context - String jwt = getCurrentJwtToken(); - if (jwt == null || jwt.isEmpty()) { - log.error( - "JWT token not found in the current request context. Email will not be sent." - ); - return; - } - - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(mailUrl)) - .header("Content-Type", "application/json") - .header("Authorization", "Bearer " + jwt) - .POST(HttpRequest.BodyPublishers.ofString(geminiResponse.toJson())) - .build(); - - try { - HttpClient client = HttpClient.newHttpClient(); - log.info("Sending email notification request..."); - HttpResponse response = client.send( - request, - HttpResponse.BodyHandlers.ofString() - ); - log.info( - "Email notification response status: {}, body: {}", - response.statusCode(), - response.body() - ); - if (response.statusCode() != 200) { - log.error( - "Error sending email notification: {}", - response.body() - ); - } else { - log.info("Email notification sent successfully."); - } - } catch (IOException | InterruptedException e) { - log.error("Exception sending email notification", e); - } - } - private String getCurrentJwtToken() { // Retrieve the JWT from the current HTTP request header try { diff --git a/src/main/java/com/alessandra_alessandro/ketchapp/controllers/TomatoesControllers.java b/src/main/java/com/alessandra_alessandro/ketchapp/controllers/TomatoesControllers.java index 7dcc656..7ae8269 100644 --- a/src/main/java/com/alessandra_alessandro/ketchapp/controllers/TomatoesControllers.java +++ b/src/main/java/com/alessandra_alessandro/ketchapp/controllers/TomatoesControllers.java @@ -7,22 +7,28 @@ import com.alessandra_alessandro.ketchapp.repositories.ActivitiesRepository; import com.alessandra_alessandro.ketchapp.repositories.TomatoesRepository; import com.alessandra_alessandro.ketchapp.utils.EntityMapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; +import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - -import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; @Service public class TomatoesControllers { - private static final Logger log = LoggerFactory.getLogger(TomatoesControllers.class); + + private static final Logger log = LoggerFactory.getLogger( + TomatoesControllers.class + ); final TomatoesRepository tomatoesRepository; private final ActivitiesRepository activitiesRepository; private final EntityMapper entityMapper; @Autowired - public TomatoesControllers(TomatoesRepository tomatoesRepository, ActivitiesRepository activitiesRepository, EntityMapper entityMapper) { + public TomatoesControllers( + TomatoesRepository tomatoesRepository, + ActivitiesRepository activitiesRepository, + EntityMapper entityMapper + ) { this.tomatoesRepository = tomatoesRepository; this.activitiesRepository = activitiesRepository; this.entityMapper = entityMapper; @@ -59,12 +65,27 @@ public TomatoDto createTomato(TomatoDto tomatoDto) { */ public List getActivitiesByTomatoId(Integer tomatoId) { log.info("Fetching activities for tomatoId: {}", tomatoId); - List activities = activitiesRepository.findByTomatoId(tomatoId); - log.info("Found {} activities for tomatoId {}", activities.size(), tomatoId); - List result = activities.stream() - .map(entityMapper::activityEntityToDto) - .collect(java.util.stream.Collectors.toList()); + List activities = activitiesRepository.findByTomatoId( + tomatoId + ); + log.info( + "Found {} activities for tomatoId {}", + activities.size(), + tomatoId + ); + List result = activities + .stream() + .map(entityMapper::activityEntityToDto) + .collect(java.util.stream.Collectors.toList()); log.info("Mapped activities to ActivityDto list: {}", result); return result; } -} \ No newline at end of file + + public TomatoDto getTomato(Integer id) { + log.info("Fetching TomatoDto by ID: {}", id); + TomatoEntity tomatoEntity = tomatoesRepository.findById(id); + TomatoDto result = entityMapper.tomatoEntityToDto(tomatoEntity); + log.info("Converted TomatoEntity to TomatoDto: {}", result); + return result; + } +} diff --git a/src/main/java/com/alessandra_alessandro/ketchapp/controllers/UsersControllers.java b/src/main/java/com/alessandra_alessandro/ketchapp/controllers/UsersControllers.java index 7c90711..3866128 100644 --- a/src/main/java/com/alessandra_alessandro/ketchapp/controllers/UsersControllers.java +++ b/src/main/java/com/alessandra_alessandro/ketchapp/controllers/UsersControllers.java @@ -41,22 +41,22 @@ public UsersControllers( /** * Returns a list of the top 100 users ordered by total hours. * - * @return a list of UserDto representing the users with their total hours + * @return a list of UsersDto representing the users with their total hours */ - public List getUsers() { + public List getUsers() { log.info("Fetching top 100 users by total hours"); List results = usersRepository.findTop100UsersByTotalHours(); - List users = new ArrayList<>(); + List users = new ArrayList<>(); for (Object[] row : results) { - UserDto userDto = new UserDto(); - userDto.setId( + UsersDto usersDto = new UsersDto(); + usersDto.setId( row[0] != null ? UUID.fromString(row[0].toString()) : null ); - userDto.setUsername(row[1] != null ? row[1].toString() : null); - userDto.setTotalHours( + usersDto.setUsername(row[1] != null ? row[1].toString() : null); + usersDto.setTotalHours( row[2] != null ? ((Number) row[2]).doubleValue() : 0.0 ); - users.add(userDto); + users.add(usersDto); } log.info("Returning {} users", users.size()); return users; @@ -295,14 +295,14 @@ public List getUserAchievements(UUID uuid) { .stream() .filter(a -> "Studied for 5 hours".equals(a.getDescription())) .findFirst(); - boolean studiedCompleted = totalHours >= 5.0; + boolean studiedCompleted = totalHours >= 1.0; AchievementEntity studiedEntity = studiedAchievement.orElseGet(() -> - new AchievementEntity(uuid, "Studied for 5 hours", studiedCompleted) + new AchievementEntity(uuid, "Studied for 1 hours", studiedCompleted) ); studiedEntity.setCompleted(studiedCompleted); achievementsRepository.save(studiedEntity); log.info( - "Updated/created 'Studied for 5 hours' achievement for user {}: completed={}", + "Updated/created 'Studied for 1 hours' achievement for user {}: completed={}", uuid, studiedCompleted ); diff --git a/src/main/java/com/alessandra_alessandro/ketchapp/models/dto/UserDto.java b/src/main/java/com/alessandra_alessandro/ketchapp/models/dto/UserDto.java index d629c69..1062fb8 100644 --- a/src/main/java/com/alessandra_alessandro/ketchapp/models/dto/UserDto.java +++ b/src/main/java/com/alessandra_alessandro/ketchapp/models/dto/UserDto.java @@ -1,18 +1,18 @@ package com.alessandra_alessandro.ketchapp.models.dto; +import java.util.UUID; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import java.util.UUID; - @Getter @Setter @NoArgsConstructor @AllArgsConstructor public class UserDto { + private UUID id; private String username; - private Double totalHours; -} \ No newline at end of file + private String email; +} diff --git a/src/main/java/com/alessandra_alessandro/ketchapp/models/dto/UsersDto.java b/src/main/java/com/alessandra_alessandro/ketchapp/models/dto/UsersDto.java new file mode 100644 index 0000000..3f23d73 --- /dev/null +++ b/src/main/java/com/alessandra_alessandro/ketchapp/models/dto/UsersDto.java @@ -0,0 +1,18 @@ +package com.alessandra_alessandro.ketchapp.models.dto; + +import java.util.UUID; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class UsersDto { + + private UUID id; + private String username; + private Double totalHours; +} diff --git a/src/main/java/com/alessandra_alessandro/ketchapp/routes/TomatoesRoutes.java b/src/main/java/com/alessandra_alessandro/ketchapp/routes/TomatoesRoutes.java index d137396..3c14873 100644 --- a/src/main/java/com/alessandra_alessandro/ketchapp/routes/TomatoesRoutes.java +++ b/src/main/java/com/alessandra_alessandro/ketchapp/routes/TomatoesRoutes.java @@ -8,16 +8,16 @@ 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 java.util.List; 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; - @RestController @RequestMapping("/api/tomatoes") public class TomatoesRoutes { + private final TomatoesControllers tomatoesController; @Autowired @@ -26,45 +26,122 @@ public TomatoesRoutes(TomatoesControllers tomatoesController) { } @Operation( - summary = "Create a new tomato record", - description = "Creates a new tomato record.", - tags = {"Activities"} + summary = "Create a new tomato record", + description = "Creates a new tomato record.", + tags = { "Activities" } ) - @ApiResponses(value = { - @ApiResponse(responseCode = "201", description = "Successfully created tomato record", - content = @Content(mediaType = "application/json", - schema = @Schema(implementation = TomatoDto.class))), + @ApiResponses( + value = { + @ApiResponse( + responseCode = "201", + description = "Successfully created tomato record", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = TomatoDto.class) + ) + ), @ApiResponse(responseCode = "400", description = "Bad request"), - @ApiResponse(responseCode = "401", description = "Unauthorized (authentication required)"), - @ApiResponse(responseCode = "500", description = "Internal server error") - }) + @ApiResponse( + responseCode = "401", + description = "Unauthorized (authentication required)" + ), + @ApiResponse( + responseCode = "500", + description = "Internal server error" + ), + } + ) @PostMapping - public ResponseEntity createTomato(@RequestBody TomatoDto tomatoDtoToCreate) { + public ResponseEntity createTomato( + @RequestBody TomatoDto tomatoDtoToCreate + ) { try { - TomatoDto createdTomato = tomatoesController.createTomato(tomatoDtoToCreate); - return ResponseEntity.status(HttpStatus.CREATED).body(createdTomato); + TomatoDto createdTomato = tomatoesController.createTomato( + tomatoDtoToCreate + ); + return ResponseEntity.status(HttpStatus.CREATED).body( + createdTomato + ); } catch (Exception e) { return ResponseEntity.badRequest().build(); } } @Operation( - summary = "Get all activities for a tomato", - description = "Fetches all activities related to a specific tomato by its id.", - tags = {"Activities"} + summary = "Get a tomato", + description = "Fetches a specific tomato by its id.", + tags = { "Tomatoes" } + ) + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "Successfully retrieved tomato", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = TomatoDto.class) + ) + ), + @ApiResponse( + responseCode = "401", + description = "Unauthorized (authentication required)" + ), + @ApiResponse( + responseCode = "404", + description = "Tomato not found" + ), + @ApiResponse( + responseCode = "500", + description = "Internal server error" + ), + } + ) + @GetMapping("/{id}") + public ResponseEntity getTomato(@PathVariable Integer id) { + TomatoDto response = tomatoesController.getTomato(id); + if (response != null) { + return ResponseEntity.ok(response); + } else { + return ResponseEntity.notFound().build(); + } + } + + @Operation( + summary = "Get all activities for a tomato", + description = "Fetches all activities related to a specific tomato by its id.", + tags = { "Activities" } + ) + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "Successfully retrieved activities", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = ActivityDto.class) + ) + ), + @ApiResponse( + responseCode = "401", + description = "Unauthorized (authentication required)" + ), + @ApiResponse( + responseCode = "404", + description = "Tomato or activities not found" + ), + @ApiResponse( + responseCode = "500", + description = "Internal server error" + ), + } ) - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully retrieved activities", - content = @Content(mediaType = "application/json", - schema = @Schema(implementation = ActivityDto.class))), - @ApiResponse(responseCode = "401", description = "Unauthorized (authentication required)"), - @ApiResponse(responseCode = "404", description = "Tomato or activities not found"), - @ApiResponse(responseCode = "500", description = "Internal server error") - }) @GetMapping("/{id}/activities") - public ResponseEntity> getActivitiesByTomatoId(@PathVariable Integer id) { + public ResponseEntity> getActivitiesByTomatoId( + @PathVariable Integer id + ) { try { - List activities = tomatoesController.getActivitiesByTomatoId(id); + List activities = + tomatoesController.getActivitiesByTomatoId(id); if (activities != null) { return ResponseEntity.ok(activities); } else { diff --git a/src/main/java/com/alessandra_alessandro/ketchapp/routes/UsersRoutes.java b/src/main/java/com/alessandra_alessandro/ketchapp/routes/UsersRoutes.java index 7bcec20..9a418b8 100644 --- a/src/main/java/com/alessandra_alessandro/ketchapp/routes/UsersRoutes.java +++ b/src/main/java/com/alessandra_alessandro/ketchapp/routes/UsersRoutes.java @@ -7,15 +7,14 @@ 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 java.time.LocalDate; +import java.util.List; +import java.util.UUID; 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.time.LocalDate; -import java.util.List; -import java.util.UUID; - @RestController @RequestMapping("/api/users") public class UsersRoutes { @@ -27,23 +26,35 @@ public UsersRoutes(UsersControllers usersController) { this.usersController = usersController; } - @Operation( - summary = "Get all users", - description = "Fetches a list of all user records.", - tags = {"Users"}) - - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully retrieved user records", - content = @Content(mediaType = "application/json", - schema = @Schema(implementation = UserDto.class))), - @ApiResponse(responseCode = "401", description = "Unauthorized (authentication required)"), - @ApiResponse(responseCode = "500", description = "Internal server error") - }) + summary = "Get all users", + description = "Fetches a list of all user records.", + tags = { "Users" } + ) + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "Successfully retrieved user records", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = UsersDto.class) + ) + ), + @ApiResponse( + responseCode = "401", + description = "Unauthorized (authentication required)" + ), + @ApiResponse( + responseCode = "500", + description = "Internal server error" + ), + } + ) @GetMapping - public ResponseEntity> getUsers() { + public ResponseEntity> getUsers() { try { - List users = usersController.getUsers(); + List users = usersController.getUsers(); return ResponseEntity.ok(users); } catch (Exception e) { return ResponseEntity.internalServerError().build(); @@ -51,18 +62,31 @@ public ResponseEntity> getUsers() { } @Operation( - summary = "Get user by UUID", - description = "Fetches a user record by its UUID.", - tags = {"Users"} + summary = "Get user by UUID", + description = "Fetches a user record by its UUID.", + tags = { "Users" } ) - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully retrieved user record", - content = @Content(mediaType = "application/json", - schema = @Schema(implementation = UserDto.class))), - @ApiResponse(responseCode = "401", description = "Unauthorized (authentication required)"), + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "Successfully retrieved user record", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = UserDto.class) + ) + ), + @ApiResponse( + responseCode = "401", + description = "Unauthorized (authentication required)" + ), @ApiResponse(responseCode = "404", description = "User not found"), - @ApiResponse(responseCode = "500", description = "Internal server error") - }) + @ApiResponse( + responseCode = "500", + description = "Internal server error" + ), + } + ) @GetMapping("/{uuid}") public ResponseEntity getUser(@PathVariable("uuid") UUID uuid) { try { @@ -73,25 +97,45 @@ public ResponseEntity getUser(@PathVariable("uuid") UUID uuid) { return ResponseEntity.notFound().build(); } } catch (Exception e) { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + return ResponseEntity.status( + HttpStatus.INTERNAL_SERVER_ERROR + ).build(); } } @Operation( - summary = "Get email by username", - description = "Fetches the email address associated with a given username.", - tags = {"Users"} + summary = "Get email by username", + description = "Fetches the email address associated with a given username.", + tags = { "Users" } + ) + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "Successfully retrieved email address", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = String.class) + ) + ), + @ApiResponse( + responseCode = "401", + description = "Unauthorized (authentication required)" + ), + @ApiResponse( + responseCode = "404", + description = "Username not found" + ), + @ApiResponse( + responseCode = "500", + description = "Internal server error" + ), + } ) - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully retrieved email address", - content = @Content(mediaType = "application/json", - schema = @Schema(implementation = String.class))), - @ApiResponse(responseCode = "401", description = "Unauthorized (authentication required)"), - @ApiResponse(responseCode = "404", description = "Username not found"), - @ApiResponse(responseCode = "500", description = "Internal server error") - }) @GetMapping("/email/{username}") - public ResponseEntity getEmailByUsername(@PathVariable String username) { + public ResponseEntity getEmailByUsername( + @PathVariable String username + ) { try { String response = usersController.getEmailByUsername(username); if (response != null) { @@ -102,32 +146,56 @@ public ResponseEntity getEmailByUsername(@PathVariable String username) } catch (IllegalArgumentException e) { return ResponseEntity.badRequest().build(); } catch (Exception e) { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + return ResponseEntity.status( + HttpStatus.INTERNAL_SERVER_ERROR + ).build(); } } @Operation( - summary = "Get tomatoes by user UUID", - description = "Fetches a list of tomatoes for a specific user by their UUID. Optionally filter by date (yyyy-MM-dd) with ?date= or by date range with ?startDate=yyyy-MM-dd&endDate=yyyy-MM-dd (both required for range)", - tags = {"Users"} + summary = "Get tomatoes by user UUID", + description = "Fetches a list of tomatoes for a specific user by their UUID. Optionally filter by date (yyyy-MM-dd) with ?date= or by date range with ?startDate=yyyy-MM-dd&endDate=yyyy-MM-dd (both required for range)", + tags = { "Users" } ) - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully retrieved tomatoes for user", - content = @Content(mediaType = "application/json", - schema = @Schema(implementation = TomatoDto.class))), - @ApiResponse(responseCode = "401", description = "Unauthorized (authentication required)"), + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "Successfully retrieved tomatoes for user", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = TomatoDto.class) + ) + ), + @ApiResponse( + responseCode = "401", + description = "Unauthorized (authentication required)" + ), @ApiResponse(responseCode = "404", description = "User not found"), - @ApiResponse(responseCode = "500", description = "Internal server error") - }) + @ApiResponse( + responseCode = "500", + description = "Internal server error" + ), + } + ) @GetMapping("/{uuid}/tomatoes") - public ResponseEntity> getUserTomatoes(@PathVariable UUID uuid, - @RequestParam(value = "date", required = false) LocalDate date, - @RequestParam(value = "startDate", required = false) LocalDate startDate, - @RequestParam(value = "endDate", required = false) LocalDate endDate) { + public ResponseEntity> getUserTomatoes( + @PathVariable UUID uuid, + @RequestParam(value = "date", required = false) LocalDate date, + @RequestParam( + value = "startDate", + required = false + ) LocalDate startDate, + @RequestParam(value = "endDate", required = false) LocalDate endDate + ) { try { List tomatoes; if (startDate != null && endDate != null) { - tomatoes = usersController.getUserTomatoes(uuid, startDate, endDate); + tomatoes = usersController.getUserTomatoes( + uuid, + startDate, + endDate + ); } else if (date != null) { tomatoes = usersController.getUserTomatoes(uuid, date); } else { @@ -142,22 +210,39 @@ public ResponseEntity> getUserTomatoes(@PathVariable UUID uuid, } @Operation( - summary = "Get activities by user UUID", - description = "Fetches a list of activities for a specific user by their UUID.", - tags = {"Users"} + summary = "Get activities by user UUID", + description = "Fetches a list of activities for a specific user by their UUID.", + tags = { "Users" } ) - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully retrieved activities for user", - content = @Content(mediaType = "application/json", - schema = @Schema(implementation = ActivityDto.class))), - @ApiResponse(responseCode = "401", description = "Unauthorized (authentication required)"), + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "Successfully retrieved activities for user", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = ActivityDto.class) + ) + ), + @ApiResponse( + responseCode = "401", + description = "Unauthorized (authentication required)" + ), @ApiResponse(responseCode = "404", description = "User not found"), - @ApiResponse(responseCode = "500", description = "Internal server error") - }) + @ApiResponse( + responseCode = "500", + description = "Internal server error" + ), + } + ) @GetMapping("/{uuid}/activities") - public ResponseEntity> getUserActivities(@PathVariable UUID uuid) { + public ResponseEntity> getUserActivities( + @PathVariable UUID uuid + ) { try { - List activities = usersController.getUserActivities(uuid); + List activities = usersController.getUserActivities( + uuid + ); if (activities != null) { return ResponseEntity.ok(activities); } else { @@ -166,27 +251,45 @@ public ResponseEntity> getUserActivities(@PathVariable UUID uu } catch (IllegalArgumentException e) { return ResponseEntity.badRequest().build(); } catch (Exception e) { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + return ResponseEntity.status( + HttpStatus.INTERNAL_SERVER_ERROR + ).build(); } } @Operation( - summary = "Get achievements by user UUID", - description = "Fetches a list of achievements for a specific user by their UUID.", - tags = {"Users"} + summary = "Get achievements by user UUID", + description = "Fetches a list of achievements for a specific user by their UUID.", + tags = { "Users" } ) - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully retrieved achievements for user", - content = @Content(mediaType = "application/json", - schema = @Schema(implementation = AchievementDto.class))), - @ApiResponse(responseCode = "401", description = "Unauthorized (authentication required)"), + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "Successfully retrieved achievements for user", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = AchievementDto.class) + ) + ), + @ApiResponse( + responseCode = "401", + description = "Unauthorized (authentication required)" + ), @ApiResponse(responseCode = "404", description = "User not found"), - @ApiResponse(responseCode = "500", description = "Internal server error") - }) + @ApiResponse( + responseCode = "500", + description = "Internal server error" + ), + } + ) @GetMapping("/{uuid}/achievements") - public ResponseEntity> getUserAchievements(@PathVariable UUID uuid) { + public ResponseEntity> getUserAchievements( + @PathVariable UUID uuid + ) { try { - List achievements = usersController.getUserAchievements(uuid); + List achievements = + usersController.getUserAchievements(uuid); if (achievements != null) { return ResponseEntity.ok(achievements); } else { @@ -195,29 +298,50 @@ public ResponseEntity> getUserAchievements(@PathVariable UU } catch (IllegalArgumentException e) { return ResponseEntity.badRequest().build(); } catch (Exception e) { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + return ResponseEntity.status( + HttpStatus.INTERNAL_SERVER_ERROR + ).build(); } } @Operation( - summary = "Get statistics by user UUID", - description = "Fetches statistics for a specific user by their UUID and a date range.", - tags = {"Users"} + summary = "Get statistics by user UUID", + description = "Fetches statistics for a specific user by their UUID and a date range.", + tags = { "Users" } ) - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully retrieved statistics for user", - content = @Content(mediaType = "application/json", - schema = @Schema(implementation = StatisticsDto.class))), - @ApiResponse(responseCode = "401", description = "Unauthorized (authentication required)"), + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "Successfully retrieved statistics for user", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = StatisticsDto.class) + ) + ), + @ApiResponse( + responseCode = "401", + description = "Unauthorized (authentication required)" + ), @ApiResponse(responseCode = "404", description = "User not found"), - @ApiResponse(responseCode = "500", description = "Internal server error") - }) + @ApiResponse( + responseCode = "500", + description = "Internal server error" + ), + } + ) @GetMapping("/{uuid}/statistics") - public ResponseEntity getUserStatistics(@PathVariable UUID uuid, - @RequestParam LocalDate startDate, - @RequestParam LocalDate endDate) { + public ResponseEntity getUserStatistics( + @PathVariable UUID uuid, + @RequestParam LocalDate startDate, + @RequestParam LocalDate endDate + ) { try { - StatisticsDto statistics = usersController.getUserStatistics(uuid, startDate, endDate); + StatisticsDto statistics = usersController.getUserStatistics( + uuid, + startDate, + endDate + ); if (statistics != null) { return ResponseEntity.ok(statistics); } else { @@ -226,31 +350,50 @@ public ResponseEntity getUserStatistics(@PathVariable UUID uuid, } catch (IllegalArgumentException e) { return ResponseEntity.badRequest().build(); } catch (Exception e) { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + return ResponseEntity.status( + HttpStatus.INTERNAL_SERVER_ERROR + ).build(); } } @Operation( - summary = "Create a new user", - description = "Creates a new user record.", - tags = {"Users"} + summary = "Create a new user", + description = "Creates a new user record.", + tags = { "Users" } + ) + @ApiResponses( + value = { + @ApiResponse( + responseCode = "201", + description = "User created successfully", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = NewUserDto.class) + ) + ), + @ApiResponse( + responseCode = "400", + description = "Invalid input data" + ), + @ApiResponse( + responseCode = "500", + description = "Internal server error" + ), + } ) - @ApiResponses(value = { - @ApiResponse(responseCode = "201", description = "User created successfully", - content = @Content(mediaType = "application/json", - schema = @Schema(implementation = NewUserDto.class))), - @ApiResponse(responseCode = "400", description = "Invalid input data"), - @ApiResponse(responseCode = "500", description = "Internal server error") - }) @PostMapping - public ResponseEntity createUser(@RequestBody NewUserDto newUserDto) { + public ResponseEntity createUser( + @RequestBody NewUserDto newUserDto + ) { try { NewUserDto created = usersController.createUser(newUserDto); return ResponseEntity.status(HttpStatus.CREATED).body(created); } catch (IllegalArgumentException e) { return ResponseEntity.badRequest().build(); } catch (Exception e) { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + return ResponseEntity.status( + HttpStatus.INTERNAL_SERVER_ERROR + ).build(); } } -} \ No newline at end of file +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index fc5fa56..68ec616 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -31,7 +31,7 @@ GEMINI_API_KEY=AIzaSyClXWWxzTCaB6mMZl1Uqcr_3Pe2xZgFHyE # Kafka Configuration app.kafka.topic.mail-service=MailService -spring.kafka.bootstrap-servers=151.42.165.160:29092 +spring.kafka.bootstrap-servers=kafka:9092 spring.kafka.consumer.group-id=KafkaID spring.kafka.consumer.auto-offset-reset=earliest # important for initial consumer