diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 95dfe4cf..71449184 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -3,6 +3,11 @@ on: push: branches: - master + - develop + pull_request: + branches: + - master + - develop env: AWS_REGION: eu-central-1 @@ -41,6 +46,7 @@ jobs: deploy: needs: build + if: github.event_name != 'pull_request' name: Deploy runs-on: ubuntu-latest steps: @@ -62,4 +68,4 @@ jobs: deployment_package: ${{ env.JAR_FILE }} - name: Print finished deployment - run: echo "Deployment completed successfully!" + run: echo "Deployment completed successfully!" \ No newline at end of file diff --git a/src/main/java/com/chat/yourway/ChatYourWayApplication.java b/src/main/java/com/chat/yourway/ChatYourWayApplication.java index 123f9fa8..a88f7fe2 100644 --- a/src/main/java/com/chat/yourway/ChatYourWayApplication.java +++ b/src/main/java/com/chat/yourway/ChatYourWayApplication.java @@ -2,7 +2,11 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.scheduling.annotation.EnableAsync; +@EnableCaching +@EnableAsync @SpringBootApplication public class ChatYourWayApplication { diff --git a/src/main/java/com/chat/yourway/config/openapi/OpenApiMessages.java b/src/main/java/com/chat/yourway/config/openapi/OpenApiMessages.java index 5ffe3f20..83f840c9 100644 --- a/src/main/java/com/chat/yourway/config/openapi/OpenApiMessages.java +++ b/src/main/java/com/chat/yourway/config/openapi/OpenApiMessages.java @@ -51,6 +51,9 @@ public class OpenApiMessages { "Topic added to favourite successfully"; public static final String SUCCESSFULLY_REMOVE_TOPIC_FROM_FAVOURITE = "Topic removed from favourite successfully"; + + public static final String SUCCESSFULLY_COMPLAIN_TOPIC = + "Topic was complained successfully"; public static final String USER_DID_NOT_SUBSCRIBED_TO_TOPIC = "User did not subscribe to topic"; diff --git a/src/main/java/com/chat/yourway/config/security/SecurityConfig.java b/src/main/java/com/chat/yourway/config/security/SecurityConfig.java index 8acb1b79..d709974f 100644 --- a/src/main/java/com/chat/yourway/config/security/SecurityConfig.java +++ b/src/main/java/com/chat/yourway/config/security/SecurityConfig.java @@ -1,10 +1,9 @@ package com.chat.yourway.config.security; -import com.chat.yourway.exception.ContactNotFoundException; -import com.chat.yourway.repository.ContactRepository; -import lombok.RequiredArgsConstructor; +import com.chat.yourway.service.interfaces.ContactService; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; @@ -14,16 +13,17 @@ import org.springframework.security.crypto.password.PasswordEncoder; @Configuration -@RequiredArgsConstructor public class SecurityConfig { - private final ContactRepository contactRepository; + private final ContactService contactService; + + public SecurityConfig(@Lazy ContactService contactService) { + this.contactService = contactService; + } @Bean public UserDetailsService userDetailsService() { - return username -> contactRepository.findByEmailIgnoreCase(username) - .orElseThrow(() -> new ContactNotFoundException( - String.format("Contact with email: %s wasn't found", username))); + return contactService::findByEmail; } @Bean diff --git a/src/main/java/com/chat/yourway/config/websocket/WebSocketConfig.java b/src/main/java/com/chat/yourway/config/websocket/WebSocketConfig.java index 56f50e9a..fb74aeee 100644 --- a/src/main/java/com/chat/yourway/config/websocket/WebSocketConfig.java +++ b/src/main/java/com/chat/yourway/config/websocket/WebSocketConfig.java @@ -23,6 +23,6 @@ public void configureMessageBroker(MessageBrokerRegistry registry) { @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint(properties.getEndpoint()); - registry.addEndpoint(properties.getEndpoint()).withSockJS(); + registry.addEndpoint(properties.getEndpoint()).setAllowedOriginPatterns("*").withSockJS(); } } diff --git a/src/main/java/com/chat/yourway/controller/ChangePasswordController.java b/src/main/java/com/chat/yourway/controller/ChangePasswordController.java index ee1f4193..f86c642e 100644 --- a/src/main/java/com/chat/yourway/controller/ChangePasswordController.java +++ b/src/main/java/com/chat/yourway/controller/ChangePasswordController.java @@ -2,6 +2,7 @@ import com.chat.yourway.config.openapi.OpenApiExamples; import com.chat.yourway.dto.request.ChangePasswordDto; +import com.chat.yourway.dto.request.RestorePasswordDto; import com.chat.yourway.dto.response.ApiErrorResponseDto; import com.chat.yourway.service.interfaces.ChangePasswordService; import io.swagger.v3.oas.annotations.Operation; @@ -10,6 +11,7 @@ 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 lombok.RequiredArgsConstructor; import org.springframework.http.HttpHeaders; import org.springframework.security.core.annotation.AuthenticationPrincipal; @@ -43,9 +45,8 @@ public class ChangePasswordController { content = @Content(schema = @Schema(implementation = ChangePasswordDto.class), examples = @ExampleObject(value = OpenApiExamples.CHANGE_PASSWORD, description = "Old and new passwords")))) - @PatchMapping(path = "/password", - consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE) - public void changePassword(@RequestBody ChangePasswordDto request, + @PatchMapping(path = "/password", consumes = APPLICATION_JSON_VALUE) + public void changePassword(@Valid @RequestBody ChangePasswordDto request, @AuthenticationPrincipal UserDetails userDetails) { changePasswordService.changePassword(request, userDetails); } @@ -70,8 +71,8 @@ public void sendRequestToRestorePassword(@RequestParam String email, @ApiResponse(responseCode = "404", description = EMAIL_TOKEN_NOT_FOUND, content = @Content(schema = @Schema(implementation = ApiErrorResponseDto.class))) }) - @PatchMapping(path = "/password/restore", produces = APPLICATION_JSON_VALUE) - public void restorePassword(@RequestParam String newPassword, @RequestParam String token) { - changePasswordService.restorePassword(newPassword, token); + @PatchMapping(path = "/password/restore", consumes = APPLICATION_JSON_VALUE) + public void restorePassword(@Valid @RequestBody RestorePasswordDto restorePasswordDto) { + changePasswordService.restorePassword(restorePasswordDto); } } diff --git a/src/main/java/com/chat/yourway/controller/ChatController.java b/src/main/java/com/chat/yourway/controller/ChatController.java index 2621a8bf..fa9d0385 100644 --- a/src/main/java/com/chat/yourway/controller/ChatController.java +++ b/src/main/java/com/chat/yourway/controller/ChatController.java @@ -2,10 +2,12 @@ import com.chat.yourway.dto.request.MessagePrivateRequestDto; import com.chat.yourway.dto.request.MessagePublicRequestDto; +import com.chat.yourway.dto.request.PageRequestDto; import com.chat.yourway.dto.response.MessageResponseDto; import com.chat.yourway.service.interfaces.ChatMessageService; import jakarta.validation.Valid; import java.security.Principal; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.messaging.handler.annotation.DestinationVariable; import org.springframework.messaging.handler.annotation.MessageMapping; @@ -32,4 +34,11 @@ public MessageResponseDto sendToPrivateTopic(@DestinationVariable Integer topicI return chatMessageService.sendToPrivateTopic(topicId, message, email); } + @MessageMapping("/history/topic/{topicId}") + public List getTopicHistory(@DestinationVariable Integer topicId, + @Valid @Payload PageRequestDto pageRequestDto, Principal principal) { + String email = principal.getName(); + return chatMessageService.sendMessageHistoryByTopicId(topicId, pageRequestDto, email); + } + } diff --git a/src/main/java/com/chat/yourway/controller/MessageController.java b/src/main/java/com/chat/yourway/controller/MessageController.java index c964e868..07a98d4c 100644 --- a/src/main/java/com/chat/yourway/controller/MessageController.java +++ b/src/main/java/com/chat/yourway/controller/MessageController.java @@ -1,14 +1,10 @@ package com.chat.yourway.controller; -import static com.chat.yourway.config.openapi.OpenApiMessages.CONTACT_UNAUTHORIZED; import static com.chat.yourway.config.openapi.OpenApiMessages.MESSAGE_HAS_ALREADY_REPORTED; import static com.chat.yourway.config.openapi.OpenApiMessages.MESSAGE_NOT_FOUND; -import static com.chat.yourway.config.openapi.OpenApiMessages.SUCCESSFULLY_FOUND_MESSAGE; import static com.chat.yourway.config.openapi.OpenApiMessages.SUCCESSFULLY_REPORTED_MESSAGE; -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; import com.chat.yourway.dto.response.ApiErrorResponseDto; -import com.chat.yourway.dto.response.MessageResponseDto; import com.chat.yourway.service.interfaces.MessageService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; @@ -16,9 +12,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; import java.security.Principal; -import java.util.List; import lombok.RequiredArgsConstructor; -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.RequestMapping; @@ -29,32 +23,22 @@ @RequestMapping("/messages") @RequiredArgsConstructor public class MessageController { + private final MessageService messageService; @Operation(summary = "Make report to message", - responses = { - @ApiResponse(responseCode = "200", description = SUCCESSFULLY_REPORTED_MESSAGE, - content = @Content), - @ApiResponse(responseCode = "400", description = MESSAGE_HAS_ALREADY_REPORTED, - content = @Content(schema = @Schema(implementation = ApiErrorResponseDto.class))), - @ApiResponse(responseCode = "404", description = MESSAGE_NOT_FOUND, - content = @Content(schema = @Schema(implementation = ApiErrorResponseDto.class))) - }) + responses = { + @ApiResponse(responseCode = "200", description = SUCCESSFULLY_REPORTED_MESSAGE, + content = @Content), + @ApiResponse(responseCode = "400", description = MESSAGE_HAS_ALREADY_REPORTED, + content = @Content(schema = @Schema(implementation = ApiErrorResponseDto.class))), + @ApiResponse(responseCode = "404", description = MESSAGE_NOT_FOUND, + content = @Content(schema = @Schema(implementation = ApiErrorResponseDto.class))) + }) @PostMapping("/{id}/report") public void reportMessage( @PathVariable int id, Principal principal) { String email = principal.getName(); messageService.reportMessageById(id, email); } - - @Operation(summary = "Find all messages by topic id", - responses = { - @ApiResponse(responseCode = "200", description = SUCCESSFULLY_FOUND_MESSAGE), - @ApiResponse(responseCode = "403", description = CONTACT_UNAUTHORIZED, - content = @Content(schema = @Schema(implementation = ApiErrorResponseDto.class))) - }) - @GetMapping(path = "/all/{topicId}", produces = APPLICATION_JSON_VALUE) - public List findAllByTopicId(@PathVariable Integer topicId){ - return messageService.findAllByTopicId(topicId); - } } diff --git a/src/main/java/com/chat/yourway/controller/TopicController.java b/src/main/java/com/chat/yourway/controller/TopicController.java index 19ab9367..5bc7f297 100644 --- a/src/main/java/com/chat/yourway/controller/TopicController.java +++ b/src/main/java/com/chat/yourway/controller/TopicController.java @@ -1,24 +1,6 @@ package com.chat.yourway.controller; -import static com.chat.yourway.config.openapi.OpenApiMessages.ALREADY_SUBSCRIBED; -import static com.chat.yourway.config.openapi.OpenApiMessages.CONTACT_UNAUTHORIZED; -import static com.chat.yourway.config.openapi.OpenApiMessages.CONTACT_WASNT_SUBSCRIBED; -import static com.chat.yourway.config.openapi.OpenApiMessages.INVALID_VALUE; -import static com.chat.yourway.config.openapi.OpenApiMessages.OWNER_CANT_UNSUBSCRIBED; -import static com.chat.yourway.config.openapi.OpenApiMessages.RECIPIENT_EMAIL_NOT_EXIST; -import static com.chat.yourway.config.openapi.OpenApiMessages.SEARCH_TOPIC_VALIDATION; -import static com.chat.yourway.config.openapi.OpenApiMessages.SUCCESSFULLY_ADD_TOPIC_TO_FAVOURITE; -import static com.chat.yourway.config.openapi.OpenApiMessages.SUCCESSFULLY_CREATED_TOPIC; -import static com.chat.yourway.config.openapi.OpenApiMessages.SUCCESSFULLY_DELETE_TOPIC; -import static com.chat.yourway.config.openapi.OpenApiMessages.SUCCESSFULLY_FOUND_TOPIC; -import static com.chat.yourway.config.openapi.OpenApiMessages.SUCCESSFULLY_REMOVE_TOPIC_FROM_FAVOURITE; -import static com.chat.yourway.config.openapi.OpenApiMessages.SUCCESSFULLY_SUBSCRIBED; -import static com.chat.yourway.config.openapi.OpenApiMessages.SUCCESSFULLY_UNSUBSCRIBED; -import static com.chat.yourway.config.openapi.OpenApiMessages.SUCCESSFULLY_UPDATED_TOPIC; -import static com.chat.yourway.config.openapi.OpenApiMessages.TOPIC_NOT_ACCESS; -import static com.chat.yourway.config.openapi.OpenApiMessages.TOPIC_NOT_FOUND; -import static com.chat.yourway.config.openapi.OpenApiMessages.USER_DID_NOT_SUBSCRIBED_TO_TOPIC; -import static com.chat.yourway.config.openapi.OpenApiMessages.VALUE_NOT_UNIQUE; +import static com.chat.yourway.config.openapi.OpenApiMessages.*; import static java.nio.charset.StandardCharsets.UTF_8; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @@ -300,7 +282,7 @@ public List findAllByTopicName( content = @Content(schema = @Schema(implementation = ApiErrorResponseDto.class))) }) @ResponseStatus(HttpStatus.NO_CONTENT) - @PatchMapping(path = "{topic-id}/favourite/add", consumes = APPLICATION_JSON_VALUE) + @PatchMapping(path = "{topic-id}/favourite/add") public void addToFavouriteTopic( @PathVariable("topic-id") Integer topicId, @AuthenticationPrincipal UserDetails userDetails) { topicSubscriberService.addTopicToFavourite(topicId, userDetails); @@ -324,7 +306,7 @@ public void addToFavouriteTopic( content = @Content(schema = @Schema(implementation = ApiErrorResponseDto.class))) }) @ResponseStatus(HttpStatus.NO_CONTENT) - @PatchMapping(path = "{topic-id}/favourite/remove", consumes = APPLICATION_JSON_VALUE) + @PatchMapping(path = "{topic-id}/favourite/remove") public void removeToFavouriteTopic( @PathVariable("topic-id") Integer topicId, @AuthenticationPrincipal UserDetails userDetails) { topicSubscriberService.removeTopicFromFavourite(topicId, userDetails); @@ -350,10 +332,32 @@ public List findAllFavouriteTopics( responses = { @ApiResponse(responseCode = "200", description = SUCCESSFULLY_FOUND_TOPIC) }) - @GetMapping(path = "/popular/public") + @GetMapping(path = "/popular/public", produces = APPLICATION_JSON_VALUE) public List findAllPopularPublicTopics() { return topicService.findPopularPublicTopics(); } + @Operation( + summary = "Complain topic", + responses = { + @ApiResponse(responseCode = "204", description = SUCCESSFULLY_COMPLAIN_TOPIC), + @ApiResponse( + responseCode = "403", + description = CONTACT_UNAUTHORIZED, + content = @Content(schema = @Schema(implementation = ApiErrorResponseDto.class))), + @ApiResponse( + responseCode = "404", + description = TOPIC_NOT_FOUND, + content = @Content(schema = @Schema(implementation = ApiErrorResponseDto.class))), + @ApiResponse( + responseCode = "409", + description = USER_DID_NOT_SUBSCRIBED_TO_TOPIC, + content = @Content(schema = @Schema(implementation = ApiErrorResponseDto.class))) + }) + @PatchMapping("/{topic-id}/complain") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void complainTopic(@AuthenticationPrincipal UserDetails userDetails, @PathVariable("topic-id") Integer topicId) { + topicSubscriberService.complainTopic(topicId, userDetails); + } } diff --git a/src/main/java/com/chat/yourway/dto/request/ChangePasswordDto.java b/src/main/java/com/chat/yourway/dto/request/ChangePasswordDto.java index e9d72a6d..a1d5eb3e 100644 --- a/src/main/java/com/chat/yourway/dto/request/ChangePasswordDto.java +++ b/src/main/java/com/chat/yourway/dto/request/ChangePasswordDto.java @@ -1,11 +1,15 @@ package com.chat.yourway.dto.request; +import com.chat.yourway.annotation.PasswordValidation; import lombok.AllArgsConstructor; import lombok.Data; @Data @AllArgsConstructor public class ChangePasswordDto { + @PasswordValidation private String oldPassword; + + @PasswordValidation private String newPassword; } diff --git a/src/main/java/com/chat/yourway/dto/request/PageRequestDto.java b/src/main/java/com/chat/yourway/dto/request/PageRequestDto.java new file mode 100644 index 00000000..91cb82de --- /dev/null +++ b/src/main/java/com/chat/yourway/dto/request/PageRequestDto.java @@ -0,0 +1,26 @@ +package com.chat.yourway.dto.request; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@ToString +public class PageRequestDto { + + @NotNull(message = "Page should not be null") + @Min(value = 0, message = "Page should be greater or equals 0") + private Integer page; + + @NotNull(message = "Page size should not be null") + @Min(value = 1, message = "Page size should be greater or equals 1") + private Integer pageSize; + +} diff --git a/src/main/java/com/chat/yourway/dto/request/RestorePasswordDto.java b/src/main/java/com/chat/yourway/dto/request/RestorePasswordDto.java new file mode 100644 index 00000000..3c194421 --- /dev/null +++ b/src/main/java/com/chat/yourway/dto/request/RestorePasswordDto.java @@ -0,0 +1,26 @@ +package com.chat.yourway.dto.request; + +import com.chat.yourway.annotation.PasswordValidation; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@AllArgsConstructor +@NoArgsConstructor +@Setter +@Getter +@ToString +public class RestorePasswordDto { + + @Schema(description = "New password", example = "Password-321") + @PasswordValidation + private String newPassword; + + @Schema(description = "Email token", example = "245034-cc65-4dce-b374-7419fbfc18e5") + @NotEmpty(message = "Email token cannot be empty") + private String emailToken; +} diff --git a/src/main/java/com/chat/yourway/dto/response/TopicSubscriberResponseDto.java b/src/main/java/com/chat/yourway/dto/response/TopicSubscriberResponseDto.java index 2364d60c..855d8685 100644 --- a/src/main/java/com/chat/yourway/dto/response/TopicSubscriberResponseDto.java +++ b/src/main/java/com/chat/yourway/dto/response/TopicSubscriberResponseDto.java @@ -22,4 +22,6 @@ public class TopicSubscriberResponseDto { private boolean isPermittedSendingMessage; + private boolean hasComplaint; + } diff --git a/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java b/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java index 8c65bcc5..b30518a9 100644 --- a/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java +++ b/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java @@ -5,7 +5,6 @@ import com.chat.yourway.config.websocket.WebsocketProperties; import com.chat.yourway.model.event.ContactEvent; -import com.chat.yourway.service.interfaces.ChatMessageService; import com.chat.yourway.service.interfaces.ChatNotificationService; import com.chat.yourway.service.interfaces.ContactEventService; import java.time.Instant; @@ -28,7 +27,6 @@ public class StompSubscriptionListener { private final WebsocketProperties properties; private final ContactEventService contactEventService; - private final ChatMessageService chatMessageService; private final ChatNotificationService chatNotificationService; private static String lastMessage; @@ -41,10 +39,6 @@ public void handleWebSocketSubscribeListener(SessionSubscribeEvent event) { String email = getEmail(event); try { - if (isPrivateTopicDestination(destination)) { - chatMessageService.sendMessageHistoryByTopicId(getTopicId(event), email); - } - if (isTopicDestination(destination)) { lastMessage = contactEventService.getByTopicIdAndEmail(getTopicId(event), email) .getLastMessage(); diff --git a/src/main/java/com/chat/yourway/model/Message.java b/src/main/java/com/chat/yourway/model/Message.java index 28884d10..51c222f6 100644 --- a/src/main/java/com/chat/yourway/model/Message.java +++ b/src/main/java/com/chat/yourway/model/Message.java @@ -2,6 +2,7 @@ import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; @@ -40,10 +41,10 @@ public class Message { private String content; @Column(name = "timestamp", nullable = false) private LocalDateTime timestamp; - @ManyToOne + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "topic_id", referencedColumnName = "id", nullable = false) private Topic topic; - @ManyToMany + @ManyToMany(fetch = FetchType.LAZY) @JoinTable( schema = "chat", name = "contact_message_report", diff --git a/src/main/java/com/chat/yourway/model/TopicSubscriber.java b/src/main/java/com/chat/yourway/model/TopicSubscriber.java index 5ab3362f..02b0d980 100644 --- a/src/main/java/com/chat/yourway/model/TopicSubscriber.java +++ b/src/main/java/com/chat/yourway/model/TopicSubscriber.java @@ -52,4 +52,7 @@ public class TopicSubscriber { @Column(name = "is_favourite_topic") private boolean isFavouriteTopic; + @Column(name = "has_complaint") + private boolean hasComplaint; + } diff --git a/src/main/java/com/chat/yourway/repository/MessageRepository.java b/src/main/java/com/chat/yourway/repository/MessageRepository.java index 3cda1e9f..87d065d8 100644 --- a/src/main/java/com/chat/yourway/repository/MessageRepository.java +++ b/src/main/java/com/chat/yourway/repository/MessageRepository.java @@ -3,6 +3,7 @@ import com.chat.yourway.model.Message; import java.time.LocalDateTime; import java.util.List; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; @@ -29,7 +30,7 @@ public interface MessageRepository extends JpaRepository { nativeQuery = true) void saveReportFromContactToMessage(String email, Integer messageId); - List findAllByTopicId(Integer topic_id); + List findAllByTopicId(Integer topic_id, Pageable pageable); @Query(value = """ SELECT COUNT(*) diff --git a/src/main/java/com/chat/yourway/repository/TopicSubscriberRepository.java b/src/main/java/com/chat/yourway/repository/TopicSubscriberRepository.java index 83a0b4ef..5a519eeb 100644 --- a/src/main/java/com/chat/yourway/repository/TopicSubscriberRepository.java +++ b/src/main/java/com/chat/yourway/repository/TopicSubscriberRepository.java @@ -67,4 +67,19 @@ void updateFavouriteTopicStatusByTopicIdAndContactEmail( "SELECT CASE WHEN COUNT(ts) > 0 then true else false end from TopicSubscriber ts " + "where ts.topic.id = :topicId and ts.contact.isPermittedSendingPrivateMessage = false") boolean checkIfExistProhibitionSendingPrivateMessage(@Param("topicId") Integer topicId); + + @Modifying + @Query( + nativeQuery = true, + value = + "UPDATE chat.topic_subscriber " + + "SET has_complaint = :hasComplaint " + + "FROM chat.contact c " + + "WHERE contact_id = c.id " + + "AND topic_id = :topicId " + + "AND c.email = :contactEmail") + void updateHasComplaintStatusByTopicIdAndContactEmail( + @Param("topicId") int topicId, + @Param("contactEmail") String contactEmail, + @Param("hasComplaint") boolean hasComplaint); } diff --git a/src/main/java/com/chat/yourway/security/JwtAuthFilter.java b/src/main/java/com/chat/yourway/security/JwtAuthFilter.java index 7e0f2f44..4475aedf 100644 --- a/src/main/java/com/chat/yourway/security/JwtAuthFilter.java +++ b/src/main/java/com/chat/yourway/security/JwtAuthFilter.java @@ -38,8 +38,9 @@ protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) throws ServletException, IOException { - if (isNotAuthorizationHeader(request)) { - logger.warn("Header does not contain " + AUTHORIZATION); + if (isNotAuthorizationHeader(request) && isNotTokenParameter(request)) { + log.warn("Request without authorization. Header or parameter does not contain {}", + AUTHORIZATION); filterChain.doFilter(request, response); return; } @@ -85,4 +86,8 @@ private boolean isNotAuthorizationHeader(HttpServletRequest request) { return request.getHeader(AUTHORIZATION) == null; } + private boolean isNotTokenParameter(HttpServletRequest request) { + return request.getParameter(AUTHORIZATION) == null; + } + } diff --git a/src/main/java/com/chat/yourway/security/JwtService.java b/src/main/java/com/chat/yourway/security/JwtService.java index 8667aff4..4955c868 100644 --- a/src/main/java/com/chat/yourway/security/JwtService.java +++ b/src/main/java/com/chat/yourway/security/JwtService.java @@ -40,16 +40,20 @@ public String generateRefreshToken(UserDetails userDetails) { } public String extractToken(HttpServletRequest request) { - final String authHeader = request.getHeader(AUTHORIZATION); + String token = request.getHeader(AUTHORIZATION); + if (token == null) { + token = request.getParameter(AUTHORIZATION); + } + final String tokenType = jwtProperties.getTokenType(); final String tokenTypePrefix = tokenType + " "; - if (isNotValidTokenType(authHeader, tokenTypePrefix)) { + if (isNotValidTokenType(token, tokenTypePrefix)) { log.warn("Invalid token type, token type should be [{}]", tokenType); throw new InvalidTokenException( "Invalid token type, token type should be [" + tokenType + "]"); } - return authHeader.substring(tokenTypePrefix.length()); + return token.substring(tokenTypePrefix.length()); } public boolean isTokenValid(String token, UserDetails userDetails) { @@ -67,8 +71,8 @@ private String generateAccessToken(Map extraClaims, UserDetails return buildToken(extraClaims, userDetails, jwtProperties.getExpiration()); } - private boolean isNotValidTokenType(String authHeader, String tokenTypePrefix) { - return authHeader == null || !authHeader.startsWith(tokenTypePrefix); + private boolean isNotValidTokenType(String token, String tokenTypePrefix) { + return token == null || !token.startsWith(tokenTypePrefix); } private String buildToken(Map extraClaims, UserDetails userDetails, diff --git a/src/main/java/com/chat/yourway/service/ChangePasswordServiceImpl.java b/src/main/java/com/chat/yourway/service/ChangePasswordServiceImpl.java index ba070990..ca35a8b8 100644 --- a/src/main/java/com/chat/yourway/service/ChangePasswordServiceImpl.java +++ b/src/main/java/com/chat/yourway/service/ChangePasswordServiceImpl.java @@ -2,6 +2,7 @@ import com.chat.yourway.dto.common.EmailMessageInfoDto; import com.chat.yourway.dto.request.ChangePasswordDto; +import com.chat.yourway.dto.request.RestorePasswordDto; import com.chat.yourway.exception.EmailTokenNotFoundException; import com.chat.yourway.model.email.EmailMessageType; import com.chat.yourway.model.email.EmailToken; @@ -36,6 +37,7 @@ public void changePassword(ChangePasswordDto request, UserDetails userDetails) { } @Override + @Transactional public void sendEmailToRestorePassword(String email, String clientHost) { var contact = contactService.findByEmail(email); @@ -52,7 +54,7 @@ public void sendEmailToRestorePassword(String email, String clientHost) { var emailMessageInfo = new EmailMessageInfoDto(contact.getNickname(), contact.getEmail(), uuidToken, - clientHost, + clientHost, EmailMessageType.RESTORE_PASSWORD); var emailMessage = emailMessageFactoryService.generateEmailMessage(emailMessageInfo); @@ -61,11 +63,11 @@ public void sendEmailToRestorePassword(String email, String clientHost) { @Override @Transactional - public void restorePassword(String newPassword, String token) { - var emailToken = - emailTokenRepository.findById(token).orElseThrow(EmailTokenNotFoundException::new); + public void restorePassword(RestorePasswordDto restorePasswordDto) { + var emailToken = emailTokenRepository.findById(restorePasswordDto.getEmailToken()) + .orElseThrow(EmailTokenNotFoundException::new); var contact = emailToken.getContact(); - var newEncodedPassword = passwordEncoder.encode(newPassword); + var newEncodedPassword = passwordEncoder.encode(restorePasswordDto.getNewPassword()); contact.setPassword(newEncodedPassword); emailTokenRepository.delete(emailToken); diff --git a/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java b/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java index f9fa2103..46e43832 100644 --- a/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java +++ b/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java @@ -3,6 +3,7 @@ import com.chat.yourway.config.websocket.WebsocketProperties; import com.chat.yourway.dto.request.MessagePrivateRequestDto; import com.chat.yourway.dto.request.MessagePublicRequestDto; +import com.chat.yourway.dto.request.PageRequestDto; import com.chat.yourway.dto.response.MessageResponseDto; import com.chat.yourway.service.interfaces.ChatMessageService; import com.chat.yourway.service.interfaces.ChatNotificationService; @@ -54,10 +55,11 @@ public MessageResponseDto sendToPrivateTopic(Integer topicId, MessagePrivateRequ } @Override - public List sendMessageHistoryByTopicId(Integer topicId, String email) { + public List sendMessageHistoryByTopicId(Integer topicId, + PageRequestDto pageRequestDto, String email) { log.trace("Started sendMessageHistoryByTopicId = [{}]", topicId); - List messages = messageService.findAllByTopicId(topicId); + List messages = messageService.findAllByTopicId(topicId, pageRequestDto); simpMessagingTemplate.convertAndSendToUser(email, toTopicDestination(topicId), messages); log.trace("Message history was sent to topicId = [{}]", topicId); diff --git a/src/main/java/com/chat/yourway/service/ContactServiceImpl.java b/src/main/java/com/chat/yourway/service/ContactServiceImpl.java index a57826a2..a45032f8 100644 --- a/src/main/java/com/chat/yourway/service/ContactServiceImpl.java +++ b/src/main/java/com/chat/yourway/service/ContactServiceImpl.java @@ -3,13 +3,17 @@ import com.chat.yourway.dto.request.ContactRequestDto; import com.chat.yourway.dto.request.EditContactProfileRequestDto; import com.chat.yourway.dto.response.ContactProfileResponseDto; -import com.chat.yourway.exception.*; +import com.chat.yourway.exception.ContactNotFoundException; +import com.chat.yourway.exception.PasswordsAreNotEqualException; +import com.chat.yourway.exception.ValueNotUniqException; import com.chat.yourway.model.Contact; import com.chat.yourway.model.Role; import com.chat.yourway.repository.ContactRepository; import com.chat.yourway.service.interfaces.ContactService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; @@ -26,13 +30,15 @@ public class ContactServiceImpl implements ContactService { @Transactional @Override public Contact create(ContactRequestDto contactRequestDto) { - log.trace("Started create contact, contact email: {}", contactRequestDto.getEmail()); + log.trace("Started create contact, contact email: [{}]", contactRequestDto.getEmail()); + if (isEmailExists(contactRequestDto.getEmail())) { + log.warn("Email [{}] already in use", contactRequestDto.getEmail()); throw new ValueNotUniqException( - String.format("Email %s already in use", contactRequestDto.getEmail())); + String.format("Email [%s] already in use", contactRequestDto.getEmail())); } - return contactRepository.save( + Contact contact = contactRepository.save( Contact.builder() .nickname(contactRequestDto.getNickname()) .avatarId(contactRequestDto.getAvatarId()) @@ -42,61 +48,78 @@ public Contact create(ContactRequestDto contactRequestDto) { .isPrivate(true) .role(Role.USER) .build()); + + log.info("New contact with email [{}] was created", contactRequestDto.getEmail()); + return contact; } @Override + @Transactional(readOnly = true) + @Cacheable(value = "contacts", key = "#email") public Contact findByEmail(String email) { - log.trace("Started findByEmail: {}", email); - return contactRepository + log.trace("Started findByEmail: [{}]", email); + Contact contact = contactRepository .findByEmailIgnoreCase(email) - .orElseThrow( - () -> new ContactNotFoundException(String.format("Email %s wasn't found", email))); + .orElseThrow(() -> { + log.warn("Email [{}] wasn't found", email); + return new ContactNotFoundException(String.format("Email [%s] wasn't found", email)); + }); + + log.info("Contact was found by email [{}]", email); + return contact; } @Override + @Transactional + @CacheEvict(value = "contacts", key = "#email") public void changePasswordByEmail(String password, String email) { + log.trace("Started change password by email [{}]", email); contactRepository.changePasswordByEmail(passwordEncoder.encode(password), email); + log.info("Password was changed by email [{}]", email); } @Override public void verifyPassword(String password, String encodedPassword) { + log.trace("Started verify password"); + if (!passwordEncoder.matches(password, encodedPassword)) { + log.warn("Password was not verify"); throw new PasswordsAreNotEqualException(); } + log.info("Password was verified"); } - @Transactional @Override + @Transactional + @CacheEvict(value = "contacts", key = "#userDetails.getUsername()") public void updateContactProfile( EditContactProfileRequestDto editContactProfileRequestDto, UserDetails userDetails) { - log.trace("Started updating contact profile: {}", editContactProfileRequestDto); + log.trace("Started updating contact profile: [{}]", editContactProfileRequestDto); + String email = userDetails.getUsername(); - Contact contact = - contactRepository - .findByEmailIgnoreCase(email) - .orElseThrow( - () -> new ContactNotFoundException(String.format("Email %s wasn't found", email))); + + Contact contact = findByEmail(email); contact.setNickname(editContactProfileRequestDto.getNickname()); contact.setAvatarId(editContactProfileRequestDto.getAvatarId()); - contact = contactRepository.save(contact); - log.trace("Updated contact: {}", contact); + contactRepository.save(contact); + + log.info("Updated contact by email [{}]", email); } @Override public boolean isEmailExists(String email) { + log.trace("Started check is email exists in repository"); return contactRepository.existsByEmailIgnoreCase(email); } @Override public ContactProfileResponseDto getContactProfile(UserDetails userDetails) { String email = userDetails.getUsername(); - Contact contact = - contactRepository - .findByEmailIgnoreCase(email) - .orElseThrow( - () -> new ContactNotFoundException(String.format("Email %s wasn't found", email))); + log.trace("Started get contact profile by email [{}]", email); + + Contact contact = findByEmail(email); ContactProfileResponseDto responseDto = new ContactProfileResponseDto(); responseDto.setNickname(contact.getNickname()); @@ -104,23 +127,30 @@ public ContactProfileResponseDto getContactProfile(UserDetails userDetails) { responseDto.setEmail(email); responseDto.setHasPermissionSendingPrivateMessage(contact.isPermittedSendingPrivateMessage()); + log.info("Contact profile was got by email [{}]", email); return responseDto; } @Override @Transactional + @CacheEvict(value = "contacts", key = "#userDetails.getUsername()") public void permitSendingPrivateMessages(UserDetails userDetails) { + log.trace("Started permit sending private messages by email [{}]", userDetails.getUsername()); boolean isPermittedSendingPrivateMessage = true; changePermissionSendingPrivateMessages(userDetails, isPermittedSendingPrivateMessage); + log.info("Permitted sending private messages by email [{}]", userDetails.getUsername()); } @Override @Transactional + @CacheEvict(value = "contacts", key = "#userDetails.getUsername()") public void prohibitSendingPrivateMessages(UserDetails userDetails) { + log.trace("Started prohibit sending private messages by email [{}]", userDetails.getUsername()); boolean isPermittedSendingPrivateMessage = false; changePermissionSendingPrivateMessages(userDetails, isPermittedSendingPrivateMessage); + log.info("Prohibited sending private messages by email [{}]", userDetails.getUsername()); } private void changePermissionSendingPrivateMessages( diff --git a/src/main/java/com/chat/yourway/service/MessageServiceImpl.java b/src/main/java/com/chat/yourway/service/MessageServiceImpl.java index f92e1090..07ca7ec1 100644 --- a/src/main/java/com/chat/yourway/service/MessageServiceImpl.java +++ b/src/main/java/com/chat/yourway/service/MessageServiceImpl.java @@ -1,5 +1,6 @@ package com.chat.yourway.service; +import com.chat.yourway.dto.request.PageRequestDto; import com.chat.yourway.dto.request.MessagePrivateRequestDto; import com.chat.yourway.dto.request.MessagePublicRequestDto; import com.chat.yourway.dto.response.MessageResponseDto; @@ -17,10 +18,15 @@ import com.chat.yourway.service.interfaces.TopicSubscriberService; import jakarta.transaction.Transactional; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; @Service @@ -101,9 +107,16 @@ public void reportMessageById(Integer messageId, String email) { } @Override - public List findAllByTopicId(Integer topicId) { + public List findAllByTopicId(Integer topicId, PageRequestDto pageRequestDto) { log.trace("Get all messages for topic with ID: {}", topicId); - List messages = messageRepository.findAllByTopicId(topicId); + + Integer page = pageRequestDto.getPage(); + Integer pageSize = pageRequestDto.getPageSize(); + Pageable pageable = PageRequest.of(page, pageSize, Sort.Direction.DESC, "timestamp"); + + List messages = new ArrayList<>(messageRepository.findAllByTopicId(topicId, pageable)); + messages.sort(Comparator.comparing(Message::getTimestamp)); + log.trace("Getting all messages for topic with ID: {}", topicId); return messageMapper.toListResponseDto(messages); } diff --git a/src/main/java/com/chat/yourway/service/TopicSubscriberServiceImpl.java b/src/main/java/com/chat/yourway/service/TopicSubscriberServiceImpl.java index 71f29887..99bc1634 100644 --- a/src/main/java/com/chat/yourway/service/TopicSubscriberServiceImpl.java +++ b/src/main/java/com/chat/yourway/service/TopicSubscriberServiceImpl.java @@ -120,6 +120,21 @@ public boolean hasProhibitionSendingPrivateMessages(Integer topicId) { return topicSubscriberRepository.checkIfExistProhibitionSendingPrivateMessage(topicId); } + @Override + @Transactional + public void complainTopic(Integer topicId, UserDetails userDetails) { + String email = userDetails.getUsername(); + boolean hasComplaint = true; + + if (!topicRepository.existsById(topicId)) { + throw new TopicNotFoundException(String.format("Topic with id [%d] is not found.", topicId)); + } else if (!topicSubscriberRepository.existsByContactEmailAndTopicIdAndUnsubscribeAtIsNull(email, topicId)) { + throw new NotSubscribedTopicException("You cannot complain topic because you did not subscribe before."); + } + + topicSubscriberRepository.updateHasComplaintStatusByTopicIdAndContactEmail(topicId, email, hasComplaint); + } + private boolean isTopicCreator(Integer topicId, String topicCreator) { return topicSubscriberRepository.existsByTopicIdAndTopicCreatedBy(topicId, topicCreator); } diff --git a/src/main/java/com/chat/yourway/service/interfaces/ChangePasswordService.java b/src/main/java/com/chat/yourway/service/interfaces/ChangePasswordService.java index d6f0fd93..ac425153 100644 --- a/src/main/java/com/chat/yourway/service/interfaces/ChangePasswordService.java +++ b/src/main/java/com/chat/yourway/service/interfaces/ChangePasswordService.java @@ -1,6 +1,7 @@ package com.chat.yourway.service.interfaces; import com.chat.yourway.dto.request.ChangePasswordDto; +import com.chat.yourway.dto.request.RestorePasswordDto; import com.chat.yourway.exception.ContactNotFoundException; import com.chat.yourway.exception.EmailTokenNotFoundException; import com.chat.yourway.exception.PasswordsAreNotEqualException; @@ -11,11 +12,11 @@ public interface ChangePasswordService { /** * Changes the password for the user's account based on the provided request and user details. * - * @param request The data transfer object (DTO) containing the necessary information for password - * change. + * @param request The data transfer object (DTO) containing the necessary information for + * password change. * @param userDetails The details of the user account for which the password change is requested. * @throws PasswordsAreNotEqualException If old password does not matched to current user - * password. + * password. */ void changePassword(ChangePasswordDto request, UserDetails userDetails); @@ -24,7 +25,7 @@ public interface ChangePasswordService { * process of sending an email to the provided email address, checking if account exists in the * system, generating email message for sending to user by inputted email. * - * @param email The email address of the user requesting password restoration. + * @param email The email address of the user requesting password restoration. * @param clientHost The client host for generating the restoration link. * @throws ContactNotFoundException If the provided email does not exist in a database. */ @@ -36,10 +37,10 @@ public interface ChangePasswordService { *

This method allows a user to restore their password by providing a new password along with * the restoration token received through the password restoration process. * - * @param newPassword The new password chosen by the user for restoration. - * @param token The restoration token received by the user for verification from email letter. + * @param restorePasswordDto The data transfer object (DTO) containing the necessary information + * for restore password. * @throws EmailTokenNotFoundException If the provided token does not exist in a database. */ - void restorePassword(String newPassword, String token); + void restorePassword(RestorePasswordDto restorePasswordDto); } diff --git a/src/main/java/com/chat/yourway/service/interfaces/ChatMessageService.java b/src/main/java/com/chat/yourway/service/interfaces/ChatMessageService.java index 40475896..9eed2e33 100644 --- a/src/main/java/com/chat/yourway/service/interfaces/ChatMessageService.java +++ b/src/main/java/com/chat/yourway/service/interfaces/ChatMessageService.java @@ -2,6 +2,7 @@ import com.chat.yourway.dto.request.MessagePrivateRequestDto; import com.chat.yourway.dto.request.MessagePublicRequestDto; +import com.chat.yourway.dto.request.PageRequestDto; import com.chat.yourway.dto.response.MessageResponseDto; import java.util.List; @@ -33,10 +34,12 @@ MessageResponseDto sendToPrivateTopic(Integer topicId, /** * Send messageHistory by topic id. * - * @param topicId The id of the topic. - * @param email The email of the sender. + * @param topicId The id of the topic. + * @param pageRequestDto Set parameters for pagination. + * @param email The email of the sender. * @return list topic messages. */ - List sendMessageHistoryByTopicId(Integer topicId, String email); + List sendMessageHistoryByTopicId(Integer topicId, + PageRequestDto pageRequestDto, String email); } diff --git a/src/main/java/com/chat/yourway/service/interfaces/MessageService.java b/src/main/java/com/chat/yourway/service/interfaces/MessageService.java index ce1dae70..13eb8b9c 100644 --- a/src/main/java/com/chat/yourway/service/interfaces/MessageService.java +++ b/src/main/java/com/chat/yourway/service/interfaces/MessageService.java @@ -2,6 +2,7 @@ import com.chat.yourway.dto.request.MessagePrivateRequestDto; import com.chat.yourway.dto.request.MessagePublicRequestDto; +import com.chat.yourway.dto.request.PageRequestDto; import com.chat.yourway.dto.response.MessageResponseDto; import com.chat.yourway.exception.MessageHasAlreadyReportedException; import com.chat.yourway.exception.MessageNotFoundException; @@ -53,11 +54,12 @@ public interface MessageService { /** * Retrieves a list of messages based on the given topic ID. * - * @param topicId The unique identifier of the topic. + * @param topicId The unique identifier of the topic. + * @param pageRequestDto Set parameters for pagination * @return A list of {@link MessageResponseDto} containing messages related to the specified topic * ID. */ - List findAllByTopicId(Integer topicId); + List findAllByTopicId(Integer topicId, PageRequestDto pageRequestDto); /** * Count saved messages by topic id and sander email between current time and set timestamp. diff --git a/src/main/java/com/chat/yourway/service/interfaces/TopicSubscriberService.java b/src/main/java/com/chat/yourway/service/interfaces/TopicSubscriberService.java index 264c73d7..c0b410ff 100644 --- a/src/main/java/com/chat/yourway/service/interfaces/TopicSubscriberService.java +++ b/src/main/java/com/chat/yourway/service/interfaces/TopicSubscriberService.java @@ -75,4 +75,20 @@ public interface TopicSubscriberService { * @return true if sending private messages is prohibited, false otherwise */ boolean hasProhibitionSendingPrivateMessages(Integer topicId); + + /** + * Registers a complaint for a specific topic. + * + * This method allows a user to complain about a particular topic identified by its unique identifier. + * The complaint details, such as the user's information, will be recorded for further investigation. + * + * @param topicId The unique identifier of the topic being complained about. + * @param userDetails The details of the user lodging the complaint. + * This should include relevant information like user ID, username, etc. + * Ensure that the userDetails parameter is not null. + * + * @throws TopicNotFoundException If topic does not exist. + * @throws NotSubscribedTopicException If contact does not subscribed to topic. + */ + void complainTopic(Integer topicId, UserDetails userDetails); } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 617789b2..023afd21 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -40,13 +40,13 @@ security.jwt.expiration=3600000 security.jwt.refresh-expiration=604800000 #CORS: -cors.allowed-origins=${CORS_ORIGINS:http://localhost:8080} +cors.allowed-origins=${CORS_ORIGINS:http://localhost:8080,http://localhost:3000} cors.allowed-methods=GET, POST, PUT, PATCH, DELETE cors.allowed-headers=* cors.allow-credentials=true # SMTP Configuration -spring.mail.host=smtp.office365.com +spring.mail.host=${SMTP_HOST:smtp.gmail.com} spring.mail.port=587 spring.mail.username=${EMAIL_ADDRESS:} spring.mail.password=${EMAIL_PASSWORD:} diff --git a/src/main/resources/db/migration/V0026__add_has_complaint_column_in_table_topic_subscriber.sql b/src/main/resources/db/migration/V0026__add_has_complaint_column_in_table_topic_subscriber.sql new file mode 100644 index 00000000..87881f3f --- /dev/null +++ b/src/main/resources/db/migration/V0026__add_has_complaint_column_in_table_topic_subscriber.sql @@ -0,0 +1,6 @@ +ALTER TABLE chat.topic_subscriber + ADD has_complaint boolean DEFAULT false; + +UPDATE chat.topic_subscriber +SET has_complaint = false +where contact_id > 0; \ No newline at end of file diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html index 4bea8008..75ee8e62 100644 --- a/src/main/resources/static/index.html +++ b/src/main/resources/static/index.html @@ -9,26 +9,64 @@

WebSocket Chat Test Client

+

+ Connect to WebSocket [http://localhost/chat?Authorization=Bearer {jwt_token}] +

-
+ +

+ Subscribe to topic [/topic/{id}] +

+
+ + + + +
+ +

+ Get topic notification [/user/specific/notify/{id}] +

+
+ - +


+

+ Get message history [/app/history/topic/{id}] +

-
-
+ +

+ Send message to public topic [/app/topic/public/{topicId}] +

-
+

+ Send message to private topic [/app/topic/private/{topicId}] +

\ No newline at end of file diff --git a/src/test/java/com/chat/yourway/integration/controller/ChatControllerTest.java b/src/test/java/com/chat/yourway/integration/controller/ChatControllerTest.java index 6667abc6..f53e9ce7 100644 --- a/src/test/java/com/chat/yourway/integration/controller/ChatControllerTest.java +++ b/src/test/java/com/chat/yourway/integration/controller/ChatControllerTest.java @@ -10,6 +10,7 @@ import com.chat.yourway.dto.request.MessagePrivateRequestDto; import com.chat.yourway.dto.request.MessagePublicRequestDto; +import com.chat.yourway.dto.request.PageRequestDto; import com.chat.yourway.dto.response.MessageNotificationResponseDto; import com.chat.yourway.dto.response.MessageResponseDto; import com.chat.yourway.integration.controller.websocketclient.TestStompFrameHandler; @@ -87,10 +88,9 @@ public class ChatControllerTest { void setUp() { String accessToken = getAccessToken(); - String URL = "ws://localhost:" + port + "/chat"; + String URL = "ws://localhost:" + port + "/chat?Authorization=" + "Bearer " + accessToken; WebSocketHttpHeaders headers = new WebSocketHttpHeaders(); - headers.add("Authorization", "Bearer " + accessToken); session = createWebSocketSession(URL, headers); } @@ -165,6 +165,7 @@ void sendToContact_shouldReturnCorrectReceivedPrivateMessageFromSelfToSelf() { void getMessages_shouldReturnReceivedMessagesHistoryFromTopic() { // Given int topicId = 12; + PageRequestDto pageRequestDto = new PageRequestDto(0, 10); //Stored subscription results for testing CompletableFuture resultKeeper = new CompletableFuture<>(); @@ -172,6 +173,10 @@ void getMessages_shouldReturnReceivedMessagesHistoryFromTopic() { session.subscribe("/user/topic/" + topicId, new TestStompFrameHandler<>(resultKeeper, objectMapper, MessageResponseDto[].class)); + // Get topic message history + byte[] pageBytes = objectMapper.writeValueAsBytes(pageRequestDto); + session.send("/app/history/topic/" + topicId, pageBytes); + // Then MessageResponseDto[] messageResponseDtos = resultKeeper.get(3, SECONDS); assertThat(messageResponseDtos).isNotNull(); diff --git a/src/test/java/com/chat/yourway/integration/controller/MessageControllerTest.java b/src/test/java/com/chat/yourway/integration/controller/MessageControllerTest.java index 1aed810a..1e6c9351 100644 --- a/src/test/java/com/chat/yourway/integration/controller/MessageControllerTest.java +++ b/src/test/java/com/chat/yourway/integration/controller/MessageControllerTest.java @@ -1,21 +1,13 @@ package com.chat.yourway.integration.controller; import static com.github.springtestdbunit.annotation.DatabaseOperation.CLEAN_INSERT; -import static org.springframework.http.MediaType.APPLICATION_JSON; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.chat.yourway.integration.extension.PostgresExtension; import com.chat.yourway.integration.extension.RedisExtension; -import com.chat.yourway.model.Message; -import com.chat.yourway.repository.MessageRepository; import com.github.springtestdbunit.DbUnitTestExecutionListener; import com.github.springtestdbunit.annotation.DatabaseSetup; -import java.util.List; -import java.util.stream.Collectors; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -28,7 +20,6 @@ import org.springframework.test.context.TestExecutionListeners; import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.ResultActions; @ExtendWith({PostgresExtension.class, RedisExtension.class}) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @@ -50,44 +41,8 @@ public class MessageControllerTest { @Autowired private MockMvc mockMvc; - @Autowired - private MessageRepository messageRepository; - private static final String URI = "/messages/"; - //----------------------------------- - // GET - //----------------------------------- - - @Test - @DisplayName("findAllByTopicId should return empty list of all messages by topic id") - void findAllByTopicId_shouldReturnEmptyListOfAllMessagesByTopicId() throws Exception { - // When - int notExistingTopicId = 99; - var result = mockMvc.perform(get(URI + "all/" + notExistingTopicId)); - - // Then - result - .andExpect(status().isOk()) - .andExpect(content().contentType(APPLICATION_JSON)) - .andExpect(content().json("[]")); - } - - @Test - @DisplayName("findAllByTopicId should return list of all messages by topic id") - public void findAllByTopicId_shouldReturnListOfAllMessagesByTopicId() throws Exception { - // Given - int topicId = 11; - List messages = messageRepository.findAllByTopicId(topicId); - - // When - var result = mockMvc.perform(get(URI + "all/" + topicId)); - - // Then - result.andExpect(status().isOk()); - assertMessagesEquals(result, messages); - } - //----------------------------------- // POST //----------------------------------- @@ -137,25 +92,4 @@ public void reportMessage_shouldReturn400ForAlreadyReportedMessage() throws Exce result.andExpect(status().isBadRequest()); } - //----------------------------------- - // Private methods - //----------------------------------- - private void assertMessagesEquals(ResultActions result, List messages) throws Exception { - result - .andExpect(content().contentType(APPLICATION_JSON)) - .andExpect(jsonPath("$[*].id").value(messages.stream() - .map(Message::getId) - .collect(Collectors.toList()))) - .andExpect(jsonPath("$[*].sentFrom").value(messages.stream() - .map(Message::getSentFrom) - .collect(Collectors.toList()))) - .andExpect(jsonPath("$[*].sendTo").value(messages.stream() - .map(Message::getSendTo) - .collect(Collectors.toList()))) - .andExpect(jsonPath("$[*].content").value(messages.stream() - .map(Message::getContent) - .collect(Collectors.toList()))) - .andExpect(jsonPath("$[*].timestamp").isNotEmpty()); - } - } diff --git a/src/test/java/com/chat/yourway/integration/service/impl/ChangePasswordServiceImplTestValidation.java b/src/test/java/com/chat/yourway/integration/service/impl/ChangePasswordServiceImplTestValidation.java index 3b41ebf3..e7d3fca8 100644 --- a/src/test/java/com/chat/yourway/integration/service/impl/ChangePasswordServiceImplTestValidation.java +++ b/src/test/java/com/chat/yourway/integration/service/impl/ChangePasswordServiceImplTestValidation.java @@ -16,6 +16,7 @@ import com.chat.yourway.dto.common.EmailMessageDto; import com.chat.yourway.dto.common.EmailMessageInfoDto; import com.chat.yourway.dto.request.ChangePasswordDto; +import com.chat.yourway.dto.request.RestorePasswordDto; import com.chat.yourway.exception.ContactNotFoundException; import com.chat.yourway.exception.EmailTokenNotFoundException; import com.chat.yourway.exception.PasswordsAreNotEqualException; @@ -202,9 +203,10 @@ public void shouldSetNewPassword_whenUserGaveCorrectToken() { var oldPassword = contactService.findByEmail(EMAIL).getPassword(); var newPassword = "newPassword"; var uuidToken = "token"; + var restorePasswordDto = new RestorePasswordDto(newPassword, uuidToken); // When - changePasswordService.restorePassword(newPassword, uuidToken); + changePasswordService.restorePassword(restorePasswordDto); // Then assertAll( @@ -231,10 +233,11 @@ public void shouldThrowEmailTokenNotFoundException_whenUserGaveIncorrectToken() var emailTokenRepositoryMock = mock(EmailTokenRepository.class); var newPassword = "newPassword"; var uuidToken = "UUID"; + var restorePasswordDto = new RestorePasswordDto(newPassword, uuidToken); // When assertThrows(EmailTokenNotFoundException.class, - () -> changePasswordService.restorePassword(newPassword, uuidToken)); + () -> changePasswordService.restorePassword(restorePasswordDto)); // Then verify(passwordEncoderMock, never()).encode(newPassword); diff --git a/src/test/java/com/chat/yourway/integration/service/impl/ContactServiceImplTest.java b/src/test/java/com/chat/yourway/integration/service/impl/ContactServiceImplTest.java index 6e5c3715..89b93783 100644 --- a/src/test/java/com/chat/yourway/integration/service/impl/ContactServiceImplTest.java +++ b/src/test/java/com/chat/yourway/integration/service/impl/ContactServiceImplTest.java @@ -204,7 +204,7 @@ public void shouldSuccessfullyProhibitSendingPrivateMessages_whenUserChangePermi contactService.prohibitSendingPrivateMessages(contact); // Then - var result = contactService.findByEmail(contactEmail); + var result = contactRepository.findByEmailIgnoreCase(contactEmail).get(); assertThat(result) .extracting(Contact::isPermittedSendingPrivateMessage) diff --git a/src/test/java/com/chat/yourway/integration/service/impl/MessageServiceImplTest.java b/src/test/java/com/chat/yourway/integration/service/impl/MessageServiceImplTest.java index 62be8740..4f63849e 100644 --- a/src/test/java/com/chat/yourway/integration/service/impl/MessageServiceImplTest.java +++ b/src/test/java/com/chat/yourway/integration/service/impl/MessageServiceImplTest.java @@ -1,5 +1,10 @@ package com.chat.yourway.integration.service.impl; +import static com.github.springtestdbunit.annotation.DatabaseOperation.CLEAN_INSERT; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertThrows; + import com.chat.yourway.exception.MessageHasAlreadyReportedException; import com.chat.yourway.integration.extension.PostgresExtension; import com.chat.yourway.integration.extension.RedisExtension; @@ -7,9 +12,7 @@ import com.chat.yourway.repository.MessageRepository; import com.chat.yourway.service.MessageServiceImpl; import com.github.springtestdbunit.DbUnitTestExecutionListener; -import com.github.springtestdbunit.annotation.DatabaseOperation; import com.github.springtestdbunit.annotation.DatabaseSetup; -import com.github.springtestdbunit.annotation.DatabaseTearDown; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -22,10 +25,6 @@ import org.springframework.test.context.support.DirtiesContextTestExecutionListener; import org.springframework.test.context.transaction.TransactionalTestExecutionListener; -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertThrows; - @ExtendWith({PostgresExtension.class, RedisExtension.class}) @SpringBootTest @TestExecutionListeners( @@ -37,6 +36,12 @@ MockitoTestExecutionListener.class, ResetMocksTestExecutionListener.class }) +@DatabaseSetup(value = { + "/dataset/mockdb/topic.xml", + "/dataset/mockdb/message.xml", + "/dataset/mockdb/contact.xml", + "/dataset/mockdb/contact_message_report.xml"}, + type = CLEAN_INSERT) public class MessageServiceImplTest { @Autowired ContactRepository contactRepository; @Autowired MessageRepository messageRepository; @@ -44,14 +49,10 @@ public class MessageServiceImplTest { @Test @DisplayName("should save report to message when user makes report") - @DatabaseSetup(value = "/dataset/report-to-message-dataset.xml", type = DatabaseOperation.INSERT) - @DatabaseTearDown( - value = "/dataset/report-to-message-dataset.xml", - type = DatabaseOperation.DELETE) public void shouldSaveReportToMessage_WhenUserMakesReport() { // Given - var messageId = 2; - var email = "user3@gmail.com"; + var messageId = 101; + var email = "oleg@gmail.com"; // When messageService.reportMessageById(messageId, email); @@ -67,14 +68,10 @@ public void shouldSaveReportToMessage_WhenUserMakesReport() { @Test @DisplayName("should delete message when user makes report and message reached max attempts") - @DatabaseSetup(value = "/dataset/report-to-message-dataset.xml", type = DatabaseOperation.CLEAN_INSERT) - @DatabaseTearDown( - value = "/dataset/report-to-message-dataset.xml", - type = DatabaseOperation.DELETE) public void shouldDeleteMessage_WhenUserMakesReportAndMessageReachedMaxAttempts() { // Given - var messageId = 1; - var email = "user3@gmail.com"; + var messageId = 100; + var email = "oleg@gmail.com"; // When messageService.reportMessageById(messageId, email); @@ -88,14 +85,10 @@ public void shouldDeleteMessage_WhenUserMakesReportAndMessageReachedMaxAttempts( @Test @DisplayName("should throw MessageHasAlreadyReportedException when user makes report again") - @DatabaseSetup(value = "/dataset/report-to-message-dataset.xml", type = DatabaseOperation.INSERT) - @DatabaseTearDown( - value = "/dataset/report-to-message-dataset.xml", - type = DatabaseOperation.DELETE) public void shouldThrowMessageHasAlreadyReportedException_WhenUserMakesReportAgain() { // Given - var messageId = 1; - var email = "user2@gmail.com"; + var messageId = 100; + var email = "anton@gmail.com"; // When // Then diff --git a/src/test/java/com/chat/yourway/integration/service/impl/TopicSubscriberServiceImplTest.java b/src/test/java/com/chat/yourway/integration/service/impl/TopicSubscriberServiceImplTest.java index 657114c8..8c40aa14 100644 --- a/src/test/java/com/chat/yourway/integration/service/impl/TopicSubscriberServiceImplTest.java +++ b/src/test/java/com/chat/yourway/integration/service/impl/TopicSubscriberServiceImplTest.java @@ -48,7 +48,7 @@ public class TopicSubscriberServiceImplTest { @Test @DatabaseSetup( value = "/dataset/favourite-topics-of-contact.xml", - type = DatabaseOperation.INSERT) + type = DatabaseOperation.CLEAN_INSERT) @DatabaseTearDown( value = "/dataset/favourite-topics-of-contact.xml", type = DatabaseOperation.DELETE) @@ -73,7 +73,7 @@ public void shouldSuccessfullyAddTopicToFavourite_whenUserMarkTopicAsFavourite() @Test @DatabaseSetup( value = "/dataset/favourite-topics-of-contact.xml", - type = DatabaseOperation.INSERT) + type = DatabaseOperation.CLEAN_INSERT) @DatabaseTearDown( value = "/dataset/favourite-topics-of-contact.xml", type = DatabaseOperation.DELETE) @@ -99,7 +99,7 @@ public void shouldSuccessfullyRemoveTopicFromFavourite_whenUserUnmarkTopicAsFavo @Test @DatabaseSetup( value = "/dataset/favourite-topics-of-contact.xml", - type = DatabaseOperation.INSERT) + type = DatabaseOperation.CLEAN_INSERT) @DatabaseTearDown( value = "/dataset/favourite-topics-of-contact.xml", type = DatabaseOperation.DELETE) @@ -121,7 +121,7 @@ public void shouldThrowTopicNotFoundException_whenUserMarkTopicAsFavouriteAndTop @Test @DatabaseSetup( value = "/dataset/favourite-topics-of-contact.xml", - type = DatabaseOperation.INSERT) + type = DatabaseOperation.CLEAN_INSERT) @DatabaseTearDown( value = "/dataset/favourite-topics-of-contact.xml", type = DatabaseOperation.DELETE) @@ -144,7 +144,7 @@ public void shouldThrowTopicNotFoundException_whenUserMarkTopicAsFavouriteAndTop @Test @DatabaseSetup( value = "/dataset/favourite-topics-of-contact.xml", - type = DatabaseOperation.INSERT) + type = DatabaseOperation.CLEAN_INSERT) @DatabaseTearDown( value = "/dataset/favourite-topics-of-contact.xml", type = DatabaseOperation.DELETE) @@ -167,7 +167,7 @@ public void shouldThrowTopicNotFoundException_whenUserMarkTopicAsFavouriteAndTop @Test @DatabaseSetup( value = "/dataset/favourite-topics-of-contact.xml", - type = DatabaseOperation.INSERT) + type = DatabaseOperation.CLEAN_INSERT) @DatabaseTearDown( value = "/dataset/favourite-topics-of-contact.xml", type = DatabaseOperation.DELETE) @@ -187,4 +187,75 @@ public void shouldThrowTopicNotFoundException_whenUserMarkTopicAsFavouriteAndTop () -> topicSubscriberService.removeTopicFromFavourite(topicId, contact)); } + @Test + @DatabaseSetup( + value = "/dataset/complain-topic-dataset.xml", + type = DatabaseOperation.CLEAN_INSERT) + @DatabaseTearDown( + value = "/dataset/complain-topic-dataset.xml", + type = DatabaseOperation.DELETE) + @DisplayName( + "should successfully complain topic when user complain topic") + public void shouldSuccessfullyComplainTopic_whenUserComplainTopic() { + // Given + var contactEmail = "vasil1132@gmail.com"; + var contact = contactService.findByEmail(contactEmail); + var topicId = 111123; + + // When + topicSubscriberService.complainTopic(topicId, contact); + + // Then + var result = topicService.findById(topicId).getTopicSubscribers().stream() + .filter(topicSubscriber -> topicSubscriber.getContact().getEmail().equals(contactEmail)) + .anyMatch(TopicSubscriberResponseDto::isHasComplaint); + + assertThat(result) + .withFailMessage("Expecting containing complaint to topic by user") + .isTrue(); + } + + @Test + @DatabaseSetup( + value = "/dataset/complain-topic-dataset.xml", + type = DatabaseOperation.CLEAN_INSERT) + @DatabaseTearDown( + value = "/dataset/complain-topic-dataset.xml", + type = DatabaseOperation.DELETE) + @DisplayName( + "should throw TopicNotFoundException when user complain topic") + public void shouldThrowTopicNotFoundException_whenUserComplainTopic() { + // Given + var contactEmail = "vasil1132@gmail.com"; + var contact = contactService.findByEmail(contactEmail); + var topicId = 1; + + // When + // Then + assertThrows( + TopicNotFoundException.class, + () -> topicSubscriberService.complainTopic(topicId, contact)); + } + + @Test + @DatabaseSetup( + value = "/dataset/complain-topic-dataset.xml", + type = DatabaseOperation.CLEAN_INSERT) + @DatabaseTearDown( + value = "/dataset/complain-topic-dataset.xml", + type = DatabaseOperation.DELETE) + @DisplayName( + "should throw NotSubscribedTopicException when user complain topic") + public void shouldThrowNotSubscribedTopicException_whenUserComplainTopic() { + // Given + var contactEmail = "vasil1132@gmail.com"; + var contact = contactService.findByEmail(contactEmail); + var topicId = 111124; + + // When + // Then + assertThrows( + NotSubscribedTopicException.class, + () -> topicSubscriberService.complainTopic(topicId, contact)); + } } diff --git a/src/test/java/com/chat/yourway/unit/listener/StompSubscriptionListenerTest.java b/src/test/java/com/chat/yourway/unit/listener/StompSubscriptionListenerTest.java index 657198fd..8a717ba9 100644 --- a/src/test/java/com/chat/yourway/unit/listener/StompSubscriptionListenerTest.java +++ b/src/test/java/com/chat/yourway/unit/listener/StompSubscriptionListenerTest.java @@ -15,7 +15,6 @@ import com.chat.yourway.config.websocket.WebsocketProperties; import com.chat.yourway.listener.StompSubscriptionListener; import com.chat.yourway.model.event.ContactEvent; -import com.chat.yourway.service.interfaces.ChatMessageService; import com.chat.yourway.service.interfaces.ChatNotificationService; import com.chat.yourway.service.interfaces.ContactEventService; import java.security.Principal; @@ -45,9 +44,6 @@ public class StompSubscriptionListenerTest { @Mock private ContactEventService contactEventService; - @Mock - private ChatMessageService chatMessageService; - @Mock private ChatNotificationService chatNotificationService; @@ -94,22 +90,6 @@ public void handleWebSocketSubscribeListener_shouldSaveEvent() { assertThat(capturedEvent.getLastMessage()).isEqualTo(lastMessage); } - @Test - public void handleWebSocketSubscribeListener_shouldSendMessageHistory() { - // Given - String email = "anton@gmail.com"; - String password = "Password-123"; - int topicId = 1; - String destination = "/user/topic/" + topicId; - var event = createSubscribeEvent(destination, getPrincipal(email, password)); - - // When - stompSubscriptionListener.handleWebSocketSubscribeListener(event); - - // Then - verify(chatMessageService, times(1)).sendMessageHistoryByTopicId(topicId, email); - } - @Test public void handleWebSocketSubscribeListener_shouldNotifyTopicSubscribers() { // Given diff --git a/src/test/java/com/chat/yourway/unit/service/impl/ChangePasswordServiceImplTestValidation.java b/src/test/java/com/chat/yourway/unit/service/impl/ChangePasswordServiceImplTestValidation.java index 6a7435d0..f0f1e22f 100644 --- a/src/test/java/com/chat/yourway/unit/service/impl/ChangePasswordServiceImplTestValidation.java +++ b/src/test/java/com/chat/yourway/unit/service/impl/ChangePasswordServiceImplTestValidation.java @@ -3,6 +3,7 @@ import com.chat.yourway.dto.common.EmailMessageDto; import com.chat.yourway.dto.common.EmailMessageInfoDto; import com.chat.yourway.dto.request.ChangePasswordDto; +import com.chat.yourway.dto.request.RestorePasswordDto; import com.chat.yourway.exception.EmailTokenNotFoundException; import com.chat.yourway.exception.PasswordsAreNotEqualException; import com.chat.yourway.model.Contact; @@ -178,6 +179,7 @@ public void restorePassword_shouldSetNewPassword_whenUserGaveCorrectToken() { // Given var newPassword = "newPassword"; var uuidToken = UUID.randomUUID().toString(); + var restorePasswordDto = new RestorePasswordDto(newPassword, uuidToken); var contact = Contact.builder() .id(1) @@ -198,7 +200,7 @@ public void restorePassword_shouldSetNewPassword_whenUserGaveCorrectToken() { when(emailTokenRepository.findById(uuidToken)).thenReturn(Optional.of(emailToken)); // When - changePasswordService.restorePassword(newPassword, uuidToken); + changePasswordService.restorePassword(restorePasswordDto); // Then verify(emailTokenRepository).findById(uuidToken); @@ -213,13 +215,14 @@ public void restorePassword_shouldThrowEmailTokenNotFoundException_whenUserGaveI // Given var newPassword = "newPassword"; var uuidToken = UUID.randomUUID().toString(); + var restorePasswordDto = new RestorePasswordDto(newPassword, uuidToken); when(emailTokenRepository.findById(uuidToken)).thenReturn(Optional.empty()); // When assertThrows( EmailTokenNotFoundException.class, - () -> changePasswordService.restorePassword(newPassword, uuidToken)); + () -> changePasswordService.restorePassword(restorePasswordDto)); // Then verify(emailTokenRepository).findById(uuidToken); diff --git a/src/test/java/com/chat/yourway/unit/service/impl/MessageServiceImplTest.java b/src/test/java/com/chat/yourway/unit/service/impl/MessageServiceImplTest.java index bb1ac2c2..abe1f3e5 100644 --- a/src/test/java/com/chat/yourway/unit/service/impl/MessageServiceImplTest.java +++ b/src/test/java/com/chat/yourway/unit/service/impl/MessageServiceImplTest.java @@ -16,6 +16,7 @@ import com.chat.yourway.dto.request.MessagePrivateRequestDto; import com.chat.yourway.dto.request.MessagePublicRequestDto; +import com.chat.yourway.dto.request.PageRequestDto; import com.chat.yourway.dto.response.MessageResponseDto; import com.chat.yourway.dto.response.TopicResponseDto; import com.chat.yourway.exception.MessageHasAlreadyReportedException; @@ -40,6 +41,9 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; import org.springframework.test.util.ReflectionTestUtils; @ExtendWith(MockitoExtension.class) @@ -246,11 +250,13 @@ public void createPrivate_shouldThrowTopicNotFoundException() { public void findAllByTopicId_shouldReturnListOfMessages() { // Given int topicId = 1; + Pageable pageable = PageRequest.of(0, 10, Sort.Direction.DESC, "timestamp"); + PageRequestDto pageRequestDto = new PageRequestDto(0, 10); List messages = getPublicMessages(); - when(messageRepository.findAllByTopicId(topicId)).thenReturn(messages); + when(messageRepository.findAllByTopicId(topicId, pageable)).thenReturn(messages); // When - List result = messageService.findAllByTopicId(topicId); + List result = messageService.findAllByTopicId(topicId, pageRequestDto); // Then assertNotNull(result); @@ -258,7 +264,7 @@ public void findAllByTopicId_shouldReturnListOfMessages() { for (int i = 0; i < messages.size(); i++) { assertMessageEquals(messages.get(i), result.get(i)); } - verify(messageRepository, times(1)).findAllByTopicId(topicId); + verify(messageRepository, times(1)).findAllByTopicId(topicId, pageable); } @Test @@ -266,15 +272,17 @@ public void findAllByTopicId_shouldReturnListOfMessages() { public void findAllByTopicId_shouldReturnEmptyList() { // Given int nonExistentTopicId = 99; - when(messageRepository.findAllByTopicId(nonExistentTopicId)).thenReturn(List.of()); + Pageable pageable = PageRequest.of(0, 10, Sort.Direction.DESC, "timestamp"); + PageRequestDto pageRequestDto = new PageRequestDto(0, 10); + when(messageRepository.findAllByTopicId(nonExistentTopicId, pageable)).thenReturn(List.of()); // When - List result = messageService.findAllByTopicId(nonExistentTopicId); + List result = messageService.findAllByTopicId(nonExistentTopicId, pageRequestDto); // Then assertNotNull(result); assertTrue(result.isEmpty()); - verify(messageRepository, times(1)).findAllByTopicId(nonExistentTopicId); + verify(messageRepository, times(1)).findAllByTopicId(nonExistentTopicId, pageable); } @Test diff --git a/src/test/resources/dataset/complain-topic-dataset.xml b/src/test/resources/dataset/complain-topic-dataset.xml new file mode 100644 index 00000000..e02eb539 --- /dev/null +++ b/src/test/resources/dataset/complain-topic-dataset.xml @@ -0,0 +1,38 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/dataset/mockdb/contact.xml b/src/test/resources/dataset/mockdb/contact.xml index 62c33733..6a1f7a1d 100644 --- a/src/test/resources/dataset/mockdb/contact.xml +++ b/src/test/resources/dataset/mockdb/contact.xml @@ -22,4 +22,15 @@ avatar_id="7" is_permitted_sending_private_message="true" /> + \ No newline at end of file diff --git a/src/test/resources/dataset/report-to-message-dataset.xml b/src/test/resources/dataset/report-to-message-dataset.xml deleted file mode 100644 index 046ee8d5..00000000 --- a/src/test/resources/dataset/report-to-message-dataset.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file