commit 0d5bdffea2f0de3fadec03ccff211e45d6acecca Author: Florian THIERRY Date: Mon May 17 22:22:54 2021 +0200 Initial commit. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..549e00a --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..120731a --- /dev/null +++ b/pom.xml @@ -0,0 +1,69 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.4.5 + + + fr.ippon.example + intellij-features + 0.0.1-SNAPSHOT + intellij-features + Demo project for Spring Boot + + 11 + + + + org.springframework.boot + spring-boot-starter-mail + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + io.pebbletemplates + pebble + 3.1.2 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + diff --git a/src/main/docker/docker-compose.yml b/src/main/docker/docker-compose.yml new file mode 100644 index 0000000..0013797 --- /dev/null +++ b/src/main/docker/docker-compose.yml @@ -0,0 +1,7 @@ +version: '3.6' +services: + mailer: + image: "mailhog/mailhog" + ports: + - "1025:1025" + - "8025:8025" \ No newline at end of file diff --git a/src/main/java/fr/ippon/example/intellijfeatures/IntellijFeaturesApplication.java b/src/main/java/fr/ippon/example/intellijfeatures/IntellijFeaturesApplication.java new file mode 100644 index 0000000..970ef86 --- /dev/null +++ b/src/main/java/fr/ippon/example/intellijfeatures/IntellijFeaturesApplication.java @@ -0,0 +1,13 @@ +package fr.ippon.example.intellijfeatures; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class IntellijFeaturesApplication { + + public static void main(String[] args) { + SpringApplication.run(IntellijFeaturesApplication.class, args); + } + +} diff --git a/src/main/java/fr/ippon/example/intellijfeatures/config/ServiceConfiguration.java b/src/main/java/fr/ippon/example/intellijfeatures/config/ServiceConfiguration.java new file mode 100644 index 0000000..8feb66b --- /dev/null +++ b/src/main/java/fr/ippon/example/intellijfeatures/config/ServiceConfiguration.java @@ -0,0 +1,16 @@ +package fr.ippon.example.intellijfeatures.config; + +import com.mitchellbosecke.pebble.PebbleEngine; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ServiceConfiguration { + /** + * Basic pebble engine. + */ + @Bean + public PebbleEngine pebbleEngine() { + return new PebbleEngine.Builder().build(); + } +} diff --git a/src/main/java/fr/ippon/example/intellijfeatures/controller/MailController.java b/src/main/java/fr/ippon/example/intellijfeatures/controller/MailController.java new file mode 100644 index 0000000..00300d9 --- /dev/null +++ b/src/main/java/fr/ippon/example/intellijfeatures/controller/MailController.java @@ -0,0 +1,23 @@ +package fr.ippon.example.intellijfeatures.controller; + +import fr.ippon.example.intellijfeatures.model.User; +import fr.ippon.example.intellijfeatures.services.mail.EmailService; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/mails") +public class MailController { + private final EmailService emailService; + + public MailController(EmailService emailService) { + this.emailService = emailService; + } + + @PostMapping("/send") + public void sendMail(@RequestBody User user) { + emailService.sendMail(user); + } +} diff --git a/src/main/java/fr/ippon/example/intellijfeatures/exception/InternalServerErrorException.java b/src/main/java/fr/ippon/example/intellijfeatures/exception/InternalServerErrorException.java new file mode 100644 index 0000000..86392b2 --- /dev/null +++ b/src/main/java/fr/ippon/example/intellijfeatures/exception/InternalServerErrorException.java @@ -0,0 +1,15 @@ +package fr.ippon.example.intellijfeatures.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR) +public class InternalServerErrorException extends TechnicalException { + public InternalServerErrorException(String message) { + super(message); + } + + public InternalServerErrorException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/fr/ippon/example/intellijfeatures/exception/TechnicalException.java b/src/main/java/fr/ippon/example/intellijfeatures/exception/TechnicalException.java new file mode 100644 index 0000000..1033d4d --- /dev/null +++ b/src/main/java/fr/ippon/example/intellijfeatures/exception/TechnicalException.java @@ -0,0 +1,23 @@ +package fr.ippon.example.intellijfeatures.exception; + +/** + * Technical exception. + */ +public class TechnicalException extends RuntimeException { + /** + * Constructs an exception with a message. + * @param message The description of the error met. + */ + public TechnicalException(final String message) { + super(message); + } + + /** + * Constructs an exception with a message and a code. + * @param message The description of the error met. + * @param cause The cause of the exception. + */ + public TechnicalException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/fr/ippon/example/intellijfeatures/model/User.java b/src/main/java/fr/ippon/example/intellijfeatures/model/User.java new file mode 100644 index 0000000..8812c89 --- /dev/null +++ b/src/main/java/fr/ippon/example/intellijfeatures/model/User.java @@ -0,0 +1,13 @@ +package fr.ippon.example.intellijfeatures.model; + +import lombok.*; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class User { + private String name; + private String email; +} diff --git a/src/main/java/fr/ippon/example/intellijfeatures/services/PebbleService.java b/src/main/java/fr/ippon/example/intellijfeatures/services/PebbleService.java new file mode 100644 index 0000000..c3fbfd2 --- /dev/null +++ b/src/main/java/fr/ippon/example/intellijfeatures/services/PebbleService.java @@ -0,0 +1,25 @@ +package fr.ippon.example.intellijfeatures.services; + +import com.mitchellbosecke.pebble.PebbleEngine; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.util.Map; + +@Service +public class PebbleService { + private final PebbleEngine engine; + + public PebbleService(PebbleEngine engine) { + this.engine = engine; + } + + public String loadTemplate(String templatePath, Map templateVars) throws IOException { + Writer writer = new StringWriter(); + engine.getTemplate(templatePath) + .evaluate(writer, templateVars); + return writer.toString(); + } +} diff --git a/src/main/java/fr/ippon/example/intellijfeatures/services/mail/EmailSender.java b/src/main/java/fr/ippon/example/intellijfeatures/services/mail/EmailSender.java new file mode 100644 index 0000000..dea7b5e --- /dev/null +++ b/src/main/java/fr/ippon/example/intellijfeatures/services/mail/EmailSender.java @@ -0,0 +1,27 @@ +package fr.ippon.example.intellijfeatures.services.mail; + +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.stereotype.Service; + +import javax.mail.MessagingException; +import javax.mail.internet.MimeMessage; + +@Service +public class EmailSender { + private final JavaMailSender javaMailSender; + + public EmailSender(JavaMailSender javaMailSender) { + this.javaMailSender = javaMailSender; + } + + public void sendEmail(String recipient, String subject, String htmlContent, String textContent) throws MessagingException { + MimeMessage mimeMessage = javaMailSender.createMimeMessage(); + + MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true); + helper.setTo(recipient); + helper.setSubject(subject); + helper.setText(textContent, htmlContent); + javaMailSender.send(mimeMessage); + } +} diff --git a/src/main/java/fr/ippon/example/intellijfeatures/services/mail/EmailService.java b/src/main/java/fr/ippon/example/intellijfeatures/services/mail/EmailService.java new file mode 100644 index 0000000..6871ca8 --- /dev/null +++ b/src/main/java/fr/ippon/example/intellijfeatures/services/mail/EmailService.java @@ -0,0 +1,45 @@ +package fr.ippon.example.intellijfeatures.services.mail; + +import fr.ippon.example.intellijfeatures.exception.InternalServerErrorException; +import fr.ippon.example.intellijfeatures.model.User; +import fr.ippon.example.intellijfeatures.services.PebbleService; +import org.springframework.stereotype.Service; + +import javax.mail.MessagingException; +import java.io.IOException; +import java.util.Map; + +@Service +public class EmailService { + private final EmailSender emailSender; + private final PebbleService pebbleService; + + public EmailService(EmailSender emailSender, PebbleService pebbleService) { + this.emailSender = emailSender; + this.pebbleService = pebbleService; + } + + public void sendMail(User user) { + String htmlContent; + String textContent; + try { + htmlContent = pebbleService.loadTemplate( + "templates/mail/user-mail.html", + Map.of("user", user) + ); + + textContent = pebbleService.loadTemplate( + "templates/mail/user-mail.txt", + Map.of("user", user) + ); + } catch (IOException exception) { + throw new InternalServerErrorException("Unable to send mail, cause to a template loading error.", exception); + } + + try { + emailSender.sendEmail(user.getEmail(), "Hello", htmlContent, textContent); + } catch (MessagingException exception) { + throw new InternalServerErrorException("Unable to send mail, cause to a technical sending error.", exception); + } + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..c496fff --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,4 @@ +spring: + mail: + host: localhost + port: 1025 \ No newline at end of file diff --git a/src/main/resources/templates/mail/user-mail.html b/src/main/resources/templates/mail/user-mail.html new file mode 100644 index 0000000..4122fb3 --- /dev/null +++ b/src/main/resources/templates/mail/user-mail.html @@ -0,0 +1,20 @@ + + + Hello world! + + + +
+ Hello {{ user.name }}! +
+ + diff --git a/src/main/resources/templates/mail/user-mail.txt b/src/main/resources/templates/mail/user-mail.txt new file mode 100644 index 0000000..b949528 --- /dev/null +++ b/src/main/resources/templates/mail/user-mail.txt @@ -0,0 +1 @@ +Hello {{ user.name }}! \ No newline at end of file diff --git a/src/test/java/fr/ippon/example/intellijfeatures/IntellijFeaturesApplicationTests.java b/src/test/java/fr/ippon/example/intellijfeatures/IntellijFeaturesApplicationTests.java new file mode 100644 index 0000000..0e8da22 --- /dev/null +++ b/src/test/java/fr/ippon/example/intellijfeatures/IntellijFeaturesApplicationTests.java @@ -0,0 +1,13 @@ +package fr.ippon.example.intellijfeatures; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class IntellijFeaturesApplicationTests { + + @Test + void contextLoads() { + } + +}