diff --git a/pom.xml b/pom.xml
index 2566156..c993578 100644
--- a/pom.xml
+++ b/pom.xml
@@ -49,6 +49,10 @@
org.springframework.boot
spring-boot-starter-webflux
+
+ org.springframework.boot
+ spring-boot-starter-mail
+
diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/controllers/EmailController.java b/src/main/java/ar/utn/ba/ddsi/mailing/controllers/EmailController.java
index fec8ee0..5eb555a 100644
--- a/src/main/java/ar/utn/ba/ddsi/mailing/controllers/EmailController.java
+++ b/src/main/java/ar/utn/ba/ddsi/mailing/controllers/EmailController.java
@@ -1,5 +1,7 @@
package ar.utn.ba.ddsi.mailing.controllers;
+import ar.utn.ba.ddsi.mailing.models.dto.email.EmailInputDTO;
+import ar.utn.ba.ddsi.mailing.models.dto.email.EmailOutputDTO;
import ar.utn.ba.ddsi.mailing.models.entities.Email;
import ar.utn.ba.ddsi.mailing.services.IEmailService;
import org.springframework.web.bind.annotation.*;
@@ -15,12 +17,12 @@ public EmailController(IEmailService emailService) {
}
@PostMapping
- public Email crearEmail(@RequestBody Email email) {
+ public EmailOutputDTO crearEmail(@RequestBody EmailInputDTO email) {
return emailService.crearEmail(email);
}
@GetMapping
- public List obtenerEmails(@RequestParam(required = false) Boolean pendiente) {
+ public List obtenerEmails(@RequestParam(required = false) Boolean pendiente) {
return emailService.obtenerEmails(pendiente);
}
}
\ No newline at end of file
diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/models/dto/email/EmailInputDTO.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/dto/email/EmailInputDTO.java
new file mode 100644
index 0000000..df37efb
--- /dev/null
+++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/dto/email/EmailInputDTO.java
@@ -0,0 +1,12 @@
+package ar.utn.ba.ddsi.mailing.models.dto.email;
+
+import ar.utn.ba.ddsi.mailing.models.entities.adapters.IEmailSender;
+import lombok.Data;
+
+@Data
+public class EmailInputDTO {
+ private String destinatario;
+ private String remitente;
+ private String asunto;
+ private String contenido;
+}
diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/models/dto/email/EmailOutputDTO.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/dto/email/EmailOutputDTO.java
new file mode 100644
index 0000000..dcb82cc
--- /dev/null
+++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/dto/email/EmailOutputDTO.java
@@ -0,0 +1,12 @@
+package ar.utn.ba.ddsi.mailing.models.dto.email;
+
+import lombok.Data;
+
+@Data
+public class EmailOutputDTO {
+ private Long id;
+ private String destinatario;
+ private String remitente;
+ private String asunto;
+ private String contenido;
+}
diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/Alerta.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/Alerta.java
new file mode 100644
index 0000000..49d2700
--- /dev/null
+++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/Alerta.java
@@ -0,0 +1,24 @@
+package ar.utn.ba.ddsi.mailing.models.entities;
+
+import ar.utn.ba.ddsi.mailing.models.entities.strategies.CondicionAlerta;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+public class Alerta {
+ @Getter
+ @Setter
+ private Long id;
+ private String nombre;
+ private List condiciones;
+
+ public Alerta(String nombre, List condiciones) {
+ this.nombre = nombre;
+ this.condiciones = condiciones;
+ }
+
+ public boolean cumpleCondicionesAlerta(Clima clima){
+ return condiciones.stream().allMatch(condicion -> condicion.seCumple(clima));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/Email.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/Email.java
index eb940be..a46bba6 100644
--- a/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/Email.java
+++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/Email.java
@@ -1,5 +1,6 @@
package ar.utn.ba.ddsi.mailing.models.entities;
+import ar.utn.ba.ddsi.mailing.models.entities.adapters.IEmailSender;
import lombok.Getter;
import lombok.Setter;
@@ -12,6 +13,7 @@ public class Email {
private String asunto;
private String contenido;
private boolean enviado;
+ private IEmailSender emailSender;
public Email(String destinatario, String remitente, String asunto, String contenido) {
this.destinatario = destinatario;
@@ -23,5 +25,7 @@ public Email(String destinatario, String remitente, String asunto, String conten
public void enviar() {
//TODO: Implementación pendiente. Podríamos usar adapters
+ // HECHO: IMPLEMENTACIÓN DE ADAPTER
+ this.emailSender.send(this);
}
}
\ No newline at end of file
diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/adapters/IEmailSender.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/adapters/IEmailSender.java
new file mode 100644
index 0000000..5d6f648
--- /dev/null
+++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/adapters/IEmailSender.java
@@ -0,0 +1,7 @@
+package ar.utn.ba.ddsi.mailing.models.entities.adapters;
+
+import ar.utn.ba.ddsi.mailing.models.entities.Email;
+
+public interface IEmailSender {
+ void send(Email email);
+}
diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/adapters/impl/JavaMailAdapter.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/adapters/impl/JavaMailAdapter.java
new file mode 100644
index 0000000..35a178a
--- /dev/null
+++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/adapters/impl/JavaMailAdapter.java
@@ -0,0 +1,34 @@
+package ar.utn.ba.ddsi.mailing.models.entities.adapters.impl;
+
+import ar.utn.ba.ddsi.mailing.models.entities.Email;
+import ar.utn.ba.ddsi.mailing.models.entities.adapters.IEmailSender;
+import jakarta.mail.MessagingException;
+import jakarta.mail.internet.MimeMessage;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.MimeMessageHelper;
+
+public class JavaMailAdapter implements IEmailSender {
+ private final JavaMailSender javaMailSender;
+
+ public JavaMailAdapter(JavaMailSender javaMailSender) {
+ this.javaMailSender = javaMailSender;
+ }
+
+ @Override
+ public void send(Email email) {
+ // 1) Convertimos nuestro dominio Email a MimeMessage
+ MimeMessage mimeMessage = javaMailSender.createMimeMessage();
+ try {
+ MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, "UTF-8");
+ helper.setTo(email.getDestinatario());
+ helper.setFrom(email.getRemitente());
+ helper.setSubject(email.getAsunto());
+ helper.setText(email.getContenido(), false); // false = texto plano
+
+ // 2) Enviamos usando JavaMailSender
+ javaMailSender.send(mimeMessage);
+ } catch (MessagingException ex) {
+ throw new RuntimeException("Error al enviar email: " + ex.getMessage(), ex);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/strategies/CondicionAlerta.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/strategies/CondicionAlerta.java
new file mode 100644
index 0000000..1a5a768
--- /dev/null
+++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/strategies/CondicionAlerta.java
@@ -0,0 +1,7 @@
+package ar.utn.ba.ddsi.mailing.models.entities.strategies;
+
+import ar.utn.ba.ddsi.mailing.models.entities.Clima;
+
+public interface CondicionAlerta {
+ boolean seCumple(Clima clima);
+}
diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/strategies/impl/Humedad.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/strategies/impl/Humedad.java
new file mode 100644
index 0000000..07bfaac
--- /dev/null
+++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/strategies/impl/Humedad.java
@@ -0,0 +1,17 @@
+package ar.utn.ba.ddsi.mailing.models.entities.strategies.impl;
+
+import ar.utn.ba.ddsi.mailing.models.entities.Clima;
+import ar.utn.ba.ddsi.mailing.models.entities.strategies.CondicionAlerta;
+
+public class Humedad implements CondicionAlerta {
+ private Double umbral;
+
+ public Humedad(Double umbral){
+ this.umbral = umbral; // 60%
+ }
+
+ @Override
+ public boolean seCumple(Clima clima) {
+ return clima.getHumedad() > this.umbral;
+ }
+}
diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/strategies/impl/Temperatura.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/strategies/impl/Temperatura.java
new file mode 100644
index 0000000..111d0b0
--- /dev/null
+++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/strategies/impl/Temperatura.java
@@ -0,0 +1,18 @@
+package ar.utn.ba.ddsi.mailing.models.entities.strategies.impl;
+
+import ar.utn.ba.ddsi.mailing.models.entities.Clima;
+import ar.utn.ba.ddsi.mailing.models.entities.strategies.CondicionAlerta;
+
+public class Temperatura implements CondicionAlerta {
+ private final Double umbralCelsius;
+
+ public Temperatura(Double umbralCelsius) {
+ this.umbralCelsius = umbralCelsius; // 35
+ }
+
+ @Override
+ public boolean seCumple(Clima clima) {
+ return clima.getTemperaturaCelsius() > this.umbralCelsius
+ || clima.getTemperaturaFahrenheit() > this.umbralCelsius + 60.0;
+ }
+}
diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/IAlertaRepository.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/IAlertaRepository.java
new file mode 100644
index 0000000..93523a3
--- /dev/null
+++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/IAlertaRepository.java
@@ -0,0 +1,11 @@
+package ar.utn.ba.ddsi.mailing.models.repositories;
+
+import ar.utn.ba.ddsi.mailing.models.entities.Alerta;
+import ar.utn.ba.ddsi.mailing.models.entities.Email;
+
+import java.util.List;
+
+public interface IAlertaRepository {
+ Alerta save(Alerta alerta);
+ List findAll();
+}
diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/impl/AlertaRepository.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/impl/AlertaRepository.java
new file mode 100644
index 0000000..fb03de9
--- /dev/null
+++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/impl/AlertaRepository.java
@@ -0,0 +1,34 @@
+package ar.utn.ba.ddsi.mailing.models.repositories.impl;
+
+import ar.utn.ba.ddsi.mailing.models.entities.Alerta;
+import ar.utn.ba.ddsi.mailing.models.repositories.IAlertaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+
+@Repository
+public class AlertaRepository implements IAlertaRepository {
+ private final Map alertas = new HashMap<>();
+ private final AtomicLong idGenerator = new AtomicLong(1);
+
+ @Override
+ public Alerta save(Alerta alerta) {
+ if (alerta.getId() == null) {
+ Long id = idGenerator.getAndIncrement();
+ alerta.setId(id);
+ alertas.put(id, alerta);
+ } else {
+ alertas.put(alerta.getId(), alerta);
+ }
+ return alerta;
+ }
+
+ @Override
+ public List findAll() {
+ return new ArrayList<>(alertas.values());
+ }
+}
diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/services/IEmailService.java b/src/main/java/ar/utn/ba/ddsi/mailing/services/IEmailService.java
index 5be1682..f69da6e 100644
--- a/src/main/java/ar/utn/ba/ddsi/mailing/services/IEmailService.java
+++ b/src/main/java/ar/utn/ba/ddsi/mailing/services/IEmailService.java
@@ -1,11 +1,13 @@
package ar.utn.ba.ddsi.mailing.services;
+import ar.utn.ba.ddsi.mailing.models.dto.email.EmailInputDTO;
+import ar.utn.ba.ddsi.mailing.models.dto.email.EmailOutputDTO;
import ar.utn.ba.ddsi.mailing.models.entities.Email;
import java.util.List;
public interface IEmailService {
- Email crearEmail(Email email);
- List obtenerEmails(Boolean pendiente);
+ EmailOutputDTO crearEmail(EmailInputDTO inputDTO);
+ List obtenerEmails(Boolean pendiente);
void procesarPendientes();
void loguearEmailsPendientes();
}
\ No newline at end of file
diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/services/impl/AlertasService.java b/src/main/java/ar/utn/ba/ddsi/mailing/services/impl/AlertasService.java
index f5d52b6..a8c54a5 100644
--- a/src/main/java/ar/utn/ba/ddsi/mailing/services/impl/AlertasService.java
+++ b/src/main/java/ar/utn/ba/ddsi/mailing/services/impl/AlertasService.java
@@ -1,7 +1,9 @@
package ar.utn.ba.ddsi.mailing.services.impl;
+import ar.utn.ba.ddsi.mailing.models.dto.email.EmailInputDTO;
import ar.utn.ba.ddsi.mailing.models.entities.Clima;
import ar.utn.ba.ddsi.mailing.models.entities.Email;
+import ar.utn.ba.ddsi.mailing.models.repositories.IAlertaRepository;
import ar.utn.ba.ddsi.mailing.models.repositories.IClimaRepository;
import ar.utn.ba.ddsi.mailing.services.IAlertasService;
import org.slf4j.Logger;
@@ -15,19 +17,19 @@
@Service
public class AlertasService implements IAlertasService {
private static final Logger logger = LoggerFactory.getLogger(AlertasService.class);
- private static final double TEMPERATURA_ALERTA = 35.0;
- private static final int HUMEDAD_ALERTA = 60;
+ private final IAlertaRepository alertaRepository;
private final IClimaRepository climaRepository;
private final EmailService emailService;
private final String remitente;
private final List destinatarios;
public AlertasService(
- IClimaRepository climaRepository,
+ IAlertaRepository alertaRepository, IClimaRepository climaRepository,
EmailService emailService,
@Value("${email.alertas.remitente}") String remitente,
@Value("${email.alertas.destinatarios}") String destinatarios) {
+ this.alertaRepository = alertaRepository;
this.climaRepository = climaRepository;
this.emailService = emailService;
this.remitente = remitente;
@@ -63,8 +65,8 @@ public Mono generarAlertasYAvisar() {
private boolean cumpleCondicionesAlerta(Clima clima) {
//TODO: podríamos refactorizar el diseño para que no sea un simple método, pues puede ser más complejo
- return clima.getTemperaturaCelsius() > TEMPERATURA_ALERTA &&
- clima.getHumedad() > HUMEDAD_ALERTA;
+ // HECHO
+ return this.alertaRepository.findAll().stream().anyMatch(alerta -> alerta.cumpleCondicionesAlerta(clima));
}
private void generarYEnviarEmail(Clima clima) {
@@ -84,8 +86,13 @@ private void generarYEnviarEmail(Clima clima) {
);
for (String destinatario : destinatarios) {
- Email email = new Email(destinatario, remitente, asunto, mensaje);
- emailService.crearEmail(email);
+ // Email email = new Email(destinatario, remitente, asunto, mensaje);
+ EmailInputDTO dto = new EmailInputDTO();
+ dto.setDestinatario(destinatario);
+ dto.setRemitente(remitente);
+ dto.setAsunto(asunto);
+ dto.setContenido(mensaje);
+ emailService.crearEmail(dto);
}
logger.info("Email de alerta generado para {} - Enviado a {} destinatarios",
diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/services/impl/EmailService.java b/src/main/java/ar/utn/ba/ddsi/mailing/services/impl/EmailService.java
index e1ffb85..1e52e3a 100644
--- a/src/main/java/ar/utn/ba/ddsi/mailing/services/impl/EmailService.java
+++ b/src/main/java/ar/utn/ba/ddsi/mailing/services/impl/EmailService.java
@@ -1,5 +1,7 @@
package ar.utn.ba.ddsi.mailing.services.impl;
+import ar.utn.ba.ddsi.mailing.models.dto.email.EmailInputDTO;
+import ar.utn.ba.ddsi.mailing.models.dto.email.EmailOutputDTO;
import ar.utn.ba.ddsi.mailing.models.entities.Email;
import ar.utn.ba.ddsi.mailing.models.repositories.IEmailRepository;
import ar.utn.ba.ddsi.mailing.services.IEmailService;
@@ -18,16 +20,17 @@ public EmailService(IEmailRepository emailRepository) {
}
@Override
- public Email crearEmail(Email email) {
- return emailRepository.save(email);
+ public EmailOutputDTO crearEmail(EmailInputDTO inputDTO) {
+ Email email = this.emailRepository.save(this.dtoTOEmail(inputDTO));
+ return this.emailToDTO(email);
}
@Override
- public List obtenerEmails(Boolean pendiente) {
+ public List obtenerEmails(Boolean pendiente) {
if (pendiente != null) {
- return emailRepository.findByEnviado(!pendiente);
+ return emailRepository.findByEnviado(!pendiente).stream().map(this::emailToDTO).toList();
}
- return emailRepository.findAll();
+ return emailRepository.findAll().stream().map(this::emailToDTO).toList();
}
@Override
@@ -40,9 +43,28 @@ public void procesarPendientes() {
}
}
+ public Email dtoTOEmail (EmailInputDTO dto) {
+ return new Email(
+ dto.getDestinatario(),
+ dto.getRemitente(),
+ dto.getAsunto(),
+ dto.getContenido()
+ );
+ }
+
+ public EmailOutputDTO emailToDTO(Email email) {
+ EmailOutputDTO outputDTO = new EmailOutputDTO();
+ outputDTO.setId(email.getId());
+ outputDTO.setDestinatario(email.getDestinatario());
+ outputDTO.setRemitente(email.getRemitente());
+ outputDTO.setAsunto(email.getAsunto());
+ outputDTO.setContenido(email.getContenido());
+ return outputDTO;
+ }
+
@Override
public void loguearEmailsPendientes() {
- List pendientes = obtenerEmails(true);
+ List pendientes = obtenerEmails(true);
logger.info("Emails pendientes de envío: {}", pendientes.size());
pendientes.forEach(email ->
logger.info("Email pendiente - ID: {}, Destinatario: {}, Asunto: {}",