forked from halo-dev/halo
-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'upstream/main'
- Loading branch information
Showing
24 changed files
with
783 additions
and
194 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
47 changes: 47 additions & 0 deletions
47
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,47 @@ | ||
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 sender; | ||
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); | ||
} | ||
|
||
/** | ||
* Gets email sender address. | ||
* | ||
* @return sender if not blank, otherwise username | ||
*/ | ||
public String getSender() { | ||
return StringUtils.defaultIfBlank(sender, 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.getSender(), senderConfig.getDisplayName()); | ||
|
||
helper.setSubject(subject); | ||
helper.setText(raw, html); | ||
helper.setTo(toEmail); | ||
}; | ||
} | ||
} |
116 changes: 116 additions & 0 deletions
116
...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,116 @@ | ||
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 = """ | ||
你好!<br/> | ||
这是一封测试邮件,旨在验证您的邮箱发件配置是否正确。<br/> | ||
此邮件由系统自动发送,请勿回复。<br/> | ||
祝好 | ||
"""; | ||
|
||
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/verify-connection", | ||
this::verifyEmailSenderConfig, | ||
builder -> builder.operationId("VerifyEmailSenderConfig") | ||
.description("Verify email sender config.") | ||
.tag(tag) | ||
.requestBody(requestBodyBuilder() | ||
.required(true) | ||
.implementation(ValidationRequest.class) | ||
) | ||
.response(responseBuilder().implementation(Void.class)) | ||
) | ||
.build(); | ||
} | ||
|
||
private Mono<ServerResponse> verifyEmailSenderConfig(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)) | ||
.flatMap(user -> { | ||
var email = user.getSpec().getEmail(); | ||
if (StringUtils.isBlank(email)) { | ||
return Mono.error(new ServerWebInputException( | ||
"Your email is missing, please set it in your profile.")); | ||
} | ||
return Mono.just(email); | ||
}); | ||
} | ||
|
||
@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"); | ||
} | ||
} |
Oops, something went wrong.