From 5c3140ff789e1afb38665394813546563480cb36 Mon Sep 17 00:00:00 2001 From: Lucas Barbosa Dourado Date: Wed, 26 Nov 2025 21:49:09 -0300 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20Cria=C3=A7=C3=A3o=20da=20camada=20d?= =?UTF-8?q?e=20servi=C3=A7o=20EmailService?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reminderapi/mail/engine/MailEngine.java | 34 +++------- .../mail/service/EmailService.java | 51 +++++++++++++++ .../dto/request/CreateReminderRequestDTO.java | 4 +- .../reminderapi/reminder/entity/Reminder.java | 16 +++++ .../scheduler/ReminderSchedulerService.java | 8 ++- .../reminder/service/ReminderService.java | 16 ++++- .../reminderapi/user/entity/User.java | 18 +++++- .../reminderapi/user/service/UserService.java | 40 +++++++----- src/main/resources/application.properties | 18 +++--- .../templates/email/email-template.html | 1 + .../reminder/service/ReminderServiceTest.java | 64 +++++++++---------- 11 files changed, 180 insertions(+), 90 deletions(-) create mode 100644 src/main/java/br/com/springnoobs/reminderapi/mail/service/EmailService.java diff --git a/src/main/java/br/com/springnoobs/reminderapi/mail/engine/MailEngine.java b/src/main/java/br/com/springnoobs/reminderapi/mail/engine/MailEngine.java index c3d82b1..4271d56 100644 --- a/src/main/java/br/com/springnoobs/reminderapi/mail/engine/MailEngine.java +++ b/src/main/java/br/com/springnoobs/reminderapi/mail/engine/MailEngine.java @@ -1,7 +1,5 @@ package br.com.springnoobs.reminderapi.mail.engine; -import br.com.springnoobs.reminderapi.reminder.entity.Reminder; -import br.com.springnoobs.reminderapi.user.entity.Contact; import jakarta.mail.MessagingException; import jakarta.mail.internet.MimeMessage; import org.slf4j.Logger; @@ -12,9 +10,6 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.util.HashMap; import java.util.Map; @Component @@ -24,25 +19,20 @@ public class MailEngine { private final JavaMailSender mailSender; - private static final DateTimeFormatter DATE_FORMATTER = - DateTimeFormatter.ofPattern("dd/MM/yyyy").withZone(ZoneId.of("America/Sao_Paulo")); - public MailEngine(JavaMailSender mailSender) { this.mailSender = mailSender; } - public void sendEmail(Contact contact, Reminder reminder) { + public void sendEmail(Map variables) { try { MimeMessage message = mailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(message, true); - helper.setTo(contact.getEmail()); - helper.setSubject("Lembrete" + " - " + reminder.getTitle()); + helper.setTo(variables.get("email")); + helper.setSubject(variables.get("subject")); String mailTemplate = getEmailTemplateContent(); - Map variables = buildEmailVariables(contact, reminder, "#"); - mailTemplate = replaceVariables(mailTemplate, variables); helper.setText(mailTemplate, true); @@ -57,8 +47,11 @@ private String replaceVariables(String template, Map variables) String result = template; for (Map.Entry entry : variables.entrySet()) { - String placeholder = "{{" + entry.getKey() + "}}"; - result = result.replace(placeholder, entry.getValue()); + String emailVariable = "{{" + entry.getKey() + "}}"; + + if (result.contains(emailVariable)) { + result = result.replace(emailVariable, entry.getValue()); + } } return result; @@ -69,15 +62,4 @@ private String getEmailTemplateContent() throws IOException { return new String(resource.getInputStream().readAllBytes(), StandardCharsets.UTF_8); } - - private Map buildEmailVariables(Contact contact, Reminder reminder, String disableUrl) { - Map map = new HashMap<>(); - - map.put("name", contact.getUser().getFirstName()); - map.put("title", reminder.getTitle()); - map.put("remind_at", DATE_FORMATTER.format(reminder.getRemindAt())); - map.put("disable_notification_url", disableUrl); - - return map; - } } diff --git a/src/main/java/br/com/springnoobs/reminderapi/mail/service/EmailService.java b/src/main/java/br/com/springnoobs/reminderapi/mail/service/EmailService.java new file mode 100644 index 0000000..60c6621 --- /dev/null +++ b/src/main/java/br/com/springnoobs/reminderapi/mail/service/EmailService.java @@ -0,0 +1,51 @@ +package br.com.springnoobs.reminderapi.mail.service; + +import br.com.springnoobs.reminderapi.mail.engine.MailEngine; +import br.com.springnoobs.reminderapi.reminder.entity.Reminder; +import br.com.springnoobs.reminderapi.user.entity.Contact; +import org.springframework.stereotype.Service; + +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.Map; + +@Service +public class EmailService { + + private final MailEngine mailEngine; + + private static final DateTimeFormatter DATE_FORMATTER = + DateTimeFormatter.ofPattern("dd/MM/yyyy").withZone(ZoneId.of("America/Sao_Paulo")); + + public EmailService(MailEngine mailEngine) { + this.mailEngine = mailEngine; + } + + public void send(Reminder reminder) { + if(reminder.getUser() == null) + { + throw new RuntimeException("User not found"); + } + + Contact contact = reminder.getUser().getContact(); + + Map variables = buildEmailVariables(contact, reminder, "#"); + + mailEngine.sendEmail(variables); + } + + private Map buildEmailVariables(Contact contact, Reminder reminder, String disableUrl) { + Map map = new HashMap<>(); + + map.put("name", contact.getUser().getFirstName()); + map.put("email", contact.getEmail()); + map.put("title", reminder.getTitle()); + map.put("remind_at", reminder.getRemindAt() != null ? DATE_FORMATTER.format(reminder.getRemindAt()) : DATE_FORMATTER.format(reminder.getDueDate())); + map.put("due_date", DATE_FORMATTER.format(reminder.getDueDate())); + map.put("disable_notification_url", disableUrl); + map.put("subject", "Lembrete" + " - " + reminder.getTitle()); + + return map; + } +} diff --git a/src/main/java/br/com/springnoobs/reminderapi/reminder/dto/request/CreateReminderRequestDTO.java b/src/main/java/br/com/springnoobs/reminderapi/reminder/dto/request/CreateReminderRequestDTO.java index b3b79a3..a75228c 100644 --- a/src/main/java/br/com/springnoobs/reminderapi/reminder/dto/request/CreateReminderRequestDTO.java +++ b/src/main/java/br/com/springnoobs/reminderapi/reminder/dto/request/CreateReminderRequestDTO.java @@ -1,9 +1,11 @@ package br.com.springnoobs.reminderapi.reminder.dto.request; +import br.com.springnoobs.reminderapi.user.dto.request.CreateUserRequestDTO; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import java.time.Instant; public record CreateReminderRequestDTO( @NotBlank(message = "Title must not be null") String title, - @NotNull(message = "RemindAt must not be null") Instant remindAt) {} + @NotNull(message = "DueDate must not be null") Instant dueDate, + @NotNull(message = "User must not be null") CreateUserRequestDTO user) {} diff --git a/src/main/java/br/com/springnoobs/reminderapi/reminder/entity/Reminder.java b/src/main/java/br/com/springnoobs/reminderapi/reminder/entity/Reminder.java index d3c07c7..d07a52b 100644 --- a/src/main/java/br/com/springnoobs/reminderapi/reminder/entity/Reminder.java +++ b/src/main/java/br/com/springnoobs/reminderapi/reminder/entity/Reminder.java @@ -1,9 +1,13 @@ package br.com.springnoobs.reminderapi.reminder.entity; +import br.com.springnoobs.reminderapi.user.entity.User; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.FetchType; import java.time.Instant; @Entity @@ -24,6 +28,10 @@ public class Reminder { private boolean sent = false; + @ManyToOne(optional = false, fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; + public Reminder() {} public Reminder( @@ -98,4 +106,12 @@ public Instant getDueDate() { public void setDueDate(Instant dueDate) { this.dueDate = dueDate; } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } } diff --git a/src/main/java/br/com/springnoobs/reminderapi/reminder/scheduler/ReminderSchedulerService.java b/src/main/java/br/com/springnoobs/reminderapi/reminder/scheduler/ReminderSchedulerService.java index 9914f7f..2ff696c 100644 --- a/src/main/java/br/com/springnoobs/reminderapi/reminder/scheduler/ReminderSchedulerService.java +++ b/src/main/java/br/com/springnoobs/reminderapi/reminder/scheduler/ReminderSchedulerService.java @@ -1,5 +1,6 @@ package br.com.springnoobs.reminderapi.reminder.scheduler; +import br.com.springnoobs.reminderapi.mail.service.EmailService; import br.com.springnoobs.reminderapi.reminder.entity.Reminder; import br.com.springnoobs.reminderapi.reminder.exception.NotFoundException; import br.com.springnoobs.reminderapi.reminder.repository.ReminderRepository; @@ -15,22 +16,25 @@ public class ReminderSchedulerService { private final ReminderRepository repository; private final TaskScheduler taskScheduler; + private final EmailService emailService; private final Map> scheduledTasks = new ConcurrentHashMap<>(); - public ReminderSchedulerService(ReminderRepository repository, TaskScheduler taskScheduler) { + public ReminderSchedulerService(ReminderRepository repository, TaskScheduler taskScheduler, EmailService emailService) { this.repository = repository; this.taskScheduler = taskScheduler; + this.emailService = emailService; } public void createSchedule(Reminder reminder) { ScheduledFuture future = taskScheduler.schedule( () -> { + emailService.send(reminder); reminder.setExecutedAt(Instant.now()); reminder.setSent(true); repository.save(reminder); deleteReminderSchedule(reminder.getId()); }, - reminder.getRemindAt()); + reminder.getDueDate()); scheduledTasks.put(reminder.getId(), future); } diff --git a/src/main/java/br/com/springnoobs/reminderapi/reminder/service/ReminderService.java b/src/main/java/br/com/springnoobs/reminderapi/reminder/service/ReminderService.java index d6bf6d0..c871357 100644 --- a/src/main/java/br/com/springnoobs/reminderapi/reminder/service/ReminderService.java +++ b/src/main/java/br/com/springnoobs/reminderapi/reminder/service/ReminderService.java @@ -11,30 +11,40 @@ import br.com.springnoobs.reminderapi.reminder.scheduler.ReminderSchedulerService; import java.time.Instant; +import br.com.springnoobs.reminderapi.user.entity.User; +import br.com.springnoobs.reminderapi.user.service.UserService; import org.springframework.beans.BeanUtils; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Service public class ReminderService { private final ReminderRepository repository; + private final UserService userService; private final ReminderSchedulerService reminderSchedulerService; - public ReminderService(ReminderRepository repository, ReminderSchedulerService reminderSchedulerService) { + public ReminderService(ReminderRepository repository, UserService userService, ReminderSchedulerService reminderSchedulerService) { this.repository = repository; + this.userService = userService; this.reminderSchedulerService = reminderSchedulerService; } + @Transactional public ReminderResponseDTO create(CreateReminderRequestDTO dto) { - if (dto.remindAt().isBefore(Instant.now())) { - throw new PastRemindAtException("RemindAt should be a date in the future!"); + if (dto.dueDate().isBefore(Instant.now())) { + throw new PastRemindAtException("DueDate should be a date in the future!"); } Reminder reminder = new Reminder(); BeanUtils.copyProperties(dto, reminder); + User user = userService.createAndSaveUser(dto.user()); + + reminder.setUser(user); + Reminder savedReminder = repository.save(reminder); reminderSchedulerService.createSchedule(savedReminder); diff --git a/src/main/java/br/com/springnoobs/reminderapi/user/entity/User.java b/src/main/java/br/com/springnoobs/reminderapi/user/entity/User.java index badd29a..4d2018c 100644 --- a/src/main/java/br/com/springnoobs/reminderapi/user/entity/User.java +++ b/src/main/java/br/com/springnoobs/reminderapi/user/entity/User.java @@ -1,7 +1,11 @@ package br.com.springnoobs.reminderapi.user.entity; +import br.com.springnoobs.reminderapi.reminder.entity.Reminder; import jakarta.persistence.*; +import java.util.ArrayList; +import java.util.List; + @Entity public class User { @@ -16,13 +20,17 @@ public class User { @OneToOne(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) private Contact contact; + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) + private List reminders = new ArrayList<>(); + public User() {} - public User(Long id, String firstName, String lastName, Contact contact) { + public User(Long id, String firstName, String lastName, Contact contact, List reminders) { this.id = id; this.firstName = firstName; this.lastName = lastName; this.contact = contact; + this.reminders = reminders; } public Long getId() { @@ -56,4 +64,12 @@ public Contact getContact() { public void setContact(Contact contact) { this.contact = contact; } + + public List getReminders() { + return reminders; + } + + public void setReminders(List reminders) { + this.reminders = reminders; + } } diff --git a/src/main/java/br/com/springnoobs/reminderapi/user/service/UserService.java b/src/main/java/br/com/springnoobs/reminderapi/user/service/UserService.java index d24c8d8..6e795a6 100644 --- a/src/main/java/br/com/springnoobs/reminderapi/user/service/UserService.java +++ b/src/main/java/br/com/springnoobs/reminderapi/user/service/UserService.java @@ -27,23 +27,9 @@ public UserService(UserRepository userRepository, ContactRepository contactRepos @Transactional public UserResponseDTO create(CreateUserRequestDTO dto) { - if (contactRepository.existsByEmail(dto.contactRequestDTO().email())) { - throw new EmailAlreadyExistsException("Email already exists"); - } - User user = new User(); - user.setFirstName(dto.firstName()); - user.setLastName(dto.lastName()); + User user = createAndSaveUser(dto); - User savedUser = userRepository.save(user); - - Contact contact = new Contact(); - contact.setEmail(dto.contactRequestDTO().email()); - contact.setPhoneNumber(dto.contactRequestDTO().phoneNumber()); - contact.setUser(savedUser); - - contactRepository.save(contact); - savedUser.setContact(contact); - return UserMapper.toResponse(savedUser); + return UserMapper.toResponse(user); } public UserResponseDTO findByEmail(String email) { @@ -63,4 +49,26 @@ public void delete(Long id) { User user = userRepository.findById(id).orElseThrow(() -> new UserNotFoundException("User not found" + id)); userRepository.delete(user); } + + public User createAndSaveUser(CreateUserRequestDTO request) { + if (contactRepository.existsByEmail(request.contactRequestDTO().email())) { + throw new EmailAlreadyExistsException("Email already exists"); + } + + User user = new User(); + user.setFirstName(request.firstName()); + user.setLastName(request.lastName()); + + User savedUser = userRepository.save(user); + + Contact contact = new Contact(); + contact.setEmail(request.contactRequestDTO().email()); + contact.setPhoneNumber(request.contactRequestDTO().phoneNumber()); + contact.setUser(savedUser); + + contactRepository.save(contact); + savedUser.setContact(contact); + + return savedUser; + } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 2068da8..d6a65ae 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,15 +1,15 @@ spring.application.name=reminder-api -spring.datasource.url=${DB_CONNECTION_URL} -spring.datasource.username=${DB_USERNAME} -spring.datasource.password=${DB_PASSWORD} -spring.datasource.driver-class-name=${DB_DRIVER_CLASS_NAME} -spring.jpa.database-platform=${DB_DIALECT} +spring.datasource.url=jdbc:mysql://localhost:3306/reminder-api +spring.datasource.username=root +spring.datasource.password=root +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver +spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect spring.jpa.generate-ddl=true spring.jpa.hibernate.ddl-auto=update -spring.mail.host=${MAIL_HOST} -spring.mail.port=${MAIL_PORT} -spring.mail.username=${MAIL_USERNAME} -spring.mail.password=${MAIL_PASSWORD} +spring.mail.host=smtp.gmail.com +spring.mail.port=587 +spring.mail.username=douradoblucas@gmail.com +spring.mail.password=dnxuwepsuawasscw spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true \ No newline at end of file diff --git a/src/main/resources/templates/email/email-template.html b/src/main/resources/templates/email/email-template.html index 2b0341d..707282e 100644 --- a/src/main/resources/templates/email/email-template.html +++ b/src/main/resources/templates/email/email-template.html @@ -12,6 +12,7 @@

🔔 Notificação de Lembrete

Título: {{title}}

Data do Lembrete: {{remind_at}}

+

Data do Vencimento: {{due_date}}

diff --git a/src/test/java/br/com/springnoobs/reminderapi/reminder/service/ReminderServiceTest.java b/src/test/java/br/com/springnoobs/reminderapi/reminder/service/ReminderServiceTest.java index df00d8b..e97a704 100644 --- a/src/test/java/br/com/springnoobs/reminderapi/reminder/service/ReminderServiceTest.java +++ b/src/test/java/br/com/springnoobs/reminderapi/reminder/service/ReminderServiceTest.java @@ -97,38 +97,38 @@ void shouldReturnReminderWhenTryFindReminderByIdWithValidId() { assertEquals("Title", reminderDTO.title()); } - @Test - void shouldCreateReminderWhenRequestIsValid() { - // Arrange - Instant remindAt = Instant.now().plusSeconds(60); - - CreateReminderRequestDTO request = new CreateReminderRequestDTO("Create", remindAt); - - Reminder reminder = new Reminder(); - reminder.setTitle(request.title()); - reminder.setRemindAt(request.remindAt()); - - when(repository.save(any())).thenReturn(reminder); - - // Act - ReminderResponseDTO response = service.create(request); - - // Assert - assertEquals("Create", response.title()); - assertEquals(remindAt, response.remindAt()); - verify(repository).save(any()); - } - - @Test - void shouldThrowPastRemindAtExceptionWhenTryCreateReminderWithPastRemindAt() { - // Arrange - Instant remindAt = Instant.now().minusSeconds(60); - - CreateReminderRequestDTO request = new CreateReminderRequestDTO("Create", remindAt); - - // Act And Assert - assertThrows(PastRemindAtException.class, () -> service.create(request)); - } +// @Test +// void shouldCreateReminderWhenRequestIsValid() { +// // Arrange +// Instant remindAt = Instant.now().plusSeconds(60); +// +// CreateReminderRequestDTO request = new CreateReminderRequestDTO("Create", remindAt); +// +// Reminder reminder = new Reminder(); +// reminder.setTitle(request.title()); +// reminder.setRemindAt(request.remindAt()); +// +// when(repository.save(any())).thenReturn(reminder); +// +// // Act +// ReminderResponseDTO response = service.create(request); +// +// // Assert +// assertEquals("Create", response.title()); +// assertEquals(remindAt, response.remindAt()); +// verify(repository).save(any()); +// } + +// @Test +// void shouldThrowPastRemindAtExceptionWhenTryCreateReminderWithPastRemindAt() { +// // Arrange +// Instant remindAt = Instant.now().minusSeconds(60); +// +// CreateReminderRequestDTO request = new CreateReminderRequestDTO("Create", remindAt); +// +// // Act And Assert +// assertThrows(PastRemindAtException.class, () -> service.create(request)); +// } @Test void shouldUpdateReminderWhenRequestIsValid() { From 2718689edd6678d9c9f9e24961785e63b149005c Mon Sep 17 00:00:00 2001 From: Lucas Barbosa Dourado Date: Wed, 26 Nov 2025 21:56:43 -0300 Subject: [PATCH 2/6] =?UTF-8?q?fix:=20Altera=C3=A7=C3=A3o=20de=20nomenclat?= =?UTF-8?q?ura=20de=20variavel=20para=20repository?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/springnoobs/reminderapi/user/service/UserService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/br/com/springnoobs/reminderapi/user/service/UserService.java b/src/main/java/br/com/springnoobs/reminderapi/user/service/UserService.java index 2bf175a..4e40f36 100644 --- a/src/main/java/br/com/springnoobs/reminderapi/user/service/UserService.java +++ b/src/main/java/br/com/springnoobs/reminderapi/user/service/UserService.java @@ -59,7 +59,7 @@ public User createAndSaveUser(CreateUserRequestDTO request) { user.setFirstName(request.firstName()); user.setLastName(request.lastName()); - User savedUser = userRepository.save(user); + User savedUser = repository.save(user); Contact contact = new Contact(); contact.setEmail(request.contactRequestDTO().email()); From 11140746c259f617642af2594e996d10e67b4e6f Mon Sep 17 00:00:00 2001 From: Lucas Barbosa Dourado Date: Wed, 26 Nov 2025 22:16:24 -0300 Subject: [PATCH 3/6] =?UTF-8?q?fix:=20Atualiza=C3=A7=C3=A3o=20dos=20testes?= =?UTF-8?q?=20para=20cobrir=20100%=20da=20classe=20de=20Reminder.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reminder/service/ReminderServiceTest.java | 92 ++++++++++++------- 1 file changed, 60 insertions(+), 32 deletions(-) diff --git a/src/test/java/br/com/springnoobs/reminderapi/reminder/service/ReminderServiceTest.java b/src/test/java/br/com/springnoobs/reminderapi/reminder/service/ReminderServiceTest.java index ef5c54d..5f981a8 100644 --- a/src/test/java/br/com/springnoobs/reminderapi/reminder/service/ReminderServiceTest.java +++ b/src/test/java/br/com/springnoobs/reminderapi/reminder/service/ReminderServiceTest.java @@ -13,6 +13,11 @@ import br.com.springnoobs.reminderapi.reminder.exception.PastRemindAtException; import br.com.springnoobs.reminderapi.reminder.repository.ReminderRepository; import br.com.springnoobs.reminderapi.reminder.scheduler.ReminderSchedulerService; +import br.com.springnoobs.reminderapi.user.dto.request.ContactRequestDTO; +import br.com.springnoobs.reminderapi.user.dto.request.CreateUserRequestDTO; +import br.com.springnoobs.reminderapi.user.entity.Contact; +import br.com.springnoobs.reminderapi.user.entity.User; +import br.com.springnoobs.reminderapi.user.service.UserService; import java.time.Instant; import java.util.List; import java.util.Optional; @@ -33,6 +38,9 @@ class ReminderServiceTest { @Mock private ReminderSchedulerService reminderSchedulerService; + @Mock + private UserService userService; + @InjectMocks private ReminderService service; @@ -97,38 +105,58 @@ void shouldReturnReminderWhenTryFindReminderByIdWithValidId() { assertEquals("Title", reminderDTO.title()); } -// @Test -// void shouldCreateReminderWhenRequestIsValid() { -// // Arrange -// Instant remindAt = Instant.now().plusSeconds(60); -// -// CreateReminderRequestDTO request = new CreateReminderRequestDTO("Create", remindAt); -// -// Reminder reminder = new Reminder(); -// reminder.setTitle(request.title()); -// reminder.setRemindAt(request.remindAt()); -// -// when(repository.save(any())).thenReturn(reminder); -// -// // Act -// ReminderResponseDTO response = service.create(request); -// -// // Assert -// assertEquals("Create", response.title()); -// assertEquals(remindAt, response.remindAt()); -// verify(repository).save(any()); -// } - -// @Test -// void shouldThrowPastRemindAtExceptionWhenTryCreateReminderWithPastRemindAt() { -// // Arrange -// Instant remindAt = Instant.now().minusSeconds(60); -// -// CreateReminderRequestDTO request = new CreateReminderRequestDTO("Create", remindAt); -// -// // Act And Assert -// assertThrows(PastRemindAtException.class, () -> service.create(request)); -// } + @Test + void shouldCreateReminderWhenRequestIsValid() { + // Arrange + Instant dueDate = Instant.now().plusSeconds(60); + + CreateUserRequestDTO createUserRequestDTO = new CreateUserRequestDTO("First Name", "Last Name", new ContactRequestDTO("email@test.com", "123456789")); + + CreateReminderRequestDTO request = new CreateReminderRequestDTO("Create", dueDate, createUserRequestDTO); + + Reminder reminder = new Reminder(); + reminder.setTitle(request.title()); + reminder.setDueDate(request.dueDate()); + + User user = new User(); + + user.setFirstName(createUserRequestDTO.firstName()); + user.setLastName(createUserRequestDTO.lastName()); + + Contact contact = new Contact(); + contact.setEmail(createUserRequestDTO.contactRequestDTO().email()); + contact.setPhoneNumber(createUserRequestDTO.contactRequestDTO().phoneNumber()); + + user.setContact(contact); + + reminder.setUser(user); + + when(repository.save(any())).thenReturn(reminder); + when(userService.createAndSaveUser(createUserRequestDTO)).thenReturn(user); + + // Act + ReminderResponseDTO response = service.create(request); + + // Assert + assertEquals("Create", response.title()); + assertEquals(dueDate, reminder.getDueDate()); + assertNotNull(reminder.getUser()); + assertEquals(reminder.getUser().getFirstName(), user.getFirstName()); + verify(repository).save(any()); + } + + @Test + void shouldThrowPastRemindAtExceptionWhenTryCreateReminderWithPastRemindAt() { + // Arrange + Instant dueDate = Instant.now().minusSeconds(60); + + CreateUserRequestDTO createUserRequestDTO = new CreateUserRequestDTO("First Name", "Last Name", new ContactRequestDTO("email@test.com", "123456789")); + + CreateReminderRequestDTO request = new CreateReminderRequestDTO("Create", dueDate, createUserRequestDTO); + + // Act And Assert + assertThrows(PastRemindAtException.class, () -> service.create(request)); + } @Test void shouldUpdateReminderWhenRequestIsValid() { From 50a72f1e3934ce71f7c9ef6c02c3181406ae4e85 Mon Sep 17 00:00:00 2001 From: Lucas Barbosa Dourado Date: Sat, 29 Nov 2025 19:36:45 -0300 Subject: [PATCH 4/6] =?UTF-8?q?fix:=20Cria=C3=A7=C3=A3o=20de=20testes=20de?= =?UTF-8?q?=20Controller=20para=20findAll?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.properties | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index d6a65ae..2068da8 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,15 +1,15 @@ spring.application.name=reminder-api -spring.datasource.url=jdbc:mysql://localhost:3306/reminder-api -spring.datasource.username=root -spring.datasource.password=root -spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver -spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect +spring.datasource.url=${DB_CONNECTION_URL} +spring.datasource.username=${DB_USERNAME} +spring.datasource.password=${DB_PASSWORD} +spring.datasource.driver-class-name=${DB_DRIVER_CLASS_NAME} +spring.jpa.database-platform=${DB_DIALECT} spring.jpa.generate-ddl=true spring.jpa.hibernate.ddl-auto=update -spring.mail.host=smtp.gmail.com -spring.mail.port=587 -spring.mail.username=douradoblucas@gmail.com -spring.mail.password=dnxuwepsuawasscw +spring.mail.host=${MAIL_HOST} +spring.mail.port=${MAIL_PORT} +spring.mail.username=${MAIL_USERNAME} +spring.mail.password=${MAIL_PASSWORD} spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true \ No newline at end of file From 3b192d30fba960e4c47505f0b67b338c555a181c Mon Sep 17 00:00:00 2001 From: Lucas Barbosa Dourado Date: Sat, 29 Nov 2025 19:44:12 -0300 Subject: [PATCH 5/6] =?UTF-8?q?fix:=20Formata=C3=A7=C3=A3o=20de=20c=C3=B3d?= =?UTF-8?q?igo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reminderapi/mail/engine/MailEngine.java | 7 +++---- .../reminderapi/mail/service/EmailService.java | 14 ++++++++------ .../reminderapi/reminder/entity/Reminder.java | 5 +++-- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/main/java/br/com/springnoobs/reminderapi/mail/engine/MailEngine.java b/src/main/java/br/com/springnoobs/reminderapi/mail/engine/MailEngine.java index 4271d56..17ace52 100644 --- a/src/main/java/br/com/springnoobs/reminderapi/mail/engine/MailEngine.java +++ b/src/main/java/br/com/springnoobs/reminderapi/mail/engine/MailEngine.java @@ -2,16 +2,15 @@ import jakarta.mail.MessagingException; import jakarta.mail.internet.MimeMessage; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Map; import org.slf4j.Logger; import org.springframework.core.io.ClassPathResource; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Component; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.Map; - @Component public class MailEngine { diff --git a/src/main/java/br/com/springnoobs/reminderapi/mail/service/EmailService.java b/src/main/java/br/com/springnoobs/reminderapi/mail/service/EmailService.java index 60c6621..b09d40a 100644 --- a/src/main/java/br/com/springnoobs/reminderapi/mail/service/EmailService.java +++ b/src/main/java/br/com/springnoobs/reminderapi/mail/service/EmailService.java @@ -3,12 +3,11 @@ import br.com.springnoobs.reminderapi.mail.engine.MailEngine; import br.com.springnoobs.reminderapi.reminder.entity.Reminder; import br.com.springnoobs.reminderapi.user.entity.Contact; -import org.springframework.stereotype.Service; - import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.HashMap; import java.util.Map; +import org.springframework.stereotype.Service; @Service public class EmailService { @@ -23,14 +22,13 @@ public EmailService(MailEngine mailEngine) { } public void send(Reminder reminder) { - if(reminder.getUser() == null) - { + if (reminder.getUser() == null) { throw new RuntimeException("User not found"); } Contact contact = reminder.getUser().getContact(); - Map variables = buildEmailVariables(contact, reminder, "#"); + Map variables = buildEmailVariables(contact, reminder, "#"); mailEngine.sendEmail(variables); } @@ -41,7 +39,11 @@ private Map buildEmailVariables(Contact contact, Reminder remind map.put("name", contact.getUser().getFirstName()); map.put("email", contact.getEmail()); map.put("title", reminder.getTitle()); - map.put("remind_at", reminder.getRemindAt() != null ? DATE_FORMATTER.format(reminder.getRemindAt()) : DATE_FORMATTER.format(reminder.getDueDate())); + map.put( + "remind_at", + reminder.getRemindAt() != null + ? DATE_FORMATTER.format(reminder.getRemindAt()) + : DATE_FORMATTER.format(reminder.getDueDate())); map.put("due_date", DATE_FORMATTER.format(reminder.getDueDate())); map.put("disable_notification_url", disableUrl); map.put("subject", "Lembrete" + " - " + reminder.getTitle()); diff --git a/src/main/java/br/com/springnoobs/reminderapi/reminder/entity/Reminder.java b/src/main/java/br/com/springnoobs/reminderapi/reminder/entity/Reminder.java index c033d55..4d4b2f6 100644 --- a/src/main/java/br/com/springnoobs/reminderapi/reminder/entity/Reminder.java +++ b/src/main/java/br/com/springnoobs/reminderapi/reminder/entity/Reminder.java @@ -2,12 +2,13 @@ import br.com.springnoobs.reminderapi.user.entity.User; import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import jakarta.persistence.ManyToOne; import jakarta.persistence.JoinColumn; -import jakarta.persistence.FetchType; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import java.time.Instant; @Entity From 7b8f6daaa822a835d324c94654c91b9200aaa014 Mon Sep 17 00:00:00 2001 From: Lucas Barbosa Dourado Date: Sat, 29 Nov 2025 20:27:09 -0300 Subject: [PATCH 6/6] fix: Ajustes nos testes para a camada reminderService --- .../controller/ReminderControllerTest.java | 12 +++++++-- .../reminder/service/ReminderServiceTest.java | 26 +++++++++++++++++-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/test/java/br/com/springnoobs/reminderapi/reminder/controller/ReminderControllerTest.java b/src/test/java/br/com/springnoobs/reminderapi/reminder/controller/ReminderControllerTest.java index 73ffe08..8a27e1a 100644 --- a/src/test/java/br/com/springnoobs/reminderapi/reminder/controller/ReminderControllerTest.java +++ b/src/test/java/br/com/springnoobs/reminderapi/reminder/controller/ReminderControllerTest.java @@ -16,6 +16,8 @@ import br.com.springnoobs.reminderapi.reminder.exception.NotFoundException; import br.com.springnoobs.reminderapi.reminder.exception.PastDueDateException; import br.com.springnoobs.reminderapi.reminder.service.ReminderService; +import br.com.springnoobs.reminderapi.user.dto.request.ContactRequestDTO; +import br.com.springnoobs.reminderapi.user.dto.request.CreateUserRequestDTO; import com.fasterxml.jackson.databind.ObjectMapper; import java.time.Instant; import java.util.List; @@ -89,7 +91,10 @@ void shouldReturnNotFoundWhenFindByIdWithInvalidId() throws Exception { @Test void shouldCreateReminderWhenRequestIsValid() throws Exception { - var request = new CreateReminderRequestDTO("New Reminder", Instant.now().plusSeconds(60)); + CreateUserRequestDTO createUserRequestDTO = new CreateUserRequestDTO( + "First Name", "Last Name", new ContactRequestDTO("email@test.com", "123456789")); + + var request = new CreateReminderRequestDTO("New Reminder", Instant.now().plusSeconds(60), createUserRequestDTO); var response = new ReminderResponseDTO(request.title(), request.dueDate()); when(service.create(request)).thenReturn(response); @@ -103,8 +108,11 @@ void shouldCreateReminderWhenRequestIsValid() throws Exception { @Test void shouldReturnBadRequestWhenCreatingReminderWithPastDate() throws Exception { + CreateUserRequestDTO createUserRequestDTO = new CreateUserRequestDTO( + "First Name", "Last Name", new ContactRequestDTO("email@test.com", "123456789")); + var request = - new CreateReminderRequestDTO("Past Reminder", Instant.now().minusSeconds(60)); + new CreateReminderRequestDTO("Past Reminder", Instant.now().minusSeconds(60), createUserRequestDTO); when(service.create(request)).thenThrow(new PastDueDateException("Remind at date must be in the future")); diff --git a/src/test/java/br/com/springnoobs/reminderapi/reminder/service/ReminderServiceTest.java b/src/test/java/br/com/springnoobs/reminderapi/reminder/service/ReminderServiceTest.java index 0ef9ddc..d9d6ae4 100644 --- a/src/test/java/br/com/springnoobs/reminderapi/reminder/service/ReminderServiceTest.java +++ b/src/test/java/br/com/springnoobs/reminderapi/reminder/service/ReminderServiceTest.java @@ -107,14 +107,32 @@ void shouldReturnReminderWhenTryFindReminderByIdWithValidId() { @Test void shouldCreateReminderWhenRequestIsValid() { + CreateUserRequestDTO createUserRequestDTO = new CreateUserRequestDTO( + "First Name", "Last Name", new ContactRequestDTO("email@test.com", "123456789")); + // Arrange Instant dueDate = Instant.now().plusSeconds(60); - CreateReminderRequestDTO request = new CreateReminderRequestDTO("Create", dueDate); + CreateReminderRequestDTO request = new CreateReminderRequestDTO("Create", dueDate, createUserRequestDTO); Reminder reminder = new Reminder(); reminder.setTitle(request.title()); reminder.setDueDate(request.dueDate()); + + User user = new User(); + + user.setFirstName(createUserRequestDTO.firstName()); + user.setLastName(createUserRequestDTO.lastName()); + + Contact contact = new Contact(); + contact.setEmail(createUserRequestDTO.contactRequestDTO().email()); + contact.setPhoneNumber(createUserRequestDTO.contactRequestDTO().phoneNumber()); + + user.setContact(contact); + + reminder.setUser(user); + when(repository.save(any())).thenReturn(reminder); + when(userService.createAndSaveUser(createUserRequestDTO)).thenReturn(user); // Act ReminderResponseDTO response = service.create(request); @@ -129,7 +147,11 @@ void shouldCreateReminderWhenRequestIsValid() { void shouldThrowDueDateExceptionWhenTryCreateReminderWithPastDueDate() { // Arrange Instant dueDate = Instant.now().minusSeconds(60); - CreateReminderRequestDTO request = new CreateReminderRequestDTO("Create", dueDate); + + CreateUserRequestDTO createUserRequestDTO = new CreateUserRequestDTO( + "First Name", "Last Name", new ContactRequestDTO("email@test.com", "123456789")); + + CreateReminderRequestDTO request = new CreateReminderRequestDTO("Create", dueDate, createUserRequestDTO); // Act And Assert assertThrows(PastDueDateException.class, () -> service.create(request));