-
-
Notifications
You must be signed in to change notification settings - Fork 9.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add an API for validate email config
- Loading branch information
Showing
6 changed files
with
236 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
37 changes: 37 additions & 0 deletions
37
application/src/main/java/run/halo/app/notification/EmailSenderHelper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package run.halo.app.notification; | ||
|
||
import lombok.Data; | ||
import lombok.NonNull; | ||
import org.apache.commons.lang3.StringUtils; | ||
import org.springframework.mail.javamail.JavaMailSender; | ||
import org.springframework.mail.javamail.MimeMessagePreparator; | ||
|
||
public interface EmailSenderHelper { | ||
|
||
@NonNull | ||
JavaMailSender createJavaMailSender(EmailSenderConfig senderConfig); | ||
|
||
@NonNull | ||
MimeMessagePreparator createMimeMessagePreparator(EmailSenderConfig senderConfig, | ||
String toEmail, String subject, String raw, String html); | ||
|
||
@Data | ||
class EmailSenderConfig { | ||
private boolean enable; | ||
private String displayName; | ||
private String username; | ||
private String password; | ||
private String host; | ||
private Integer port; | ||
private String encryption; | ||
|
||
/** | ||
* Gets email display name. | ||
* | ||
* @return display name if not blank, otherwise username. | ||
*/ | ||
public String getDisplayName() { | ||
return StringUtils.defaultIfBlank(displayName, username); | ||
} | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
application/src/main/java/run/halo/app/notification/EmailSenderHelperImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package run.halo.app.notification; | ||
|
||
import java.nio.charset.StandardCharsets; | ||
import java.util.Properties; | ||
import lombok.NonNull; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.mail.javamail.JavaMailSender; | ||
import org.springframework.mail.javamail.JavaMailSenderImpl; | ||
import org.springframework.mail.javamail.MimeMessageHelper; | ||
import org.springframework.mail.javamail.MimeMessagePreparator; | ||
import org.springframework.stereotype.Component; | ||
|
||
/** | ||
* <p>A default implementation of {@link EmailSenderHelper}.</p> | ||
* | ||
* @author guqing | ||
* @since 2.14.0 | ||
*/ | ||
@Slf4j | ||
@Component | ||
public class EmailSenderHelperImpl implements EmailSenderHelper { | ||
|
||
@Override | ||
@NonNull | ||
public JavaMailSender createJavaMailSender(EmailSenderConfig senderConfig) { | ||
JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl(); | ||
javaMailSender.setHost(senderConfig.getHost()); | ||
javaMailSender.setPort(senderConfig.getPort()); | ||
javaMailSender.setUsername(senderConfig.getUsername()); | ||
javaMailSender.setPassword(senderConfig.getPassword()); | ||
|
||
Properties props = javaMailSender.getJavaMailProperties(); | ||
props.put("mail.transport.protocol", "smtp"); | ||
props.put("mail.smtp.auth", "true"); | ||
if ("SSL".equals(senderConfig.getEncryption())) { | ||
props.put("mail.smtp.ssl.enable", "true"); | ||
} | ||
|
||
if ("TLS".equals(senderConfig.getEncryption())) { | ||
props.put("mail.smtp.starttls.enable", "true"); | ||
} | ||
|
||
if ("NONE".equals(senderConfig.getEncryption())) { | ||
props.put("mail.smtp.ssl.enable", "false"); | ||
props.put("mail.smtp.starttls.enable", "false"); | ||
} | ||
|
||
if (log.isDebugEnabled()) { | ||
props.put("mail.debug", "true"); | ||
} | ||
return javaMailSender; | ||
} | ||
|
||
@Override | ||
@NonNull | ||
public MimeMessagePreparator createMimeMessagePreparator(EmailSenderConfig senderConfig, | ||
String toEmail, String subject, String raw, String html) { | ||
return mimeMessage -> { | ||
MimeMessageHelper helper = | ||
new MimeMessageHelper(mimeMessage, true, StandardCharsets.UTF_8.name()); | ||
helper.setFrom(senderConfig.getUsername(), senderConfig.getDisplayName()); | ||
|
||
helper.setSubject(subject); | ||
helper.setText(raw, html); | ||
helper.setTo(toEmail); | ||
}; | ||
} | ||
} |
115 changes: 115 additions & 0 deletions
115
...ation/src/main/java/run/halo/app/notification/endpoint/EmailConfigValidationEndpoint.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package run.halo.app.notification.endpoint; | ||
|
||
import static org.springdoc.core.fn.builders.apiresponse.Builder.responseBuilder; | ||
import static org.springdoc.core.fn.builders.requestbody.Builder.requestBodyBuilder; | ||
|
||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import java.security.Principal; | ||
import lombok.Data; | ||
import lombok.EqualsAndHashCode; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.apache.commons.lang3.StringUtils; | ||
import org.springdoc.webflux.core.fn.SpringdocRouteBuilder; | ||
import org.springframework.mail.MailException; | ||
import org.springframework.security.core.context.ReactiveSecurityContextHolder; | ||
import org.springframework.security.core.context.SecurityContext; | ||
import org.springframework.stereotype.Component; | ||
import org.springframework.web.reactive.function.server.RouterFunction; | ||
import org.springframework.web.reactive.function.server.ServerRequest; | ||
import org.springframework.web.reactive.function.server.ServerResponse; | ||
import org.springframework.web.server.ServerWebInputException; | ||
import reactor.core.publisher.Mono; | ||
import run.halo.app.core.extension.User; | ||
import run.halo.app.core.extension.endpoint.CustomEndpoint; | ||
import run.halo.app.extension.GroupVersion; | ||
import run.halo.app.extension.ReactiveExtensionClient; | ||
import run.halo.app.notification.EmailSenderHelper; | ||
|
||
/** | ||
* Validation endpoint for email config. | ||
* | ||
* @author guqing | ||
* @since 2.14.0 | ||
*/ | ||
@Slf4j | ||
@Component | ||
@RequiredArgsConstructor | ||
public class EmailConfigValidationEndpoint implements CustomEndpoint { | ||
private static final String EMAIL_SUBJECT = "测试邮件 - 验证邮箱连通性"; | ||
private static final String EMAIL_BODY = """ | ||
你好! | ||
这是一封测试邮件,旨在验证您的邮箱发件配置是否正确。 | ||
此邮件由系统自动发送,请勿回复。 | ||
祝好 | ||
"""; | ||
|
||
private final EmailSenderHelper emailSenderHelper; | ||
private final ReactiveExtensionClient client; | ||
|
||
@Override | ||
public RouterFunction<ServerResponse> endpoint() { | ||
var tag = "console.api.notification.halo.run/v1alpha1/Notifier"; | ||
return SpringdocRouteBuilder.route() | ||
.POST("/notifiers/default-email-notifier/validation", this::validateEmailConfig, | ||
builder -> builder.operationId("ValidateEmailConfig") | ||
.description("Validate email config") | ||
.tag(tag) | ||
.requestBody(requestBodyBuilder() | ||
.required(true) | ||
.implementation(ValidationRequest.class) | ||
) | ||
.response(responseBuilder().implementation(Void.class)) | ||
) | ||
.build(); | ||
} | ||
|
||
private Mono<ServerResponse> validateEmailConfig(ServerRequest request) { | ||
return request.bodyToMono(ValidationRequest.class) | ||
.switchIfEmpty( | ||
Mono.error(new ServerWebInputException("Required request body is missing.")) | ||
) | ||
.flatMap(validationRequest -> getCurrentUserEmail() | ||
.flatMap(recipient -> { | ||
var mailSender = emailSenderHelper.createJavaMailSender(validationRequest); | ||
var message = emailSenderHelper.createMimeMessagePreparator(validationRequest, | ||
recipient, EMAIL_SUBJECT, EMAIL_BODY, EMAIL_BODY); | ||
try { | ||
mailSender.send(message); | ||
} catch (MailException e) { | ||
String errorMsg = | ||
"Failed to send email, please check your email configuration."; | ||
log.error(errorMsg, e); | ||
throw new ServerWebInputException(errorMsg, null, e); | ||
} | ||
return ServerResponse.ok().build(); | ||
}) | ||
); | ||
} | ||
|
||
Mono<String> getCurrentUserEmail() { | ||
return ReactiveSecurityContextHolder.getContext() | ||
.map(SecurityContext::getAuthentication) | ||
.map(Principal::getName) | ||
.flatMap(username -> client.fetch(User.class, username)) | ||
.map(user -> user.getSpec().getEmail()) | ||
.defaultIfEmpty(StringUtils.EMPTY) | ||
.doOnNext(email -> { | ||
if (StringUtils.isBlank(email)) { | ||
throw new ServerWebInputException( | ||
"Your email is missing, please set it in your profile."); | ||
} | ||
}); | ||
} | ||
|
||
@Data | ||
@EqualsAndHashCode(callSuper = true) | ||
@Schema(name = "EmailConfigValidationRequest") | ||
static class ValidationRequest extends EmailSenderHelper.EmailSenderConfig { | ||
} | ||
|
||
@Override | ||
public GroupVersion groupVersion() { | ||
return GroupVersion.parseAPIVersion("console.api.notification.halo.run/v1alpha1"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters