Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Bug/6593/fix send email for user in patch update status #426

Merged
Merged
20 changes: 20 additions & 0 deletions core/src/main/java/greencity/controller/EmailController.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,24 @@ public ResponseEntity<Void> sendScheduledNotification(@RequestBody ScheduledEmai
emailService.sendScheduledNotificationEmail(message);
return ResponseEntity.ok().build();
}

/**
* Method for sending an email notification about the status change of a place
* to the user.
*
* @param dto Object containing the necessary information for sending the status
* change notification email. The object includes: - userName: The
* name of the user. - userEmail: The email of the user who will
* receive the notification. - placeName: The name of the place whose
* status has been changed. - newStatus: The new status of the place.
*
* @return ResponseEntity with HTTP status 200 OK if the email was successfully
* sent. If any error occurs, an appropriate error response will be
* returned.
*/
@PostMapping("/sendPlaceStatusChange")
public ResponseEntity<Object> sendPlaceStatusChange(@RequestBody PlaceStatusChangeDto dto) {
emailService.sendPlaceStatusChangeNotification(dto);
return ResponseEntity.ok().build();
}
}
3 changes: 2 additions & 1 deletion core/src/main/resources/messages_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,5 @@ advice.for.block=You received this email for security reasons. To protect your a
profile.text=If you no longer wish to receive these emails, you can unsubscribe from them in your
profile=profile
advice.general.ubs=You are receiving this email because you are a registered member of Pick Up City.
read.more=READ MORE
read.more=READ MORE
your.place.status.changed=The status of your place has been updated. You are receiving this email because the status of your place was changed. Thank you for using our service!
3 changes: 2 additions & 1 deletion core/src/main/resources/messages_uk.properties
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,5 @@ advice.for.block=\u0412\u0438\u0020\u043E\u0442\u0440\u0438\u043C\u0430\u043B\u0
profile.text=\u042f\u043a\u0449\u043e\u0020\u0432\u0438\u0020\u0431\u0456\u043b\u044c\u0448\u0435\u0020\u043d\u0435\u0020\u0445\u043e\u0447\u0435\u0442\u0435\u0020\u043e\u0442\u0440\u0438\u043c\u0443\u0432\u0430\u0442\u0438\u0020\u0440\u043e\u0437\u0441\u0438\u043b\u043a\u0443\u002c\u0020\u0432\u0438\u0020\u043c\u043e\u0436\u0435\u0442\u0435\u0020\u0432\u0456\u0434\u043f\u0438\u0441\u0430\u0442\u0438\u0441\u044f\u0020\u0432\u0456\u0434\u0020\u043d\u0435\u0457\u0020\u0443\u0020\u0441\u0432\u043e\u0454\u043c\u0443
profile=\u043f\u0440\u043e\u0444\u0456\u043b\u0456
advice.general.ubs=\u0412\u0438\u0020\u043e\u0442\u0440\u0438\u043c\u0430\u043b\u0438\u0020\u0446\u0435\u0439\u0020\u0435\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u0438\u0439\u0020\u043b\u0438\u0441\u0442\u002c\u0020\u0442\u043e\u043c\u0443\u0020\u0449\u043e\u0020\u0454\u0020\u0437\u0430\u0440\u0435\u0454\u0441\u0442\u0440\u043e\u0432\u0430\u043d\u0438\u043c\u0020\u043a\u043b\u0456\u0454\u043d\u0442\u043e\u043c\u0020\u0050\u0069\u0063\u006b\u0020\u0055\u0070\u0020\u0043\u0069\u0074\u0079\u002e
read.more=\u0427\u0418\u0422\u0410\u0422\u0418 \u0414\u0410\u041b\u0406
read.more=\u0427\u0418\u0422\u0410\u0422\u0418 \u0414\u0410\u041b\u0406
ChernenkoVitaliy marked this conversation as resolved.
Show resolved Hide resolved
your.place.status.changed=\u0421\u0442\u0430\u0442\u0443\u0441\u0020\u0432\u0430\u0448\u043E\u0433\u043E\u0020\u043C\u0456\u0441\u0446\u044F\u0020\u0431\u0443\u0432\u0020\u043E\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0439\u002E\u0020\u0412\u0438\u0020\u043E\u0442\u0440\u0438\u043C\u0430\u043B\u0438\u0020\u0446\u0435\u0439\u0020\u043B\u0438\u0441\u0442\u002C\u0020\u0442\u043E\u043C\u0443\u0020\u0449\u043E\u0020\u0441\u0442\u0430\u0442\u0443\u0441\u0020\u0432\u0430\u0448\u043E\u0433\u043E\u0020\u043C\u0456\u0441\u0446\u044F\u0020\u0431\u0443\u043B\u043E\u0020\u0437\u043C\u0456\u043D\u0435\u043D\u043E\u002E\u0020\u0414\u044F\u043A\u0443\u0454\u043C\u043E\u002C\u0020\u0449\u043E\u0020\u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0454\u0442\u0435\u0441\u044C\u0020\u043D\u0430\u0448\u0438\u043C\u0020\u0441\u0435\u0440\u0432\u0456\u0441\u043E\u043C\u0021
105 changes: 105 additions & 0 deletions core/src/main/resources/templates/email/place-status-change.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<!DOCTYPE html>
<html th:lang="${language}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<style>
body {
margin: 0;
padding: 0;
background-color: #F5F6F6;
}

.email-container {
font-family: Lato, sans-serif;
font-size: 16px;
width: 100%;
max-width: 600px;
margin: 0 auto;
background-color: #E3E6E8;
}

.header {
text-align: center;
padding: 30px;
background-color: #13AA57;
}

.header-image {
height: 30px;
vertical-align: bottom;
}

.content {
padding: 26px;
text-align: left;
color: #333333 !important;
}

.top-text {
margin-top: 0;
color: #333333 !important;
}

.main-text {
line-height: 1.4;
color: #333333 !important;
}

.bottom-text {
margin-bottom: 0;
color: #333333 !important;
}

.footer {
text-align: center;
padding: 10px;
font-size: 12px;
color: #666666;
background-color: #CACFD3;
}

@media only screen and (max-width: 600px) {
body {
font-size: 13px;
}

.header {
padding: 20px;
}

.header-image {
height: 25px;
}

.footer {
font-size: 10px;
}
}
</style>
</head>
<body>
<div class="email-container">
<div class="header">
<a th:href="${clientLink}" target="_blank">
<img class="header-image" src="https://csb10032000a548f571.blob.core.windows.net/allfiles/5eaa9e18-f91f-4d3a-9926-da1239317a98GreenCity-Logo-White.png" alt="GreenCityLogo">
</a>
</div>

<div class="content">
<p class="top-text">
<b th:text="#{hi.user(${name})}"></b>
</p>

<p class="main-text">
The status of the place "<b th:text="${placeName}"></b>" has been updated to: <b th:text="${placeStatus}"></b>.
</p>
</div>

<div class="footer">
<p class="bottom-text" th:text="#{your.place.status.changed}"></p>
</div>
</div>
</body>
</html>
24 changes: 24 additions & 0 deletions core/src/test/java/greencity/controller/EmailControllerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import greencity.dto.econews.InterestingEcoNewsDto;
import greencity.dto.violation.UserViolationMailDto;
import greencity.enums.PlaceStatus;
import greencity.message.PlaceStatusChangeDto;
import greencity.message.ScheduledEmailMessage;
import greencity.message.SendHabitNotification;
import greencity.message.SendReportEmailMessage;
Expand Down Expand Up @@ -176,4 +178,26 @@ void sendUserReceivedScheduledNotification() {
.content(content))
.andExpect(status().isOk());
}

@Test
@SneakyThrows
void sendPlaceStatusChangeTest() {
PlaceStatusChangeDto dto = new PlaceStatusChangeDto();
dto.setUserName("John Doe");
dto.setUserEmail("test@example.com");
dto.setPlaceName("Green Park");
dto.setNewStatus(PlaceStatus.APPROVED);

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
String content = objectMapper.writeValueAsString(dto);

mockMvc.perform(MockMvcRequestBuilders.post(LINK + "/sendPlaceStatusChange")
.contentType(MediaType.APPLICATION_JSON)
.header("Authorization", "Bearer your_token_here") // Додати заголовок Authorization (якщо потрібен)
.content(content))
.andExpect(status().isOk());

verify(emailService).sendPlaceStatusChangeNotification(dto);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public class EmailConstants {
public static final String DEACTIVATION = "user.deactivation.subject";
public static final String ACTIVATION = "user.activation.subject";
public static final String VIOLATION_EMAIL = "user.violation.subject";
public static final String PLACE_NAME = "placeName";
public static final String PLACE_STATUS = "placeStatus";
// params
public static final String CLIENT_LINK = "clientLink";
public static final String USER_NAME = "name";
Expand Down Expand Up @@ -53,4 +55,5 @@ public class EmailConstants {
public static final String SCHEDULED_NOTIFICATION_PAGE = "scheduled-notification-email-page";
public static final String RECEIVE_INTERESTING_NEWS_EMAIL_PAGE = "receive-interesting-news-email-page";
public static final String BLOCKED_USER_PAGE = "blocked-user-page";
public static final String PLACE_STATUS_CHANGE_PAGE = "place-status-change";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package greencity.message;

import greencity.enums.PlaceStatus;
import lombok.*;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class PlaceStatusChangeDto {
private String placeName;
private PlaceStatus newStatus;
private String userName;
private String userEmail;
}
12 changes: 11 additions & 1 deletion service-api/src/main/java/greencity/service/EmailService.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import greencity.dto.user.UserActivationDto;
import greencity.dto.user.UserDeactivationReasonDto;
import greencity.dto.violation.UserViolationMailDto;
import greencity.message.PlaceStatusChangeDto;
import greencity.message.ScheduledEmailMessage;
import greencity.message.SendReportEmailMessage;

Expand Down Expand Up @@ -85,7 +86,7 @@ void sendRestoreEmail(Long userId, String userFistName, String userEmail, String

/**
* Method for send violation to user.
*
*
* @param dto {@link UserViolationMailDto}-includes all information about
* Violation.
*/
Expand Down Expand Up @@ -138,4 +139,13 @@ void sendCreateNewPasswordForEmployee(Long employeeId, String employeeFistName,
void sendBlockAccountNotificationWithUnblockLinkEmail(
Long userId, String userFistName, String userEmail, String token, String language,
boolean isUbs);

/**
* Sends an email notification to a user regarding the status change of a place.
*
* @param dto the data transfer object containing information about the user,
* place, and the new status of the place (e.g., PROPOSED, DECLINED,
* APPROVED, DELETED).
*/
void sendPlaceStatusChangeNotification(PlaceStatusChangeDto dto);
}
14 changes: 14 additions & 0 deletions service/src/main/java/greencity/service/EmailServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import greencity.dto.user.UserActivationDto;
import greencity.dto.user.UserDeactivationReasonDto;
import greencity.dto.violation.UserViolationMailDto;
import greencity.message.PlaceStatusChangeDto;
import greencity.message.ScheduledEmailMessage;
import greencity.message.SendReportEmailMessage;
import greencity.validator.EmailAddressValidator;
Expand Down Expand Up @@ -317,6 +318,19 @@ private Map<String, Object> buildModelMapForPasswordRestore(Long userId, String
return model;
}

@Override
public void sendPlaceStatusChangeNotification(PlaceStatusChangeDto dto) {
ChernenkoVitaliy marked this conversation as resolved.
Show resolved Hide resolved
Map<String, Object> model = new HashMap<>();
model.put(EmailConstants.CLIENT_LINK, clientLink);
model.put(EmailConstants.USER_NAME, dto.getUserName());
model.put(EmailConstants.PLACE_NAME, dto.getPlaceName());
model.put(EmailConstants.PLACE_STATUS, dto.getNewStatus().name());
model.put(EmailConstants.LANGUAGE, "en");

String template = createEmailTemplate(model, EmailConstants.PLACE_STATUS_CHANGE_PAGE);
sendEmail(dto.getUserEmail(), "Status of your place has been updated", template);
}

private String getClientLinkByIsUbs(boolean isUbs) {
return clientLink + "/#" + (isUbs ? "/ubs" : "/greenCity");
}
Expand Down
1 change: 1 addition & 0 deletions service/src/test/java/greencity/ModelUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -711,4 +711,5 @@ public static TestersSignInRequest getTestersSignInRequestWithInvalidSecretKey()
.secretKey("invalid-secret-key")
.build();
}

}
31 changes: 29 additions & 2 deletions service/src/test/java/greencity/service/EmailServiceImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
import greencity.dto.user.UserDeactivationReasonDto;
import greencity.dto.violation.UserViolationMailDto;
import greencity.enums.EmailPreferencePeriodicity;
import greencity.enums.PlaceStatus;
import greencity.exception.exceptions.WrongEmailException;
import greencity.message.PlaceStatusChangeDto;
import greencity.message.ScheduledEmailMessage;
import greencity.message.SendReportEmailMessage;
import jakarta.mail.Session;
Expand All @@ -21,6 +23,7 @@
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
Expand All @@ -29,13 +32,14 @@
import org.thymeleaf.ITemplateEngine;

import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;

import static greencity.ModelUtils.getSubscriberDto;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.*;
VasylyshynDmytro marked this conversation as resolved.
Show resolved Hide resolved

import org.thymeleaf.context.Context;

@ExtendWith(MockitoExtension.class)
Expand All @@ -52,6 +56,7 @@ class EmailServiceImplTest {

@BeforeEach
public void setup() {
Mockito.reset(javaMailSender, templateEngine, messageSource);
service = new EmailServiceImpl(javaMailSender, templateEngine, Executors.newCachedThreadPool(),
"http://localhost:4200",
"test@email.com", messageSource);
Expand Down Expand Up @@ -241,6 +246,28 @@ void sendBlockAccountNotificationWithUnblockLinkEmailTest(Long id, String name,
verify(javaMailSender).createMimeMessage();
}

@Test
void sendPlaceStatusChangeNotificationTest() throws InterruptedException {
PlaceStatusChangeDto dto = new PlaceStatusChangeDto();
dto.setUserName("John Doe");
dto.setPlaceName("Central Park");
dto.setNewStatus(PlaceStatus.APPROVED);
dto.setUserEmail("john.doe@example.com");

MimeMessage mimeMessage = mock(MimeMessage.class);
when(javaMailSender.createMimeMessage()).thenReturn(mimeMessage);
doNothing().when(javaMailSender).send(any(MimeMessage.class));
CountDownLatch latch = new CountDownLatch(1);
doAnswer(invocation -> {
latch.countDown();
return null;
}).when(javaMailSender).send(any(MimeMessage.class));
service.sendPlaceStatusChangeNotification(dto);
latch.await();
verify(javaMailSender).createMimeMessage();
verify(javaMailSender).send(mimeMessage);
}

private static Locale getLocale(String language) {
return switch (language) {
case "ua" -> UA_LOCALE;
Expand Down
Loading