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
4 changes: 4 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -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.*;
Expand All @@ -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<Email> obtenerEmails(@RequestParam(required = false) Boolean pendiente) {
public List<EmailOutputDTO> obtenerEmails(@RequestParam(required = false) Boolean pendiente) {
return emailService.obtenerEmails(pendiente);
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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;
}
24 changes: 24 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,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<CondicionAlerta> condiciones;

public Alerta(String nombre, List<CondicionAlerta> condiciones) {
this.nombre = nombre;
this.condiciones = condiciones;
}

public boolean cumpleCondicionesAlerta(Clima clima){
return condiciones.stream().allMatch(condicion -> condicion.seCumple(clima));
}
}
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.entities.adapters.IEmailSender;
import lombok.Getter;
import lombok.Setter;

Expand All @@ -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;
Expand All @@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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<Alerta> findAll();
}
Original file line number Diff line number Diff line change
@@ -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<Long, Alerta> 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<Alerta> findAll() {
return new ArrayList<>(alertas.values());
}
}
Original file line number Diff line number Diff line change
@@ -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<Email> obtenerEmails(Boolean pendiente);
EmailOutputDTO crearEmail(EmailInputDTO inputDTO);
List<EmailOutputDTO> obtenerEmails(Boolean pendiente);
void procesarPendientes();
void loguearEmailsPendientes();
}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<String> 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;
Expand Down Expand Up @@ -63,8 +65,8 @@ public Mono<Void> 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) {
Expand All @@ -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",
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<Email> obtenerEmails(Boolean pendiente) {
public List<EmailOutputDTO> 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
Expand All @@ -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<Email> pendientes = obtenerEmails(true);
List<EmailOutputDTO> pendientes = obtenerEmails(true);
logger.info("Emails pendientes de envío: {}", pendientes.size());
pendientes.forEach(email ->
logger.info("Email pendiente - ID: {}, Destinatario: {}, Asunto: {}",
Expand Down