Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ public Email crearEmail(@RequestBody Email email) {
public List<Email> obtenerEmails(@RequestParam(required = false) Boolean pendiente) {
return emailService.obtenerEmails(pendiente);
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package ar.utn.ba.ddsi.mailing.models.adapters;

import ar.utn.ba.ddsi.mailing.models.entities.Email;

public interface IEmailAdapter {
public void enviar(Email email);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package ar.utn.ba.ddsi.mailing.models.adapters.impl;

import ar.utn.ba.ddsi.mailing.models.adapters.IEmailAdapter;
import ar.utn.ba.ddsi.mailing.models.entities.Email;

public class EmailAdapter implements IEmailAdapter {

@Override
public void enviar(Email email) {
// Simulación de envío
System.out.printf("Email enviado a %s con asunto '%s'%n",
email.getDestinatario(), email.getAsunto());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package ar.utn.ba.ddsi.mailing.models.dtos;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class EmailInputDTO {
private String destinatario;
private String asunto;
private String contenido;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package ar.utn.ba.ddsi.mailing.models.dtos;

import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class EmailOutputDTO {
private Long id;
private String destinatario;
private String remitente;
private String asunto;
private String contenido;
private boolean enviado;

}
39 changes: 39 additions & 0 deletions src/main/java/ar/utn/ba/ddsi/mailing/models/entities/Alerta.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package ar.utn.ba.ddsi.mailing.models.entities;

import lombok.Getter;

import java.time.LocalDateTime;

@Getter
public class Alerta {
private final Clima clima;
private final String mensaje;
private final LocalDateTime fechaGeneracion;

public Alerta(Clima clima) {
this.clima = clima;
this.fechaGeneracion = LocalDateTime.now();
this.mensaje = generarMensaje(clima);
}

private String generarMensaje(Clima clima) {
return 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()
);
}

public Email generarEmail(String remitente, String destinatario) {
String asunto = "Alerta de Clima - Condiciones Extremas";
return new Email(destinatario, remitente, asunto, mensaje);
}
}
18 changes: 18 additions & 0 deletions src/main/java/ar/utn/ba/ddsi/mailing/models/entities/Ciudad.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package ar.utn.ba.ddsi.mailing.models.entities;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class Ciudad {
private String nombre;
private String region;
private String pais;

public Ciudad(String nombre, String region, String pais) {
this.nombre = nombre;
this.region = region;
this.pais = pais;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@
@Setter
public class Clima {
private Long id;
private String ciudad;
private String region;
private String pais;
private Ciudad ciudad;
private Double temperaturaCelsius;
private Double temperaturaFahrenheit;
private String condicion;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package ar.utn.ba.ddsi.mailing.models.entities;

public class CondicionAlerta {
private double temperaturaAlerta;
private int humedadAlerta;

public CondicionAlerta(double temperaturaAlerta, int humedadAlerta) {
this.temperaturaAlerta = temperaturaAlerta;
this.humedadAlerta = humedadAlerta;
}

public boolean cumple(Clima clima) {
return clima.getTemperaturaCelsius() > temperaturaAlerta &&
clima.getHumedad() > humedadAlerta;
}
}
13 changes: 11 additions & 2 deletions src/main/java/ar/utn/ba/ddsi/mailing/models/entities/Email.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ar.utn.ba.ddsi.mailing.models.entities;

import ar.utn.ba.ddsi.mailing.models.adapters.IEmailAdapter;
import lombok.Getter;
import lombok.Setter;

Expand All @@ -13,6 +14,8 @@ public class Email {
private String contenido;
private boolean enviado;

private IEmailAdapter emailAdapter;

public Email(String destinatario, String remitente, String asunto, String contenido) {
this.destinatario = destinatario;
this.remitente = remitente;
Expand All @@ -22,6 +25,12 @@ public Email(String destinatario, String remitente, String asunto, String conten
}

public void enviar() {
//TODO: Implementación pendiente. Podríamos usar adapters

if (emailAdapter == null) {
throw new IllegalStateException("No se configuró el adaptador del email");
}
emailAdapter.enviar(this);
this.enviado = true;
}
}
}

Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
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.Alerta;
import ar.utn.ba.ddsi.mailing.models.entities.CondicionAlerta;
import ar.utn.ba.ddsi.mailing.models.entities.Email;
import ar.utn.ba.ddsi.mailing.models.repositories.IClimaRepository;
import ar.utn.ba.ddsi.mailing.services.IAlertasService;
Expand All @@ -15,23 +17,29 @@
@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<String> destinatarios;
private final CondicionAlerta condicionAlerta;

// double TEMPERATURA_ALERTA = 35.0;
// private static final int HUMEDAD_ALERTA = 60;

public AlertasService(
IClimaRepository climaRepository,
EmailService emailService,
@Value("${email.alertas.remitente}") String remitente,
@Value("${email.alertas.destinatarios}") String destinatarios) {
IClimaRepository climaRepository,
EmailService emailService,
@Value("${email.alertas.remitente}") String remitente,
@Value("${email.alertas.destinatarios}") String destinatarios,
@Value("${alerta.temperatura.minima}") double tempMin,
@Value("${alerta.humedad.minima}") int humedadMin)
{
this.climaRepository = climaRepository;
this.emailService = emailService;
this.remitente = remitente;
this.destinatarios = Arrays.asList(destinatarios.split(","));
this.condicionAlerta = new CondicionAlerta(tempMin, humedadMin);
}

@Override
Expand All @@ -43,15 +51,16 @@ public Mono<Void> generarAlertasYAvisar() {
})
.flatMap(climas -> {
climas.stream()
.filter(this::cumpleCondicionesAlerta)
.forEach(this::generarYEnviarEmail);

.filter(condicionAlerta::cumple)
.map(Alerta::new)
.forEach(this::enviarAlertaPorEmail);

// Marcar todos como procesados
climas.forEach(clima -> {
clima.setProcesado(true);
climaRepository.save(clima);
});

return Mono.empty();
})
.onErrorResume(e -> {
Expand All @@ -61,34 +70,13 @@ public Mono<Void> 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 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()
);

private void enviarAlertaPorEmail(Alerta alerta) {
for (String destinatario : destinatarios) {
Email email = new Email(destinatario, remitente, asunto, mensaje);
Email email = alerta.generarEmail(remitente, destinatario);
emailService.crearEmail(email);
}
logger.info("Email de alerta generado para {} - Enviado a {} destinatarios",
clima.getCiudad(), destinatarios.size());

logger.info("Alerta generada para {} - Emails creados para {} destinatarios",
alerta.getClima().getCiudad(), destinatarios.size());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package ar.utn.ba.ddsi.mailing.services.impl;

import ar.utn.ba.ddsi.mailing.models.entities.Ciudad;
import ar.utn.ba.ddsi.mailing.models.entities.Clima;
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.models.repositories.IClimaRepository;
import ar.utn.ba.ddsi.mailing.services.IClimaService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -15,33 +16,34 @@
@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 IClimaRepository climaRepository;
private final WebClient webClient;
private final String apiKey;
private final String[] ciudadesArgentinas;

public ClimaService(
IClimaRepository climaRepository,
@Value("${weather.api.key}") String apiKey,
@Value("${weather.api.base-url}") String baseUrl) {
this.climaRepository = climaRepository;
this.apiKey = apiKey;
this.webClient = WebClient.builder()
.baseUrl(baseUrl)
.build();
public ClimaService(
IClimaRepository climaRepository,
@Value("${weather.api.key}") String apiKey,
@Value("${weather.api.base-url}") String baseUrl,
@Value("${ciudades.argentina}") String[] ciudadesArgentinas
) {
this.climaRepository = climaRepository;
this.apiKey = apiKey;
this.ciudadesArgentinas = ciudadesArgentinas;

this.webClient = WebClient.builder()
.baseUrl(baseUrl)
.build();
}

@Override
@Override
public Mono<Void> actualizarClimaCiudades() {
return Flux.fromArray(CIUDADES_ARGENTINA)
return Flux.fromArray(ciudadesArgentinas)
.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 -> {
Expand All @@ -62,16 +64,20 @@ private Mono<Clima> obtenerClimaDeAPI(String ciudad) {
.retrieve()
.bodyToMono(WeatherResponse.class)
.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.setCondicion(response.getCurrent().getCondition().getText());
clima.setVelocidadVientoKmh(response.getCurrent().getWind_kph());
clima.setHumedad(response.getCurrent().getHumidity());
return clima;
Clima clima = new Clima();
Ciudad ciudadObj = new Ciudad(
response.getLocation().getName(),
response.getLocation().getRegion(),
response.getLocation().getCountry()
);
clima.setCiudad(ciudadObj);
clima.setTemperaturaCelsius(response.getCurrent().getTemp_c());
clima.setTemperaturaFahrenheit(response.getCurrent().getTemp_f());
clima.setCondicion(response.getCurrent().getCondition().getText());
clima.setVelocidadVientoKmh(response.getCurrent().getWind_kph());
clima.setHumedad(response.getCurrent().getHumidity());

return clima;
});
}
}
Loading