From 26c915eefe99bdd8985600593e11e37fbf738d7e Mon Sep 17 00:00:00 2001 From: FatttSnake Date: Tue, 5 Dec 2023 18:18:05 +0800 Subject: [PATCH] Finish mail settings management api --- .../controller/system/SettingsController.kt | 33 +++++++-- .../api/converter/system/SettingsConverter.kt | 9 ++- .../fatweb/api/param/system/MailSendParam.kt | 23 +++++++ .../api/param/system/MailSettingsParam.kt | 21 +++++- .../fatweb/api/properties/ServerProperties.kt | 8 +++ .../api/service/system/ISettingsService.kt | 22 ++++-- .../system/impl/SettingsServiceImpl.kt | 25 ++++++- .../fatweb/api/settings/MailSecurityType.kt | 25 +++++++ .../top/fatweb/api/settings/MailSettings.kt | 16 +++++ .../kotlin/top/fatweb/api/util/MailUtil.kt | 47 +++++++++++++ .../fatweb/api/vo/system/MailSettingsVo.kt | 67 +++++++++++++++++++ .../top/fatweb/api/vo/system/SettingsVo.kt | 50 +------------- src/main/resources/application.yml | 1 + .../resources/db/migration/R__Basic_data.sql | 10 ++- 14 files changed, 287 insertions(+), 70 deletions(-) create mode 100644 src/main/kotlin/top/fatweb/api/param/system/MailSendParam.kt create mode 100644 src/main/kotlin/top/fatweb/api/settings/MailSecurityType.kt create mode 100644 src/main/kotlin/top/fatweb/api/util/MailUtil.kt create mode 100644 src/main/kotlin/top/fatweb/api/vo/system/MailSettingsVo.kt diff --git a/src/main/kotlin/top/fatweb/api/controller/system/SettingsController.kt b/src/main/kotlin/top/fatweb/api/controller/system/SettingsController.kt index 7a2684d..bd3e407 100644 --- a/src/main/kotlin/top/fatweb/api/controller/system/SettingsController.kt +++ b/src/main/kotlin/top/fatweb/api/controller/system/SettingsController.kt @@ -2,11 +2,14 @@ package top.fatweb.api.controller.system import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.tags.Tag +import jakarta.validation.Valid +import org.springframework.security.access.prepost.PreAuthorize import org.springframework.web.bind.annotation.* import top.fatweb.api.entity.common.ResponseResult +import top.fatweb.api.param.system.MailSendParam import top.fatweb.api.param.system.MailSettingsParam import top.fatweb.api.service.system.ISettingsService -import top.fatweb.api.vo.system.SettingsVo +import top.fatweb.api.vo.system.MailSettingsVo /** * System settings controller @@ -22,17 +25,18 @@ class SettingsController( private val settingsService: ISettingsService ) { /** - * Get all settings + * Get mail settings * - * @return Response object includes all settings + * @return Response object includes mail settings * @author FatttSnake, fatttsnake@gmail.com * @since 1.0.0 * @see ResponseResult - * @see SettingsVo + * @see MailSettingsVo */ - @Operation(summary = "获取全部设置") - @GetMapping - fun get(): ResponseResult = ResponseResult.success(data = settingsService.get()) + @Operation(summary = "获取邮件设置") + @GetMapping("/mail") + @PreAuthorize("hasAnyAuthority('system:settings:query:mail')") + fun getMail(): ResponseResult = ResponseResult.success(data = settingsService.getMail()) /** * Update mail settings @@ -46,8 +50,23 @@ class SettingsController( */ @Operation(summary = "更新邮件设置") @PutMapping("/mail") + @PreAuthorize("hasAnyAuthority('system:settings:modify:mail')") fun updateMail(@RequestBody mailSettingsParam: MailSettingsParam): ResponseResult { settingsService.updateMail(mailSettingsParam) return ResponseResult.success() } + + /** + * Send mail test + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + @Operation(summary = "邮件发送测试") + @PostMapping("/mail") + @PreAuthorize("hasAnyAuthority('system:settings:modify:mail')") + fun sendMail(@RequestBody @Valid mailSendParam: MailSendParam): ResponseResult { + settingsService.sendMail(mailSendParam) + return ResponseResult.success() + } } \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/api/converter/system/SettingsConverter.kt b/src/main/kotlin/top/fatweb/api/converter/system/SettingsConverter.kt index 673d882..c3370ff 100644 --- a/src/main/kotlin/top/fatweb/api/converter/system/SettingsConverter.kt +++ b/src/main/kotlin/top/fatweb/api/converter/system/SettingsConverter.kt @@ -2,6 +2,7 @@ package top.fatweb.api.converter.system import top.fatweb.api.settings.MailSettings import top.fatweb.api.settings.SystemSettings +import top.fatweb.api.vo.system.MailSettingsVo import top.fatweb.api.vo.system.SettingsVo /** @@ -19,14 +20,16 @@ object SettingsConverter { * @author FatttSnake, fatttsnake@gmail.com * @since 1.0.0 * @see MailSettings - * @see SettingsVo.MailSettingsVo + * @see MailSettingsVo */ - private fun mailSettingsToMailSettingsVo(mailSettings: MailSettings) = SettingsVo.MailSettingsVo( + fun mailSettingsToMailSettingsVo(mailSettings: MailSettings) = MailSettingsVo( host = mailSettings.host, port = mailSettings.port, + securityType = mailSettings.securityType, username = mailSettings.username, password = mailSettings.password, - from = mailSettings.from + from = mailSettings.from, + fromName = mailSettings.fromName ) /** diff --git a/src/main/kotlin/top/fatweb/api/param/system/MailSendParam.kt b/src/main/kotlin/top/fatweb/api/param/system/MailSendParam.kt new file mode 100644 index 0000000..6d7641a --- /dev/null +++ b/src/main/kotlin/top/fatweb/api/param/system/MailSendParam.kt @@ -0,0 +1,23 @@ +package top.fatweb.api.param.system + +import io.swagger.v3.oas.annotations.media.Schema +import jakarta.validation.constraints.NotBlank + +/** + * Mail send parameters + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ +@Schema(description = "邮件发送请求参数") +data class MailSendParam( + /** + * Receiver + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + @Schema(description = "接收者") + @field:NotBlank + val to: String? +) diff --git a/src/main/kotlin/top/fatweb/api/param/system/MailSettingsParam.kt b/src/main/kotlin/top/fatweb/api/param/system/MailSettingsParam.kt index d4168f9..0446b78 100644 --- a/src/main/kotlin/top/fatweb/api/param/system/MailSettingsParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/system/MailSettingsParam.kt @@ -1,6 +1,7 @@ package top.fatweb.api.param.system import io.swagger.v3.oas.annotations.media.Schema +import top.fatweb.api.settings.MailSecurityType /** * Mail settings parameters @@ -28,6 +29,15 @@ data class MailSettingsParam( @Schema(description = "端口号") val port: Int?, + /** + * Security type + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + @Schema(description = "安全类型", allowableValues = ["None", "SSL/TLS", "StartTls"], defaultValue = "None") + val securityType: MailSecurityType? = MailSecurityType.NONE, + /** * Username * @@ -53,5 +63,14 @@ data class MailSettingsParam( * @since 1.0.0 */ @Schema(description = "发送者") - val from: String? + val from: String?, + + /** + * Sender name + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + @Schema(description = "发送者名称") + val fromName: String? ) \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/api/properties/ServerProperties.kt b/src/main/kotlin/top/fatweb/api/properties/ServerProperties.kt index 4be7eef..5176cfb 100644 --- a/src/main/kotlin/top/fatweb/api/properties/ServerProperties.kt +++ b/src/main/kotlin/top/fatweb/api/properties/ServerProperties.kt @@ -15,6 +15,14 @@ import java.time.ZonedDateTime @Component @ConfigurationProperties("app") object ServerProperties { + /** + * App name + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + lateinit var appName: String + /** * Version * diff --git a/src/main/kotlin/top/fatweb/api/service/system/ISettingsService.kt b/src/main/kotlin/top/fatweb/api/service/system/ISettingsService.kt index 750e1be..9327762 100644 --- a/src/main/kotlin/top/fatweb/api/service/system/ISettingsService.kt +++ b/src/main/kotlin/top/fatweb/api/service/system/ISettingsService.kt @@ -1,7 +1,8 @@ package top.fatweb.api.service.system +import top.fatweb.api.param.system.MailSendParam import top.fatweb.api.param.system.MailSettingsParam -import top.fatweb.api.vo.system.SettingsVo +import top.fatweb.api.vo.system.MailSettingsVo /** * Settings service interface @@ -11,21 +12,32 @@ import top.fatweb.api.vo.system.SettingsVo */ interface ISettingsService { /** - * Get all settings + * Get mail settings * - * @return SettingVo object + * @return MailSettingVo object * @author FatttSnake, fatttsnake@gmail.com * @since 1.0.0 - * @see SettingsVo + * @see MailSettingsVo */ - fun get(): SettingsVo + fun getMail(): MailSettingsVo? /** * Update mail settings * + * @param mailSettingsParam Mail settings parameters * @author FatttSnake, fatttsnake@gmail.com * @since 1.0.0 * @see MailSettingsParam */ fun updateMail(mailSettingsParam: MailSettingsParam) + + /** + * Send mail + * + * @param mailSendParam Send mail parameters + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + * @see MailSettingsParam + */ + fun sendMail(mailSendParam: MailSendParam) } \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/api/service/system/impl/SettingsServiceImpl.kt b/src/main/kotlin/top/fatweb/api/service/system/impl/SettingsServiceImpl.kt index 37ab1b1..18b97f4 100644 --- a/src/main/kotlin/top/fatweb/api/service/system/impl/SettingsServiceImpl.kt +++ b/src/main/kotlin/top/fatweb/api/service/system/impl/SettingsServiceImpl.kt @@ -2,11 +2,14 @@ package top.fatweb.api.service.system.impl import org.springframework.stereotype.Service import top.fatweb.api.converter.system.SettingsConverter +import top.fatweb.api.param.system.MailSendParam import top.fatweb.api.param.system.MailSettingsParam +import top.fatweb.api.properties.ServerProperties import top.fatweb.api.service.system.ISettingsService import top.fatweb.api.settings.MailSettings import top.fatweb.api.settings.SettingsOperator -import top.fatweb.api.vo.system.SettingsVo +import top.fatweb.api.util.MailUtil +import top.fatweb.api.vo.system.MailSettingsVo /** * Settings service implement @@ -17,15 +20,33 @@ import top.fatweb.api.vo.system.SettingsVo */ @Service class SettingsServiceImpl : ISettingsService { - override fun get(): SettingsVo = SettingsConverter.systemSettingsToSettingsVo(SettingsOperator.settings()) + override fun getMail(): MailSettingsVo? = SettingsOperator.settings().mail?.let { + SettingsConverter.mailSettingsToMailSettingsVo( + it + ) + } override fun updateMail(mailSettingsParam: MailSettingsParam) { mailSettingsParam.apply { SettingsOperator.setMailValue(MailSettings::host, host) SettingsOperator.setMailValue(MailSettings::port, port) + SettingsOperator.setMailValue(MailSettings::securityType, securityType) SettingsOperator.setMailValue(MailSettings::username, username) SettingsOperator.setMailValue(MailSettings::password, password) SettingsOperator.setMailValue(MailSettings::from, from) + SettingsOperator.setMailValue(MailSettings::fromName, fromName) + } + + MailUtil.init() + } + + override fun sendMail(mailSendParam: MailSendParam) { + mailSendParam.to?.let { + MailUtil.sendSimpleMail( + "${ServerProperties.appName} Test Message", + "This is a test email sent when testing the system email sending service.", + it + ) } } } \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/api/settings/MailSecurityType.kt b/src/main/kotlin/top/fatweb/api/settings/MailSecurityType.kt new file mode 100644 index 0000000..8288221 --- /dev/null +++ b/src/main/kotlin/top/fatweb/api/settings/MailSecurityType.kt @@ -0,0 +1,25 @@ +package top.fatweb.api.settings + +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonValue + +enum class MailSecurityType(val code: String) { + NONE("None"), + SSL_TLS("SSL/TLS"), + START_TLS("StartTls"); + + @JsonCreator + fun fromCode(code: String): MailSecurityType? { + values().forEach { + if (it.code == code) { + return it + } + } + return null + } + + @JsonValue + override fun toString(): String { + return code + } +} \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/api/settings/MailSettings.kt b/src/main/kotlin/top/fatweb/api/settings/MailSettings.kt index 0d50f95..4c0c0f2 100644 --- a/src/main/kotlin/top/fatweb/api/settings/MailSettings.kt +++ b/src/main/kotlin/top/fatweb/api/settings/MailSettings.kt @@ -26,6 +26,14 @@ data class MailSettings( */ var port: Int? = null, + /** + * Security type + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + var securityType: MailSecurityType? = MailSecurityType.NONE, + /** * Username * @@ -49,4 +57,12 @@ data class MailSettings( * @since 1.0.0 */ var from: String? = null, + + /** + * Sender name + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + var fromName: String? = null ) \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/api/util/MailUtil.kt b/src/main/kotlin/top/fatweb/api/util/MailUtil.kt new file mode 100644 index 0000000..9cad5e0 --- /dev/null +++ b/src/main/kotlin/top/fatweb/api/util/MailUtil.kt @@ -0,0 +1,47 @@ +package top.fatweb.api.util + +import org.springframework.mail.MailSender +import org.springframework.mail.SimpleMailMessage +import org.springframework.mail.javamail.JavaMailSenderImpl +import top.fatweb.api.settings.MailSecurityType +import top.fatweb.api.settings.MailSettings +import top.fatweb.api.settings.SettingsOperator +import java.util.* + +object MailUtil { + private val mailSender: JavaMailSenderImpl = JavaMailSenderImpl() + + init { + init() + } + + fun init() { + mailSender.defaultEncoding = Charsets.UTF_8.name() + mailSender.protocol = "smtp" + mailSender.host = SettingsOperator.getMailValue(MailSettings::host) + SettingsOperator.getMailValue(MailSettings::port)?.let { mailSender.port = it } + mailSender.username = SettingsOperator.getMailValue(MailSettings::username) + mailSender.password = SettingsOperator.getMailValue(MailSettings::password) + + val properties = Properties() + when (SettingsOperator.getMailValue(MailSettings::securityType)) { + MailSecurityType.SSL_TLS -> properties.setProperty("mail.smtp.ssl.enable", "true") + MailSecurityType.START_TLS -> properties.setProperty("mail.smtp.starttls.enable", "true") + else -> {} + } + properties["mail.smtp.timeout"] = "10000" + mailSender.javaMailProperties = properties + } + + fun getSender(): MailSender = mailSender + + fun sendSimpleMail(subject: String, text: String, vararg to: String) { + mailSender.send(SimpleMailMessage().apply { + setSubject(subject) + from = "${SettingsOperator.getMailValue(MailSettings::fromName)}<${SettingsOperator.getMailValue(MailSettings::from)}>" + sentDate = Date() + setTo(*to) + setText(text) + }) + } +} \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/api/vo/system/MailSettingsVo.kt b/src/main/kotlin/top/fatweb/api/vo/system/MailSettingsVo.kt new file mode 100644 index 0000000..b909211 --- /dev/null +++ b/src/main/kotlin/top/fatweb/api/vo/system/MailSettingsVo.kt @@ -0,0 +1,67 @@ +package top.fatweb.api.vo.system + +import top.fatweb.api.settings.MailSecurityType + +/** + * Mail settings value object + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ +data class MailSettingsVo( + /** + * Host + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + val host: String?, + + /** + * Port + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + val port: Int?, + + /** + * Security type + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + val securityType: MailSecurityType?, + + /** + * Username + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + val username: String?, + + /** + * Password + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + val password: String?, + + /** + * Sender + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + val from: String?, + + /** + * Sender name + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + val fromName: String? +) \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/api/vo/system/SettingsVo.kt b/src/main/kotlin/top/fatweb/api/vo/system/SettingsVo.kt index b88a84c..4557402 100644 --- a/src/main/kotlin/top/fatweb/api/vo/system/SettingsVo.kt +++ b/src/main/kotlin/top/fatweb/api/vo/system/SettingsVo.kt @@ -15,52 +15,4 @@ data class SettingsVo( * @see MailSettingsVo */ val mail: MailSettingsVo? -) { - /** - * Mail settings value object - * - * @author FatttSnake, fatttsnake@gmail.com - * @since 1.0.0 - */ - data class MailSettingsVo( - /** - * Host - * - * @author FatttSnake, fatttsnake@gmail.com - * @since 1.0.0 - */ - val host: String?, - - /** - * Port - * - * @author FatttSnake, fatttsnake@gmail.com - * @since 1.0.0 - */ - val port: Int?, - - /** - * Username - * - * @author FatttSnake, fatttsnake@gmail.com - * @since 1.0.0 - */ - val username: String?, - - /** - * Password - * - * @author FatttSnake, fatttsnake@gmail.com - * @since 1.0.0 - */ - val password: String?, - - /** - * Sender - * - * @author FatttSnake, fatttsnake@gmail.com - * @since 1.0.0 - */ - val from: String? - ) -} \ No newline at end of file +) \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 10f5d01..dbf4f94 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,4 +1,5 @@ app: + app-name: FatWeb version: @project.version@ build-time: @build.timestamp@ diff --git a/src/main/resources/db/migration/R__Basic_data.sql b/src/main/resources/db/migration/R__Basic_data.sql index dd102e3..8f36440 100644 --- a/src/main/resources/db/migration/R__Basic_data.sql +++ b/src/main/resources/db/migration/R__Basic_data.sql @@ -54,7 +54,9 @@ insert into t_power (id, type_id) (1030402, 4), (1040103, 4), (1050101, 4), - (1050301, 4) + (1050102, 4), + (1050301, 4), + (1050302, 4) as new_value on duplicate key update type_id = new_value.type_id; @@ -122,8 +124,10 @@ insert into t_operation(id, name, code, func_id) (1030402, '多个', 'system:group:delete:multiple', 1030400), (1040103, '列表', 'system:power:query:list', 1040100), (1510101, '列表', 'system:log:query:all', 1510100), - (1520101, '全部', 'system:settings:query:all', 1520100), - (1520301, '全部', 'system:settings:modify:all', 1520300) as new_value + (1520101, '基础', 'system:settings:query:base', 1520100), + (1520102, '邮件', 'system:settings:query:mail', 1520100), + (1520301, '基础', 'system:settings:modify:base', 1520300), + (1520302, '邮件', 'system:settings:modify:mail', 1520300) as new_value on duplicate key update name=new_value.name, code=new_value.code, func_id=new_value.func_id; \ No newline at end of file