From 79b22dbca5fe809e0e6ffeec9389c58317615dc1 Mon Sep 17 00:00:00 2001 From: nicolasvultaggio Date: Sat, 24 May 2025 15:41:21 -0300 Subject: [PATCH] =?UTF-8?q?implemento=20mejoras=20de=20dise=C3=B1o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mailing/controllers/EmailController.java | 8 +- .../mailing/models/dto/EmailInputDTO.java | 13 +++ .../mailing/models/dto/EmailOutputDTO.java | 11 +++ .../mailing/models/entities/Temperatura.java | 17 ++++ .../models/entities/alerts/Alerta.java | 19 ++++ .../models/entities/{ => climas}/Clima.java | 18 ++-- .../models/entities/{ => emails}/Email.java | 7 +- .../models/entities/lugares/Ciudad.java | 30 ++++++ .../mailing/models/entities/lugares/Pais.java | 10 ++ .../models/entities/lugares/Region.java | 11 +++ .../repositories/IAlertaRepository.java | 10 ++ .../repositories/ICiudadRepository.java | 10 ++ .../models/repositories/IClimaRepository.java | 2 +- .../models/repositories/IEmailRepository.java | 2 +- .../repositories/impl/AlertaRepository.java | 31 ++++++ .../repositories/impl/CiudadRepository.java | 26 +++++ .../repositories/impl/ClimaRepository.java | 8 +- .../repositories/impl/EmailRepository.java | 2 +- .../mailing/schedulers/AlertasScheduler.java | 2 +- .../mailing/schedulers/EmailScheduler.java | 14 ++- .../mailing/services/IAlertasService.java | 2 +- .../ddsi/mailing/services/IEmailService.java | 9 +- .../ddsi/mailing/services/ISeederService.java | 13 +++ .../mailing/services/impl/AlertasService.java | 94 ++++++++----------- .../mailing/services/impl/ClimaService.java | 31 +++--- .../mailing/services/impl/EmailService.java | 81 ++++++++++++++-- .../mailing/services/impl/SeederService.java | 38 ++++++++ .../ba/ddsi/mailing/utils/IAlertDetecter.java | 8 ++ .../mailing/utils/IEmailSenderAdapter.java | 7 ++ .../mailing/utils/impl/AlertDetecter.java | 17 ++++ .../mailing/utils/impl/SenderByLibrary.java | 13 +++ 31 files changed, 461 insertions(+), 103 deletions(-) create mode 100644 src/main/java/ar/utn/ba/ddsi/mailing/models/dto/EmailInputDTO.java create mode 100644 src/main/java/ar/utn/ba/ddsi/mailing/models/dto/EmailOutputDTO.java create mode 100644 src/main/java/ar/utn/ba/ddsi/mailing/models/entities/Temperatura.java create mode 100644 src/main/java/ar/utn/ba/ddsi/mailing/models/entities/alerts/Alerta.java rename src/main/java/ar/utn/ba/ddsi/mailing/models/entities/{ => climas}/Clima.java (50%) rename src/main/java/ar/utn/ba/ddsi/mailing/models/entities/{ => emails}/Email.java (77%) create mode 100644 src/main/java/ar/utn/ba/ddsi/mailing/models/entities/lugares/Ciudad.java create mode 100644 src/main/java/ar/utn/ba/ddsi/mailing/models/entities/lugares/Pais.java create mode 100644 src/main/java/ar/utn/ba/ddsi/mailing/models/entities/lugares/Region.java create mode 100644 src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/IAlertaRepository.java create mode 100644 src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/ICiudadRepository.java create mode 100644 src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/impl/AlertaRepository.java create mode 100644 src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/impl/CiudadRepository.java create mode 100644 src/main/java/ar/utn/ba/ddsi/mailing/services/ISeederService.java create mode 100644 src/main/java/ar/utn/ba/ddsi/mailing/services/impl/SeederService.java create mode 100644 src/main/java/ar/utn/ba/ddsi/mailing/utils/IAlertDetecter.java create mode 100644 src/main/java/ar/utn/ba/ddsi/mailing/utils/IEmailSenderAdapter.java create mode 100644 src/main/java/ar/utn/ba/ddsi/mailing/utils/impl/AlertDetecter.java create mode 100644 src/main/java/ar/utn/ba/ddsi/mailing/utils/impl/SenderByLibrary.java 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..ba35021 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,6 +1,8 @@ package ar.utn.ba.ddsi.mailing.controllers; -import ar.utn.ba.ddsi.mailing.models.entities.Email; +import ar.utn.ba.ddsi.mailing.models.dto.EmailInputDTO; +import ar.utn.ba.ddsi.mailing.models.dto.EmailOutputDTO; +import ar.utn.ba.ddsi.mailing.models.entities.emails.Email; import ar.utn.ba.ddsi.mailing.services.IEmailService; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -15,8 +17,8 @@ public EmailController(IEmailService emailService) { } @PostMapping - public Email crearEmail(@RequestBody Email email) { - return emailService.crearEmail(email); + public EmailOutputDTO crearEmail(@RequestBody EmailInputDTO emailInputDTO) { + return emailService.crearEmail(emailInputDTO); } @GetMapping diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/models/dto/EmailInputDTO.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/dto/EmailInputDTO.java new file mode 100644 index 0000000..20fa5f6 --- /dev/null +++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/dto/EmailInputDTO.java @@ -0,0 +1,13 @@ +package ar.utn.ba.ddsi.mailing.models.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +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/EmailOutputDTO.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/dto/EmailOutputDTO.java new file mode 100644 index 0000000..9e1c70b --- /dev/null +++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/dto/EmailOutputDTO.java @@ -0,0 +1,11 @@ +package ar.utn.ba.ddsi.mailing.models.dto; + +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public class EmailOutputDTO { + 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/Temperatura.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/Temperatura.java new file mode 100644 index 0000000..a81e3f4 --- /dev/null +++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/Temperatura.java @@ -0,0 +1,17 @@ +package ar.utn.ba.ddsi.mailing.models.entities; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +public class Temperatura { + private double temperaturaCelsius; //keep it simple + + private double getTemperaturaFahrenheit(){ + return (temperaturaCelsius * 9 / 5) + 32; + } + +} diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/alerts/Alerta.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/alerts/Alerta.java new file mode 100644 index 0000000..95d6e5a --- /dev/null +++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/alerts/Alerta.java @@ -0,0 +1,19 @@ +package ar.utn.ba.ddsi.mailing.models.entities.alerts; + +import ar.utn.ba.ddsi.mailing.models.entities.Temperatura; +import ar.utn.ba.ddsi.mailing.models.entities.lugares.Ciudad; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class Alerta { + private Long id; + private Ciudad ciudad; + private Temperatura temperatura; + private Integer humedad; + private String condicion; + private Double velocidadVientoKmh; + boolean procesado = false; +} diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/Clima.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/climas/Clima.java similarity index 50% rename from src/main/java/ar/utn/ba/ddsi/mailing/models/entities/Clima.java rename to src/main/java/ar/utn/ba/ddsi/mailing/models/entities/climas/Clima.java index 4eaa65b..85790f1 100644 --- a/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/Clima.java +++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/climas/Clima.java @@ -1,18 +1,17 @@ -package ar.utn.ba.ddsi.mailing.models.entities; +package ar.utn.ba.ddsi.mailing.models.entities.climas; +import ar.utn.ba.ddsi.mailing.models.entities.Temperatura; +import ar.utn.ba.ddsi.mailing.models.entities.lugares.Ciudad; import lombok.Getter; import lombok.Setter; import java.time.LocalDateTime; @Getter @Setter -public class Clima { +public class Clima { //responsabilidad: se la cambio, la ciudad conoce su clima, no al reves private Long id; - private String ciudad; - private String region; - private String pais; - private Double temperaturaCelsius; - private Double temperaturaFahrenheit; + private Ciudad ciudad; + private Temperatura temperatura; private String condicion; private Double velocidadVientoKmh; private Integer humedad; @@ -23,4 +22,9 @@ public Clima() { this.fechaActualizacion = LocalDateTime.now(); this.procesado = false; } + + public boolean getProcesado(){ + return procesado; + } + } \ 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/emails/Email.java similarity index 77% rename from src/main/java/ar/utn/ba/ddsi/mailing/models/entities/Email.java rename to src/main/java/ar/utn/ba/ddsi/mailing/models/entities/emails/Email.java index eb940be..48baed0 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/emails/Email.java @@ -1,4 +1,4 @@ -package ar.utn.ba.ddsi.mailing.models.entities; +package ar.utn.ba.ddsi.mailing.models.entities.emails; import lombok.Getter; import lombok.Setter; @@ -13,15 +13,14 @@ public class Email { private String contenido; private boolean enviado; + public Email(String destinatario, String remitente, String asunto, String contenido) { this.destinatario = destinatario; this.remitente = remitente; this.asunto = asunto; this.contenido = contenido; this.enviado = false; - } - public void enviar() { - //TODO: Implementación pendiente. Podríamos usar adapters } + } \ No newline at end of file diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/lugares/Ciudad.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/lugares/Ciudad.java new file mode 100644 index 0000000..ab96d9a --- /dev/null +++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/lugares/Ciudad.java @@ -0,0 +1,30 @@ +package ar.utn.ba.ddsi.mailing.models.entities.lugares; + +import ar.utn.ba.ddsi.mailing.models.entities.climas.Clima; +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +@Setter +@Getter +public class Ciudad { + String nombre; + Region region; + List climas; + public Ciudad(String nombre,Region region) { + this.nombre = nombre; + this.region = region; + climas = new ArrayList<>(); + } + + public void agregarClima(Clima clima){ + this.climas.add(clima); + } + + public Clima obtenerClimaMasReciente(){ + return climas.stream().max(Comparator.comparing(Clima::getFechaActualizacion)).orElse(null); + } +} diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/lugares/Pais.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/lugares/Pais.java new file mode 100644 index 0000000..c1cc292 --- /dev/null +++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/lugares/Pais.java @@ -0,0 +1,10 @@ +package ar.utn.ba.ddsi.mailing.models.entities.lugares; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class Pais { + String nombre; +} diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/lugares/Region.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/lugares/Region.java new file mode 100644 index 0000000..1ef0b65 --- /dev/null +++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/entities/lugares/Region.java @@ -0,0 +1,11 @@ +package ar.utn.ba.ddsi.mailing.models.entities.lugares; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class Region { + String nombre; + Pais pais; +} 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..2535ea9 --- /dev/null +++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/IAlertaRepository.java @@ -0,0 +1,10 @@ +package ar.utn.ba.ddsi.mailing.models.repositories; + +import ar.utn.ba.ddsi.mailing.models.entities.alerts.Alerta; + +import java.util.List; + +public interface IAlertaRepository { + public void save(Alerta alerta); + public List findByProcesado(boolean procesado); +} diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/ICiudadRepository.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/ICiudadRepository.java new file mode 100644 index 0000000..8a0ec50 --- /dev/null +++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/ICiudadRepository.java @@ -0,0 +1,10 @@ +package ar.utn.ba.ddsi.mailing.models.repositories; + +import ar.utn.ba.ddsi.mailing.models.entities.lugares.Ciudad; + +import java.util.List; + +public interface ICiudadRepository { + public List findAll(); + public void save(Ciudad ciudad); +} diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/IClimaRepository.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/IClimaRepository.java index 8e7dfb4..d58e57a 100644 --- a/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/IClimaRepository.java +++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/IClimaRepository.java @@ -1,6 +1,6 @@ package ar.utn.ba.ddsi.mailing.models.repositories; -import ar.utn.ba.ddsi.mailing.models.entities.Clima; +import ar.utn.ba.ddsi.mailing.models.entities.climas.Clima; import java.util.List; import java.util.Optional; diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/IEmailRepository.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/IEmailRepository.java index ad96d89..efe2145 100644 --- a/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/IEmailRepository.java +++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/IEmailRepository.java @@ -1,6 +1,6 @@ package ar.utn.ba.ddsi.mailing.models.repositories; -import ar.utn.ba.ddsi.mailing.models.entities.Email; +import ar.utn.ba.ddsi.mailing.models.entities.emails.Email; import java.util.List; import java.util.Optional; 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..ad085c0 --- /dev/null +++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/impl/AlertaRepository.java @@ -0,0 +1,31 @@ +package ar.utn.ba.ddsi.mailing.models.repositories.impl; + +import ar.utn.ba.ddsi.mailing.models.entities.alerts.Alerta; +import ar.utn.ba.ddsi.mailing.models.entities.climas.Clima; +import ar.utn.ba.ddsi.mailing.models.repositories.IAlertaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; + +@Repository +public class AlertaRepository implements IAlertaRepository { + List alertas; + private final AtomicLong idGenerator = new AtomicLong(1); + + @Override + public void save(Alerta alerta) { + if (alerta.getId() == null) { + Long id = idGenerator.getAndIncrement(); + alerta.setId(id); + alertas.add(alerta); + }//si ya esta en el repo listo, ya esta + } + + @Override + public List findByProcesado(boolean procesado) { + return alertas.stream() + .filter(a -> a.isProcesado() == procesado) + .toList(); + } +} diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/impl/CiudadRepository.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/impl/CiudadRepository.java new file mode 100644 index 0000000..808cd90 --- /dev/null +++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/impl/CiudadRepository.java @@ -0,0 +1,26 @@ +package ar.utn.ba.ddsi.mailing.models.repositories.impl; + +import ar.utn.ba.ddsi.mailing.models.entities.lugares.Ciudad; +import ar.utn.ba.ddsi.mailing.models.repositories.ICiudadRepository; +import org.springframework.stereotype.Repository; + +import java.util.ArrayList; +import java.util.List; + +@Repository +public class CiudadRepository implements ICiudadRepository { + private final List ciudades; + + public CiudadRepository() { + ciudades = new ArrayList<>(); + } + @Override + public List findAll() { + return ciudades; + } + + @Override + public void save(Ciudad ciudad) { + ciudades.add(ciudad); + } +} diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/impl/ClimaRepository.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/impl/ClimaRepository.java index 864349b..e8d67ad 100644 --- a/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/impl/ClimaRepository.java +++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/impl/ClimaRepository.java @@ -1,6 +1,6 @@ package ar.utn.ba.ddsi.mailing.models.repositories.impl; -import ar.utn.ba.ddsi.mailing.models.entities.Clima; +import ar.utn.ba.ddsi.mailing.models.entities.climas.Clima; import ar.utn.ba.ddsi.mailing.models.repositories.IClimaRepository; import org.springframework.stereotype.Repository; import java.util.*; @@ -18,10 +18,10 @@ public Clima save(Clima clima) { Long id = idGenerator.getAndIncrement(); clima.setId(id); climas.put(id, clima); - ciudadToId.put(clima.getCiudad(), id); + ciudadToId.put(clima.getCiudad().getNombre(), id); } else { climas.put(clima.getId(), clima); - ciudadToId.put(clima.getCiudad(), clima.getId()); + ciudadToId.put(clima.getCiudad().getNombre(), clima.getId()); } return clima; } @@ -45,7 +45,7 @@ public Optional findByCiudad(String ciudad) { @Override public List findByProcesado(boolean procesado) { return climas.values().stream() - .filter(c -> c.isProcesado() == procesado) + .filter(c -> c.getProcesado() == procesado) .toList(); } diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/impl/EmailRepository.java b/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/impl/EmailRepository.java index 2920146..d01efec 100644 --- a/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/impl/EmailRepository.java +++ b/src/main/java/ar/utn/ba/ddsi/mailing/models/repositories/impl/EmailRepository.java @@ -1,6 +1,6 @@ package ar.utn.ba.ddsi.mailing.models.repositories.impl; -import ar.utn.ba.ddsi.mailing.models.entities.Email; +import ar.utn.ba.ddsi.mailing.models.entities.emails.Email; import ar.utn.ba.ddsi.mailing.models.repositories.IEmailRepository; import org.springframework.stereotype.Repository; import java.util.*; diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/schedulers/AlertasScheduler.java b/src/main/java/ar/utn/ba/ddsi/mailing/schedulers/AlertasScheduler.java index 231faf7..df52aaa 100644 --- a/src/main/java/ar/utn/ba/ddsi/mailing/schedulers/AlertasScheduler.java +++ b/src/main/java/ar/utn/ba/ddsi/mailing/schedulers/AlertasScheduler.java @@ -17,7 +17,7 @@ public AlertasScheduler(IAlertasService alertasService) { @Scheduled(fixedRate = 60000) // Cada 1 minuto public void procesarAlertas() { - alertasService.generarAlertasYAvisar() + alertasService.generarAlertasYGuardar() .doOnSuccess(v -> logger.info("Procesamiento de alertas completado")) .doOnError(e -> logger.error("Error en el procesamiento de alertas: {}", e.getMessage())) .subscribe(); diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/schedulers/EmailScheduler.java b/src/main/java/ar/utn/ba/ddsi/mailing/schedulers/EmailScheduler.java index 64fc589..f002e73 100644 --- a/src/main/java/ar/utn/ba/ddsi/mailing/schedulers/EmailScheduler.java +++ b/src/main/java/ar/utn/ba/ddsi/mailing/schedulers/EmailScheduler.java @@ -1,13 +1,15 @@ package ar.utn.ba.ddsi.mailing.schedulers; import ar.utn.ba.ddsi.mailing.services.IEmailService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class EmailScheduler { private final IEmailService emailService; - + private static final Logger logger = LoggerFactory.getLogger(EmailScheduler.class); public EmailScheduler(IEmailService emailService) { this.emailService = emailService; } @@ -17,8 +19,18 @@ public void procesarEmailsPendientes() { emailService.procesarPendientes(); } + @Scheduled(cron = "${cron.expression}") + public void revisarAlertasYEnviarEmails() { + emailService.revisarAlertasYEnviarEmails() + .doOnSuccess(v -> logger.info("Enviado de emails completado")) + .doOnError(e -> logger.error("Error en el enviado de emails: {}", e.getMessage())) + .subscribe(); + } + @Scheduled(cron = "${cron.expression}") public void loguearEmailsPendientes() { emailService.loguearEmailsPendientes(); } + + } \ No newline at end of file diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/services/IAlertasService.java b/src/main/java/ar/utn/ba/ddsi/mailing/services/IAlertasService.java index 65bc0a4..2f15147 100644 --- a/src/main/java/ar/utn/ba/ddsi/mailing/services/IAlertasService.java +++ b/src/main/java/ar/utn/ba/ddsi/mailing/services/IAlertasService.java @@ -3,5 +3,5 @@ import reactor.core.publisher.Mono; public interface IAlertasService { - Mono generarAlertasYAvisar(); + Mono generarAlertasYGuardar(); } \ No newline at end of file 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..19d1a15 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,16 @@ package ar.utn.ba.ddsi.mailing.services; -import ar.utn.ba.ddsi.mailing.models.entities.Email; +import ar.utn.ba.ddsi.mailing.models.dto.EmailInputDTO; +import ar.utn.ba.ddsi.mailing.models.dto.EmailOutputDTO; +import ar.utn.ba.ddsi.mailing.models.entities.emails.Email; +import reactor.core.publisher.Mono; + import java.util.List; public interface IEmailService { - Email crearEmail(Email email); + EmailOutputDTO crearEmail(EmailInputDTO emailInputDTO); List obtenerEmails(Boolean pendiente); void procesarPendientes(); + public Mono revisarAlertasYEnviarEmails(); void loguearEmailsPendientes(); } \ No newline at end of file diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/services/ISeederService.java b/src/main/java/ar/utn/ba/ddsi/mailing/services/ISeederService.java new file mode 100644 index 0000000..da70725 --- /dev/null +++ b/src/main/java/ar/utn/ba/ddsi/mailing/services/ISeederService.java @@ -0,0 +1,13 @@ +package ar.utn.ba.ddsi.mailing.services; + +import ar.utn.ba.ddsi.mailing.models.entities.lugares.Ciudad; +import ar.utn.ba.ddsi.mailing.models.entities.lugares.Pais; +import ar.utn.ba.ddsi.mailing.models.entities.lugares.Region; +import ar.utn.ba.ddsi.mailing.models.repositories.ICiudadRepository; + +public interface ISeederService { + + public void inicializar(); + + +} 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..61d3dd8 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,9 +1,14 @@ package ar.utn.ba.ddsi.mailing.services.impl; -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.entities.alerts.Alerta; +import ar.utn.ba.ddsi.mailing.models.entities.climas.Clima; +import ar.utn.ba.ddsi.mailing.models.entities.emails.Email; +import ar.utn.ba.ddsi.mailing.models.repositories.IAlertaRepository; +import ar.utn.ba.ddsi.mailing.models.repositories.ICiudadRepository; import ar.utn.ba.ddsi.mailing.models.repositories.IClimaRepository; +import ar.utn.ba.ddsi.mailing.models.repositories.impl.AlertaRepository; import ar.utn.ba.ddsi.mailing.services.IAlertasService; +import ar.utn.ba.ddsi.mailing.utils.IAlertDetecter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; @@ -15,43 +20,39 @@ @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 IClimaRepository climaRepository; - private final EmailService emailService; - private final String remitente; - private final List destinatarios; + private final ICiudadRepository ciudadRepository; + private final IAlertDetecter alertDetecter; + private final IAlertaRepository alertaRepository; public AlertasService( - IClimaRepository climaRepository, - EmailService emailService, - @Value("${email.alertas.remitente}") String remitente, - @Value("${email.alertas.destinatarios}") String destinatarios) { + IClimaRepository climaRepository, + ICiudadRepository ciudadRepository, + IAlertDetecter alertDetecter, IAlertaRepository alertaRepository) { this.climaRepository = climaRepository; - this.emailService = emailService; - this.remitente = remitente; - this.destinatarios = Arrays.asList(destinatarios.split(",")); + this.ciudadRepository = ciudadRepository; + this.alertDetecter = alertDetecter; + this.alertaRepository = alertaRepository; } @Override - public Mono generarAlertasYAvisar() { - return Mono.fromCallable(() -> climaRepository.findByProcesado(false)) - .flatMap(climas -> { - logger.info("Procesando {} registros de clima no procesados", climas.size()); - return Mono.just(climas); + public Mono generarAlertasYGuardar() { + return Mono.fromCallable(ciudadRepository::findAll) + .flatMap(ciudades -> { + logger.info("Procesando climas de ciudades"); + return Mono.just(ciudades); }) - .flatMap(climas -> { - climas.stream() - .filter(this::cumpleCondicionesAlerta) - .forEach(this::generarYEnviarEmail); - - // Marcar todos como procesados - climas.forEach(clima -> { - clima.setProcesado(true); - climaRepository.save(clima); + .flatMap(ciudades -> { + ciudades.forEach(ciudad -> { + Clima climaMasReciente = ciudad.obtenerClimaMasReciente(); + if(!climaMasReciente.getProcesado() && alertDetecter.cumpleCondicionesAlerta(climaMasReciente)) { + Alerta alerta = this.generarAlerta(climaMasReciente); + alertaRepository.save(alerta); + climaMasReciente.setProcesado(true); + climaRepository.save(climaMasReciente); + } }); - return Mono.empty(); }) .onErrorResume(e -> { @@ -61,34 +62,15 @@ public Mono generarAlertasYAvisar() { .then(); } - 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; + private Alerta generarAlerta(Clima clima) { + Alerta alerta = new Alerta(); + alerta.setCiudad(clima.getCiudad()); + alerta.setTemperatura(clima.getTemperatura()); + alerta.setCondicion(clima.getCondicion()); + alerta.setVelocidadVientoKmh(clima.getVelocidadVientoKmh()); + alerta.setHumedad(clima.getHumedad()); + return alerta; } - private void generarYEnviarEmail(Clima clima) { - String asunto = "Alerta de Clima - Condiciones Extremas"; - String mensaje = String.format( - "ALERTA: Condiciones climáticas extremas detectadas en %s\n\n" + - "Temperatura: %.1f°C\n" + - "Humedad: %d%%\n" + - "Condición: %s\n" + - "Velocidad del viento: %.1f km/h\n\n" + - "Se recomienda tomar precauciones.", - clima.getCiudad(), - clima.getTemperaturaCelsius(), - clima.getHumedad(), - clima.getCondicion(), - clima.getVelocidadVientoKmh() - ); - for (String destinatario : destinatarios) { - Email email = new Email(destinatario, remitente, asunto, mensaje); - emailService.crearEmail(email); - } - - logger.info("Email de alerta generado para {} - Enviado a {} destinatarios", - clima.getCiudad(), destinatarios.size()); - } } \ No newline at end of file diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/services/impl/ClimaService.java b/src/main/java/ar/utn/ba/ddsi/mailing/services/impl/ClimaService.java index d2296b4..389b91e 100644 --- a/src/main/java/ar/utn/ba/ddsi/mailing/services/impl/ClimaService.java +++ b/src/main/java/ar/utn/ba/ddsi/mailing/services/impl/ClimaService.java @@ -1,6 +1,9 @@ package ar.utn.ba.ddsi.mailing.services.impl; -import ar.utn.ba.ddsi.mailing.models.entities.Clima; +import ar.utn.ba.ddsi.mailing.models.entities.climas.Clima; +import ar.utn.ba.ddsi.mailing.models.entities.Temperatura; +import ar.utn.ba.ddsi.mailing.models.entities.lugares.Ciudad; +import ar.utn.ba.ddsi.mailing.models.repositories.ICiudadRepository; import ar.utn.ba.ddsi.mailing.models.repositories.IClimaRepository; import ar.utn.ba.ddsi.mailing.models.dto.external.weatherapi.WeatherResponse; import ar.utn.ba.ddsi.mailing.services.IClimaService; @@ -15,11 +18,8 @@ @Service public class ClimaService implements IClimaService { private static final Logger logger = LoggerFactory.getLogger(ClimaService.class); - private static final String[] CIUDADES_ARGENTINA = { - "Buenos Aires", "Cordoba", "Rosario", "Mendoza", "Tucuman", - "La Plata", "Mar del Plata", "Salta", "Santa Fe", "San Juan" - }; + private final ICiudadRepository ciudadRepository; private final IClimaRepository climaRepository; private final WebClient webClient; private final String apiKey; @@ -27,21 +27,23 @@ public class ClimaService implements IClimaService { public ClimaService( IClimaRepository climaRepository, @Value("${weather.api.key}") String apiKey, - @Value("${weather.api.base-url}") String baseUrl) { + @Value("${weather.api.base-url}") String baseUrl, + ICiudadRepository ciudadRepository) { this.climaRepository = climaRepository; this.apiKey = apiKey; this.webClient = WebClient.builder() .baseUrl(baseUrl) .build(); + this.ciudadRepository = ciudadRepository; } @Override public Mono actualizarClimaCiudades() { - return Flux.fromArray(CIUDADES_ARGENTINA) + return Flux.fromStream(ciudadRepository.findAll().stream()) .flatMap(this::obtenerClimaDeAPI) .flatMap(clima -> { climaRepository.save(clima); - logger.info("Clima actualizado para: {}", clima.getCiudad()); + logger.info("Clima actualizado para: {}", clima.getCiudad().getNombre()); return Mono.empty(); }) .onErrorResume(e -> { @@ -51,12 +53,12 @@ public Mono actualizarClimaCiudades() { .then(); } - private Mono obtenerClimaDeAPI(String ciudad) { + private Mono obtenerClimaDeAPI(Ciudad ciudad) { return webClient.get() .uri(uriBuilder -> uriBuilder .path("/current.json") .queryParam("key", apiKey) - .queryParam("q", ciudad) + .queryParam("q", ciudad.getNombre()) .queryParam("aqi", "no") .build()) .retrieve() @@ -64,14 +66,13 @@ private Mono obtenerClimaDeAPI(String ciudad) { .map(response -> { Clima clima = new Clima(); clima.setCiudad(ciudad); - clima.setRegion(response.getLocation().getRegion()); - clima.setPais(response.getLocation().getCountry()); - clima.setTemperaturaCelsius(response.getCurrent().getTemp_c()); - clima.setTemperaturaFahrenheit(response.getCurrent().getTemp_f()); + clima.setTemperatura(new Temperatura(response.getCurrent().getTemp_c())); clima.setCondicion(response.getCurrent().getCondition().getText()); clima.setVelocidadVientoKmh(response.getCurrent().getWind_kph()); clima.setHumedad(response.getCurrent().getHumidity()); + ciudad.agregarClima(clima); return clima; }); } -} \ No newline at end of file + +} \ No newline at end of file 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..93c1eca 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,25 +1,46 @@ package ar.utn.ba.ddsi.mailing.services.impl; -import ar.utn.ba.ddsi.mailing.models.entities.Email; +import ar.utn.ba.ddsi.mailing.models.dto.EmailInputDTO; +import ar.utn.ba.ddsi.mailing.models.dto.EmailOutputDTO; +import ar.utn.ba.ddsi.mailing.models.entities.alerts.Alerta; +import ar.utn.ba.ddsi.mailing.models.entities.climas.Clima; +import ar.utn.ba.ddsi.mailing.models.entities.emails.Email; +import ar.utn.ba.ddsi.mailing.models.repositories.IAlertaRepository; import ar.utn.ba.ddsi.mailing.models.repositories.IEmailRepository; import ar.utn.ba.ddsi.mailing.services.IEmailService; +import ar.utn.ba.ddsi.mailing.utils.IEmailSenderAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +import java.util.Arrays; import java.util.List; @Service public class EmailService implements IEmailService { private static final Logger logger = LoggerFactory.getLogger(EmailService.class); private final IEmailRepository emailRepository; - - public EmailService(IEmailRepository emailRepository) { + private final String remitente; + private final List destinatarios; + private final IEmailSenderAdapter sender; + private final IAlertaRepository alertaRepository; + public EmailService(IEmailRepository emailRepository, + EmailService emailService, + @Value("${email.alertas.remitente}") String remitente, + @Value("${email.alertas.destinatarios}") String destinatarios, IEmailSenderAdapter sender, IAlertaRepository alertaRepository) { + this.remitente = remitente; + this.destinatarios = Arrays.asList(destinatarios.split(",")); this.emailRepository = emailRepository; + this.sender = sender; + this.alertaRepository = alertaRepository; } @Override - public Email crearEmail(Email email) { - return emailRepository.save(email); + public EmailOutputDTO crearEmail(EmailInputDTO emailInputDTO) { + Email email = emailRepository.save(new Email(emailInputDTO.getDestinatario(),emailInputDTO.getRemitente(),emailInputDTO.getAsunto(), emailInputDTO.getContenido())); + return new EmailOutputDTO(email.getDestinatario(),email.getRemitente(),email.getAsunto(),email.getContenido()); } @Override @@ -34,7 +55,7 @@ public List obtenerEmails(Boolean pendiente) { public void procesarPendientes() { List pendientes = emailRepository.findByEnviado(false); for (Email email : pendientes) { - email.enviar(); + sender.enviar(email); email.setEnviado(true); emailRepository.save(email); } @@ -51,4 +72,52 @@ public void loguearEmailsPendientes() { email.getAsunto()) ); } + + private void generarYGuardarEmail(Alerta alerta) { + String asunto = "Alerta de Clima - Condiciones Extremas"; + String mensaje = String.format( + "ALERTA: Condiciones climáticas extremas detectadas en %s\n\n" + + "Temperatura: %.1f°C\n" + + "Humedad: %d%%\n" + + "Condición: %s\n" + + "Velocidad del viento: %.1f km/h\n\n" + + "Se recomienda tomar precauciones.", + alerta.getCiudad(), + alerta.getTemperatura().getTemperaturaCelsius(), + alerta.getHumedad(), + alerta.getCondicion(), + alerta.getVelocidadVientoKmh() + ); + + for (String destinatario : destinatarios) { + EmailInputDTO emailInputDTO = new EmailInputDTO(destinatario, remitente, asunto, mensaje); + this.crearEmail(emailInputDTO); + } + + logger.info("Email de alerta generado para {} - Enviado a {} destinatarios", + alerta.getCiudad().getNombre(), destinatarios.size()); + } + @Override + public Mono revisarAlertasYEnviarEmails() { + return Mono.fromCallable(() -> alertaRepository.findByProcesado(false)) + .flatMap(alertas -> { + logger.info("Procesando {} registros de alertas no procesadas", alertas.size()); + return Mono.just(alertas); + }) + .flatMap(alertas -> { + alertas.forEach(this::generarYGuardarEmail); + + alertas.forEach(alerta -> { + alerta.setProcesado(true); + alertaRepository.save(alerta); + }); + + return Mono.empty(); + }) + .onErrorResume(e -> { + logger.error("Error al procesar alertas: {}", e.getMessage()); + return Mono.empty(); + }) + .then(); + } } \ No newline at end of file diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/services/impl/SeederService.java b/src/main/java/ar/utn/ba/ddsi/mailing/services/impl/SeederService.java new file mode 100644 index 0000000..1a0c047 --- /dev/null +++ b/src/main/java/ar/utn/ba/ddsi/mailing/services/impl/SeederService.java @@ -0,0 +1,38 @@ +package ar.utn.ba.ddsi.mailing.services.impl; + +import ar.utn.ba.ddsi.mailing.models.entities.lugares.Ciudad; +import ar.utn.ba.ddsi.mailing.models.entities.lugares.Pais; +import ar.utn.ba.ddsi.mailing.models.entities.lugares.Region; +import ar.utn.ba.ddsi.mailing.models.repositories.ICiudadRepository; +import ar.utn.ba.ddsi.mailing.services.ISeederService; + +public class SeederService implements ISeederService { + + ICiudadRepository ciudadRepository; + + private static Pais generarPais(String nombre){ + return new Pais(nombre); + }; + + private Region generarRegion(String nombre, Pais pais){ + return new Region(nombre,pais); + } + + private Ciudad generarCiudad(String nombre, Region region){ + return new Ciudad(nombre,region); + } + + public void inicializar(){ + Pais argentina = generarPais("Argentina"); + Region buenosAires = generarRegion("Buenos Aires", argentina); + + Ciudad laPlata = generarCiudad("La Plata", buenosAires); + Ciudad capitalFederal = generarCiudad("Capital Federal", buenosAires); + Ciudad marDelPLata = generarCiudad("Mar Del PLata", buenosAires); + + ciudadRepository.save(laPlata); + ciudadRepository.save(capitalFederal); + ciudadRepository.save(marDelPLata); + + } +} diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/utils/IAlertDetecter.java b/src/main/java/ar/utn/ba/ddsi/mailing/utils/IAlertDetecter.java new file mode 100644 index 0000000..5d30d30 --- /dev/null +++ b/src/main/java/ar/utn/ba/ddsi/mailing/utils/IAlertDetecter.java @@ -0,0 +1,8 @@ +package ar.utn.ba.ddsi.mailing.utils; + +import ar.utn.ba.ddsi.mailing.models.entities.climas.Clima; + +public interface IAlertDetecter { + + boolean cumpleCondicionesAlerta(Clima clima); +} diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/utils/IEmailSenderAdapter.java b/src/main/java/ar/utn/ba/ddsi/mailing/utils/IEmailSenderAdapter.java new file mode 100644 index 0000000..7b4bd93 --- /dev/null +++ b/src/main/java/ar/utn/ba/ddsi/mailing/utils/IEmailSenderAdapter.java @@ -0,0 +1,7 @@ +package ar.utn.ba.ddsi.mailing.utils; + +import ar.utn.ba.ddsi.mailing.models.entities.emails.Email; + +public interface IEmailSenderAdapter { + void enviar(Email email); +} diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/utils/impl/AlertDetecter.java b/src/main/java/ar/utn/ba/ddsi/mailing/utils/impl/AlertDetecter.java new file mode 100644 index 0000000..4b7d21f --- /dev/null +++ b/src/main/java/ar/utn/ba/ddsi/mailing/utils/impl/AlertDetecter.java @@ -0,0 +1,17 @@ +package ar.utn.ba.ddsi.mailing.utils.impl; + +import ar.utn.ba.ddsi.mailing.models.entities.climas.Clima; +import ar.utn.ba.ddsi.mailing.utils.IAlertDetecter; +import org.springframework.stereotype.Component; + +@Component +public class AlertDetecter implements IAlertDetecter { + + private final double TEMPERATURA_ALERTA = 35.0; + private final int HUMEDAD_ALERTA = 60; + + public boolean cumpleCondicionesAlerta(Clima clima) { + return clima.getTemperatura().getTemperaturaCelsius() > TEMPERATURA_ALERTA && + clima.getHumedad() > HUMEDAD_ALERTA; + } +} diff --git a/src/main/java/ar/utn/ba/ddsi/mailing/utils/impl/SenderByLibrary.java b/src/main/java/ar/utn/ba/ddsi/mailing/utils/impl/SenderByLibrary.java new file mode 100644 index 0000000..d20dbbd --- /dev/null +++ b/src/main/java/ar/utn/ba/ddsi/mailing/utils/impl/SenderByLibrary.java @@ -0,0 +1,13 @@ +package ar.utn.ba.ddsi.mailing.utils.impl; + +import ar.utn.ba.ddsi.mailing.models.entities.emails.Email; +import ar.utn.ba.ddsi.mailing.utils.IEmailSenderAdapter; +import org.springframework.stereotype.Component; + +@Component +public class SenderByLibrary implements IEmailSenderAdapter { + @Override + public void enviar(Email email) { + //todo + } +}