| @@ -0,0 +1,42 @@ | |||
| package com.ffii.core.utils; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| import org.springframework.context.i18n.LocaleContextHolder; | |||
| import java.util.Locale; | |||
| /** this utils follow "-" standard ("zh-TW", no "zh_TW") */ | |||
| public abstract class LocaleUtils { | |||
| public static Locale getLocale() { | |||
| return LocaleContextHolder.getLocale(); | |||
| } | |||
| public static String getLocaleStr() { | |||
| return toLocaleStr(LocaleContextHolder.getLocale()); | |||
| } | |||
| public static String toLocaleStr(Locale locale) { | |||
| String language = locale.getLanguage(); | |||
| String country = locale.getCountry(); | |||
| if (StringUtils.isNotBlank(country)) { | |||
| return language + "-" + country; | |||
| } else { | |||
| return language; | |||
| } | |||
| } | |||
| /** | |||
| * @param localeStr | |||
| * e.g. zh-TW | |||
| */ | |||
| public static Locale from(String localeStr) { | |||
| String[] localeArr = localeStr.split("-"); | |||
| if (localeArr.length == 1) { | |||
| return new Locale(localeArr[0]); | |||
| } else { | |||
| return new Locale(localeArr[0], localeArr[1]); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,38 @@ | |||
| package com.ffii.fpsms.modules.common | |||
| import com.ffii.fpsms.modules.settings.service.SettingsService | |||
| import org.apache.commons.lang3.StringUtils | |||
| open class MailSMTP(settingsService: SettingsService) { | |||
| open var host: String? = null | |||
| open var port: Int? = null | |||
| open var username: String? = null | |||
| open var password: String? = null | |||
| open var auth: Boolean? = null | |||
| init { | |||
| this.host = settingsService.getString(SettingNames.MAIL_SMTP_HOST) | |||
| this.port = settingsService.getInt(SettingNames.MAIL_SMTP_PORT) | |||
| this.username = settingsService.getString(SettingNames.MAIL_SMTP_USERNAME) | |||
| this.password = settingsService.getString(SettingNames.MAIL_SMTP_PASSWORD) | |||
| this.auth = settingsService.getBoolean(SettingNames.MAIL_SMTP_AUTH) | |||
| } | |||
| final override fun equals(other: Any?): Boolean { | |||
| if (other == null || other !is MailSMTP) return false | |||
| val o = other as MailSMTP | |||
| if (StringUtils.equals( | |||
| this.host, | |||
| o.host | |||
| ) && this.port == o.port && | |||
| StringUtils.equals(this.username, o.username) && | |||
| StringUtils.equals(this.password, o.password) | |||
| ) { | |||
| return true | |||
| } | |||
| return false | |||
| } | |||
| } | |||
| @@ -38,6 +38,8 @@ public abstract class SettingNames { | |||
| public static final String MAIL_SMTP_RECIPIENTS = "MAIL.smtp.recipients"; | |||
| public static final String MAIL_SMTP_AUTH = "MAIL.smtp.auth"; | |||
| public static final String JS_VERSION = "JS.version"; | |||
| public static final String REPORT_DAILYMAINT_RECIPIENTS_MECH = "REPORT.dailyMaint.recipients.mech"; | |||
| @@ -0,0 +1,246 @@ | |||
| package com.ffii.fpsms.modules.common.mail.pojo | |||
| import jakarta.mail.internet.InternetAddress | |||
| open class MailRequest() { | |||
| val PRIORITY_HIGHEST: Int = 1 | |||
| val PRIORITY_HIGH: Int = 2 | |||
| val PRIORITY_NORMAL: Int = 3 | |||
| val PRIORITY_LOW: Int = 4 | |||
| val PRIORITY_LOWEST: Int = 5 | |||
| open var from: InternetAddress? = null | |||
| open var to: List<InternetAddress> = mutableListOf() | |||
| open var subject: String? = null | |||
| open var template: String? = null | |||
| open var templateContent: String? = null | |||
| open var args: Map<String, Any?> = mapOf() | |||
| open var priority: Int? = null | |||
| open var replyTo: InternetAddress? = null | |||
| open var cc: List<InternetAddress> = mutableListOf() | |||
| open var bcc: List<InternetAddress> = mutableListOf() | |||
| open var attachments: Map<String, ByteArray> = mapOf() | |||
| open fun builder(): Builder { | |||
| return Builder() | |||
| } | |||
| open fun addAttachment(attachmentFilename: String, byteArray: ByteArray) { | |||
| this.attachments += Pair(attachmentFilename, byteArray) | |||
| } | |||
| open fun addTo(to: InternetAddress) { | |||
| this.to += to | |||
| } | |||
| open fun addCc(cc: InternetAddress) { | |||
| this.cc += cc | |||
| } | |||
| open fun addBcc(bcc: InternetAddress) { | |||
| this.bcc += bcc | |||
| } | |||
| open class Builder() { | |||
| open var mailRequest:MailRequest = MailRequest() | |||
| init { | |||
| this.mailRequest = MailRequest() | |||
| } | |||
| open fun build(): MailRequest { | |||
| return this.mailRequest | |||
| } | |||
| open fun addAttachment(attachmentFilename: String, byteArray: ByteArray): Builder { | |||
| mailRequest.addAttachment(attachmentFilename, byteArray) | |||
| return this | |||
| } | |||
| @Suppress("INAPPLICABLE_JVM_NAME") | |||
| @JvmName("addToInternetAddress") | |||
| open fun addTo(to: InternetAddress): Builder { | |||
| mailRequest.addTo(to) | |||
| return this | |||
| } | |||
| @Suppress("INAPPLICABLE_JVM_NAME") | |||
| @JvmName("addToString") | |||
| open fun addTo(to: String): Builder { | |||
| mailRequest.addTo(InternetAddress(to)) | |||
| return this | |||
| } | |||
| @Suppress("INAPPLICABLE_JVM_NAME") | |||
| @JvmName("addToList") | |||
| open fun addTo(to: List<String>): Builder { | |||
| to.forEach { | |||
| if (it.isNotEmpty()) { | |||
| mailRequest.addTo(InternetAddress(it)) | |||
| } | |||
| } | |||
| return this | |||
| } | |||
| @Suppress("INAPPLICABLE_JVM_NAME") | |||
| @JvmName("addCcInternetAddress") | |||
| open fun addCc(cc: InternetAddress): Builder { | |||
| mailRequest.addCc(cc) | |||
| return this | |||
| } | |||
| @Suppress("INAPPLICABLE_JVM_NAME") | |||
| @JvmName("addCcString") | |||
| open fun addCc(cc: String): Builder { | |||
| mailRequest.addCc(InternetAddress(cc)) | |||
| return this | |||
| } | |||
| @Suppress("INAPPLICABLE_JVM_NAME") | |||
| @JvmName("addCcStringList") | |||
| open fun addCc(cc: List<String>): Builder { | |||
| cc.forEach { | |||
| if (it.isNotEmpty()) { | |||
| mailRequest.addCc(InternetAddress(it)) | |||
| } | |||
| } | |||
| return this | |||
| } | |||
| @Suppress("INAPPLICABLE_JVM_NAME") | |||
| @JvmName("addBccInternetAddress") | |||
| open fun addBcc(bcc: InternetAddress): Builder { | |||
| mailRequest.addBcc(bcc) | |||
| return this | |||
| } | |||
| @Suppress("INAPPLICABLE_JVM_NAME") | |||
| @JvmName("addBccString") | |||
| open fun addBcc(bcc: String): Builder { | |||
| mailRequest.addBcc(InternetAddress(bcc)) | |||
| return this | |||
| } | |||
| @Suppress("INAPPLICABLE_JVM_NAME") | |||
| @JvmName("addBccStringList") | |||
| open fun addBcc(bcc: List<String>): Builder { | |||
| bcc.forEach { | |||
| if (it.isNotEmpty()) { | |||
| mailRequest.addBcc(InternetAddress(it)) | |||
| } | |||
| } | |||
| return this | |||
| } | |||
| @Suppress("INAPPLICABLE_JVM_NAME") | |||
| @JvmName("fromInternetAddress") | |||
| open fun from(from: InternetAddress): Builder { | |||
| mailRequest.from = from | |||
| return this | |||
| } | |||
| @Suppress("INAPPLICABLE_JVM_NAME") | |||
| @JvmName("fromString") | |||
| open fun from(from: String): Builder { | |||
| mailRequest.from = InternetAddress(from) | |||
| return this | |||
| } | |||
| @Suppress("INAPPLICABLE_JVM_NAME") | |||
| @JvmName("toListInternetAddress") | |||
| open fun to(to: List<InternetAddress>): Builder { | |||
| mailRequest.to = to | |||
| return this | |||
| } | |||
| @Suppress("INAPPLICABLE_JVM_NAME") | |||
| @JvmName("toListString") | |||
| open fun to(to: List<String>): Builder { | |||
| mailRequest.to = to.map { InternetAddress(it) } | |||
| return this | |||
| } | |||
| open fun subject(subject: String?): Builder { | |||
| mailRequest.subject = subject | |||
| return this | |||
| } | |||
| open fun template(template: String?): Builder { | |||
| mailRequest.template = template | |||
| return this | |||
| } | |||
| open fun templateContent(templateContent: String?): Builder { | |||
| mailRequest.templateContent = templateContent | |||
| return this | |||
| } | |||
| open fun args(args: Map<String, Any?>): Builder { | |||
| mailRequest.args = args | |||
| return this | |||
| } | |||
| @Suppress("INAPPLICABLE_JVM_NAME") | |||
| @JvmName("replyToInternetAddress") | |||
| open fun replyTo(replyTo: InternetAddress?): Builder { | |||
| mailRequest.replyTo = replyTo | |||
| return this | |||
| } | |||
| @Suppress("INAPPLICABLE_JVM_NAME") | |||
| @JvmName("replyToString") | |||
| open fun replyTo(replyTo: String?): Builder { | |||
| mailRequest.replyTo = InternetAddress(replyTo) | |||
| return this | |||
| } | |||
| @Suppress("INAPPLICABLE_JVM_NAME") | |||
| @JvmName("ccListInternetAddress") | |||
| open fun cc(cc: List<InternetAddress>): Builder { | |||
| mailRequest.cc = cc | |||
| return this | |||
| } | |||
| @Suppress("INAPPLICABLE_JVM_NAME") | |||
| @JvmName("ccListString") | |||
| open fun cc(cc: List<String>): Builder { | |||
| mailRequest.cc = cc.map { InternetAddress(it) } | |||
| return this | |||
| } | |||
| @Suppress("INAPPLICABLE_JVM_NAME") | |||
| @JvmName("bccListInternetAddress") | |||
| open fun bcc(bcc: List<InternetAddress>): Builder { | |||
| mailRequest.bcc = bcc | |||
| return this | |||
| } | |||
| @Suppress("INAPPLICABLE_JVM_NAME") | |||
| @JvmName("bccListString") | |||
| open fun bcc(bcc: List<String>): Builder { | |||
| mailRequest.bcc = bcc.map { InternetAddress(it) } | |||
| return this | |||
| } | |||
| open fun attachments(attachments: Map<String, ByteArray>): Builder { | |||
| mailRequest.attachments = attachments | |||
| return this | |||
| } | |||
| open fun priority(priority: Int?): Builder { | |||
| mailRequest.priority = priority | |||
| return this | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,88 @@ | |||
| package com.ffii.fpsms.modules.common.mail.service | |||
| import com.ffii.fpsms.modules.common.SettingNames | |||
| import com.ffii.fpsms.modules.common.mail.pojo.MailRequest | |||
| import com.ffii.fpsms.modules.common.mail.web.models.WorkHourRecords | |||
| import com.ffii.fpsms.modules.settings.service.SettingsService | |||
| import com.ffii.fpsms.modules.user.service.UserService | |||
| import jakarta.mail.internet.InternetAddress | |||
| import org.apache.commons.logging.Log | |||
| import org.apache.commons.logging.LogFactory | |||
| import org.springframework.scheduling.annotation.Scheduled | |||
| import org.springframework.stereotype.Service | |||
| import java.time.DayOfWeek | |||
| import java.time.LocalDate | |||
| import java.time.YearMonth | |||
| import java.time.format.DateTimeFormatter | |||
| data class TableRow( | |||
| val staffId: String, | |||
| val name: String, | |||
| val missingDates: MutableList<LocalDate>, | |||
| ) | |||
| @Service | |||
| open class MailReminderService( | |||
| val mailService: MailService, | |||
| val userService: UserService, | |||
| val settingsService: SettingsService, | |||
| ) { | |||
| protected val logger: Log = LogFactory.getLog(javaClass) | |||
| private val FULLTIME = "FT" | |||
| private val PARTTIME = "PT" | |||
| private val dateFormat: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") | |||
| private fun isSettingsConfigValid(): Boolean { | |||
| try { | |||
| val username = settingsService.findByName(SettingNames.MAIL_SMTP_USERNAME).orElseThrow().value | |||
| val pw = settingsService.findByName(SettingNames.MAIL_SMTP_USERNAME).orElseThrow().value | |||
| return !username.isNullOrEmpty() && !pw.isNullOrEmpty() | |||
| } catch (e: Error) { | |||
| return false | |||
| } | |||
| } | |||
| private fun createHTMLTable(naughtyList: MutableList<TableRow>): String { | |||
| val tableStarter = StringBuilder(" <table width='100%' border='1' align='center'> ") | |||
| val header = StringBuilder( | |||
| " <tr> " | |||
| + " <th>StaffId</th> " | |||
| + " <th>Name</th> " | |||
| + " <th>Missing Dates</th> " | |||
| + " </tr> " | |||
| ) | |||
| tableStarter.append(header) | |||
| for (per in naughtyList) { | |||
| tableStarter.append( | |||
| " <tr> " | |||
| + " <td>${per.staffId}</td>" | |||
| + " <td>${per.name}</td>" | |||
| + " <td>${per.missingDates.joinToString(", ")}</td>" | |||
| + " </tr> " | |||
| ) | |||
| } | |||
| val footer = StringBuilder(" </table> ") | |||
| return tableStarter.toString() | |||
| } | |||
| private fun createEmailRequest(content: String, emailTo: List<String>) { | |||
| // val subject = settingsService.findByName(SettingNames.TIMESHEET_MAIL_SUBJECT).orElseThrow().value | |||
| // val template = settingsService.findByName(SettingNames.TIMESHEET_MAIL_TEMPLATE).orElseThrow().value | |||
| // val cc = settingsService.findByName(SettingNames.TIMESHEET_MAIL_CC).orElseThrow().value.split(",") | |||
| // val bcc = settingsService.findByName(SettingNames.TIMESHEET_MAIL_BCC).orElseThrow().value.split(",") | |||
| val mailRequest = MailRequest.Builder() | |||
| // .subject(subject) | |||
| // .templateContent(template) | |||
| .args( | |||
| mapOf( | |||
| Pair("date", content), | |||
| ) | |||
| ) | |||
| .addTo(emailTo) | |||
| // .addCc(cc) | |||
| // .addBcc(bcc) | |||
| .build() | |||
| val mailRequestList = mutableListOf<MailRequest>() | |||
| mailRequestList += mailRequest | |||
| mailService.send(mailRequestList) | |||
| } | |||
| } | |||
| @@ -0,0 +1,47 @@ | |||
| package com.ffii.fpsms.modules.common.mail.service | |||
| import com.ffii.fpsms.modules.common.MailSMTP | |||
| import com.ffii.fpsms.modules.settings.service.SettingsService | |||
| import org.springframework.mail.javamail.JavaMailSender | |||
| import org.springframework.mail.javamail.JavaMailSenderImpl | |||
| import org.springframework.stereotype.Service | |||
| import java.util.* | |||
| @Service | |||
| open class MailSenderService(private val settingsService: SettingsService) { | |||
| private var sender: JavaMailSender? = null | |||
| private var mailConfigCachs: MailSMTP? = null | |||
| open fun get(): JavaMailSender { | |||
| val config = MailSMTP(settingsService) | |||
| if (this.sender == null || (mailConfigCachs == null) || !config.equals(this.mailConfigCachs)) { | |||
| this.mailConfigCachs = config | |||
| val sender = JavaMailSenderImpl() | |||
| val props = Properties() | |||
| val auth = config.auth ?: false | |||
| if (auth) { | |||
| props["mail.smtp.timeout"] = "20000" | |||
| props["mail.smtp.connectiontimeout"] = "10000" | |||
| } | |||
| props["mail.smtp.auth"] = auth | |||
| // The below setting needs to be included when the SMTP has TLS Version | |||
| // props["mail.smtp.starttls.enable"] = "true" | |||
| // props["mail.smtp.ssl.protocols"] = "TLSv1.2" | |||
| sender.host = config.host | |||
| sender.port = config.port!! | |||
| if (auth) { | |||
| sender.username = config.username | |||
| sender.password = config.password | |||
| } | |||
| sender.javaMailProperties = props | |||
| this.sender = sender | |||
| } | |||
| return this.sender ?: JavaMailSenderImpl() | |||
| } | |||
| } | |||
| @@ -0,0 +1,215 @@ | |||
| package com.ffii.fpsms.modules.common.mail.service | |||
| import com.ffii.core.exception.InternalServerErrorException | |||
| import com.ffii.core.utils.LocaleUtils | |||
| import com.ffii.fpsms.modules.common.ErrorCodes | |||
| import com.ffii.fpsms.modules.common.SettingNames | |||
| import com.ffii.fpsms.modules.common.mail.pojo.MailRequest | |||
| import com.ffii.fpsms.modules.common.mail.web.models.MailSave | |||
| import com.ffii.fpsms.modules.settings.entity.Settings | |||
| import com.ffii.fpsms.modules.settings.entity.SettingsRepository | |||
| import com.ffii.fpsms.modules.settings.service.SettingsService | |||
| import freemarker.cache.StringTemplateLoader | |||
| import freemarker.template.* | |||
| import jakarta.mail.MessagingException | |||
| import jakarta.mail.internet.InternetAddress | |||
| import org.apache.commons.logging.Log | |||
| import org.apache.commons.logging.LogFactory | |||
| import org.springframework.core.io.ByteArrayResource | |||
| import org.springframework.mail.javamail.MimeMessageHelper | |||
| import org.springframework.scheduling.annotation.Async | |||
| import org.springframework.security.crypto.password.PasswordEncoder | |||
| import org.springframework.stereotype.Service | |||
| import org.springframework.ui.freemarker.FreeMarkerTemplateUtils | |||
| import java.io.IOException | |||
| import java.text.ParseException | |||
| import java.util.* | |||
| @Service | |||
| open class MailService( | |||
| private val mailSenderService: MailSenderService, | |||
| private val freemarkerConfig: Configuration, | |||
| private val settingsService: SettingsService, | |||
| private val passwordEncoder: PasswordEncoder, | |||
| private val settingsRepository: SettingsRepository, | |||
| ) { | |||
| protected val logger: Log = LogFactory.getLog(javaClass) | |||
| @Throws( | |||
| MessagingException::class, | |||
| TemplateNotFoundException::class, | |||
| MalformedTemplateNameException::class, | |||
| ParseException::class, | |||
| IOException::class, | |||
| TemplateException::class | |||
| ) | |||
| open fun doSend(mailRequests: List<MailRequest>, locale: Locale) { | |||
| val sender = mailSenderService.get() | |||
| for (mailRequest in mailRequests) { | |||
| val mimeMessage = sender.createMimeMessage() | |||
| val helper = MimeMessageHelper(mimeMessage, true, "UTF-8") | |||
| mailRequest.subject?.let { helper.setSubject(it) } | |||
| var template: Template? = null | |||
| if (mailRequest.template != null) { | |||
| template = try { | |||
| freemarkerConfig | |||
| .getTemplate((mailRequest.template + "_" + LocaleUtils.toLocaleStr(locale)) + ".ftl") | |||
| } catch (e: TemplateNotFoundException) { | |||
| freemarkerConfig.getTemplate(mailRequest.template + ".ftl") | |||
| } | |||
| } else { | |||
| // Create a FreeMarker configuration | |||
| val configuration = Configuration(Configuration.VERSION_2_3_32) | |||
| // Create a template loader and add the template content | |||
| val templateLoader = StringTemplateLoader() | |||
| templateLoader.putTemplate("myTemplate", mailRequest.templateContent) | |||
| configuration.templateLoader = templateLoader | |||
| try { | |||
| // Get the template by name | |||
| template = configuration.getTemplate("myTemplate") | |||
| } catch (e: IOException) { | |||
| // Handle any IO exceptions | |||
| } | |||
| } | |||
| helper.setText( | |||
| FreeMarkerTemplateUtils.processTemplateIntoString(template!!, mailRequest.args), | |||
| true | |||
| ) | |||
| val from: InternetAddress?; | |||
| if (mailRequest.from != null) { | |||
| helper.setFrom(mailRequest.from!!) | |||
| from = mailRequest.from | |||
| } else { | |||
| helper.setFrom(settingsService.getString(SettingNames.MAIL_SMTP_USERNAME)) | |||
| from = InternetAddress(settingsService.getString(SettingNames.MAIL_SMTP_USERNAME)) | |||
| } | |||
| if (mailRequest.priority != null) helper.setPriority(mailRequest.priority!!) | |||
| if (mailRequest.replyTo != null) helper.setReplyTo(mailRequest.replyTo!!) | |||
| if (mailRequest.to.isNotEmpty()) helper.setTo( | |||
| mailRequest.to.toTypedArray() | |||
| ) | |||
| if (mailRequest.cc.isNotEmpty()) helper.setCc( | |||
| mailRequest.cc.toTypedArray() | |||
| ) | |||
| if (mailRequest.bcc.isNotEmpty()) helper.setBcc( | |||
| mailRequest.bcc.toTypedArray() | |||
| ) | |||
| if (mailRequest.attachments.isNotEmpty()) { | |||
| for ((key, value) in mailRequest.attachments.entries) { | |||
| helper.addAttachment(key, ByteArrayResource(value)) | |||
| } | |||
| } | |||
| if (from != null) { | |||
| sender.send(mimeMessage) | |||
| } | |||
| } | |||
| } | |||
| @Throws(ParseException::class) | |||
| fun send(mailRequests: List<MailRequest>, locale: Locale) { | |||
| try { | |||
| doSend(mailRequests, locale) | |||
| } catch (e: MessagingException) { | |||
| throw InternalServerErrorException(ErrorCodes.SEND_EMAIL_ERROR, e) | |||
| } catch (e: IOException) { | |||
| throw InternalServerErrorException(ErrorCodes.SEND_EMAIL_ERROR, e) | |||
| } catch (e: TemplateException) { | |||
| throw InternalServerErrorException(ErrorCodes.SEND_EMAIL_ERROR, e) | |||
| } | |||
| } | |||
| @Throws(ParseException::class) | |||
| fun send(mailRequests: List<MailRequest>) { | |||
| send(mailRequests, LocaleUtils.getLocale()) | |||
| } | |||
| @Throws(ParseException::class) | |||
| fun send(mailRequest: MailRequest, locale: Locale) { | |||
| send(mutableListOf(mailRequest), locale) | |||
| } | |||
| @Async | |||
| @Throws(ParseException::class) | |||
| open fun asyncSend(mailRequests: List<MailRequest>, locale: Locale) { | |||
| try { | |||
| doSend(mailRequests, locale) | |||
| } catch (e: MessagingException) { | |||
| logger.error("send email error", e) | |||
| } catch (e: IOException) { | |||
| logger.error("send email error", e) | |||
| } catch (e: TemplateException) { | |||
| logger.error("send email error", e) | |||
| } | |||
| } | |||
| @Async | |||
| @Throws(ParseException::class) | |||
| open fun asyncSend(mailRequest: MailRequest, locale: Locale) { | |||
| asyncSend(mutableListOf(mailRequest), locale) | |||
| } | |||
| @Async | |||
| @Throws(ParseException::class) | |||
| open fun asyncSend(mailRequests: List<MailRequest>) { | |||
| asyncSend(mailRequests, LocaleUtils.getLocale()) | |||
| } | |||
| @Async | |||
| @Throws(ParseException::class) | |||
| open fun asyncSend(mailRequest: MailRequest) { | |||
| asyncSend(mutableListOf(mailRequest)) | |||
| } | |||
| open fun saveMail(mailSave: MailSave): List<Settings> { | |||
| // ------------------ save mail settings ------------------ // | |||
| val settings = mutableListOf<Settings>() | |||
| mailSave.settings.forEach { setting -> | |||
| val tempSetting = settingsRepository.findById(setting.id).orElseThrow() | |||
| settings += tempSetting.apply { | |||
| value = setting.value | |||
| } | |||
| } | |||
| // ------------------ save timesheet mail details ------------------ // | |||
| val mailCc = settingsRepository.findByName("TIMESHEET.mail.cc").orElseThrow() | |||
| settings += mailCc.apply { | |||
| value = mailSave.template.cc | |||
| } | |||
| val mailBcc = settingsRepository.findByName("TIMESHEET.mail.bcc").orElseThrow() | |||
| settings += mailBcc.apply { | |||
| value = mailSave.template.bcc | |||
| } | |||
| val mailSubject = settingsRepository.findByName("TIMESHEET.mail.subject").orElseThrow() | |||
| settings += mailSubject.apply { | |||
| value = mailSave.template.subject | |||
| } | |||
| val mailTemplate = settingsRepository.findByName("TIMESHEET.mail.template").orElseThrow() | |||
| settings += mailTemplate.apply { | |||
| value = mailSave.template.template | |||
| } | |||
| // ------------------ save all ------------------ // | |||
| settingsRepository.saveAll(settings) | |||
| return settings | |||
| } | |||
| } | |||
| @@ -0,0 +1,27 @@ | |||
| package com.ffii.fpsms.modules.common.mail.web | |||
| import com.ffii.fpsms.modules.common.mail.service.MailReminderService | |||
| import com.ffii.fpsms.modules.common.mail.service.MailService | |||
| import com.ffii.fpsms.modules.common.mail.web.models.MailSave | |||
| import com.ffii.fpsms.modules.settings.entity.Settings | |||
| import com.ffii.fpsms.modules.settings.service.SettingsService | |||
| import jakarta.validation.Valid | |||
| import org.springframework.web.bind.annotation.* | |||
| @RestController | |||
| @RequestMapping("/mails") | |||
| class MailController( | |||
| private val settingsService: SettingsService, | |||
| private val mailService: MailService, | |||
| private val mailReminderService: MailReminderService, | |||
| ) { | |||
| @GetMapping("/setting") | |||
| fun mailSetting(): List<Settings> { | |||
| return settingsService.findAllByCategory("MAIL") | |||
| } | |||
| @PostMapping("/save") | |||
| fun saveMail(@Valid @RequestBody mailSave: MailSave): List<Settings> { | |||
| return mailService.saveMail(mailSave) | |||
| } | |||
| } | |||
| @@ -0,0 +1,21 @@ | |||
| package com.ffii.fpsms.modules.common.mail.web.models | |||
| data class Setting ( | |||
| val id: Long, | |||
| val name: String, | |||
| val value: String, | |||
| val category: String, | |||
| val type: String, | |||
| ) | |||
| data class Template ( | |||
| val cc: String?, | |||
| val bcc: String?, | |||
| val subject: String, | |||
| val template: String?, | |||
| ) | |||
| data class MailSave ( | |||
| val settings: List<Setting>, | |||
| val template: Template | |||
| ) | |||
| @@ -0,0 +1,9 @@ | |||
| package com.ffii.fpsms.modules.common.mail.web.models | |||
| import java.time.LocalDate | |||
| data class WorkHourRecords( | |||
| val staffId: Long, | |||
| val recordDate: LocalDate, | |||
| val hours: Double, | |||
| ) | |||
| @@ -1,5 +1,6 @@ | |||
| package com.ffii.fpsms.modules.settings.entity; | |||
| import java.util.List; | |||
| import java.util.Optional; | |||
| import org.springframework.data.repository.query.Param; | |||
| @@ -9,4 +10,6 @@ import com.ffii.core.support.AbstractRepository; | |||
| public interface SettingsRepository extends AbstractRepository<Settings, Long> { | |||
| Optional<Settings> findByName(@Param("name") String name); | |||
| List<Settings> findAllByCategory(@Param("category") String category); | |||
| } | |||
| @@ -5,6 +5,7 @@ import java.time.LocalDateTime; | |||
| import java.time.LocalTime; | |||
| import java.time.format.DateTimeFormatter; | |||
| import java.time.format.DateTimeParseException; | |||
| import java.util.List; | |||
| import java.util.Optional; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| @@ -29,6 +30,10 @@ public class SettingsService extends AbstractIdEntityService<Settings, Long, Set | |||
| return this.repository.findByName(name); | |||
| } | |||
| public List<Settings> findAllByCategory(String category) { | |||
| return this.repository.findAllByCategory(category); | |||
| } | |||
| public boolean validateType(String type, String value) { | |||
| if (StringUtils.isBlank(type)) return true; | |||
| @@ -0,0 +1,13 @@ | |||
| -- liquibase formatted sql | |||
| -- changeset cyril:settings | |||
| INSERT INTO settings (id,name,value,category,`type`) | |||
| VALUES (7,'MAIL.smtp.host','smtp.office365.com','MAIL','string'); | |||
| INSERT INTO settings (id,name,value,category,`type`) | |||
| VALUES (8,'MAIL.smtp.port','587','MAIL','integer'); | |||
| INSERT INTO settings (id,name,value,category,`type`) | |||
| VALUES (9,'MAIL.smtp.username','','MAIL','string'); | |||
| INSERT INTO settings (id,name,value,category,`type`) | |||
| VALUES (10,'MAIL.smtp.password','','MAIL','string'); | |||
| INSERT INTO settings (id,name,value,category,`type`) | |||
| VALUES (11,'MAIL.smtp.auth','false','MAIL','boolean'); | |||